GD - 4th - Game Architecture


Published on

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Bad architectures create problems, and often you will end up solving the wrong problem in order to work around the architecture.
    Why is this?
    Bad architecture can produce a lot of side affects. Code that affects lots of systems synchronously can sometimes do really weird things you weren’t expecting, causing hard to trace bugs.
    Bad architectures are hard to follow, especially when you’re not stepping through the code because you don’t necessarily know what will call what, or what side effects will occur based on a single function call.
    As a result, bad architectures are hard to debug. There’s lots of things to step into and trace before you can find the root of the problem.
    Bad architectures are also very hard to reuse, since ripping out any one given system to use somewhere else (or replace in the current game) can cause a very large number of side effects
    Generally, near the end of projects you will spend more time debugging and trying to find a way around the architecture in order to fix an issue than you will actually fixing the issue. And even then your fix may not actually solve the problem, or may create more.
    Known as the OMG HAX syndrome.
  • Fortunately, following the principles of OOP will improve the mess
    We’re going to spend a bit of time talking about some of the principles of OOP you probably take for granted
    Though not principles of OOP, principles of good design will also help us create a well architected engine.
    Coupling is the degree to which modules rely on each other
    The $10 word here is ortogonality, which isn’t actually a word
    “is a system design property which facilitates the making of complex designs feasible and compact “ - Wikipedia
  • Encapsulation is a principle we take for granted
    Remember that encapsulation is not just data hiding, though they are closely related. It means that data, and the processes to edit that data are kept together.
    Encapsulation implies that an object should be a cohesive whole
    Which also means that it should do one thing and ONLY one thing.
    Any modification from classes outside itself increases coupling, and introduces side effects
    It also implies that instances of the same class should not edit each others
  • Encapsulation should also be applied between instances
    By editing the state of an object outside it’s own scope, you can introduce a layer of hidden coupling, not necessarily between systems but between objects in the same systems, and between instances of the same object
    This may not sound bad, but it can produce some seriously mean side effects as you move forward with developing your engine.
    It also makes concurrency harder, since editing instances of the same objects means they can’t be parallelized.
    You always want to design for concurrency.
    Which means objects should always be in a valid state before and after a function call.
    Instances should always edit each other through function calls, or better, message passing, which we’ll get to.
  • Inheritance is frequently overused.
    It tightly couples the child to the parent, and all things that use the child to the parent. It’s often an invisible form of coupling you don’t want.
    It is usually used to reuse code, a place where it is usually not welcome.
    Inheriting to reuse code usually means you’re actually looking at a containment relationship. A “has a” relationship if you will.
    But it is important to understand inheritance should only be used not where you want to reuse code, but where an object needs to be reused under difference circumstances.
    Interfaces are probably the best example of this
    Frequently told inheritance is an “is a” relationship. That if something “is” something else, than you’re looking at inheritance. This is not necessarily true.
    If something “is” something else, but will never be used like that something else, there is no reason to inherit.
    So we run into the “is a” vs. “has a” vs. “needs to be used as a” relationship. Know which one you’re working with.
    Anthoer way to think of it is “Extends the functionality of…”
    But remember, you may not need all of the functionality of the base class, so make sure you’re using it under the right circumstances.
    Remember, large inheritance degrades performance silently, and other architectures can do similar things with less overhead, and more flexibility
    Components are my personal favorite.
    Flexibility is offered in that you can always add random components (at compile time or at run time) to any class you want.
    In the last point, we can protect and control the data of a single component far easier than we can on a class with an inheritance tree.
    Changes can be made at any point in the tree, which makes things difficult
    Although components are my personal favorite, you’ll find they don’t solve all problems. Remember, there are no magic bullets.
    This is a best practice (which we’ll get to) not a steadfast rule. Use the rules where you think they’re needed, just be careful you’re not overusing anything.
  • Polymorphism probably doesn’t deserve it’s own slide. It’s an important concept to OOP, especially as it relates to inheritance, but not hugely important to this architecture talk, which is more about relationships between classes.
    There are two ways polymorphism can go.
    Readable. For example math operations on matricides that can take integers, floats, and other matricies.
    Unreadable. For example Damage functions on your creatures that can take both Creatures and Bullets. (well if the player shot the bullet, which one do I use again?)
  • How many people have heard of design patterns?
    How many people can name a few?
    Singleton, Factory, Façade, Proxy, Model / View / Controller, Iterator, Command, Observer / Listener, Chain of Responsibility
    Singleton is a favorite, and it’s where we’ll start
  • Creational pattern (meaning it describes how an object gets created)
    Usually Instance() will create the object if it doesn’t exist, and holds onto it via a static member pointer
    A singleton is usually being used as a global, and globals wreak havoc on encapsulation and concurrency
    But if you’re working with a single instance of something that isn’t easily contained in another class, a singleton is better than a global for various reasons, including their portability into factories
    1 instance per thread constructions
    Swapping constructions (get an instance that is currently viable)
    Control whether instances can be allocated
    Always avoid the “static class” a class where all members are static. These are just bad ideas, since they’re so hard to change

  • Behavioral pattern means it changes the way things behave (other examples are Command and Chain of Responsibility)
    Already you can see reduced coupling because the subject doesn’t need to know what the subjects are, or where they are, or even if they exist at all.
    Furthermore, listeners don’t need to even know what subject they’re listening to, just that they’ll be informed if they need to change.
  • Not in Design Patterns
    Probably my favorite pattern, since it illustrates a key point in design: Data and representation of that data are separate.
    CSS in web development
    Code behinds in ASP.NET and XAML

  • The idea here is to completely separate the visual identity of the creature from its thought process
    (It has an image problem)
    Also, you make sure the view is only asking the model for data, not the other way around.
    The model shouldn’t care what is happening in renderer land
    The second may look more complicated, but it has advantages.
    We can add more views of the same model, which is an easy way to do radar systems and maps.
    We can completely remove the view and have a completely working AI system, which can think either off screen, or even on a separate computer, without ever being rendered.

  • For more information, read Design Patterns
    Command is probably the one I use most of these three.
    Allows you to easily support macros (see the composite pattern) as well as undo opperations
    They’re great for input handlers (bind keys to command creation functions via a map) as well as for any undoable operation.
    The others are included just because you might want to sound smart one day.
  • Best practices are a management idea (but we won’t hold that against it)
    It’s the idea that there is a way of doing things that will produce the results you want faster and more efficiently than other methods of doing the same thing.
    For programmers, it’s something that’s not standardized (or written in the coding standards of your company) but following it tends to lead to good code, well architected systems, and things that are easy to change without side effects.
    Basically, you don’t have to do these, but they tend to be good ideas.
    They’re like design patterns in that, people found that certain practices led to bad results, and that doing things in a certain way would keep these things from happening.
    I recommend two books on the subject
    These are my personal favorites, but there are others including Effective C++, Effective C#, Effective STL, etc.
  • Know when to refactor.
    Refactoring is a general term for taking the same functionality and making it better. This includes redesigns and simple changes to pull out common code into funciton calls.
    If functions or classes are becoming monolithic, it’s time to think about where things may be split up.
    Refactoring doesn’t necessarily change the external interface, but the internal workings
    Know when to rearchitect
    Rearchitecting is technically refactoring, but in my mind, it’s going back to the drawing board because things just aren’t working right
    If you can, rearchitecting should be done in stages, so you’re always left with working code.
    Both refactoring and rearchitecting are there to improve your engine, but they’ll break lots of things along the way.
    They will ALWAYS break things along the way.
    Get into the habit of the TDD cycle (even if you’re not doing TDD).
    Always make sure your previous functionality is still working before moving on.
  • GD - 4th - Game Architecture

    1. 1. Game Architecture : wanna play a good game ? [ Wijanarko Sukma . Department of Informatics ]
    2. 2. Taken from the Presentation slide of : Jeff Ward Associate Programmer Bethesda Game Studios [ Wijanarko Sukma . Department of Informatics ]
    3. 3. How can architecture help us : Concurrency Maintainability Code Ownership Usability Performance Stability Architecture [ Wijanarko Sukma . Department of Informatics ]
    4. 4. Bad architecture creates problems Produces side effects Hard to follow Hard to debug Hard to reuse Spend more time finding a way around the architecture than fixing the problem OMG HAX! Bad Architecture [ Wijanarko Sukma . Department of Informatics ]
    5. 5. Stability Reusability Cohesion Orthogonally Why do Architect (Design) [ Wijanarko Sukma . Department of Informatics ]
    6. 6. A well architected system is easy to understand, change, debug, and reuse. [ Wijanarko Sukma . Department of Informatics ]
    7. 7. Principles of OOP (Object Oriented Programming) Design Patterns Best Practices Know this first [ Wijanarko Sukma . Department of Informatics ]
    8. 8. Example Engine [ Wijanarko Sukma . Department of Informatics ] Logic State Data File Loader Output Input
    9. 9. Basics Encapsulation Inheritance Polymorphism Principles of good design Reduced coupling Increased reliability Increased reusability orthogonality OOP Principles [ Wijanarko Sukma . Department of Informatics ]
    10. 10. “Encapsulation is a programming mechanism that binds together code and the data it manipulates, and that keeps both safe from outside interference and misuse.” – Schildt Encapsulation is not just data hiding! Implies each object should be a cohesive whole Encapsulation [ Wijanarko Sukma . Department of Informatics ]
    11. 11. Accessing elements between instances It’s a convenience feature, not a good idea “Always Design for Concurrency” – Tip 41 in The Pragmatic Programmer Even if you don’t need it, a cleaner architecture results. Instance Encapsulation [ Wijanarko Sukma . Department of Informatics ] Creature Creature
    12. 12. Key overused concept of OOP “ Inherit not to reuse, but to be reused.” “Is a” vs. “has a” vs. “needs to used as a” Degrades performance Prefer components over inheritance Cleaner architecture Faster execution time and overhead More flexibility More encapsulated Inheritance [ Wijanarko Sukma . Department of Informatics ]
    13. 13. Important as it relates to inheritance… Just realize that polymorphism goes two ways Readable Unreadable Polymorphism [ Wijanarko Sukma . Department of Informatics ]
    14. 14. Book Design Patterns by “The Gang of Four” (Gamma Helm Johnson Vlissides) The same problems keep coming up in CS We keep solving them in the same (or similar) ways. Is there a pattern here? Intro to Design Patterns [ Wijanarko Sukma . Department of Informatics ]
    15. 15. Creational pattern Only one instance of the object exists Private constructor with public accessor (usually Class::Instance()) Really nice name for a global Often overused, and often not a real solution Singletons translate well to factories Singleton Or “Patterns Don’t Solve all Problems” [ Wijanarko Sukma . Department of Informatics ]
    16. 16. Singletons (or factories) welcome… Renderers Resource managers Memory managers Message queues Singleton Example [ Wijanarko Sukma . Department of Informatics ]
    17. 17. Behavioral pattern Inform multiple dependant objects of changes Usually implemented as Subject and IListener objects Listeners add themselves to subjects When a subject changes, all listeners are notified. Great for message queues Observer / Listener [ Wijanarko Sukma . Department of Informatics ]
    18. 18. Architectural pattern Keeps data and representation separate Model = data, view = representation Controller is what sends messages to the model and view. Advantages One data, multiple views Data manipulates data, and doesn’t care if its being viewed Change renderers without changing anything else MVC Model View Controller [ Wijanarko Sukma . Department of Informatics ]
    19. 19. Separate view from everything else MVC Example [ Wijanarko Sukma . Department of Informatics ] Renderer 3DObj Creature Vs. Creature Model CreatureView Renderer 3DObj CreatureRadarView
    20. 20. Complete decoupling of logic from display Easier to test, since you can watch just the logic Easier to change (both the display and the logic) Can run the view without the logic Can run the logic without the view Can distribute the logic So long as instances are encapsulated Advantages of MVC [ Wijanarko Sukma . Department of Informatics ]
    21. 21. Command An object that represents stuff that should be done, as an object Only needs to understand “Execute” and “Undo” Great for input handlers, macros, and undoable operations Façade Encapsulate an entire system by providing a single coherent interface Proxy A stand in for a concrete object. Other Quick Patterns [ Wijanarko Sukma . Department of Informatics ]
    22. 22. Management idea That there is a technique that is more effective than any other technique at delivering positive results. Something you don’t have to do, but it’s a good idea. They’re like design patterns on a small scale. Best Practices [ Wijanarko Sukma . Department of Informatics ]
    23. 23. Management Best Practices Use version control Do automated testing Have automated builds Coding Best Practices Prefer compile / link time errors to run time errors Give one entity one cohesive responsibility Prefer composition to inheritance Always code for concurrency (in terms of architecture) Examples of Best Practices [ Wijanarko Sukma . Department of Informatics ]
    24. 24. Best Practices Are key to your survival as a coder… … and key to your code’s survival [ Wijanarko Sukma . Department of Informatics ]
    25. 25. Know what you’re doing and why. Know that one approach to inheritance is better and know why. Know when you’re coupling systems inadvertently Know when you’re coupling instances Know when to test Know how to test Know when to automate Some Advices [ Wijanarko Sukma . Department of Informatics ]
    26. 26. Know when to refactor Know when to rearchitect Know that both are going to break everything Final Words [ Wijanarko Sukma . Department of Informatics ]
    27. 27. Game Dev lecturers team By Wijanarko Sukma (5105100173) [ Wijanarko Sukma . Department of Informatics ]