# SDL game/engine?

This topic is 2839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

hello, forum! i've started to create a game some weeks ago, and i already have a similar post here, but i didn't get too much answers, so sorry for reposting. okay, so my idea was at first, to create a game (a 2d platform shooter) and i've written some code (mostly based on lazy foo's sdl tutorials). then, a day or two before, i realized that my code was ugly and i started to rewrite it. now i have some better structured code but i still need some help in a lot of things. it looks that i can reuse the whole thing later, so it would be important for me to get some things work. first, loading things (other than saves and maps). if i'd write particles like this (from lazy foo's):
Particle::Particle( int X, int Y )
{
//Set offsets
x = X - 5 + ( rand() % 25 );
y = Y - 5 + ( rand() % 25 );

//Initialize animation
frame = rand() % 5;

//Set type
switch( rand() % 3 )
{
case 0: type = red; break;
case 1: type = green; break;
case 2: type = blue; break;
}
}

it would work only with three kind of surfaces. how can i make it so when i start writing the game, i can create particles of many surfaces without changing the code in particle.h or whatever is it in? second, tiling. i get the idea of it, but i have the same problem with it as with particles. i know these are just lazy foo's examples, but i haven't got too much idea of implementing them a different way. i accept any kind of tutorials or example code about them. third, a jumping character, and 2d physics. i don't want it to have complicated physics, just objects falling down from air. i could use some example code here. what i've created so far is at https://sourceforge.net/projects/yolane/ please give me suggestions!

##### Share on other sites
Some comments on that particle constructor: don't randomize it's position in the constructor itself. That may seem to be a good idea right now, but it'll make your particle class less flexible. How to deal with particles that have to be at the specified position? Or particles that need a bigger spread? Instead, just use the specified position, and let the code that generates particles do the randomizing.

Same goes for materials or textures: pass those as arguments to the constructor, and let the particle generator select the materials.

As for tilemaps, a tilemap class would just hold a list of textures/tile images, and a 2D array of indices into that list. A level-loader function would then construct a tilemap object based on data read from a file (or from some other source).

As for falling objects, just apply a gravitational force to them. That is, every object would have a position and a velocity. The gravity pull would simply alter the velocity of an object.

So:
Vector2 gravity = Vector2(0, 9.81);class FallingThingie{    Vector2 position;    Vector2 velocity;    public void update()    {        position += velocity;        velocity += gravity;        // You may want to limit an objects speed, which can be done by        // capping the length of 'velocity'.    }}

• For world coordinates, don't use integers, use floats or doubles instead. You can always convert them to integers when you need to, for example when rendering them.
• Don't store speed as a separate variable - the length of your velocity vector is the speed.
• You may want to give those structs some member functions to make them easier to work with: for example, a collidesWithBox() and containsBox() function for the collision box class. And for a position class (Vector2), some overloaded operators (+, -, +=, -=, *, /) would make using them quite easy.
• I wouldn't put that Control struct inside your Object class, either: an object should ideally have no notion of how it is controlled. Baking it in will only make such an object less flexible - at best it's dead weight.
• Move those velocity and collision box structs out of the Object class - they are useful for other purposes as well. Personally I'd call them something like vector2 and rectangle, and I'd specify their specific purpose inside the Object class with the variable names instead (Vector2 velocity; Rectangle collisionBox;).
• Read up on initializer lists. You may also want to read up on copy constructors and assignment operators.
• Wrapping namespaces around classes is... peculiar. I would only use them in large projects, to group related classes together, and this isn't a large one. It only seems to make your code harder to read here (Object::Object::Object?!).
• For font qualities, use an enum instead.

[Edited by - Captain P on April 10, 2010 7:15:14 AM]

##### Share on other sites
thanks for the advices, i'm gonna make the changes. how do you mean an objects shouldn't have notion of how it is controlled? i mean how would it move then?

edit: and also what should i do with copy constructors?

[Edited by - sandorlev on April 11, 2010 9:28:20 AM]

##### Share on other sites
Quote:
 Original post by sandorlevhow do you mean an objects shouldn't have notion of how it is controlled? i mean how would it move then?

Some other code would tell the object to move. With a player-controller object, you would have some code that listens for input and based on that, it will move the player object. Enemy objects would be moved by AI code. But the objects themselves don't need to know about that - they just need to provide some functions by which they can be moved.

Quote:
 edit: and also what should i do with copy constructors?

Just read up on them, so you know where and when they need to be used, and how. Like constructors and destructors, a default implementation for the copy constructor and assignment operator will be created if you don't provide one yourself. For most cases (POD types, that is, Plain Old Data) that is fine, but as soon as you start to dynamically allocate things inside a class, things can subtly go wrong.

##### Share on other sites
sounds good. i've rewritten my code so it now uses initializer lists. another thing i've done is managers. i've created manager classes which manage loading and destructing data.

they work like this:
Texture::TextureManager tm;Texture::Texture* texture = tm.loadTexture("example.jpg");tm.removeAllTextures();

what do you think about it?

i keep namespaces because they separate stuff. like i
don't want the monitor's default width to be mixed with something other's.

##### Share on other sites
Quote:
 what do you think about it?
I question designs that rely on "manager" classes. Such a design reflects notions of a people hierarchy. It suggests that the designer had no underlying design, so copied what seemed a good alternative, which is how people work. Your manager class is an arbitrary collection of work. Why does the class exist? Only to group together functions.

If you think otherwise, you should be able to clearly explain the underlying model that you have created with pen and paper.

##### Share on other sites
it keeps track of every texture loaded with it so they can be cleaned up easily. i don't understand what's the problem with it.

##### Share on other sites
The name "Manager" for some conjures up images of singletons and big ugly monolithic classes that do far more than they should. In particular, "Managers" are prime candidates for violating the Single Responsibility Principle (see link in sig). Basically, you want a class to only be doing a single conceptual chunk of work.

You might be better off calling it TextureLoader, or Texture::Loader, as long as you're using namespaces. If you're going to cache textures so you only have to load them once, you might want to delegate that to an internal TextureCache, but that might be overkill, at least for now. The idea is to keep all your classes fairly small and manageable.

##### Share on other sites
okay, so let me clear this manager stuff (or fontloader):
it's a class which has a private list of fonts. its loadfont method adds every font loaded with it to the list before returning them. that way, at the end of the program, they can be easily closed by calling closeallfonts(). or, if it's needed to close one before the end, it can be closed by closefont(font). it does no more and no less.

i'm sure i want to use this kind of class in my game, it makes it much easier to manage loaded data (eg. i don't have to call sdl_freesurface() for like 20 times in the end). what i'm asking is, would it be a good idea to include it in my "engine" (which is basically all the stuff i think is reusable in the game)?

##### Share on other sites
Caches and loaders fit well within a framework, yes - when designed well, they're easy to reuse and do make things easier to work with. I used to call these 'managers' as well, but as the others have pointed out, 'manager' is a rather generic term, so more specific names are better.

I wouldn't use a list under the hood, though - a dictionary that maps filenames to resources makes it easier to check what resources have been loaded already.

##### Share on other sites
#include "Yolane.h"int main(int argc, char* argv[]){	Yolane::init();	Yolane::TextureLoader tl;	Yolane::Texture* texture = tl.loadTexture("character.png", true);	//...	tl.destroyTexture("character.png");	//or tl.destroyAllTextures();	Yolane::quit();	return 0;}

##### Share on other sites
Fair enough - though you could look into smart pointers, to automate the resource cleanup phase. I wouldn't give the texture loader a destroy-texture function though - the Texture destructor should be able to take care of that itself.

##### Share on other sites
Quote:
 though you could look into smart pointers

would it be a good idea to use smart pointers taken from enginuity (with 'immobjects' as the base class of everything)?

##### Share on other sites
Quote:
Original post by sandorlev
Quote:
 though you could look into smart pointers

would it be a good idea to use smart pointers taken from enginuity (with 'immobjects' as the base class of everything)?
Assuming C++, take a look at boost/tr1::shared_ptr (unless your requirements are unusual, it's pretty much the go-to solution for reference-counted smart pointers in C++).

##### Share on other sites
i don't know what am i doing wrong, but my destructors never get called, even if i delete objects at the end.

also, for the Texture class, which is a wrapper for SDL_Surface, is it a good destructor?
Yolane::Texture::~Texture{    SDL_FreeSurface(image);    //is this really needed?    delete this;};

##### Share on other sites
Writing delete this; is a very bad idea. delete invokes the destructor of the deleted object... You need to call delete on the same level as you call new (or let a smart pointer handle that). An object can't delete itself (nor can it create itself)...

As for destructors not getting called, make sure any base class have virtual destructors... But I suspect your problem is related to you trying to have objects call delete on themselves. ;)

##### Share on other sites
Quote:
 Original post by sandorlevi've started to create a game some weeks ago
Please do recognize the difference between character input, button pressed, gesture... I still find SDL based apps floating around which will just assume QWERTY-US. This always mildly annoyed me since I was a non-US layout user, and pains me to no end now that I am a non-QWERTY user.
The GIMP is particularly hateful, mapping its accelerators to the letter being generated by the button press rather than the button press itself.

I've tolerated all those games trying to guess the glyph from the button pressed while binding input and failing horribly. It happens, and it's presentation-only. It's ok. WASD is still to the right places, although it maps to - say - ,AOE. It's fine.

But some other games and apps, as I already said, are perpetuating the nasty habit of binding by character (taking the above issue to the next level). This is terrible, terrible, terrible. In 2010, not correctly managing keyboard input is a total shame, shame, shame.

Make sure you don't do that.

##### Share on other sites
Quote:
 Original post by Beyond_RepairAs for destructors not getting called, make sure any base class have virtual destructors... But I suspect your problem is related to you trying to have objects call delete on themselves. ;)

the bad thing is that it is a virtual destructor, and i did not include delete this in my own code, i just asked if it would be ok. i made a destructor which opens a file and writes "texture deleted" or something like this so i can see if it works and it doesn't :(

Quote:
 Please do recognize the difference between character input, button pressed, gesture...

okay, thanks for the tip but how do i do it? by the way, i plan to use arrow keys, space and return only, so it should be ok.

i realized that i was stupid, at first i didn't even think of memory leaks or stuff, but now i know i shouldn't have started this way. so i'm asking for a little help, if someone has the time/spirit for helping me correct my code, please tell me. i'm going to svn commit it today or maybe tomorrow.

##### Share on other sites
Quote:
 Original post by sandorlevi made a destructor which opens a file and writes "texture deleted" or something like this so i can see if it works and it doesn't :(

You can also place a breakpoint in the destructor. Either way, you'll have to show some code (e.g. how and where you create the texture instance and how and where you release it). So, go ahead and commit. ;)

##### Share on other sites
i've just commited. there are about 10 lines to delete/fix, maybe some not even commented, so i'm not sure it can be compiled.

##### Share on other sites
Quote:
 Original post by sandorlevi've just commited. there are about 10 lines to delete/fix, maybe some not even commented, so i'm not sure it can be compiled.

Always make sure the repository is in a working state. You'll want to be able to do a checkout at any moment, on any machine, and have it up and running without hassle. Your repository is incomplete (main function? project files/make files?) and I can't find any notion about dependencies. I know you're using SDL, but what version? Ideally, you'll want to add the necessary files to the repository. Otherwise you may find yourself guessing as to what SDL version your 1 or 2 years old project used - because it doesn't work with the latest version.

I also noticed you're stuffing multiple classes into a single file. That's confusing: I wouldn't expect to find the Texture and TextureLoader classes in Screen.h/cpp. Just place them in separate files (and name them according to the class - this makes searching through a project much more predictable and easy). If you end up with lots of files (10 isn't much ;)), organize them in folders - and that would perhaps be an appropriate time to use namespaces: each folder (module) it's own namespace.

In most cases, passing std::strings by const reference is better. It prevents the string from being copied (because you're passing a reference) and the const disallows the function to alter the given string (only const member functions can be called on it - which in turn promise not to alter the string).

Making Texture's destructor virtual is only necessary if you intend to give Texture polymorphic behavior. That is, you're planning to derive classes from Texture, each with it's own specific behavior, but you want to treat them all as Textures. That means, you want some virtual member functions, so the correct version is called depending on the actual type of the texture. In such cases, you need a virtual destructor.

Your Texture class is hiding some useful information, like width, height and bpp. Provide some member functions for those. This also means you can throw away that ScreenData struct - it's only duplicating existing data.

I noticed Screen inherits from Texture. I understand that Screen is a surface that can be blitted to, but you're mixing it with Window functionality: a screen doesn't have a caption or a notion of what 'windowed' is - it's just a surface. A Window class that contains a Texture instance (named 'screen') would fit better here - no inheritance from Texture required.

Perhaps the most glaring problem is your memory management. There are various functions that return pointers to new'ed Texture instances, but I couldn't find a single 'delete' call. You'll want to be very strict with who owns what - generally speaking, the code that allocated resources should also clean them up.

I would also look carefully into your Texture class'es assignment operator (hint: you're missing the copy constructor). What happens if you've got two Texture instances (a and b) and you're assigning b to a, and you're then destroying b? A freed it's own surface and then set it's surface pointer to point to b's surface, but when b is destroyed, it frees it's surface. A still points to that surface. Auch. You performed a shallow copy while you needed to perform a deep copy.

But think about it: does it make sense for textures to be copied and assigned? Probably not, unless you want to copy a texture in order to modify a copy at run-time. If you don't need that, then just declare the assignment operator and copy constructor private. That essentially says: instances of this class can't be copied.

As for your problem, Texture's destructor not being called, it's hard to tell without having a working repository, but I guess it's because you're never cleaning up your textures. Which means you're leaking memory. Remember: anything you 'new' must be 'delete'd.

EDIT: If you can, try to get a hold of a copy of 'Effective C++' by Scott Meyers. I'd say it's a must for anyone who's working with C++.

##### Share on other sites
Quote:
 Original post by Captain PBut think about it: does it make sense for textures to be copied and assigned? Probably not, unless you want to copy a texture in order to modify a copy at run-time. If you don't need that, then just declare the assignment operator and copy constructor private. That essentially says: instances of this class can't be copied.

it's because i need to create new textures every time the text of textbox changes. or should i do it by deleting and then addig a new one?

Quote:
 Making Texture's destructor virtual is only necessary if you intend to give Texture polymorphic behavior.

i just didn't want window to have a destructor, but i'm gonna change it as you adviced.

i got effective c++, and i've already started reading. it seems to be a great book, thanks for telling :)

##### Share on other sites
Quote:
 Original post by sandorlevit's because i need to create new textures every time the text of textbox changes. or should i do it by deleting and then addig a new one?

Delete the previous one and create a new one, yes. Why copy the old one if you're going to overwrite it anyway? You won't be using any of the old data.

I've just gotten into the habit of explicitly disallowing copying for non-POD types if it's not needed. You either spend time getting it right, or you take the easy way out by disabling it. If, however, you don't bother writing copy constructors and assignment operators, default versions will be created for you, and for non-POD types, that can lead to subtle problems (leaks, double deletes).

Quote:
 i just didn't want window to have a destructor, but i'm gonna change it as you adviced.

If a class needs a destructor, it needs one, whether you want it or not. ;)

##### Share on other sites
Quote:
 Original post by Captain PI've just gotten into the habit of explicitly disallowing copying for non-POD types if it's not needed.

it sounds good. i've googled it but didn't find how to.

Quote:
 I wouldn't give the texture loader a destroy-texture function though - the Texture destructor should be able to take care of that itself.

if i destroy it with the textureloader, it deletes the filename from the map, if i call delete, i cannot load it again (because it's still in the list of already loaded files).

what do you think, does it make any sense if i use my own structs instead of sdl's (like yolane::rectangle instead of sdl_rect, yolane::color instead of sdl_color), so when making a game with yolane, people wouldn't have to know anything about sdl's structs?

EDIT: if in the window class, i use a texture called screen, how can i set the video mode? texture's sdl_surface is private, so i cannot modify it anytime.
EDIT2: if i load a texture with textureloader, then 'delete' it, the program crashes as the textureloader trying to delete it again. what should i do with that?

[Edited by - sandorlev on April 18, 2010 2:32:07 AM]