Page 1 of 2

OO Design Question

Posted: Thu Apr 02, 2009 12:07 am
by Maevik
If I have a class, and inside one of my class functions I wish to call a function that is part of my main code. How can I do this if my class is written as part of example.cpp and the function I want to call is part of main.cpp with the #include example.h ?

Re: OO Design Question

Posted: Thu Apr 02, 2009 3:01 am
by kostiak2
Maevik wrote:If I have a class, and inside one of my class functions I wish to call a function that is part of my main code. How can I do this if my class is written as part of example.cpp and the function I want to call is part of main.cpp with the #include example.h ?
The real question is why would you want to do that?

Maybe it's a smart design choice, but maybe, there is a better way to do it, so what are you trying to achieve exactly?

Re: OO Design Question

Posted: Thu Apr 02, 2009 7:08 am
by MarauderIIC
You would need the function prototype for the function that's in main.cpp to be present in example.cpp or example.h. Then you can call it normally. However, in an OO design, it is uncommon to have (m)any functions besides main() not be in a class of some sort (in other words, main() is the only function not inside a class). You may want to take another look at your design.

Re: OO Design Question

Posted: Thu Apr 02, 2009 1:44 pm
by Maevik
ok, lets say for instance I want to make a game using the blitting functions similar to those in lazyfoo's SDL tutorials. Let's also say that I want my objects to handle blitting their own surface to the screen.

Code: Select all

//The blitting function

void applySurface( int x , int y , SDL_Surface* source , SDL_Surface* destination , SDL_Rect* clip = NULL )
{
     SDL_Rect offset;
     offset.x = x;
     offset.y = y;

     SDL_BlitSurface( source , clip , destination , &offset );
}

Code: Select all

//An Example Class, let's say its a squirrel

class squirrel
{
private:
     int xLoc;
     int yLoc;
     SDL_Surface image;
public:
     void processInput( SDL_Event* event );
}

Code: Select all

//An example of what the processInput() function might look like

void squirred::processInput( SDL_Event* event)
{
     if( event.type == SDL_KEYDOWN )
     {
          if( event.key.keysym.sym == SDLK_UP )
          {
               yLoc -= 5;
          }
          else if( event.key.keysym.sym == SDLK_UP )
          {
               yLoc += 5;
          }
          /* blah blah blah, test screen limits and left and right and all that stuff */
     }

     //Here is where I would put the blit function to have my squirrel function draw itself to the screen.
}
So based on what Marauder is saying, I shouldn't even have the applySurface() function in my main code in the first place?

Could I then build a class called like "screen" or something, and give it those functions ( load Images, blit surfaces, initialize video mode... ) then pass the instance of my screen class into the squirrel.processInput() function along with &event ?

Code: Select all

void squirred::processInput( SDL_Event* event , myScreenClass* screen )
{
     .    
     .
     .
     screen.applySurface( xLoc , yLoc , image , screen.screenSurface );     
}
Would this be the /better/ way to do it? Is it good practice to create a class for something if you know you will only make one instance of it?

edit: edited for clarity

Re: OO Design Question

Posted: Thu Apr 02, 2009 2:37 pm
by MarauderIIC
I have something like

Code: Select all

class Game {
    Renderer renderer;
    vector<Object*> objects;
    void init();
    void handleInput();
    void update(); //Update positions
    void drawAll();
};

Code: Select all

class Object {
    int x, y;
    SDL_Surface* mySurface; //This is also an element in Renderer::loadedTextures
    public:
    SDL_Surface* getSurface();
};

Code: Select all

class Renderer {
    ...
    SDL_Surface* screen;
    SDL_Surface* background;
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    map<string, SDL_Surface*> loadedTextures;
    public:
    void draw(SDL_Surface* surf, int x, int y);
    void finishFrame();
    ~Renderer(); //This frees all the textures.
};

Code: Select all

void Game::drawAll() {
    for (vector<Object*>::iterator i = objects.begin(); i != objects.end(); ++i) {
        renderer.draw(i->getSurface(), i->getX(), i->getY());
    renderer.finishFrame();
}

Code: Select all

void Renderer::draw(SDL_Surface* surf, int x, int y) {
    SDL_Rect offset;
    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(surf, NULL, screen, &offset);
}

Code: Select all

void Renderer::finishFrame() {
    SDL_Flip(screen);
    SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 255, 255, 255)); //Reset
}
The game invokes the Renderer on all of its objects. Renderer does all the drawing. Then the game tells the renderer it's done sending objects, and the Renderer finishes. You could also pass the Renderer a list of objects and make it iterate through them, instead of one at a time, then it would know when it should wrap up the frame without the Game telling it to.

Re: OO Design Question

Posted: Thu Apr 02, 2009 3:13 pm
by kostiak2
Yeah, lazyfoo's tutorials are great, his code is terrible.. The design you suggested should be done like that, instead use something similar to what MarauderIIC suggested. I use something similar to this. (Not as complicated as that yet, but as I see it, I'll be there soon).

Re: OO Design Question

Posted: Thu Apr 02, 2009 4:34 pm
by Maevik
Thanks for all the constructive feedback guys. This is immesely helpful.

Re: OO Design Question

Posted: Fri Apr 03, 2009 6:59 pm
by dandymcgee
Thanks Marauder, that helped answer part of my question posted elsewhere. 8-)

Re: OO Design Question

Posted: Sat Apr 04, 2009 12:46 pm
by programmerinprogress
And it helped me too!

thanks for the advice ;)

Re: OO Design Question

Posted: Thu Apr 09, 2009 12:49 am
by Maevik
MarauderIIC wrote:I have something like

Code: Select all

class Game {
    Renderer renderer;
    vector<Object*> objects;
    void init();
    void handleInput();
    void update(); //Update positions
    void drawAll();
};

Code: Select all

class Object {
    int x, y;
    SDL_Surface* mySurface; //This is also an element in Renderer::loadedTextures
    public:
    SDL_Surface* getSurface();
};

Code: Select all

class Renderer {
    ...
    SDL_Surface* screen;
    SDL_Surface* background;
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    map<string, SDL_Surface*> loadedTextures;
    public:
    void draw(SDL_Surface* surf, int x, int y);
    void finishFrame();
    ~Renderer(); //This frees all the textures.
};

Code: Select all

void Game::drawAll() {
    for (vector<Object*>::iterator i = objects.begin(); i != objects.end(); ++i) {
        renderer.draw(i->getSurface(), i->getX(), i->getY());
    renderer.finishFrame();
}

Code: Select all

void Renderer::draw(SDL_Surface* surf, int x, int y) {
    SDL_Rect offset;
    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(surf, NULL, screen, &offset);
}

Code: Select all

void Renderer::finishFrame() {
    SDL_Flip(screen);
    SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 255, 255, 255)); //Reset
}
The game invokes the Renderer on all of its objects. Renderer does all the drawing. Then the game tells the renderer it's done sending objects, and the Renderer finishes. You could also pass the Renderer a list of objects and make it iterate through them, instead of one at a time, then it would know when it should wrap up the frame without the Game telling it to.
I was trying to see how far I could get trying to build an engine with this design. I came to a compiler error along the way that I absolutely cannot figure out. I thought that since I'm essentially trying to mirror your code, you might be in a position to help me :D

Code: Select all

#pragma once
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include "SDL_mixer.h"
#include <string>
#include <vector>
#include "Renderer.h"

class Game
{
private:
	//Renderer rend;
public:
	Game(void);
	bool init();
	void input( SDL_Event* event , Renderer* rend );
	~Game(void);
};

Code: Select all

error C2061: syntax error : identifier 'Renderer'	
It doesn't like me initializing an instance of the Rederer class ( you can see the two ways I was trying, both same error ) and I can't figure out why.

It doesn't seem to be a problem with the Renderer class, since if I initialize an instance in the main function it works fine.

Is there something special I need to do when making a class a member of another class?

Re: OO Design Question

Posted: Thu Apr 09, 2009 1:42 am
by Maevik
So this just started working when I created a test class to see if it was happening with any other classes that I make members. So although I was still confused about what had happened and why, I continued on with my project. After about 10 minutes, it just stopped compiling again. The exact line I changed between successful compiles was adding this line ( and only this line ) to the Renderer class deconstructor

Code: Select all

SDL_FreeSurface( background );
Even after I removed the line it would not compile again. This doesn't make sense to me at all.

Re: OO Design Question

Posted: Thu Apr 09, 2009 5:53 am
by Ginto8
Maevik wrote:So this just started working when I created a test class to see if it was happening with any other classes that I make members. So although I was still confused about what had happened and why, I continued on with my project. After about 10 minutes, it just stopped compiling again. The exact line I changed between successful compiles was adding this line ( and only this line ) to the Renderer class deconstructor

Code: Select all

SDL_FreeSurface( background );
Even after I removed the line it would not compile again. This doesn't make sense to me at all.
did you allocate background? That may be the problem.

Re: OO Design Question

Posted: Thu Apr 09, 2009 10:19 am
by wtetzner
Ginto8 wrote:
Maevik wrote:So this just started working when I created a test class to see if it was happening with any other classes that I make members. So although I was still confused about what had happened and why, I continued on with my project. After about 10 minutes, it just stopped compiling again. The exact line I changed between successful compiles was adding this line ( and only this line ) to the Renderer class deconstructor

Code: Select all

SDL_FreeSurface( background );
Even after I removed the line it would not compile again. This doesn't make sense to me at all.
did you allocate background? That may be the problem.
That wouldn't stop it from compiling. Maevik, what error message are you getting when you compile?

Re: OO Design Question

Posted: Thu Apr 09, 2009 12:20 pm
by Maevik
error C2061: syntax error : identifier 'Renderer'

It's been happening on and off still, to the point where I'm almost convinced it's a Visual Studio 9 bug. I'm really hesitant to chok it up to that though, especially when I'm learning. I just can't find any reason for the behavior I'm seeing, and I'll change something seemingly unrelated, then it wont compile, then when I change it back, it still wont compile.

Re: OO Design Question

Posted: Thu Apr 09, 2009 12:22 pm
by Maevik
Ginto8 wrote:
Maevik wrote:So this just started working when I created a test class to see if it was happening with any other classes that I make members. So although I was still confused about what had happened and why, I continued on with my project. After about 10 minutes, it just stopped compiling again. The exact line I changed between successful compiles was adding this line ( and only this line ) to the Renderer class deconstructor

Code: Select all

SDL_FreeSurface( background );
Even after I removed the line it would not compile again. This doesn't make sense to me at all.
did you allocate background? That may be the problem.
I'm not sure what you're asking. I didn't put background on the heap if that's what you mean, but I did load the file and optimize it with SDL_DisplayFormat(), it works and displays the background ~half the time.