Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

659 Good

About EWClay

  • Rank
  1. Yes. You might for example use a physics engine such as Box 2D. That doesn't stop you having a physics component to handle the connection between physics and game logic, it would just not be responsible for actually updating the physics and would not need to store the physics data.
  2. 1. Split the components even more. For AI I have a pathfinding component, a chase component, an attack component and so on. I don't have a problem with very specific components for certain tasks either, such as a sliding door component. You may be surprised at how easily a complex system can be broken up and how much simpler the design becomes when you do that. 2. Very low level systems such as physics and rendering that need to know about changes immediately should be managing their own data directly (and the components only carry an ID). For the rest I just iterate through the entity list. 3. Yes, share the data outside the component system and make the components distinct. 4. I would not use inheritance within components at all, except perhaps to derive from an abstract base component. The example of a vertex buffer is a poor one also as rendering APIs do not use inheritance in that way. 5. It doesn't matter much whether you use IDs or pointers. For me, pointers are slightly more accessible because you dont need to go back to the system to get at the data. I would use smart pointers at least to avoid the risk of memory leaks or dangling pointers.
  3. EWClay

    OOP Theory

    Then in terms of OOP theory, the design pattern you want is this: http://en.wikipedia.org/wiki/Template_method_pattern SDL_Flip is needed for every game, so factor it out and don't have the (derived) game state class even be aware of it.
  4. Normally you would classify a point such as the camera position as in front of or behind a plane using the plane equation, which will give a distance which is either positive or negative. This is independent of the coordinate system so you need build the BSP tree only once. Don't worry about the efficiency of the test; it is just a dot product and very quick compared to the cost of actually traversing the data.
  5. I've considered using inheritance within components, but always backed off from it, choosing to either use multiple components or to make the distinction in a data-driven way. This is partly because it would require a more complex system to find components. As it is, I can look up components on an entity by type. But with inheritance I would have to check every component to see whether it might derive from the one I was looking for. Then there's the possibility of multiple components of the same base type - which one did I want? This type of confusion is exactly why I went for components over inheritance in the first place.
  6. EWClay

    OOP Theory

    In terms of the basic rendering, I would just have a function to set the screen as a render target, and then functions to render to the current screen. There isn't much reason to link these things together. What do you mean by updating the screen? It's a good idea to have a framework that allows you to plug different sections of the game such as menu screens into the main update/render loop. In this case the call to update would be coming from the application, not the user code.
  7. EWClay

    Archiving C++ objects to JSON

    Last time I talked about serialization of C++ objects to and from an abstract archive format, using a templated interface similar to Boost Serialization. This time I want to get a little more specific and explain how objects can be converted to JSON (http://www.json.org/). It's quite instructive to look at JSON as a format because it maps very well the the way that objects are represented in computer code. Other formats such as XML can do the same job, but in my opinion not in such an elegant and minimal way. JSON has objects (made of key/value pairs), and a few basic types. That's it. Can that possibly be enough? Actually, yes. C++ code has many more ways of representing data, but in terms of actual content you don't need more than JSON provides. To write and parse JSON I wrote my own code, which was not very difficult. But there are many libraries available, such as SimpleJSON. I'll link all my code, including the serialization, archive and parser in a future update. Basic Types JSON has numbers, strings, a boolean type and a null value. These map to C++ types quite easily. All numerical values - integers, floats and doubles become numbers. I treat std::string as a basic type and bool is written as true or false. Objects and Classes JSON doesn't use classes; its objects are self-describing. When writing a C++ object as a JSON object, the keys come from the member names in the class, and the values come from the data in the object. This allows objects to change over time by adding or removing keys. An extra member in the class could be loaded with a default value, or a missing member ignored. What this doesn't allow for is a change of structure, which would have to be dealt with by creating a new object, but for the most part versioning is not necessary with JSON. Arrays and Containers Every C++ container is a sequence of values, so I simply map every C++ container type to a JSON array, whether a vector, list or anything else. I use templated functions to read and write the different container types from the standard library because I prefer to use those to raw arrays. Enums As part of keeping the format readable, I don't want to be writing enums as numerical values. Besides, the value might change in the code and that would make the data invalid (which is more likely than the name changing). So enums are written out as strings, and converted back from a table when loaded. I use some macros to make this neater. Inheritance JSON does not support inheritance. This doesn't matter. In terms of data, a base class is just like another member. I write it out using the name of the base class as the key. Pointers and Polymorphism This is the point where something is really missing, because JSON does not have pointer or reference types. And there's no way I can get away without it because I use polymorphic types in my data, and I need to be able to archive them. In fact, I only use smart pointers so I'm not concerned about how to represent references generically in JSON, but only how to represent a specific type of data object, which is something it is well able to cope with. To begin with I need a way to uniquely identify a type, and I get this from a string identifier which is unique to the class. I add a virtual function (using a macro) to each type that I want to serialize polymorphically. The identifier also has to be registered with the serialization system so that a handler object can be created. The handler is going to instantiate the template functions to read and write the object. (That actually amounts to two lines of extra code per polymorphic type, so nothing major in terms of interface). These polymorphic types can only be written out using smart pointers, which have a templated serialization function. What that does is write out a JSON object containing a unique identifier for the object, (which is the memory address) and the unique identifier for the type (a string) followed by the object itself (but only once per archive in the case of a shared pointer). When reading the object back I know first of all whether it needs to be created (because there may have been a previous reference to it), then I can look up the handler from the type, and then create and read the object. There's a fair amount of factories and templates behind the scenes to make this work. Next steps Does data need to begin its existence in C++? What about creating types outside of the source code, building objects using those definitions, and still being able to access those inside the program. That will be my subject next time.
  8. EWClay

    Where does game play come in?

    You can't treat game logic as totally abstract. Depending on the type of game, you might need a level editor in which you can create arbitrary objects such as trees and squirrels in a totally data driven way, and link them through mechanisms as described in the previous post. Or you might be looking for a scripting system. Is it a very specific case that a squirrel appears? Will there be many different behaviours like that in the game? Writing tree and squirrel classes might make sense if these are very common concepts throughout the game and you always want them to behave the same way. Still, you would want to minimise the responsibility of these classes and make them work as much as possible using other, more generic systems.
  9. EWClay

    OOP Newb: Am I doing this right?

    There's no reason for all those statics in Program. It can just be a class with normal members like any other.
  10. EWClay

    Game data and serialization

    Getting data into a game is a big subject and I want to talk about some of the systems I'm using in some detail, so it may take a few posts to get through it. I will narrow the subject a little first though: this is not going to be about asset loading - textures, meshes, sounds and so on. Rather it's the data that makes up the game itself, so that would be levels, entities, and all the associated information. Since in the game these are C++ objects, there needs to be a mechanism for interacting with such objects in order to save and load them. So the first step is serialization, which is simply the process of translating an object into a stream of data and vice versa. Obviously this is a well studied problem, but still a subtle one. C++ does not provide serialization out of the box. One of the best known solutions is the Boost Serialization library (http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/index.html). It's not entirely suitable for my purposes, for several reasons which I hope will become clear later, but it does offer some very useful concepts. First among these is the separation of the process of serialization from the archive format. This is one of the fundamental goals of Boost Serialization; whether it achieves it is another matter. It also puts some care into the serialization interface so that it is fairly simple (at least, for simple classes) and economical in terms of the amount of code and maintenance required. So, points that I like about Boost Serialization (and naturally intend to steal): Templated serialization functions. Virtual base classes for archives is the alternative, but this seems to be the best implementation for flexibility and efficiency. Non-intrusive code, as far as possible. Serialization has a minimal impact on the original class. Automatic serialization of containers and other common types. And what I don't like: The versioning system. Versioning is explicit in Boost Serialization and I prefer it to be automatic, as in, I can add or remove members without having to write special code to do that. Automatic object and pointer tracking. This complicates the archive format and the serialization interface. In contrast to versioning, I prefer this to be explicit. Some aspects of the interface, including operator overloading. Taking all that into account, here's a small example of a serialization function using my system:struct Rect { int16 x, y; uint16 w, h;};template void Serialize(Archive& ar, Rect& t){ ar.Serialize("X", t.x); ar.Serialize("Y", t.y); ar.Serialize("W", t.w); ar.Serialize("H", t.h);}As you can see it is templated to receive an archive and a serializable type. The function simply runs through the members and calls Serialize on the archive, providing a unique name (within this type) for each member. This function will do for loading and saving. The Serialize function on the archive is a template too and will detect the object type to serialize it correctly (and recursively). And the output, when I write to a JSON archive:{ "Rect": { "X": 32, "Y": 0, "W": 32, "H": 32 }}Now, that doesn't have to be a JSON archive. I'm using that for now because it's portable, easy to parse and human readable. But I could swich over to a binary format without changing the serialization function at all. Next time I'll go through some more details of the implementation.
  11. EWClay

    Mesh Format Confusion

    There are many formats written out by modelling packages, and these are well documented with loaders available. Typically, because artists may make use of several of these on a game, they will be loaded to an intermediate format for processing. Granny 3D is one popular choice for that step, but very much not free. After processing the mesh is written to another format, and there will be loaders for each platform the engine runs on, which may include Direct X. But that format will be very simple compared to the original, optimised for fast loading and designed to go straight to the GPU. Because every engine works differently, there is no common format for this final step.
  12. EWClay

    Is my frustum culling slow ?

    That code is very branchy. Culling an AABB is literally two dot products and a couple of comparisons per plane. See here: http://blog.makingartstudios.com/?p=155 Optimise later with SIMD if you need to, but more important is the data layout. Keep bounds data in a vector separate from everything else. Cull before rendering anything, writing out a list of objects to render. Once you get above 10000 or so, consider some sort or hierarchy.
  13. I deal with a similar case by creating temporary nodes at the start and end positions, linking to all the surrounding nodes, then path-finding as normal. The direction of the goal isn't necessarily the way you need to travel if an obstacle is in the way.
  14. EWClay

    Command queues

    No plans at the moment to add formations. I think I would use a shared path with an offset for each unit. It would mean adding clearance calculations to the pathfinder.
  15. EWClay

    Command queues

    Squad movement is looking ok now. Given solid pathfinding code and physics, it was already working reasonably well in that units could simply push other units out of the way to get where they wanted to go. It just didn't look that good. I chose a simple solution; as my squads are quite small I don't need anything too sophisticated. First I predict collisions using a circle intersection test. I only care about the next predicted collision. The unit's path is deflected either left or right depending on which requires the least deflection while still leaving room to pass. Once the collision is no longer predicted, the unit returns to the original path. It's nice because it's sort of self-correcting, and doesn't involve modifying the path or the path-following code. With that working I could move on to commands. I currently have three: move, follow and attack. Because I'm using a component system, each command is a component. Follow and attack both make use of move. It's possible to use these components directly, but I wanted to have a queuing system for setting up waypoints and general automation. How to handle that? Another component of course! The command queue sends messages to the other components to begin and end actions, they carry out the action and respond with success or failure messages. For the commands in the queue I use a Command base class with virtual functions. This makes it easy to plug in new commands. But most of the work is done in the components. This could get interesting if I start mixing it with AI. How much intelligence should an individual unit have? I want some of them to not even have the pathfinding component, so they could only follow or attack within line of sight. My attack command is very basic at the moment. It could take into account cover, different weapon types and the current health of the unit. Next, though, I think I really need to make a proper level. It's just been small test areas so far and they don't have enough scope to try out these ideas properly. So I shall put on another hat and become a level designer for a bit.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!