I am fairly new to game development so I want to ask what some of you more veteran developers do when it comes to making a game.
When I am coding, I tend to think of only the current project and I develop all the code in such a way that it makes that project work.
What I am wondering is how you separate what is to be engine code, stuff like physics, collision detection, etc that I can copy and paste into a new project, and never modify that part of it(except when improving it) and still create a whole new game around it that is code that will specifically load this game's assets and rules.
I think that makes sense.. let me know if you need any more clarification.
Thanks
I'm not exactly what you'd call a "veteran developer", but I'll try to answer anyway.
As a C++ programmer, I tend to place 'common' stuff into headers - for example, in a RPG game, the map and player classes are not placed in the main source file but in some separate headers. That allows me to re-use them much more easily than copying and pasting that stuff in a new file.
What's more, you can let the engine load game content from external files (the easiest way to do this IMO is to parse plain text files). Still talking about RPGs, you could load monster types, maps and whole campaigns/stories from external files. You could take a look at Battle for Wesnoth's excellent way to do this: they have a whole markup language (WML) through which they interpret configuration files to load all game content (including many game rules).
Example:
a general collision detection routine defined in the engine code
engine -> function physics.detect_collision(object a, object b) ... end
calling engine collision routine for instances of objects created by the game code
game -> object a,b; foo=physics.detect_collision(a,b)
Defining a collision detection routine for the specific case of two players in the game code
game -> function game.detect_player_collision(player a, player b) physics.detect_collision(a,b) end
Also, if you can, place all the engine related code into the binary(.exe) and all the game/ui related code into dynamic link libraries(.dll/.so).
But these are if you want some flexibility and modification capability.
It is quite possible to meld everything(game engine ui etc) together which works quite well for small games.
The most important thing to isolate is the game logic, in my experience. Get it mixed up with the graphics engine, and you'll be in for a world of hurt. And sure, if you have really generic code such as for vector math or basic physics, it pays to have it as an easily reusable library. So yeah, think in terms of libraries, not engines, is my opinion -- the latter are only reusable between very similar games.
I agree with claudeb about keeping different libraries.
Generally, one of the rules you should use in programming to avoid messing up everything is to split big problems into their smaller components: so you should split the problem "game" into its components - "graphics engine", "physics engine", "mathematics library", "content", ...
Still, as helfox said, in small games having everything mixed up might be pretty easy (and sometimes even easier than having everything split up). I personally prefer to write everything all together only if I want to quickly develop a little game (see Ballrunner - one night of coding, only a source file (geom.h and geom_graphics.h already existed) and a veeeery small game)
I'd go even further than claudeb and say don't think in terms of libraries - think in terms of modules.
My reasoning is that even libraries can be pretty big projects (depending, of course, on what the library tries to accomplish) and will sure as hell become a terrible mess if don't keep them organized inside. It's therefore a better approach to clearly separate library projects into several modules which don't depend on each other, provided this is possible and the library is large enough to warrant this, i.e. not a single-purpose library like zlib.
Another useful thing to keep in mind is to both modify and rely on internal states as little as possible. Not changing any internal states obviously won't work, since your game wouldn't do anything, but if you've got two equally complex ways to implement a feature -- one way that relies on internal states and modifies these states, and another one that solely relies on the input it was given and returns a value -- I'd go for the second one. It will keep testing simpler, reusing your code will be easier and you won't experience a nasty surprise if the internal state was set to a value you didn't expect.
It really is somethng you learn with experience.
Example: after you've written your first game, and are writing your second, you'll see places where you say, gee, I wish I could reuse that piece of code from the first game but it has so much specific stuff from the first game embedded in it.
You could treat the situation as hopeless, and forego a learning opportunity.
Or, you could go back to that first game, and try to separate the part that you want to reuse from the specifics of the first game. In so doing, you'll end up with some code you can use in the second game. But don't stop there. Rewrite the first game in such a way that you *can* use the same revised code in the both the first and second games.
Doing this is a first lesson in identifying modules. Repeat as necessary.
It's said that for any specific piece of reusable code, it will take at least three uses (thus two reuses) before you get the interfaces right.
It may seem like more work this way, but you'll develop a reusable codebase that will make later work easier and easier.
The technique works for large programs, too. If you find yourself writing similar code (and especially if you find youself copying and modifying a bunch of code) stop and see if you can carve out a module/function/macro/procedure/inheritable-class/template/whatever that you could use twice with different parameters. If you can, you'll save on debugging, because your bugs won't be copied from one place to the other and you won't have to track them down twice.
-- hendrik
Wow thanks for all the great responses! Definetly a ton of useful information here to go off of, thanks guys.