Is this a viable code architecture for a 2d android game?

Started by
6 comments, last by Moe091 10 years, 8 months ago

I just need to do a quick sanity check on the idea that is in my head for the code structure of my next game. Here's what I'm thinking,

Game objects will hold nothing but data, and only the data for the components they need. Eg an enemy will have a movement component(with position, movement direction, velocity, etc. and a ref the the ONE movement handler that operates on all gameobjects with a movement component), a controller handler(for the enemy this would have data relevant to the decisions its ai will make and a reference to its specific AI controller, of which one only exists and which controls all ai of this type.(if it were a player it's controller would point to an input handler instead of ai), a graphics component with its sprite info and a reference to the same gameobjects position component, as well as a reference to the games graphics handler which renders everything with a graphics component.

the main loop would loop through all the gameobjects that need updating and call their update function, and in each objects update function it would loop through its components and call their update function. the components update functions would pass itself and its parent gameobject to it's respective handler object so the handler could perform all the updates it needs to.

Thats just a general explanation of the general idea I am considering right now. A spinoff would be if each object was registered with the handler itself, then in the game loop I looped through all the games handler objects and for each handler object I looped through every object registered with it and did everything needed to be done to each object every frame.

Do either of these ideas make sense? Can you help me improve upon them, or suggest a better way? Any advice that will help advance my understanding in any way? I'm still somewhat new to games a programming so I'd love any responses that help me learn something.

Thanks guys.

Advertisement
having update() iterate through your object list and update_each() is one iteration
having update() iterate through your object list for each component type and update_some_component_type() is more iterations.
for many game types, you'll find that you only have 3 basic types of game objects as far as component types goes:
1. one or more players with lots of data to track (more than an NPC/enemy/toarhet/hostile) and therefore lots of variables, but perhaps no more "components" than an enemy. "components" tend to be those things that both pcs/player(s) and enemies/npc/targets have in common such as both having a location, orientation, current_damage, drawing method, etc.
2. "enemies" or NPC's with fewer variables, but perhaps as many components as a PC. all the same ones or almost all the same.
3. terrain type features with very few components, perhaps none that update().
so most games can usually be handled with one player type object, one enemies type object, and perhaps a terrain types object. to this one usually adds a missile type object.
this usually leads to a structure where you have a player data structure (object), or a list of PC data structures (objects), a list of
active enemies, a list of active missiles, and some type of "world map". an easy way to deal with it is have renderall(), input(), and updateall() calls in the main game loop, and deal with updating the player during input(), and enemies and missiles during update().
updateall() might take the form of:
for each enemy update_each()
for each missile update_each()
where update_each takes the form of:
for each component type update_component (component_type)
note that update_each works for both enemies and missiles, and could also be used for the player. this is the power of component systems, it's a way to design data structures to allow you to write "generic" or "generalized" code. IE code that can work with more than one type of data/input/object/thing - sort of like templates and containers in C++. this is the real power of "component systems" - not that they are components, but that any component of a given type can be processed with just one generic subroutine. the power of components isn't components, its GENERIC CODE.
due to the fact that the player and enemies tend to have the same components, its even possible to simply have the player's components be one entry in the list of enemies, then have any additional player data in a separate data structure (info only tracked for the player).
doing this simply changes where the components are stored - in the enemies list with all the rest of the components, vs in the player specific data structure. either way, player updates are probably easiest handled during input() as they occur to avoid storing input, sending messages, and such. and enemy updates occur in updateall() as usual. so only where the components are stored changes not how they get updated.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

in the final analysis, you'll probably find you only have two categories of things with components that need updating: mobile, and immobile. whether to collapse these together is one of the design choices one must face with every game, since the number of unused components for an immobile object is low, i tend to just have one type of update-able object: a "target", and then i have the player object (with components), or the player's update-able components are simply a target (IE the player is target[0]), with the rest of the player's data in a separate player specific data structure. due to the fact that things usually boil down to just one or two object types with components, i usually just forego the whole components layer altogether, and just do update_player during input(), and updateall() is just: for each target, update_target, for each missile, update missile.

if you wanted to get really slick, a missile could just be another type of target. but games can have a lot of missiles, and missiles usually need less data than enemies, and the update functions often are simpler, or different than that for targets, so it often makes sense to handle them separately to save ram, run faster, and keep the code organization cleaner, simpler, more straight forward, and more compartmentalized.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

note that

graphics type: 2d

and

platform: android

are totally irrelevant to this design question. these concepts apply to both 2d and 3d, any platform, and most genres (pretty much anything more complex than tetris, bejeweled, pong, or the like). ; )

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

one more thought:

not only do enemies and missiles sometimes tend to have different update code, the player often has more complex update code than enemies, another reason to handle all three separately, instead of with one generic update_component function.

components and generic functions that operate on them are really only applicable when the operation to be performed is identical for all components of a given type.

its often the case that player update, enemy update, and missile update are not the same. while the final change of a component like position might be the same for all three (new x = old x + delta x), determining the change to make can often differ (complex player moves / flight model vs simple enemy AI vs physics modeled missile movement). so its only the very last step of updating an object, where you change the component variables, where you can get any real advantages from generic code and components. and even there its reduced to just a generic update_location(location L, int dx, int dy, int dz) kind of thing. just about as easy to just do L.x+=dx, etc. after all, x+=dx, y+= dy, z+=dz is 3 lines, short, but perhaps not compiled inline even if desired, and update_location incurs the overhead of a function call, plus the 3 add's of x+dx, y+dy, z+dx once the call is made.

note that every games differs, and you may find commonalities in your update functions for your various object types that warrant some sort of component approach. in such cases, a "for each object update each component" vs a "for each component type update each object" approach would probably be simpler, easier to code, and run faster - just what every programmer wants. <g>

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

some games (like rpg's) also have a list of inventory items dropped on the ground, or carried on a player, in a treasure chest, etc.

yet another list of similar object types in the game world, like players, enemies, and missiles.

what list to put something in is up to you. in CyberTank, smoke and flames were projectiles. in Airships!, projectiles, smoke, flames, and craters are just another type of target as i recall (no missiles list). the player is target 0 plus additional player specific data structures (it uses a realistic physics flight model for the player's airship, which requires a LOT of variables).

in my new Zlib "game engine" i recently wrote (but have yet to use - need to start on yet another game! <g>), everything is a target. it can draw a target as a 2d billboard, 3d billboard, mesh and texture, static model, or animated model. it includes functions to update targets, do collision checks, do AI, etc.

my lower level Z3d library (used for CAVEMAN, Airships!, Armies of Steel II and the Zlib engine) handles window creation, d3d startup and shutdown, mesh, texture, model, and animation databases, animation player engine, timers, random numbers, file i/o, string <-> number conversion, a drawlist engine (throw graphics at it in any old order and it sorts optimally for d3d and draws using state management), a matrix manipulator, and a few other useful things.

then i have a 3rd module, a model and animation editor that works with the z3d library and can be linked into any game.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I think you should just start coding something learn from it. If your method is not viable, then change it.

This would be your fourth android game right?

No wonder I couldn't find this, it was moved from game programming to mobile/console. Sorry my title was misleading but this really doesn't belong in the mobile/console section.

Thanks a ton for your advice guys, especially Norman. Your advice was just slightly ahead of my skill level but after a couple read throughs I really grasped what you were saying and it was perfect. Thanks a lot. If anyone has any advice or tips about the specific java implementation that would be really helpful. I'm using libgdx btw I don't think that matters much though.

This topic is closed to new replies.

Advertisement