1 / 45

Planning for Complexity in Game Development

Yaser Zhian Dead Mage TGF 92, August 15 th , 2013. Planning for Complexity in Game Development. What This Is About. The things that you should do at the beginning of a game (or similar) project to simplify debugging, adding features, optimization, build and release.

vina
Download Presentation

Planning for Complexity in Game Development

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Yaser Zhian Dead Mage TGF 92, August 15th, 2013 Planning for Complexity in Game Development

  2. What This Is About • The things that you should do at the beginning of a game (or similar) project to simplify debugging, adding features, optimization, build and release. • We are talking about the technical and code aspect of this problem, but some of the ideas are generalizable to the rest of the team. • I can only give you some tips, not a streamlined process. That's your job. http://yaserzt.com/

  3. Audience • This is targeted towards programmers and managers in small to medium-sized teams. • More specifically, those that are developing their own tech, using C++. • There is nothing here out of the common sense. If you are looking for some dark “magick”, look somewhere else. http://yaserzt.com/

  4. Complexity • You have a limited capacity for handling complexity. • It’s a hydra; a thousand-head monster that grows two heads each time you cut off one. • Game developers face more complexity than most other people. • Everything is a trade-off; you trade simplicity for performance for functionality for your sanity. • And there are no silver bullets • … but maybe I can offer some aluminum pellets! http://yaserzt.com/

  5. Process, Process, Process (1/5) • do { Conceptualize; Build; Import; Integrate; Test;} while (0 == 0); • Iteration time is the most important factor in game development process. http://yaserzt.com/

  6. Process, Process, Process (2/5) • Ideally, you should never have to exit the game to change anything (code, assets, configuration, scripts,...) • More realistically, you should never have to exit the game to change anything except for code. • But iteration time is about more than that… http://yaserzt.com/

  7. Process, Process, Process (3/5) • Data-driven design and code is king. • Keep engineers out of the loop. Seriously! • Design your process so you “block” as little as possible. • Code reviews are good things (even informal.) • Agile philosophy is fantastic for small game developers. • But be aware of “Technical Debt” when just implementing and going forward. http://yaserzt.com/

  8. Process, Process, Process (4/5) • Automate as much as you can, as early as possible, and keep adapting. Tools, tools, tools! • Even small batch files (or shell scripts, if you prefer) can go a long way. • … not to mention, act as some kind of documentation. • A good automation language should have easy and powerful file and directory handling, text and regex manipulation, network facilities, etc. out of the box. • Source control, asset control, versioning, branches, tags, issue tracking and burndownare not just fancy words. http://yaserzt.com/

  9. Process, Process, Process (5/5) • Transparency: to know what’s going on • Discoverability: to be able to fix it when things go wrong (as they inevitably will…) • Remember: in game development, the first (and sometime only) user is the developer. Design your process, tools, tech, etc. accordingly. • Beware of the “Bus Factor”! http://yaserzt.com/

  10. Knowledge • Knowledge is power; if you don’t know what’s going on in your pipeline and engine, then who does?! • From the highest level to the lowest: • From how many characters, levels, items, etc. you have • and how many files, models, textures, etc. • to where each millisecond of each frame is spent • and who uses each kilobyte of memory • The more you know, the more you can do. http://yaserzt.com/

  11. Naming and Directory Structure (1/2) • A name is a unifying concept. Helps develop common views and more efficient and less error-prone communication. • ??? (No one knows what you need.) • Need to fulfill at least two criteria: • Guess the function of an object based on its name • Find the object you are looking for among similar “things” http://yaserzt.com/

  12. Naming and Directory Structure (2/2) • When choosing a name, consider how that name looks to these entities: • Yourself, in 6 months • Other people • Scripts and tools • Consistent (pancake vs. flapjack!) • Sortable (mmddyyyy vs. ddmmyyyy vs. yyyymmdd vs. yymd) • Please, spell correctly! http://yaserzt.com/

  13. Build System (1/4) • Automatic, quick, configurable, dependable, minimal. • Think about header and source layout, very carefully and very deliberately. • The compiler is your friend. Each compile-time error is potentially one less runtime or logical error you'd have to chase down. • Ideally, wrong code (or assets) should not compile. • Static assertion, type traits, “concepts”, template meta-programming, type system design, etc.) http://yaserzt.com/

  14. Build System (2/4) • Code build time is important. Make it as short as possible. • Plan the dependencies (inside your code.) • Use precompiled headers. • Modularize your code (into libraries.) • Use abstract interfaces (but consider the performance costs of polymorphism.) • Eliminate unnecessary inter-class dependencies. • Use forward definitions. http://yaserzt.com/

  15. Build System (3/4) • Build variations: • Full debug • Optimized debug • Profiled release • Developer release (with debug information) • Retail • and a couple more... http://yaserzt.com/

  16. Build System (4/4) • Strive to have a build that is always: • Playable • Performant • Progressing • In Memory • Stable http://yaserzt.com/

  17. That ephemeral sorcery we call Code http://yaserzt.com/

  18. Decisions to be Made • Coding Style • To OOP or not to OOP... • Concurrency and data sharing strategies • Exceptions • RTTI • Templates vs. Polymorphism • Smart pointers vs. Handles vs. Raw pointers • RAII • Lifetime and Ownership Management (and a bag full of problems) • Intrusive code instrumentation • String format • and much more... http://yaserzt.com/

  19. Performance • Premature optimization is the root of all evil, • But… • Writing high-performance code is an uphill battle; miss a step and you end up at the bottom. • Misarrange your data structures and you are in the 2-frames-per-second limbo forever. • Data (and by association, memory) is the most important factor in performance. http://yaserzt.com/

  20. Love Thy Compiler (1/2) • Use everylittle obscure compiler and platform facility that can possibly help. • But wrap them up, even if you don't care about portability (in case of a change in compilers/libraries, or if you want to disable a feature, etc.) • Don't be afraid of assembly. Learn to read through what your compiler produces. Love doesn't necessarily imply trust! http://yaserzt.com/

  21. Love Thy Compiler (2/2) • Learn about compiler #pragmas and intrinsics. • Use intrinsics instead of inline assembly, because asm usually hinders compiler optimizations. • Learn about pointer aliasing, restricted pointers and every other hint that you can give the compiler (including const) to produce better (faster) code. • Learn about your machine architecture and OS idiosyncrasies. http://yaserzt.com/

  22. Type System (1/5) • Consider implementing your own containers (STL can be too frivolous with memory.) • Plan for type metadata and reflection. • Try not to use common type keywords (int, short, float, etc.) Typedef them all. • i32, u32, i16, u64, i8, u8, byte, ch8, ch16, ... • f32, f64, v128 • ..or use <stdint.h>, (actually, <cstdint>) which is a standard header. http://yaserzt.com/

  23. Type System (2/5) • For types that are equal physically, but not semantically, e.g. • angles in degrees and radians • time in seconds and milliseconds • normalized vectors and general vectors • “Hungarian Notation” can help (commonly misapplied, e.g. in Win32 headers and docs) • degAngle = radAngle; is most probably wrong and the good thing is that it indeed looks WRONG. http://yaserzt.com/

  24. Type System (3/5) • Better yet, use different classes with no assignment operators (or at least correct ones.) • There would be no (implicit) conversion from float to Degree or Radian, • So, code like Rotate(45.0f) won’t compile • You’d have to write Rotate(Degree(45)). • The constructors and conversion operators for Degree and Radian classes will do the correct multiplication. http://yaserzt.com/

  25. Type System (4/5) • It can also help with performance in some cases: • If you have Vector3 and NormalizedVector3 classes, you can overload on them and save a normalization while keeping the same external interface:void Do (NormalizedVector3 v) {// You know the vector is normalized...}voidDo (Vector3v) {DoSmthng (normalize(v));} http://yaserzt.com/

  26. Type System (5/5) • Strings: • ASCII is dead (mostly.) • At least differentiate between these usages: • File names and paths. • User input and text shown to the user. • Internal entity names, IDs and the like. • Text file and script contents, etc. • And more. • Realize that some strings are (mostly) constant during their lifetime. (Optimization opportunity!) http://yaserzt.com/

  27. Pointers (1/2) • Don't use T* to represent a pointer to T. At least typedef something like TPtr and use that instead (or Ptr<T>.) • But consider the loss of transparency you incur when using TPtr instead if T*. • Don't use T* to represent an array. Use a struct with size information (templated for arrays with known sizes at compile-time, or a member size_t (or smaller data if suitable) if not.) • Or better yet, use std::array<T>. http://yaserzt.com/

  28. Pointers (2/2) • NULL, nullptr, the integer 0 and '\0'are different things; don’t use them interchangeably. • NULLis not the only invalid pointer value (0xcdcdcdcd, 0xcafebabe, 0xdeadc0de, …) Don't use comparison with NULL to detect this. Use an inlined function or a macro. • Don't just use NULLto pass optional values around. You can use std::optional (from C++14,) boost::optional, or write your own. http://yaserzt.com/

  29. Standard Library Independence • File Handling and asynchronous I/O • Directory handling • Random numbers • Math • Time handling • ... http://yaserzt.com/

  30. Debugging • Consider the idea that the purpose of writing code is not running it. Write code for debugging. • Logging • Assertion • Context metadata • Crash handling and crash dump • Visualizing data http://yaserzt.com/

  31. Logging • Do notoverwhelm! • Collect as much as possible, show as little as needed. • A good logging library should be: • runtime controllable • able to send logs to multiple targets • able to filter what is sent where based on audience, source, target, etc. • fast, fast, fast • as non-intrusive as possible • Employed from day 0. http://yaserzt.com/

  32. Assertion • You do use them, don't you? • Chances are, you are doing it wrong anyways! • Never use the standard assert. • Assert whenever you can, but nowhere you shouldn't. (Hint: don't assert when a configuration file is not found; make a new one!) • Assert-and-repair http://yaserzt.com/

  33. Context Metadata • Should be totally and partially disable-able. • Including, but not limited to: • Machine name, user name, code revision, build number, build parameters, time, environment, frame number, etc. • Where does the execution flow come from? (Stack trace) • Where are we now? File, line, function, instance. • Which subsystem called this piece of code? Graphics? AI? Animation? Sound? • Why did it call this? Was it initializing? Loading data? Looking for a collision? Walking the scene graph? Visiting AI actors? • How long did the function take to execute and how many times was it called in this frame? How many memory allocations did it perform? • … (use your imagination!) http://yaserzt.com/

  34. Crash Handling and Crash Dump • If you have to fail, fail as soon as possible and as loud as possible. • Gather as much data as you possibly can: place, time, what happened before and was going to happen after, context, hardware environment, software environment, user settings, etc. • Use a “Black Box” type construct. Collect some data all the time, but store it only when crashing. • Automatically submit this info to your issue tracker (during dev) or emailing it to your team (after release.) http://yaserzt.com/

  35. Visualizing Data • There is much more going on in a game than graphics (which can be seen already.) • Lots of data involved. • No clear picture from mere numbers. • Hard to understand in a single slice of time. • Add visual representations for non-visual objects: physics, bounding volumes, AI algorithms, behavioral decisions, etc. • Real-time graphs and bars too! http://yaserzt.com/

  36. Memory (1/2) • Neveruse naked new/delete in real code. • Never everuse naked new/deletein real code! • Write your own memory manager, even if it is just a wrapper over new/delete. • Don't forget malloc() and friends. • Don't forget third-party libraries. • Always be conscious about who uses how much memory. Always. http://yaserzt.com/

  37. Memory (2/2) • Always override the memory management in third party libraries (including STL) unless you have reason not to. • Writing a memory bug detector is quite easy. Write one or find one. • Memory allocation is usually a source of performance bottlenecks as well as bugs. • If you think garbage collection is the panacea for your problems, think again. http://yaserzt.com/

  38. In-Game Console • Useful for debugging and interactive experimentation. • Tied-in to the scripting system. • Make it like a good OS shell. • Can think about it as a higher-level debugger (inter-object relationships, etc.) • Give access to everything you can, but consider that the designers and artists will have to use it too. http://yaserzt.com/

  39. Serialization • Useful for much more than saving/loading or network communication. • Template magic? Some form of IDL? Übermacros? • Consider two interchangeable formats: one optimized binary and one human readable. • Make everything you can serializable. • Consider interactions with source control. • Plan for evolution of data structures over the course of development. http://yaserzt.com/

  40. Runtime Asset Management • Everything other than code that constitutes the game. • Consider going beyond simple files. • Consider treating asset management more like writing a DBMS, than a file system. • Consider integrating asset fingerprinting, change management, versioning, change detection, hot reloading, etc. • Consider asynchronous operations. http://yaserzt.com/

  41. Time • Do notunderestimate time management. • Never just use direct calls to OS to get the time for game subsystems. • Familiarize yourself with higher-resolution timers (RDTSC, QueryPerformanceCounter(), clock_gettime(), ...) • Familiarize yourself with multi-core issues, power management issues, Windows issues(!), user issues,... • Consider the difference between wall clock, game clock, camera clock, level clock, animation clock, etc. • The more time you put in time, the better the times you'll have when the time of debugging time comes! http://yaserzt.com/

  42. Screen Capture and Game Replay • Capturing still images is a must. • Capturing video is a big plus. • Capturing metadata (DEM files, anyone?) to be able to replay a scenario is a huge plus. • The game replay subsystem can be implemented with varying levels of complexity and functionality. Even a simple system can have considerable benefits. http://yaserzt.com/

  43. Runtime Statistics • Please invest in this! • You must know your own game. This is one very good way. • Anything from frame-rate and tri-count to number of memory allocations and file accesses per frame, per second or per-level. • Find interesting ways to display these data. http://yaserzt.com/

  44. Automated Testing • Full unit testing is the Holy Grail! • Testing of games and features is usually very time consuming. Any automation helps. • Any change in code or assets can have undesired side-effects: regression testing. • You can even have automatic screen-shot comparisons! • Auto test non-visual parts, if you can't manage more sophisticated methods. http://yaserzt.com/

  45. Contact us at http://deadmage.com/ And me at yaserzt@gmail.com "I know that you believe that you understood what you think I said, but I am not sure you realize that what you heard is not what I meant.” Any questions?

More Related