LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Any Game developer geeks out here? (https://www.linuxquestions.org/questions/programming-9/any-game-developer-geeks-out-here-469268/)

vharishankar 07-30-2006 11:15 PM

Any Game developer geeks out here?
 
Any serious game programmers out here?

I'm currently learning SDL as well as creating a simple game engine wrapper using C++ for it. But I find that a lot of work has already gone into creating such game engines. Many are Free/Open Source as well.

My question - is it better to "reinvent" the wheel and learn the underlying API better? I find SDL very, very easy and it's fun to create the basic game objects. I also learn a lot of stuff this way.

On the other hand there are pre-built game engines (clanlib for instance) which offer a lot of functionality and power...

Which way would you advise somebody starting out in simple game development?

spaaarky21 07-31-2006 12:09 AM

Personally, I would write my own wrapper but then again, I have somewhat of a paranoid distrust of other people's code (quality wise.) What I have noticed about bigger projects with a wide range of potential users is that code becomes cluttered with special cases. I would much rather write my own code that does exactly what I need and only what I need - not a little of what everyone else does. I'm also kind of a stickler when it comes to consistency and the way that errors are handled.

If you enjoy playing with SDL, write your own wrapper. It's a great way to learn the library. However, it has been my experience that the documentation for parts of SDL leave something to be desired so maybe using a wrapper written by someone else would be good.

vharishankar 07-31-2006 12:14 AM

I've been looking at various 3rd party game engines. Every single one of them impose a certain kind of structure and restriction on your own coding.

If I like game engine A because it does X for instance, then it doesn't do Y so well. On the other hand, game engine B does X and Y well, but it's incredibly overkill for a new game programmer looking for a simple head start.

I looked at clanlib. It's OO structure looks slightly cumbersome, but it's fairly easy to learn. I guess I'll continue playing with SDL native and then choosing other game toolkits if I find that I cannot accomplish something on my own.

I think the best approach is to develop a simple full game and then look at the underlying code to the engine, otherwise it would never be complete.

spaaarky21 07-31-2006 01:27 AM

Now that I look at clanlib, this is kind of interesting. It looks like clanlib and SDL are sort of competitors in the sense that both libraries are wrappers for system-specific code (window management, sound output, buffer management) with some added features. One just happens to be object oriented while the other isn't.

Clanlib may be a good option but make sure to realize that you may be learning more about the clanlib authors' particular way of doing things than you are about games and computer graphics in general. SDL might be better for learning because you might learn more about general, low-level CG and GUI concepts (event processing, keeping track of changes between frames, where/how rendering is done, etc) but other than that, the two would be pretty similar.

-Brandon

vharishankar 07-31-2006 01:46 AM

I'll tell you my current progress in SDL.

I've already written a simple program using the classes I've written to draw a background and a moving sprite image on it (non animated) with accompanying background music (using SDL_mixer).

I'm now on the way to writing an animation sprite class which will also incorporate simple rect collision detection.

When I was fiddling with DirectX some time back, I would only have drawn an empty background at around this stage. DirectX is a painful journey into graphics programming (mainly because of the Win32 specific aspects like creating and destroying Windows). SDL makes the trivial things far simpler and allows one to concentrate on the actual process of creating a game/game engine.

Mega Man X 07-31-2006 02:19 AM

Long time no see Harishankar!. Nice to hear about your adventures with SDL. I'm almost on the same boat as you. I've just started using SDL with Java bindings and its not going very well. I remember making some simple things with C++/SDL and it was far easier. But I will stick with Java. I just love that language ^_^.

Anyway, I have a link that you may like (if you already don't know about it):

http://lazyfooproductions.com/SDL_tutorials/index.php

Lazy Foo' is a member in this forum. His tutorials are great, to say the least. One of my problems learning SDL was finding tutorials. Have I known his page years ago, I'd not have as much grey hairs I have today...

Good luck!

vharishankar 07-31-2006 02:23 AM

Thanks MegaMan. Yes, I've seen that on too. I've looked at almost every beginner SDL tutorial there is out there (at least on the first couple of pages of google ;))

I'm now working on a trivial sprite animation class which takes a graphics file, splits it into frames and load each frame into a sprite frame object.

SDL is a walk in the park compared to DirectX. Even transparency is such a simple thing in SDL. I remember when I started writing a tiny DirectDraw program how on earth to implement transparency. I don't think I got very far with the DirectDraw tutorials. I still don't know whether I got that transparency or not in DirectDraw.

Let's see how it goes...

vharishankar 07-31-2006 03:36 AM

Perfect. Done the sprite animation class in no time at all. And the best part is that it worked absolutely right the first time. Didn't expect it to be so easy, but I guess that's what happens when you use classes and OOP. I'm going to definitely learn a lot this way.

If anybody wants to see the code I created for checking for any potential design problems that I might have missed out, I'll put the "engine" code here.

Now for the collision detection which is a little bit more tricky since I'm currently not storing the object position in the class. Maybe a little rewrite at this stage should help

dmail 07-31-2006 05:49 AM

Hmmm I'm not a geek Harishankar lol, but I'll have a look over your framework code if you want and see if I can see any potential problems.

About collision detection in 2D, this is pretty easy after you have made the choice about the precision you require. Do you want pixel level which can be expensive yet there are simple ways to eliminate most negative collisions. What type of bounding volume you are using circle, Axis Aligned Bounding Box ...

vharishankar 07-31-2006 06:14 AM

I've not yet thought about it, yet. But at the moment I guess I'd settle for rectangular collision detection although later I might use a more pixel perfect collision detection technique.

Beware, my code is very basic and doesn't implement much. I've only spent about 2 days with it but as such I think. But I want some opinions on the design considerations pretty early because I don't want to make major changes halfway after implementing a lot of functionality.

Here's the code. It's very quick and dirty at the moment, but I'm planning to add more functionality, in particular "get" and "set" functions and also collision detection for sprites.

SDLScreen class: Just to implement the basic main drawing surface of a program.

Code:

// This is the main class that handles the SDL screen as such
class SDLScreen
{
protected:
        SDL_Surface* screen;
        int width, height, depth;
        std::string window_title;
        Uint32 sdl_flags;
public:
        // Default constructor
        SDLScreen ()
        {
                width = 800;
                height = 600;
                depth = 0;
                window_title = "SDL Program";
                sdl_flags = SDL_ANYFORMAT;
        }
       
        // get the width
        int getwidth ()
        {
                return width;
        }
       
        // get the height
        int getheight ()
        {
                return height;
        }

        // Constructor with initialization
        SDLScreen (int w, int h, int d, char* title, Uint32 flags)
        {
                width = w;
                height = h;
                depth = d;
                window_title = title;
                sdl_flags = flags;
        }

        // Get the raw surface
        SDL_Surface* getsurface ()
        {
                return screen;
        }

        // Do the initialize part
        int initialize ()
        {
                if (SDL_Init (SDL_INIT_VIDEO) < 0)
                        return -1;
       
                screen = SDL_SetVideoMode (width, height, depth, sdl_flags);
                if (screen == NULL)
                        return -2;
               
                SDL_WM_SetCaption (window_title.c_str(), NULL);
                return 0;
        }

        // Update the whole screen function
        int updatescreen ()
        {
                return SDL_Flip (screen);
        }

        // Update a specific region
        void updateregion (int x, int y, int w, int h)
        {
                SDL_UpdateRect (screen, x, y, w, h);
        }

        // Destructor
        ~SDLScreen ()
        {
                SDL_FreeSurface (screen);
                SDL_Quit ();
        }
};

SDLObject class: To add a simple container for game graphics. Very basic and no collision routines yet, but planning on that soon.

Code:

// This is the SDL Object class for game graphics.
// Very basic. Just stores a surface.
class SDLObject
{
protected:
        SDL_Surface* object;
        SDL_Rect object_rect;
public:
       
        // Create a an empty object - dummy constructor
        SDLObject ()
        {
                object = NULL;
        }
       
        // Create a blank object from a screen
        int createblankfromscreen (SDLScreen* source)
        {
                SDL_Surface* temp = source->getsurface ();
                if (object != NULL)
                        SDL_FreeSurface (object);
               
                object = SDL_DisplayFormat (temp);
                SDL_FreeSurface (temp);

                if (object == NULL)
                        return -1;
               
                object_rect.x = 0;
                object_rect.y = 0;
                object_rect.w = object->w;
                object_rect.h = object->h;
        }
       
        // This will load the image with width and height specifically taken
        int createimage (char* image, int x, int y, int w, int h)
        {
                SDL_Surface* temp = IMG_Load (image);
                if (temp == NULL)
                        return -1;
               
                if (object != NULL)
                        SDL_FreeSurface (object);

                object = SDL_DisplayFormat (temp);
                SDL_FreeSurface (temp);
               
                object_rect.x = x;
                object_rect.y = y;
                object_rect.w = w;
                object_rect.h = h;
        }

        // This will load the image with width specifically taken
        int createimage (char* image, int x, int y, int w)
        {
                SDL_Surface* temp = IMG_Load (image);
                if (temp == NULL)
                        return -1;
               
                if (object != NULL)
                        SDL_FreeSurface (object);

                object = SDL_DisplayFormat (temp);
                SDL_FreeSurface (temp);
               
                object_rect.x = x;
                object_rect.y = y;
                object_rect.w = w;
                object_rect.h = object->h;
        }

       
        // This will load the image with width and height not taken
        int createimage (char* image, int x, int y)
        {
                SDL_Surface* temp = IMG_Load (image);
                if (temp == NULL)
                        return -1;

                if (object != NULL)
                        SDL_FreeSurface (object);

                object = SDL_DisplayFormat (temp);
                SDL_FreeSurface (temp);
               
                object_rect.x = x;
                object_rect.y = y;
                object_rect.w = object->w;
                object_rect.h = object->h;
        }
       
        // get the width of the surface
        int getwidth ()
        {
                return object_rect.w;
        }
       
        // get the height of the surface
        int getheight ()
        {
                return object_rect.h;
        }
       
        // Set a transparent pixel value. Do this before calling drawonscreen
        int settransparentcolor (Uint8 r, Uint8 g, Uint8 b)
        {
                Uint32 color = SDL_MapRGB (object->format, r, g, b);
                return ( SDL_SetColorKey (object, SDL_SRCCOLORKEY | SDL_RLEACCEL, color) );
        }
       
        // Draw the object on a screen object
        int  drawonscreen (SDLScreen* scr, int x, int y)
        {
                SDL_Rect dest_rect;
                dest_rect.x = x;
                dest_rect.y = y;
                dest_rect.w = 0;
                dest_rect.h = 0;
                SDL_Surface *temp = scr->getsurface ();
                int retflag =  SDL_BlitSurface (object, &object_rect, temp , &dest_rect);
                SDL_FreeSurface (temp);
                return retflag;
        }
       
        // Get the raw surface
        SDL_Surface* getsurface ()
        {
                return object;
        }
       
        // Destructor
        ~SDLObject ()
        {
                SDL_FreeSurface (object);
        }
};

SDLSprite class: Animated sprite class which contains an array of SDLObjects (I deliberately used container class rather than deriving from SDLObject for certain reasons.

Code:

class SDLSprite
{
protected:
        SDLObject* spriteframe;
        int nframes;
        int framewidth;
        int currentframe;
       
public:
        // Constructor - initialize sprite object to NULL
        SDLSprite ()
        {
                spriteframe = NULL;
                currentframe = 0;
        }
       
        // Create a sprite from an image file by getting the width and calculating the number
        // of frames. Store each frame as an SDLObject. Also get the transparent pixel
        int createsprite (char* imagefile, int fw, Uint8 r, Uint8 g, Uint8 b)
        {
                // First temporary object
                SDLObject temp;
                temp.createimage (imagefile, 0, 0);
                               
                int totalwidth = temp.getwidth ();
                int totalheight = temp.getheight ();
               
                framewidth = fw;
               
                // If the framewidth is > total width, then no go       
                if (framewidth > totalwidth)
                        return -1;
               
                nframes = totalwidth / framewidth ;
               
                // If the sprite is not null
                if (spriteframe != NULL)
                        delete[] spriteframe;
               
                spriteframe = new SDLObject[nframes];
               
                // Create each frame
                for (int i = 0; i < nframes; i ++)
                {
                        spriteframe[i].createimage (imagefile, i * framewidth, 0, framewidth);
                        spriteframe[i].settransparentcolor (r, g, b);
                }
       
                return 0;
        }
       
        // Render a single frame of animation on the screen
        int renderframe (SDLScreen* screen, int frame, int x, int y)
        {
                // If the frame is > than the current frame
                if (frame >= nframes)
                        return -1;
               
                currentframe = frame;
                return ( spriteframe[frame].drawonscreen (screen, x , y) );
        }

        // Render the current frame
        int rendercurrentframe (SDLScreen* screen, int x, int y)
        {               
                return ( spriteframe[currentframe].drawonscreen (screen, x, y) );
        }

        // Render the next frame
        int rendernextframe (SDLScreen* screen, int x, int y)
        {
                currentframe ++;
                if (currentframe >= nframes)
                        currentframe = 0;
               
                return ( spriteframe[currentframe].drawonscreen (screen, x, y) );
        }
       
        // Get the frame width
        int getframewidth ()
        {
                return framewidth;
        }

        // Destructor - delete the sprite
        ~SDLSprite ()
        {
                delete[] spriteframe;
        }
};

SDLMusic class: Very simple wrap around to SDL_mixer just to play music.

Code:

// This class is used to play SDL Music
class SDLMusic
{
protected:
        Mix_Music* music;
        std::string filename;
        int loops, freq, format, channels, chunksize;
public:
        SDLMusic (char* file, int l=1)
        {
                filename = file;
                loops = l;
                freq = MIX_DEFAULT_FREQUENCY;
                format = MIX_DEFAULT_FORMAT;
                channels = 2;
                chunksize = 4096;
        }
       
        SDLMusic (char* file, int l, int fr, int fmt, int ch, int csz)
        {
                filename = file;
                loops = l;
                freq = fr;
                format = fmt;
                channels = ch;
                chunksize = csz;
        }
       
        int initialize ()
        {
                if (Mix_OpenAudio (freq, format, channels, chunksize) < 0)
                        return -1;
                music = Mix_LoadMUS (filename.c_str ());
                if (music == NULL)
                        return -2;
               
                return 0;
        }
       
        int play ()
        {
                return ( Mix_PlayMusic (music, loops) );
        }
       
        void stop ()
        {
                Mix_HaltMusic ();
        }
       
        ~SDLMusic ()
        {
                Mix_FreeMusic (music);
                Mix_CloseAudio ();
        }
};


dmail 07-31-2006 07:17 AM

SDLscreen:
I see you pass the creation flags to the constructor and as I can't see the actual source of the creation of the screen, I suspect you are not taking advantage of the hardware. Try a call to SDL_video_mode() (think thats the correct func) and find out if you can hardware blit and if you can use hardare memory.

SDLSprite:
I don't like the hierarchy for this class (sorry), why should a sprite know about the object? Shouldn't an animated object contain a sprite class.

rendernextframe(...):
I wonder if the implemenation is really what you want? I don't see any mention of timimg. How often does the image change ie what is it's frequency. This makes me wonder if you are going to be doing time based movement at all, if not then you are designing something that will play completly different on different machines with diff cpu's gpu's etc. So with low spec you character will crawl across screen; yet with high spec he will run like Ben Johnson in the olympics.

Destructors:
I see you are deleting dynamic memory, but you do not check if its valid first this can cause hard to track problems, what if the intailisation fails and the destructor is called? You could either use boosts smart pointers or do a check
if(some_ptr){delete some_ptr;some_ptr=0;}

In SDLscreen you call the sdl free on the surface, but you do not own this surface and should not free it, sdl will do this. A small point; is there only one SDLsurface? as you are calling sdl_quit in the destructor.

Seeing as you like books, do you want some titles for game dev?

Have a look at
http://www.gamedev.net/reference/
it has some excellent articles which may help you and the forums of the same site will be of great use.

vharishankar 07-31-2006 07:30 AM

Quote:

I see you pass the creation flags to the constructor and as I can't see the actual source of the creation of the screen, I suspect you are not taking advantage of the hardware. Try a call to SDL_video_mode() (think thats the correct func) and find out if you can hardware blit and if you can use hardare memory.
It's there. Actually scroll down to the "initialize()" function.

Quote:

SDLSprite:
I don't like the hierarchy for this class (sorry), why should a sprite know about the object? Shouldn't an animated object contain a sprite class.
It's just nomenclature. I think I should just swap sprite and object terminology.

Quote:

rendernextframe(...):
I wonder if the implemenation is really what you want? I don't see any mention of timimg. How often does the image change ie what is it's frequency. This makes me wonder if you are going to be doing time based movement at all, if not then you are designing something that will play completly different on different machines with diff cpu's gpu's etc. So with low spec you character will crawl across screen; yet with high spec he will run like Ben Johnson in the olympics.
Actually I'm using this function call in the game loop. So timing is handled by the main game loop as in a normal SDL program where I can control the FPS (I know, it's not very clean OO coding, but I told you it was quick and dirty). As far as I can see, the sprite class need know nothing about timing since it's not doing the actual animation but just holding the frames and provide an easy way to render them - as such it's a glorified structure and not much more.

Quote:

Destructors:
I see you are deleting dynamic memory, but you do not check if its valid first this can cause hard to track problems, what if the intailisation fails and the destructor is called? You could either use boosts smart pointers or do a check
if(some_ptr){delete some_ptr;some_ptr=0;}
I know, I should do a lot more error checking. But as I said, it's something I hacked up in a couple of days. I expect I'll be cleaning up the classes a lot more.

Quote:

In SDLscreen you call the sdl free on the surface, but you do not own this surface and should not free it, sdl will do this. A small point; is there only one SDLsurface? as you are calling sdl_quit in the destructor.
Thanks for pointing that out. Yes, I plan on using only one SDLScreen object. I should probably not use SDL_Quit there. Maybe I should use a different SDLApp class to do that.

I'm a reluctant OO programmer as you can see my code and I don't give my classes too much functionality. To me I use classes simply to make the main program cleaner to code and not because I am an OO programming expert as such.

On a side note, this is also one reason why I am uncomfortable with Java which forces OO down your throat.

You can call me a structure driven programmer as most of my classes are glorified structures.. I usually don't mess around with inheritance, hierarchy, abstraction and all that stuff.

Thanks for your critique by the way. I am well aware of the shortcomings of this code but I was more interested in the actual usage of SDL and getting/testing the functionality rather than clean coding at the time. I'll definitely be cleaning this all up.

dmail 07-31-2006 07:47 AM

Quote:

Originally Posted by Harishankar
It's there. Actually scroll down to the "initialize()" function.

You misunderstand me have a look at this initialise func (disreguard the opengl calls).

Quote:

Actually I'm using this function call in the game loop. So timing is handled by the main game loop which I can control the FPS (I know, it's not very clean OO coding, but I told you it was quick and dirty). As far as I can see, the sprite class need know nothing about timing since it's not doing the actual animation but just holding the frames.
So does this mean all objects which have sprites have the same frequency?
Quote:

Thanks for your critique by the way. I am well aware of the shortcomings of this code but I was more interested in the actual usage of SDL than clean coding at the time. I'll definitely be cleaning this all up.
This is something which I was going to remark on in the previous post. The problem is you need to design anything like making a game or a framework, heres the catch22 how can you design when you don't know the API. This is something which I have faced many times, what I would say is keep it "dirty" and do not strive for a reusable framework; instead learn the API and then create the framework. In the end this will help you create a very good reusable piece.

vharishankar 07-31-2006 07:58 AM

Quote:

So does this mean all objects which have sprites have the same frequency?
Definitely not. Of course I can use a different check for different objects in the loop. In my example code (which is not here at the moment) I'm using a variable in the loop to control object speed to a certain iteration per x frames. There's no reason why another object shouldn't use a different one.

As I said, I didn't post the "main()" function from my code here. But I'm definitely using this along with the program and testing it as I go along so I know it at least works.

Quote:

You misunderstand me have a look at this initialise func (disreguard the opengl calls).
Hm... what is the specific call I should look at? Also if you notice, the flags are passed into the initialize function. The class is very thin that way. No checks, nothing, just simple initialization. Deliberately kept that way at the moment...

Or am I missing something?

Quote:

This is something which I was going to remark on in the previous post. The problem is you need to design anything like making a game or a framework, heres the catch22 how can you design when you don't know the API. This is something which I have faced many times, what I would say is keep it "dirty" and do not strive for a reusable framework; instead learn the API and then create the framework.
Actually I'm doing both at the moment. I'm testing the same code without object orientation. My idea is not a grand one of creating a "framework" for the whole SDL but a simple way to use SDL in my programs by taking away much of the repetitive code.

At least that's my idea initially. To make my main program avoid using tons of SDL calls and SDL Surfaces everywhere and make it messy. It's definitely dirty coding at the moment, but the advantage in my method is that once I clean up the classes, that's pretty much all I have to do.

Thanks for your tips, by the way. Very useful to know where to head.

dmail 07-31-2006 08:14 AM

Quote:

Originally Posted by Harishankar
Definitely not. Of course I can use a different check for different objects in the loop. In my example code (which is not here at the moment) I'm using a variable in the loop to control object speed to a certain iteration per x frames. There's no reason why another object shouldn't use a different one.

Surely the frequency at which the sprite changes frames is an attribute of the sprite itself. Something that can be changed by another class, but which is a property of the sprite itself.

Quote:

Hm... what is the specific call I should look at? Also if you notice, the flags are passed into the initialize function so the calling function should do all the required checks as to the best video mode etc. etc. The class is very thin that way.

Or am I missing something?
As i said before I am unsure because I can't see the call which creates the window and therefore can not see the flags passed.
From that comment, I now think the following is redundent but i'll post it anyway.
Line 83 get the video info
line 97 store pallette in hardware
line 102 checks to see if surfaces can be stored in memory
line 115 check if hardware blits can be done


All times are GMT -5. The time now is 01:30 AM.