🔒 Locked
Structuring a games code...
Advertisement
Original Post
For one thing try to use some Design Patterns...
Redo the same project many times
I used to be awefull when it came to "losing" sourcecode, I'd end up writing the same project 2 or 3 times -_-
But each time I did I noticed something - the code was getting smaller & more precise
Because I'd done it before my brain knew the design patterns it was going to follow
I was able to think 2 or 3 stages ahead & because of that real structure started to form
If you want to make the source better just throw it away & start again
Slowly the different design pattersn start to stick; you start generalising & structure emerges. It becomes automatic & you're able to think further ahead
There's no substitute for practice really, but generally the best way I've found to practice is to redo what you've just done - but from scratch
sorry if I'm repeating myself but it is totally true ;] trust meh
I used to be awefull when it came to "losing" sourcecode, I'd end up writing the same project 2 or 3 times -_-
But each time I did I noticed something - the code was getting smaller & more precise
Because I'd done it before my brain knew the design patterns it was going to follow
I was able to think 2 or 3 stages ahead & because of that real structure started to form
If you want to make the source better just throw it away & start again
Slowly the different design pattersn start to stick; you start generalising & structure emerges. It becomes automatic & you're able to think further ahead
There's no substitute for practice really, but generally the best way I've found to practice is to redo what you've just done - but from scratch
sorry if I'm repeating myself but it is totally true ;] trust meh
I'm assuming you're using C++. That said, read a book called "Design Patterns: Elements of Reusable Object-Oriented Software" from Addison-Wesley. For a quick-fix, check out this link: Design Principles and Design Patterns
Just a quick guide:
Reusable Code:
Rendering Engine
Texture Manager
Image Loader
Audio Engine
Math Libary
Utility Classes
Physics Engine
Scene Graph
Pathfinding
General AI Routines (fuzzy logic, state machines, etc).
User Interface
Game Object Manager
Configuration File
XML Loader
New Code:
Game Logic
Game Objects/Characters
Model Manager (could be standardised with good planning)
Level Loader (never has a project where the file format hasn't changed!)
Reusable Code:
Rendering Engine
Texture Manager
Image Loader
Audio Engine
Math Libary
Utility Classes
Physics Engine
Scene Graph
Pathfinding
General AI Routines (fuzzy logic, state machines, etc).
User Interface
Game Object Manager
Configuration File
XML Loader
New Code:
Game Logic
Game Objects/Characters
Model Manager (could be standardised with good planning)
Level Loader (never has a project where the file format hasn't changed!)
I apologize for the lack of info, I am using C++ with SDL and OpenGL, and i've made a real mess of my asteroids code.
http://rafb.net/paste/results/6O2hU981.html
Thanks for the articles, and information, I won't be buying any books though.
Edit: I wanted to know about like what to store in functions and stuff like that...
http://rafb.net/paste/results/6O2hU981.html
Thanks for the articles, and information, I won't be buying any books though.
Edit: I wanted to know about like what to store in functions and stuff like that...
Woah, that's a severe lack of abstraction you have in your code there son! :)
A good heuristic is for each function to do only a single thing. For example, you could break your code up and have an UpdatePlayer function, as well as a HandleInput function as well as a RenderPlayer function etc. Don't make your UpdatePlayer function render your player as well.
A good heuristic is for each function to do only a single thing. For example, you could break your code up and have an UpdatePlayer function, as well as a HandleInput function as well as a RenderPlayer function etc. Don't make your UpdatePlayer function render your player as well.
I know what you mean. But the more you code, the better your structure will be. Take my word for it. In the mean time, here are a few tips to help you:
-When you get an idea, don't immediately sit down and code it. Look at Steven Spielberg. Did you know that for every scene he directs, he shoots from MULTIPLE camera angles to determine the best view for for the final cut? Not a surprise, but take his advice. Look at your problem from multiple angles and decide on an approach that will work best.
-Formalize your code. Give yourself a standard coding paradigm. Make yourself put that space after every parenthesis. Make yourself place a g_ before each global variable. This structure will propagate throughout your code and you will find that even your design will benefit from it.
-Read professional code like a book and learn from it. Yes, it is a bit overwhelming when you are trying to look through 400,000 lines, but get over it and just pick a spot and begin. For example, I opened up the quake source one day and chose a random document. It just happened to be one of the header files that redefined int to qint and float to qreal IIRC. I went searching online and found that the reason for this is to allow for compatibility across multiple platforms in the future. There we go - one more technique from the pros. Learn from them.
Best of luck.
-When you get an idea, don't immediately sit down and code it. Look at Steven Spielberg. Did you know that for every scene he directs, he shoots from MULTIPLE camera angles to determine the best view for for the final cut? Not a surprise, but take his advice. Look at your problem from multiple angles and decide on an approach that will work best.
-Formalize your code. Give yourself a standard coding paradigm. Make yourself put that space after every parenthesis. Make yourself place a g_ before each global variable. This structure will propagate throughout your code and you will find that even your design will benefit from it.
-Read professional code like a book and learn from it. Yes, it is a bit overwhelming when you are trying to look through 400,000 lines, but get over it and just pick a spot and begin. For example, I opened up the quake source one day and chose a random document. It just happened to be one of the header files that redefined int to qint and float to qreal IIRC. I went searching online and found that the reason for this is to allow for compatibility across multiple platforms in the future. There we go - one more technique from the pros. Learn from them.
Best of luck.
Some tips based in the source code you posted (sorry if I sound a bit harsh here and there, my intentions are to give you useful feedback, no flaming):
- break up the functions into sets of smaller functions with meaningful names. For example:
This snippet is part of a huge function. If you would replace it by:
It would be much more readable already. If you apply this principle consistently thoughout your code, eventually your main function should look something like this:
Which is much more readable IMO.
You can help yourself into doing this by forcing yourself not to use functions with more than, say, 10 lines of code (this rule is not flexible enough for most cases, but you should break it as little as possible).
- Use meaningful names. I do not consider 'barray' a meaningful name. Assuming it is a an array with bullets 'bullet_array' would be more descriptive. 'drawobj()' is also not very good. I have no idea what it's supposed to draw. If it daws the player you could call it DrawPlayer(), for example.
- Use constants variables instead of hard-coded numbers (you already did this for some variables, like SCREEN_WIDTH and SCREEN_HEIGHT). You frequently use constant numbers in your code:
I have no idea what the -5 and -10 constants are supposed to be. If I assume here that they are some sort of borders, I could replace it by:
Note that this also has the advantage that if the left border changes, you need to change only in one location (instead of many; the -5 turns up alot in your code).
- And finally, what FReY said: you could go for a bit more abstraction. This is the hardest part, and can probably only be introduced by starting from scratch with a new design (on paper; one that shows every object in the game and how they relate).
Tom
- break up the functions into sets of smaller functions with meaningful names. For example:
if (keys[SDLK_SPACE]){ if (shoot){ shoot = false; shoottime=SDL_GetTicks(); for (int i=0;i<BULLET;i++){ if (barray.used==0){ barray.x=player.px; barray.y=player.py; barray.radians=player.radians; barray.xv=cos(player.radians)*10; barray.yv=sin(player.radians)*10; barray.angle=player.angle; barray.time=SDL_GetTicks(); barray.used = 1; break; } } }}This snippet is part of a huge function. If you would replace it by:
if (keys[SDLK_SPACE]){ if (shoot) { ShootBullet(); }}// and obviously move the shooting code to the ShootBulletFunctionIt would be much more readable already. If you apply this principle consistently thoughout your code, eventually your main function should look something like this:
int main(int argc, char **argv){ InitSDL(); InitOpenGL(); InitGameData(); RunGameLoop(); ShutdownSDL(); return 0;}Which is much more readable IMO.
You can help yourself into doing this by forcing yourself not to use functions with more than, say, 10 lines of code (this rule is not flexible enough for most cases, but you should break it as little as possible).
- Use meaningful names. I do not consider 'barray' a meaningful name. Assuming it is a an array with bullets 'bullet_array' would be more descriptive. 'drawobj()' is also not very good. I have no idea what it's supposed to draw. If it daws the player you could call it DrawPlayer(), for example.
- Use constants variables instead of hard-coded numbers (you already did this for some variables, like SCREEN_WIDTH and SCREEN_HEIGHT). You frequently use constant numbers in your code:
glVertex2f(-5+player.pos[0],-10+player.pos[1]); glVertex2f(-5+player.pos[2],-10+player.pos[3]); glVertex2f(-5+player.pos[4],-10+player.pos[5]);I have no idea what the -5 and -10 constants are supposed to be. If I assume here that they are some sort of borders, I could replace it by:
glVertex2f(PLAYER_LEFT_BORDER_OFFSET + player.pos[0], PLAYER_RIGHT_BORDER_OFFSET + player.pos[1]); glVertex2f(PLAYER_LEFT_BORDER_OFFSET + player.pos[2], PLAYER_RIGHT_BORDER_OFFSET + player.pos[3]); glVertex2f(PLAYER_LEFT_BORDER_OFFSET + player.pos[4], PLAYER_RIGHT_BORDER_OFFSET + player.pos[5]);// and of course you should define the constants somewhere in the top of your file:const int PLAYER_LEFT_BORDER_OFFSET = -5; const int PLAYER_RIGHT_BORDER_OFFSET = -10; Note that this also has the advantage that if the left border changes, you need to change only in one location (instead of many; the -5 turns up alot in your code).
- And finally, what FReY said: you could go for a bit more abstraction. This is the hardest part, and can probably only be introduced by starting from scratch with a new design (on paper; one that shows every object in the game and how they relate).
Tom
An easy way to keep code well structured and designed is to jot it down in Pseudo code (Structured English). It’s a lot clearer than many actual languages and allows you to get your head around the code before you go ahead and actually implement it.
As far as specific design patterns: MVC. Model-View-Controller. I use this pattern on every game I write. Usually I end up mashing the Model and Controller into one class though.
The way it works is: "model" code takes care of the game logic. "view" code takes care of drawing.
Here's the rules you have to follow:
The model knows as little about the view as possible. In the best case, the model doesn't have a link to the view at all.
The view can know pretty much everything about the model.
The model contains all the important data.
The view can contain data, but only data relevant to drawing. None of the view's data is persisted. All of the view's data can be generated from scratch using only a model.
Also, you don't have to restrict yourself to one model class and one view class. Typically there will be several model classes and several view classes. Here's the important thing: every class must either be a model class or a view class. Really. There have been times when I've tried to have a single class work as both a model & view class simultaneously, and it always ends in disaster. It may be more work in the short-term to keep the model & view seperate, but trust me, it will make you happier in the long term.
The way it works is: "model" code takes care of the game logic. "view" code takes care of drawing.
Here's the rules you have to follow:
The model knows as little about the view as possible. In the best case, the model doesn't have a link to the view at all.
The view can know pretty much everything about the model.
The model contains all the important data.
The view can contain data, but only data relevant to drawing. None of the view's data is persisted. All of the view's data can be generated from scratch using only a model.
Also, you don't have to restrict yourself to one model class and one view class. Typically there will be several model classes and several view classes. Here's the important thing: every class must either be a model class or a view class. Really. There have been times when I've tried to have a single class work as both a model & view class simultaneously, and it always ends in disaster. It may be more work in the short-term to keep the model & view seperate, but trust me, it will make you happier in the long term.
I use MVC for some simple java games i write when im bored. the model would contain the data and the game logic. the viewport would actually be an interface, so i could implement it any way i want.
this is important, because you can create, say, a console view of your game, and a swing/awt version of your view, all you need to do is make different implementations. same thing with the controller, you could abstract it out, get input from keyboard, joystick, network. abstraction is the best part of game design.
this is important, because you can create, say, a console view of your game, and a swing/awt version of your view, all you need to do is make different implementations. same thing with the controller, you could abstract it out, get input from keyboard, joystick, network. abstraction is the best part of game design.
Quote:
Original post by ScottC
I apologize for the lack of info, I am using C++ with SDL and OpenGL, and i've made a real mess of my asteroids code.
http://rafb.net/paste/results/6O2hU981.html
Thanks for the articles, and information, I won't be buying any books though.
Edit: I wanted to know about like what to store in functions and stuff like that...
It doesn't look so messy to me... and it looks like C to me...
but I mean why do you really need much abstraction for a 100 line program? Isn't that kind of overkill? You can do it but I mean.. 100 lines of code isn't very hard to manage.
Quote:
Original post by Name_Unknown
It doesn't look so messy to me... and it looks like C to me...
The language should be somewhat irrelevant, many of the concepts in a C program can be applied to C++.
Quote:
but I mean why do you really need much abstraction for a 100 line program? Isn't that kind of overkill? You can do it but I mean.. 100 lines of code isn't very hard to manage.
Abstracting in a 100 line app is a bit overkill, but it will make later code reuse easier. For example, if you abstract the code to create a window it's easier to copy and paste the abstracted code into a later project without having to worry about breaking anything.
It's also good practice for when you start writing larger programs. When it comes time to write a 10,000 line program you'll have some experience abstracting things (and probably have a better idea of some pitfalls you can avoid).
Quote:
Original post by Name_UnknownIt doesn't look so messy to me... and it looks like C to me...
How can you tell a differance?
Quote:
Original post by Will F Quote:
Original post by Name_Unknown
It doesn't look so messy to me... and it looks like C to me...
The language should be somewhat irrelevant, many of the concepts in a C program can be applied to C++.Quote:
but I mean why do you really need much abstraction for a 100 line program? Isn't that kind of overkill? You can do it but I mean.. 100 lines of code isn't very hard to manage.
Abstracting in a 100 line app is a bit overkill, but it will make later code reuse easier. For example, if you abstract the code to create a window it's easier to copy and paste the abstracted code into a later project without having to worry about breaking anything.
It's also good practice for when you start writing larger programs. When it comes time to write a 10,000 line program you'll have some experience abstracting things (and probably have a better idea of some pitfalls you can avoid).
That was the idea, being able to reuse the code, and to practice for writing larger programs.
I found its best to structure you code according to a timeline of events, and sort things according to when they should happen. For instance, lets pretend its a fixed frame system.
Then, break up the 3 timeframes into "states", so that both would probably use the same switch structure.
The exact structure here does have the flaw that it'll render PLAY 1 frame before it should, but thats gotten around by giving video it's own state variable that synchronizes at the end of the game loop.
This will help some for simpler games, what I used for bACMAN. As for larger games, the ideas carry, but the exact structure it way different.
void MainLoop(){ while (!game.terminate) { ReadKeyControls(); RunGameLogic(); RenderGameGraphics(); }}Then, break up the 3 timeframes into "states", so that both would probably use the same switch structure.
void RunGameLogic(){ switch( game.state ) { case GAME_STATE_TITLE: { if (keypressed(ENTER)) game.state = GAME_STATE_PLAY; } break; case GAME_STATE_PLAY: { if (keypressed(UP)) { if (game.ship.speed < 100) game.ship.speed += 1; } else if (keypressed(DOWN)) { if (game.ship.speed > 0) game.ship.speed -= 1; } } break; default: break; }}The exact structure here does have the flaw that it'll render PLAY 1 frame before it should, but thats gotten around by giving video it's own state variable that synchronizes at the end of the game loop.
This will help some for simpler games, what I used for bACMAN. As for larger games, the ideas carry, but the exact structure it way different.
Pen & paper is a great tool.
Thing about naming your methods for what they do. If the names end up like "CreateAPlayerAndGiveHimAGunAndLoadTheLevel()" then it should be broken down into separate methods to do each part - think of each method as doing one job.
Re-using code in libraries is a good practice to get into - saves you time and also you have to make the shared code flexible or you can't share it.
I don't generally use design patterns deliberately, but having a well-structured design on paper first is my top tip. Then implementing it in an OO fashion where each entity/thing is a class, and operations on a thing are methods of its class.
Thing about naming your methods for what they do. If the names end up like "CreateAPlayerAndGiveHimAGunAndLoadTheLevel()" then it should be broken down into separate methods to do each part - think of each method as doing one job.
Re-using code in libraries is a good practice to get into - saves you time and also you have to make the shared code flexible or you can't share it.
I don't generally use design patterns deliberately, but having a well-structured design on paper first is my top tip. Then implementing it in an OO fashion where each entity/thing is a class, and operations on a thing are methods of its class.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement