Looking for a Game Tutorial
Gabriel Campos

Hi everybody...
I am looking for a tutorial on how to make a game...not the programing...I looking for the concepts...for example..
I make the scroll of my game creating a variable CameraX and then adding each time you press the right button...
Then all I draw..tilemaps, enemy, etc... I subtract they x value from CameraX..

#SelectExpand
1if(key[KEY_RIGHT]) 2 CameraX+=Speed; 3 4 5Draw(BITMAP *Buffer){ 6 masked_blit(Sprite, Buffer, Frame*W, Stance*H, x - CameraX, y, W, H); 7}

It works..but when i start to put enemies to stage it becomes dificult and my program become a really mess...:P
All I want is some concepts of things like...To scroll I create a object Camera or make the variables in the player object....There is another way better to scroll??
Things like that would help me a lot...

bamccaig

It sounds to me like your problem is just organizing data and code. Perhaps what you are looking for is object-oriented programming? Perhaps you're looking for something like this to clean the code up:

renderer.render(player, camera);
renderer.render(enemy1, camera);
renderer.render(enemy2, camera);

???

Otherwise, I'm afraid that I don't understand what you're asking. :)

Arthur Kalliokoski

I think what she's (?) asking is how to make a game, she's got the C/C++ language and Allegro API down, but what's next?

@Gabriel Campos:
It would help if you told us what kind of game you're making, I'm guessing a side scroller of some type? Do you have some commercial game in mind to emulate?

Dario ff

Gabriel is a male name. :-/

Arthur Kalliokoski

So why did he pick a hot chick for his avatar?

[EDIT]

Upon zooming way in to the image, I guess it could be a guy... a great big ODARN echos through the trailer park!

Dario ff

If you think that's a hot chick, then so be it. I'm not going to question your tastes. ;)

On-topic: Gabriel, there are quite a lot of tutorials on the net depending on the genre you're looking for. I remember finding once a tutorial for a 2D map style like the old JRPGs(think SNES), and it was specific to Allegro as well. These are quite helpful in opening up more room for thinking and creating new, different engines. In the end, it all comes down to your creativity in doing an engine that can be maintained, that is efficient, and flexible. And that it doesn't give you a headache when coding.

gnolam
Dario ff said:

If you think that's a hot chick, then so be it.

Hot is debatable, but it's definitely a chick.

Matthew Leverton

Looks like a male FF character to me. :P

It works..but when i start to put enemies to stage it becomes dificult and my program become a really mess...:P

What is a mess? The code? Or does the game not render correctly?

Dario ff

Here's the article I was talking about.

The Beginners Guide to RPG's in Allegro and C/C++

gnolam said:

Hot is debatable, but it's definitely a chick.

The size of the head seems to steer it into the "chick" side, though with the FF style, you never know. ;)

Neil Walker
Arthur Kalliokoski

ah, yes

{"name":"sephiroth.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/e\/fe29d8fa7ec9d9abc59a03c66f76c1a8.jpg","w":432,"h":405,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/e\/fe29d8fa7ec9d9abc59a03c66f76c1a8"}sephiroth.jpg

Dario ff

Indeed, it's Sephiroth:

{"name":"sugg-sephiroth.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/9\/198ef57c0d7ca8c9fef293bfe8769391.jpg","w":400,"h":665,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/9\/198ef57c0d7ca8c9fef293bfe8769391"}sugg-sephiroth.jpg

EDIT: Ninjad!

EDIT: Ok, so what does this tell us regarding gnolam and Arthur? :P

Neil Walker

I must state that I know nothing of Final Fantasy, I just found it here, which was really quite good I thought:

http://www.tineye.com/

and pointed it at the forum static image.

Arthur Kalliokoski

And I selected the Sephiroth string and right-clicked to "Search Google" then selected Images.

bamccaig
gnolam
Dario ff said:

Ok, so what does this tell us regarding gnolam and Arthur? :P

That we're not anime-damaged enough to view ladyboys as male?

Dario ff

Swift escape. At least you didn't call him hot. ;) Though in my defense, I based myself on the fact that the name is common for males on Latin America. ;)

Ok, enough off-topic for now.

Gabriel Campos

Well...Its Sephiroth from Final Fantasy...I will change later:P;D
(*thinking* They program games and dont know final fantasy?::))
I will try to be more clear . . .
I am making a platform game...a megaman game..
the link for my game. . .
http://www.4shared.com/file/jfK0vjFo/MEGAMAN.html
A = shoot (hold to charge)
Z = jump
ESC = exit game

I have a good knowledge in c++ and allegro... This is some codes from my game...

#SelectExpand
1//I create a Header file for each class 2 3class cPlayer : public cRect{ // cRect is a class to check collision 4private: 5 int x, y...etc 6 int CameraX, CameraY; 7public: 8 cPlayer(int, int); // Initializate the variables 9 ~cPlayer(); // dont need to comment 10 void Input(); 11 void Update(); 12 void Draw(BITMAP); 13}; 14 15int main(){ 16 while(!GameManager.Done){ 17 clear(Buffer); 18 Player.Input(); 19 Player.Update(); 20 Player.Draw(Buffer); 21 draw_sprite(screen, Buffer, 0, 0); 22}

Basiclly this is my code and I use in this manner for the other objects like enemies, etc...

My problems starts here when I start to put more objects in the game...
Because I have to check the position of the objects adding (enemy.x - Player.CameraX) . its become a mess . .
I know I need to learn more OOP so i am asking a light in this point . .
I want to know things like:

??? Its better to create on cPlayer a variable CameraX or create a object / class called cCamera?
??? If create a object Camera how to make the other objects like player to recognize it?? I tryed to create a pointer in the constructor of the player but doesnt work

#SelectExpand
1class cPlayer{ 2 cCamera *Camera; 3}; 4 5cPlayer::cPlayer(cCamera *iCamera){ 6 Camera = iCamera; 7} // this doesnt work for me...

??? Whats the better way to scroll??
Well, things like that ...Will help a lot me and begginers too..

Dario ff

Its better to create on cPlayer a variable CameraX or create a object / class called cCamera

Certainly a Camera should be a single object IMO.

Quote:

If create a object Camera how to make the other objects like player to recognize it?? I tryed to create a pointer in the constructor of the player but doesnt work

Your code snippet doesn't look wrong there, I'd say that you're not passing the pointer properly.

But IMO, the key is that maybe the objects shouldn't render themselves to the screen, but actually let a "Renderer" object handle it. That way, you can make different "displays" based on the same world.

Quote:

Whats the better way to scroll??

I guess your camera class should handle that.

EDIT:

Quote:

They program games and dont know final fantasy?

FF7, no. 8-) I know about the character, but I couldn't recognize it at first sight on your avatar.

Gabriel Campos

Hmmm....
But I will pass the objects in parameters??

#SelectExpand
1 2Renderer.Render(&Player, &Camera);

But how I define the Renderer class??

#SelectExpand
1class cRenderer{ 2 3 void Render( /* what parameters here??? */);

???

J-Gamer

I always have a class Object as a base class for every object that has to be drawn, and have it have at least one virtual function: virtual void draw();
Then, I have a vector of Object pointers to all objects. The drawing code looks like this:

for(int i = 0; i<objectsvector.length(); i++)
{
    Renderer.render(objectsvector[i],&Camera);
}

And in the render function:

void cRenderer::render(Object* object, cCamera* camera)
{
    masked_blit(object->getSprite(), Buffer, object->getFrame()*object->getW(), object->getStance()*object->getH(), object->getX - camera->getX, object->getY - camera->getY(), object->getW(), object->getH());
};

you will have to make getW,getH,getY,getX,getSprite,... virtual members of Object as well.

bamccaig

Well...Its Sephiroth from Final Fantasy...I will change later:P;D

No need to change it. :)

(*thinking* They program games and dont know final fantasy?::))

<------ Ahem.

??? Its better to create on cPlayer a variable CameraX or create a object / class called cCamera?

I would create a camera class. I would probably just name it Camera though. Assuming the 'c' stands for "class", it is a useless prefix that won't add anything useful to the game. If you need more than one camera type then use namespaces to organize them or give them more descriptive names.

??? If create a object Camera how to make the other objects like player to recognize it?? I tryed to create a pointer in the constructor of the player but doesnt work

As Dario ff pointed out, I would probably not let the player class know about the camera class. Let the camera be managed separately.

But how I define the Renderer class??

class cRenderer{
     
   void Render( /* what parameters here??? */);

Rather than passing pointers, you might as well pass references. You might do something like this:

renderer.hpp#SelectExpand
1#ifndef RENDERER_HPP 2 #define RENDERER_HPP 3 4class Renderer 5{ 6private: 7 BITMAP * buffer; 8 BITMAP * screen; 9 10 int getScreenX(const Camera &, const Player &) const; 11 int getScreenY(const Camera &, const Player &) const; 12public: 13 Renderer(BITMAP *); 14 15 void paint(void); 16 void render(const GameTime &, const Camera &, const Player &); 17}; 18 19#endif

renderer.cpp#SelectExpand
1#include "renderer.hpp" 2 3Renderer::Renderer(BITMAP * screen) 4{ 5 assert(screen); 6 7 this->screen = screen; 8 this->buffer = create_bitmap(screen->w, screen->h); 9 10 if(!this->buffer) 11 { 12 throw new std::runtime_error( 13 "Failed to create screen buffer."); 14 } 15} 16 17int Renderer::getScreenX( 18 const Camera & camera, 19 const Player & player) const 20{ 21 return player.getX() - camera.getX(); 22} 23 24int Renderer::getScreenY( 25 const Camera & camera, 26 const Player & player) const 27{ 28 return player.getY() - camera.getY(); 29} 30 31void Renderer::render( 32 const GameTime & time, 33 const Camera & camera, 34 const Player & player) 35{ 36 int x = this->getScreenX(camera, player); 37 int y = this->getScreenY(camera, player); 38 BITMAP * frame = player->getFrame(time); 39 40 blit(frame, this->buffer, x, y, 0, 0, frame->w, frame->h); 41} 42 43void Render::paint(void) 44{ 45 blit( 46 this->buffer, 47 this->screen, 48 0, 49 0, 50 0, 51 0, 52 this->buffer->w, 53 this->buffer->h); 54}

If you're comfortable with inheritance and polymorphism then you could do as J-Gamer suggested and create an IDrawable interface and just make your Player class and Enemy class and other drawable classes implement that interface. That way you should be able to easily draw anything that supports the drawing logic implemented.

Dizzy Egg

That picture of Sephiroth isn't from the game of FF7...thank Yevon for that.

bamccaig

It's from the FFVII: Advent Children promotional materials. :) IIRC, I think that I used that very picture of Sephiroth as my A.cc avatar back when I joined in 2006... :P Prior to switching to Cloud for long forgotten reasons. :)

Here's a direct link to the original wallpaper from the official [English] site: http://na.square-enix.com/dvd/ff7ac/wallpapers/wp1-1.jpg

Gabriel Campos

I think the way of J-Gamer show the solution is very good . . .and will help me with other things too..like drawing by the Depth.
So, lets see...

#SelectExpand
1class cObject{ // Create a cObject class that will manager all drawable objects 2}; 3 4class cRenderer{ // Renderer class 5 BITMAP *Buffer; 6 7void Render(cObject * object, cCamera *camera){ 8 masked_blit(object->getSprite(), Buffer, object->getFrame()*object->getW(), Object->getStance()*object->getH(), object->getX - camera->getX, object->getY - camera->getY(), object->getW(), object->getH()); 9} 10}; 11 12 13int main(){ 14 std::vector<cObject *>Objects; 15 for(int i = 0; i < Objects.length(); i++){ 16 Renderer.Render(Objects[i], &Camera); 17 } 18}; 19END_OF_MAIN();

Is this the way correct??
I dont understood why J-Gamer said to use a virtual void draw();
Is really necessary??

Neil Walker

I dont understood why J said to use a virtual void draw();

I haven't read the thread, but he's probably referring to polymorphism, i.e. loose coupling is king.

It means you can have lots of sub-classes but still have call draw() called correctly when using the base class, e.g. assuming Sprite1 and Sprite2 were inherited from Object, then:

void MyGreatFunction(Object* a)
{
a->draw();
}

if not using virtual then Object::draw would be called. If using virtual then the correct ones are. The drawback is a slight overhead in determining the correct method to call.

bamccaig

I think that J-Gamer starting giving one suggestion and ended up giving a better one. Ignore the part about the draw method. Game objects generally shouldn't know how to draw themselves (they should have no concept of a screen, etc.). A third-party, like the Renderer concept should know how to draw all objects. It's the getSprite or getFrame method that you'll want to be virtual (and likely abstract AKA pure virtual) in the base class.

J-Gamer
bamccaig said:

I think that J-Gamer starting giving one suggestion and ended up giving a better one.

Did I? ;D

bamccaig said:

Ignore the part about the draw method.

I always have a draw() method in each game object. Those functions mostly take (BITMAP* buffer,float x,float y) as parameters. I do it this way, because e.g. my spacecraft has to be drawn in different ways according to a frame and mode variable within the spaceship class.

james_lohr

Well, at least you were able to identify that your code looks ugly. That's an important step. Now you just need a decade or so of experience and you might be able to write some decent code. :P

Gabriel Campos

So lets see if I understand . . .

I must have a class cObject, a class cRenderer . . .

#SelectExpand
1class cObject{ // Create a cObject class that will manager all drawable objects 2}; 3 4class cRenderer{ // Renderer class 5 BITMAP *Buffer; 6 7void Render(cObject * object, cCamera *camera){ 8 masked_blit(object->getSprite(), Buffer, object->getFrame()*object->getW(), Object->getStance()*object->getH(), object->getX - camera->getX, object->getY - camera->getY(), object->getW(), object->getH()); 9} 10}; 11 12 13int main(){ 14 std::vector<cObject *>Objects; 15 for(int i = 0; i < Objects.length(); i++){ 16 Renderer.Render(Objects[i], &Camera); 17 } 18}; 19END_OF_MAIN();

Now my last doubt(I think) . .
First, is this code correct?
And, where I put the virtual draw??
in the class cObject, in the class cRenderer or in the other classes (player, hud, enemy)??:-/

J-Gamer

And, where I put the virtual draw??
in the class cObject, in the class cRenderer or in the other classes (player, hud, enemy)??:-/

You're mixing up two concepts here... You can do it by putting a virtual draw function in the cObject class, and making all classes like player,hud,enemy,... members of it with their own non-virtual draw that draws them. OR, you can have a cRenderer class draw function that checks all Objects for their type and draws them accordingly. In the latter, you have all drawing code in the cRenderer class, whereas in the former, you have the corresponding drawing code specified in each of the classes.

bamccaig
J-Gamer said:

I do it this way, because e.g. my spacecraft has to be drawn in different ways according to a frame and mode variable within the spaceship class.

Out of curiosity, what kinds of things vary based on the "frame" and "mode"? :)

J-Gamer

Most of the time: which of the bitmaps in the different sequences are drawn.

I have e.g.: a flying mode, propulsion mode, explosion mode, vanish mode, etc.
For the flying mode, nothing special, just a plain spaceship sprite.
Propulsion mode: increase frame, draw corresponding bitmap in the propulsion sequence
Explosion: idem as propulsion, except it doesn't loop trough the sequence.
vanish mode: get smaller and smaller, according to the frame(amount of frames is set beforehand)

bamccaig

I think you should be able to accomplish all of those with an animation class and possibly a separate interface for spaceship position vs. spaceship sprite position (if those aren't always the same as the position).

The getSprite(gameTime) or getFrame(gameTime) method should return an appropriate sprite for the given mode/animation/game time. That way the actual drawing can be handled by a single rendering class and the differences in what are drawn get returned by the individual objects (preferably managed by another class under the surface, like an animation class, if non-trivial). This way your objects don't need to know anything about the drawing surface, or how to be drawn at all. They only store the data that is their state (including the visual and audio representation) and separate service objects, like our renderer, determine what to do with that data.

???

Neil Walker

I remember about 15 years ago when I first got started into game coding (at that point I thought there was something magical and complicated about how you display moving things, not knowing it was just a case of blanking the screen and drawing stuff elsewhere), I wondered whether when a player picked up an item and moved with it, whether I had to have a graphic with the player and the item and thought this will take a lot of graphics ;)

Thomas Fjellstrom

/me thinks bamccaig is falling into the OO/C++ trap of overcomplicated, overengineered patterned designs...

bamccaig

That might be what it sounds like, but in actuality it's simplifying the design instead of complicating it. Instead of making 20 different redundant calls to blit or al_draw_bitmap or whatever, you make one (or a handful) and everything else just works the same way. Your objects have a visual state and another external class knows how to draw that state (but knows nothing of specific types, like spaceships or moonmen or whathaveyou). It's actually a lot simpler of a design, but it requires a bit of forethought. :)

Thomas Fjellstrom
bamccaig said:

That might be what it sounds like, but in actuality it's simplifying the design instead of complicating it.

Depends. Every post you come up with more and more complicated patterns to add, for a BEGINNER. ;)

And no, it isn't simpler. :P

bamccaig

It's more complicated language-wise because you need to understand polymorphism, but the solution is simpler than redundantly duplicating the same basic logic over and over again. IIRC, the OP said he was knowledgeable in C++. At least, he seems comfortable enough to be introduced to/reminded of polymorphism and its benefits.

Thomas Fjellstrom
bamccaig said:

It's more complicated language-wise because you need to understand polymorphism

And a crap ton of new "design patterns". I'm not against a little polymprphosm, but springing a bunch of fancy design patterns on a newbie is silly in the extreme.

Quote:

At least, he seems comfortable enough to be introduced to/reminded of polymorphism and its benefits.

Just my oppinion, but if you haven't been introduced to Polymorphism, you aren't comfortable with C++, and you probably aren't ready for most of the fancy design patterns you are suggesting :P

Edgar Reynaldo

And a crap ton of new "design patterns". I'm not against a little polymprphosm, but springing a bunch of fancy design patterns on a newbie is silly in the extreme.

You don't need design patterns to use polymorphism, and there aren't any design patterns being used here...

All it is is inheritance, to replicate an interface for different classes, so they can be used interchangeably through a base class pointer.

#SelectExpand
1#include <allegro.h> 2 3class ObjectBase { 4protected : 5 BITMAP* sprite; 6 int x; 7 int y; 8public : 9 ObjectBase(BITMAP* image , int xpos , int ypos) : sprite(image) , x(xpos) , y(ypos) {} 10 virtual void DrawOn(BITMAP* bmp , int offsetx , int offsety) const { 11 ASSERT(bmp); 12 draw_sprite(bmp , sprite , xpos + offsetx , ypos + offsety); 13 } 14}; 15 16class Player : public ObjectBase { 17// ... 18}; 19 20class Camera { 21protected : 22 BITMAP* background; 23 int cx; 24 int cy; 25 int cw; 26 int ch; 27public : 28 Camera(BITMAP* bg , int xpos , int ypos , int width , int height) : 29 background(bg) , cx(xpos) , cy(ypos) , cw(width) , ch(height) {} 30 void SetPos(int xpos , int ypos) { 31 //... adjust xpos and ypos to make sure the camera doesn't go 'offworld' 32 cx = xpos; 33 cy = ypos; 34 } 35 void DrawBackground(BITMAP* bmp , int x , int y) { 36 ASSERT(bmp); 37 blit(background , buffer , cx , cy , x , y , cw , ch); 38 } 39 int X() {return cx;} 40 int Y() {return cy;} 41} 42 43class World { 44protected : 45 vector<ObjectBase*> objects; 46public : 47 void DrawOn(BITMAP* bmp , const Camera& cam) { 48 ASSERT(bmp); 49 cam.DrawBackground(bmp , 0 , 0); 50 int camx = cam.X(); 51 int camy = cam.Y(); 52 for (int i = 0 ; i < objects.size() ; ++i) { 53 objects->DrawOn(bmp , -camx , -camy); 54 } 55 } 56};

Thomas Fjellstrom

You don't need design patterns to use polymorphism, and there aren't any design patterns being used here...

I was talking about some of the stuff bamccaig was proposing. Fancy adapters and MVC...

Neil Walker

Good use of polymorphism as I said above helps you with loose coupling. What's worse - having a bit of thought before you write your code, or turning your code into spaghetti within a few weeks with either 30 case statements in a method or 10 methods that do the same thing but slightly different and having to remember what they all are?

I agree design patterns can be bad in the wrong hands and they do over-complicate things, but where it's relevant it makes things better. For example, most people end up coding using the Strategy, Adapter and Facade pattern without even realising it.

Gabriel Campos

Ok, lets some code:

#SelectExpand
1class cObject{ // This class will handle all objects in the game 2 private: 3 BITMAP *Buffer; 4 public: 5 virtual void Draw(cObject *Object, cCamera *Camera){ 6 // here comes a little doubt.. what to put here? 7 // Maybe this? masked_blit(Object->GetSprite(), Buffer, Object->GetFrame() * Object->GetW(), Object->GetStance() * Object->GetH(), Object->Getx(), Object->Gety(), Object->GetW(), Object->GetH()); 8} 9 10 void UpdateScreen(){ 11 draw_sprite(screen, Buffer, 0, 0); 12} 13}; 14 15............................................................................. 16 17class cPlayer : public cObject{ 18 private: 19 int x, y, W, H ..... // or maybe put this variables in the cObject class, because is common in all objects 20 BITMAP *Sprite; 21 public: 22 void Draw(){ // Here I declare the Draw in Normal?? This Way? 23 masked_blit(Sprite, Buffer, Frame * W, Stance * H, x, y, W, H); 24} 25}; 26 27............................................................................. 28 29class cCamera{ 30 int x, y....//and others definitions 31}; 32 33.............................................................................. 34 35#include <vector> 36 37int main(){ 38 std::vector<cObject *>Objects; 39 40for(int i=0; i < Objects.lenght(); i++){ 41 Objects[i].Draw(&Player, &Camera); 42} 43END_OF_MAIN();

Please, help me...I am learning a lot here... ;D

jhetfield21

if you have sprites then a good idea is to let the renderer class handle it.just make a spriteholder class(basically a class with a map/list/vector<string,Sprite*> of all the Sprites in your level or even the whole game though it's not advised) and whenever you instantiate a sprite you register it(insert it) in the sprite holder('s map/list/vector).so in the game loop the first thing you do is call the renderer and have it blit everything visible on the screen and afterward do every other calculation to change the state of the game,player,character etc so that in the next loop the renderer has all the updated info on the sprites including the new destination point and possibly another frame of the same film.

i'm currently taking a course in my uni for 2D bitmapped games and this is the way we are doing it.it's simple enough imo.then again it might not fit in this situation,i didn't really see the code but it's a good concept to know.and you don't need to implement any design patterns.

Audric

This is my take:
(I renamed cObject to cSprite because the name Object can cause a lot of confusion in c++.)

#SelectExpand
1class cSprite{ // This class will handle all moving bitmap objects in the game 2 cSprite() 3 { 4 Sprite=NULL; // Default: invisible (and non-crashing :) ) 5 } 6 public: 7 BITMAP *Sprite; // This points to an already allocated bitmap, or NULL when the object is invisible. 8 int X, Y; // Position in pixels, in "world" coordinates. 9 int W, H; // Any other members that all your cSprites need). 10 virtual void LogicUpdate(int tick); // Called once per game tick (assuming fixed-step timing). Has to be implemented by each derived class. 11} 12 13 void Draw(cCamera *cam, BITMAP *target_buffer){ 14 if (Sprite==NULL) 15 return; // To make an object invisible, set its Sprite to NULL; 16 draw_sprite(target_buffer, Sprite, X - cam->Offset_X, Y - cam->Offset_Y); 17} 18 19}; 20 21............................................................................. 22 23class cPlayer : public cObject{ 24 public: 25 26 cPlayer() 27 { 28 // Initial position 29 X=100; 30 Y=100; 31 } 32 33 void LogicUpdate(int tick) // Logic for player, not very interactive here. 34 { 35 Sprite = Player_sprite[10 + ((tick/6) % 4)]; // Changes the image once every 6 ticks, and uses sprites 10 to 13 for an array. 36 X = (tick % 200) + 100; // Moves from 100 to 300, 1 pixel per tick, then warp back and repeat. 37 } 38}; 39 40.............................................................................. 41 42#include <vector> 43 44int main(){ 45 std::vector<cSprite *> Sprites; 46 47// Code for redrawing all screen: 48// Erase all here 49... 50// Draw all sprites 51for(int i=0; i < Objects.length(); i++){ 52 Objects[i].Draw(&Camera, screen); 53} 54 55.... 56 57// Code for the logic of *** all the game*** : 58for(int i=0; i < Objects.length(); i++){ 59 Objects[i].LogicUpdate(current_frame); 60} 61 62 63END_OF_MAIN();

I didn't want to make this too complex, but note that the sprites will be displayed in the order of the collection (vector) : last ones are "above".
In my own games, Sprite has a member called Priority, and I build a collection for displaying (I omit the invisible sprites at this step) then I sort this collection by Priority, before browsing it to call Draw().

jhetfield21

you have to have priority given one way or the other if you want your characters to be able to go behind graphics as well.
this is called z-ordering.where each priority value represents something like a layer of graphics.where the layer with the lowest priority is the background,the next priority is anything else static or not that you always want your character or other characters to pass in front of,then it's your player's character with any other characters/enemies and stuff and then the highest priority is the layer with all graphics that you want your character or others to pass behind of.this is just an example nothing more.you can have more or less layers depending on what you want to do.

and principally Audric's solution is the same as what i said.

J-Gamer

The drawback is a slight overhead in determining the correct method to call.

ehh... I didn't know virtual functions cause overhead... BTW, what is overhead exactly(srr for the noobish question)

@bamccaig:
I always have the drawing code in a draw function in each class that is to be displayed on screen. It's easier to debug them because you know where to find the exact drawing code your looking for. In a cRenderer that checks the type etc, you'll have a LOT of get-functions, so you'll have to put all those in the classes as well. As you're looping trough an array of objects, the get-functions need to be declared in the object functions, but not all objects share the same properties. E.g.: a spaceship needs multiple bitmap vectors/arrays to store different animation sequences. a black hole/planet only needs one bitmap.
Because of this, you could have a virtual getcurrentbitmap() function or something like that in the object class, but that would completely destroy the purpose of an external renderer. You can as well have a draw function in your class.
In my case, the only purpose of a renderer is to sort the objects by depth and move the drawing calls out of your main loop, to avoid messy code.

jhetfield21

overhead is a term to describe the excess work that the CPU or any other part of the pc has to do when given a difficult task.for example if you call too many functions then you get an overhead in the call stack.you make too many records of function calls when you could have made less to attain the same goal.another example of overhead is polling.before interrupts where implemented the CPU had to poll the hard disk to see if a transaction had ended thus having to queue many other processes and perform context switches all the time just to make sure the transaction of a data transfer was completed.then interrupts came and then DMA.when a data transfer needs to be done it is approved and started and then DMA manages it until it's finished without having the CPU involved.

And virtual functions cause a little overhead because every object uses late binding to determine which function to use,that of the super class or the derived.but i don't think it's such an overhead to even be mentioned.i mean with today's hardware and all the object oriented programs in c++ lying around and very often well known ones at that you can see it doesn't pose a problem.

Arthur Kalliokoski

I'd say overhead is best described by the computer doing at runtime with brute force what you were too lazy to do with your brain at program design time.

jhetfield21

i hadn't thought of it like that....interesting :).

bamccaig

The very slight overhead with virtual methods is because the program has to lookup the function in a vtable at run-time (every time the method is called using a pointer or reference). It's this very mechanism that allows inheritance and polymorphism. Nearly every language that supports these concepts will implement it in a similar way. It's nothing to be concerned about. It will almost never be a bottleneck in your code.

@J-Gamer: /me is writing an example program. It's nearly 500 lines and counting, but that initial overhead should be outweighed by the code reuse later on (in a real game, when there's many different types of objects to be drawn). I think all I should have to do now is A5 stuff (initializing A5, loading some bitmaps, etc.). Well, and then debug it. :-X

Audric
J-Gamer said:

a spaceship needs multiple bitmap vectors/arrays to store different animation sequences.

Hmmmm be careful that "each instance of a spaceship" doesn't need it.

For small games, you should load such bitmaps once, on startup, and release them once, when quitting program.

Putting them as static members of each game object's class isn't an universal solution either : It prevents you from having several game elements that "share" the same image: For example a "computer-controlled allied ship" that needs the same sprites as the player ship.

Dario ff

I think the Speed game included in the latest Allegro 5 releases demonstrates well a situation where you render the same objects in different ways:

video

Having draw methods for each of these different camera styles for each object would be complicated, while different renderers could do this just by having different attributes(Screen position and size as well).

While the Speed game is pure C, it uses different "view" structures for rendering the same game objects.

Edgar Reynaldo

void cObject::Draw(cObject *Object, cCamera *Camera) {...}

You don't want to include a parameter for the cObject in cObject::Draw because it is already there in the hidden 'this' parameter.

Gabriel Campos said:

class cPlayer : public cObject{
...
void Draw();
...
};

Note that cPlayer::Draw() is not derived from your virtual cObject::Draw(cObject* Object , cCamera* Camera) function. They have two different function signatures. You're overloading the name, but not the function. The function signature of your Draw function in CPlayer should match the function signature of Draw in the cObject base class :

class Base {
...
   virtual void Function(int x);
}

class Derived : public Base {
...
   void Function(int x);// correct, function signatures match
   void Function();// incorrect, function signatures are different
}

You might want to take a look at the cplusplus.com tutorial, or the section on polymorphism.

bamccaig

I kept it all in one file to keep it simple on the forum, but I would put each class in its own header and source file for real. The actual main program stuff is hacked in and hard coded, but the polymorphic API is what matters anyway. :) Sadly, I have noticed one annoying shortcoming of my particular implementation. The player has dynamic dimensions. In order to retrieve them you need to query the current animation for the current frame, which requires the current animation to be set and started, and therefore requires game time as well. It's a little bit heavy doing all of that to determine the width and height, but one could always code static dimensions if they needed it to be cheaper/easier. The only reason I really needed it was to center the "player" on the screen for aesthetic reasons. I was able to get it done with prior knowledge anyway.

The code is pretty long. I counted 745 lines using wc. It's obviously a lot of overhead for what little it accomplishes in this simple example, but the code is reusable now. You can create n different types of objects that follow these same interfaces. It should save a lot of code, though you may find the interfaces need revision to deal with cases that I haven't accounted for.

The program mostly just dumps errors and exits if anything goes wrong, but it doesn't have to. It's built using RAII types and exception handling, so in theory it should be easy to handle errors gracefully (as can be seen in the drawing section of the main loop). I will say this: it's a lot easier to write this sort of code using Allegro 5 than it was with Allegro 4. Intern's Quest[1] wasn't designed as well as this from the start (though I learned a lot from it that lead me to here). That aside, it was still a lot more difficult to write because of all of the global state in Allegro 4 that we had to try to wrap and work around. With Allegro 5 there's less global state to deal with, and the global state that you are stuck with is already neatly hidden beneath interfaces. If I wore hats I would take one of them off to honor the developers! :P

Teh Codez

(A.cc seems to be wrongly counting my post as 90 KB long, when in fact it's only 19 KB long, so I'm forced to attach the code and link to it instead of inlining it, which would have been a much more convenient way to read it IMHO, but I digress)

           (see below)

that --> al5polytut.tar.gz <-- that

            ^ this

The following QnD GNU Makefile was used during the development of this demonstration and could be used to build it given a compatible platform.

Makefile#SelectExpand
1al5polytut: main.cpp 2 g++ -o $@ -Wall main.cpp `pkg-config --cflags --libs allegro-5.1`

If you're on an incompatible platform then you'll just need to know how to compile a single C++ source file and link to the core of Allegro 5. :)

Meh. This is the way that I like to code. It's more fun for me, but then I've never finished a game... :P I also find it a lot easier to work with though. It's a lot less error prone because you're writing once instead of writing over and over again.

The code could still use revision, but I think it's a pretty good start. If anybody actually finds it useful enough to use directly in a game then I would appreciate a mention in any credits or whatever, but I'm not going to demand it. :)

Update: moving camera now so you can see it working.

References

  1. The project is stalled, but planned to be one day resurrected. It has also been moved to GitHub.
Gabriel Campos

You don't want to include a parameter for the cObject in cObject::Draw because it is already there in the hidden 'this' parameter.

So, if a I understand i can do this

#SelectExpand
1class cObject{ 2 private: 3 int x, y, W, H; // all objects will inherit these variables 4 5 public: 6 virtual void Draw(cCamera *Camera){ 7 masked_blit(this->sprite, Buffer, this->frame*this->W, this->stance*this->H, this->x, this->y, this->W, this->H); 8} 9};

Sorry if I am wrong...I am studying and trying to learn...is a bit dificulty ::)
Thanx for the advice of the virtual function...so it must be exactlly equal to the derived classes functions...and thanx to the site..very good...
I am working now >:(, in home I will read with attention . ..

Edgar Reynaldo

So, if a I understand i can do this

When writing a class method, you don't need to use the this pointer to refer to data members, but you can if it helps you keep your code straight. You probably don't want to hardcode Buffer into your classes either, but use a parameter for the bitmap to draw to.

#SelectExpand
1 2class cObject{ 3private: 4 BITMAP* sprite; 5 int x, y, W, H; // all derived classes will inherit these variables 6 7public: 8 virtual void Draw(BITMAP* dest , cCamera *Camera) { 9 masked_blit(sprite , dest , 0 , 0 , x - Camera->x , y - Camera->y , W , H); 10 } 11 12}; 13 14enum STANCES { 15 CROUCH_LEFT = 0, 16 CROUCH_RIGHT = 1, 17 STAND_LEFT = 2, 18 STAND_RIGHT = 3 19}; 20 21#define NUM_STANCES 4 22#define NUM_FRAMES 4 23 24class Player : public cObject { 25private : 26 BITMAP* frames[NUM_STANCES][NUM_FRAMES]; 27 STANCES stance; 28 int frame_num; 29 30public : 31 void SetStance(STANCES new_stance) { 32 stance = new_stance; 33 frame_num = 0; 34 sprite = frames[stance][frame_num]; 35 } 36 // No need to redefine cObject::Draw here, but you can if you like : 37 virtual void Draw(BITMAP* dest , cCamera* Camera) { 38 cObject::Draw(dest , Camera);// call the base class method until we decide otherwise 39 } 40};

J-Gamer

Isn't it also better to have the x and y variables of cCamera private? This to prevent accidental changes of these values. Just have a getX() and getY() function in the class.

With accidental changes, I mean like looking over something like this:
if(camera.y=0)
instead of
if(camera.y==0)
If they're private, the compiler will throw an error here... If not, each time this if-statement is called, the code underneath will execute and camera.y will be set to 0.

I had this problem a lot when learning C++ after I had been programming in a BASIC language for a long time.

Thomas Fjellstrom
bamccaig said:

(A.cc seems to be wrongly counting my post as 90 KB long, when in fact it's only 19 KB long, so I'm forced to attach the code and link to it instead of inlining it, which would have been a much more convenient way to read it IMHO, but I digress)

It counts the actual size of the post-processed contents, after its done transforming bb-code and <code> tags, and highlighting code causes the size to bloat up significantly.

Audric

J-Gamer: use the -Wall option of gcc to get warnings on all suspicious code, and it will warn you on each "if (x=y)".

Gabriel Campos

My Solution:

#SelectExpand
1class cObject{ // this class will handle all objects... 2 3 public: 4 virtual void GetX(); // Dont need to comment... 5 virtual void GetY(); 6 virtual void GetW(); 7 virtual void GetH(); 8 virtual void GetImage(); 9 // and other virtual functions used to draw 10}; 11 12............................................................................... 13 14class cDrawManager(){ 15 16 private: 17 BITMAP *Buffer; // Edgar Reynaldo said to not use buffer here, but I couldn't understand why..someone give me a light 18 BITMAP *Sprite[x]; // x will be the number of all sprites in the game 19 20 public: 21 void Draw(cObject *Object, cCamera *Camera){ 22 masked_blit(Sprite[Object->GetImage()], Buffer, Object->GetFrame() * Object->GetW(); Object->GetStance() * Object->GetH(); Object->GetX() - Camera->GetX(); Object->GetY() - Camera->GetY(); Object->GetW(), Object->GetH()); 23 } 24 25 void DrawScreen(){ 26 draw_sprite(screen, Buffer, 0, 0); 27 } 28}; 29 30................................................................................. 31 32class cPlayer : public cObject{ 33 34 private: 35 int x, y, W, H, Image; // and all variables (I can put in the cObject too) 36 37 public: 38 void GetX(); // All functions derived from virtual function of cObject class... 39 void GetY(); 40 void GetW(); 41 void GetH(); 42 void GetImage(); 43}; // Dont need make any draw function in the player 44// All objects will follow this recipe.. 45 46.................................................................................. 47 48int main(){ 49 cDrawManager DrawManager; 50 cPlayer Player; 51 cCamera Camera; 52 53while(...){ 54 DrawManager.Draw(&Player, &Camera); 55 DrawManager.DrawScreen(); // if there is some problem with buffer in the DrawManager class I can send from here as a parameter (DrawScreen(Buffer); :) 56}

This is the solution I liked...Suggestions will be very apreciate..
But I still have doubts...
I create a vector and doesnt work... :P

#SelectExpand
1int main() 2#include <vector> 3 4 std::vector<cDrawManager *> SpriteObjects; 5 6 for(int i = 0; i < SpriteObjects.length(); i++){ 7 DrawManager.Draw(SpriteObjects[i], &Camera); 8 }

The compiler says that vector SpriteObjects has no member named length();
If I use .size(), .capacity(), it accepts....but not length()..
I use allegro 4.2 and DevC++...
Someone??? ???

gnolam

The compiler says that vector SpriteObjects has no member named length();

That's because std::vector doesn't have a length() member function. The one you're after is size(). :P

Gabriel Campos

Ok..but when a put size it doesnt draw anything on screen...
Sorry if I am making a topic too long...
What is the problem with my logic??

bamccaig

You're either showing us parts of your program or you're forgetting to actually initialize your objects and draw to the screen. :P If you're still having issues, show us the full program. :)

gnolam

Also: the code you're giving us shouldn't even compile...

Quote:
masked_blit(Sprite[Object->GetImage()], Buffer, Object->GetFrame() * Object->GetW(); Object->GetStance() * Object->GetH(); Object->GetX() - Camera->GetX(); Object->GetY() - Camera->GetY(); Object->GetW(), Object->GetH());

Gabriel Campos
gnolam said:

Also: the code you're giving us shouldn't even compile...

Why?? I couldnt realize . . .
I make all functions of get() virtual....

well,
I will try later in home...If doesnt work i will post here . .

J-Gamer

J-Gamer: use the -Wall option of gcc to get warnings on all suspicious code, and it will warn you on each "if (x=y)".

I didn't know that... thanks :)
But I think it's still better to make them private, just for OOP's sake ;)

BITMAP *Sprite[x]; // x will be the number of all sprites in the game

I hope you don't think this is a dynamic array... You need to replace the x by a hard-coded number, OR you should make it a vector/list/deque/whatever to let it be able to have a costumable size.

Quote:

Sprite[Object->GetImage()]

What is this supposed to do? In this case, Object->GetImage should return the index in the Sprite array of the current sprite that should be drawn... This makes code from the object to change when the order of the sprites in the Sprite array changes...

Gabriel Campos

When I wrote BITMAP *Sprite[x], x will be the number of all sprites..Lets supose that we will use 10 enemies + 1 player...will be 11 sprites, so

#SelectExpand
1BITMAP *Sprite[11]; 2//then load all bitmaps 3Sprite[0] = load_bitmap(.......); 4... 5... 6...

So when I create a object...lets supose...Player I will refer his sprite with the number of this array...
if Sprite[0] = load_bitmap("Data\\Gfx\\Player.bmp", NULL);
then the variable Image will be 0....
when the class call Sprite[Object->GetImage()], it will return the number of the image, in this case 0..

gnolam said:

Also: the code you're giving us shouldn't even compile...

Maybe because I wrote
virtual VOID GetX()???
I think it is
virtual INT GetX() . . . Always do it...My compiler is working hard you know

J-Gamer

When compiling, the compiler wants to know how much memory it should allocate for each instance of a class... this means that when using an array, it needs to know the size on beforehand. This way, you can't do this:

BITMAP *Sprite[11];
//then load all bitmaps
Sprite[0] = load_bitmap(.......);
...
...
...

In a constructor/initialisation function because the amount of bitmaps in the array sprite is set to x, for which the compiler will throw an error if it can't find an int called x that is already been given a value(it has to be global to do this, somebody please correct me if I'm wrong).

when the class call Sprite[Object->GetImage()], it will return the number of the image, in this case 0..

This means that the Object needs to know which location the image to be drawn has in the Sprite array(which is in another class)...

Dario ff

J-Gamer: Just use the <quote> </quote> tags without specifying anything and the a.cc's magic searching bunnies will do the work for you.

Example:
<quote>When compiling, the compiler wants to know how much memory it should allocate for each instance of a class...</quote>

J-Gamer said:

When compiling, the compiler wants to know how much memory it should allocate for each instance of a class...

J-Gamer

Thanks... I was wondering how you guys all do that :p
Edited the quotes in the previous message

Gabriel Campos
J-Gamer said:

In a constructor/initialisation function because the amount of bitmaps in the array sprite is set to x, for which the compiler will throw an error if it can't find an int called x that is already been given a value(it has to be global to do this, somebody please correct me if I'm wrong).

You dont understand me...I will put explicit the number 11...the x is not a variable or a parameter or nothing...it was just a example....
When using Object->GetImage()...it will return the number...its simple..

#SelectExpand
1// Its like this . . 2Sprite[5]; 3 4int x = 3; 5 6int GetX(){ 7 return x; 8} 9 10void Draw() 11 draw_sprite(Buffer, Sprite[x], 0, 0); 12// the x will be 3 (in the array number 2)

Simple...

J-Gamer

Could somebody please explain to me why the getImage() function is a function returning an int and is part of the class cObject, while it is giving the index of an image in an array of the class cDrawManager? ???

This would mean the cObject class should be aware of the contents of the cDrawManager's Sprite array.

bamccaig
J-Gamer said:

Thanks... I was wondering how you guys all do that :p

acc.js :-X

J-Gamer said:

Could somebody please explain to me why the getImage() function is a function returning an int and is part of the class cObject, while it is giving the index of an image in an array of the class cDrawManager? ???

This would mean the cObject class should be aware of the contents of the cDrawManager's Sprite array.

That's not necessarily true. Think of file descriptors. A file descriptor is basically an index into some table that the kernel has for an application. That's why STDIN, STDOUT, and STDERR are 0, 1, and 2, respectively. Your application doesn't actually know anything about that table, and couldn't get access to it if it did.

The object doesn't actually need to know what the image index refers to because (presumably) it will be passed in and set from the outside world by something that does know. Using indexes like that for your sprites isn't a terrible idea, but there are better ways to do it, especially in C++. For example, you could store boost::shared_ptr<BITMAP> and then store a copy of the sprite's smart pointer directly in your class. You could even load your sprites into a std::map<std::string, boost::shared_ptr<BITMAP> > so that you could later refer to them by name. That's generally how I have done it.

Thomas Fjellstrom

I dunno, if you treat the "index" as an opaque "bitmap id", rather than an index then you can change the underlying implementation at any time and not have to worry about passing pointers around, or using string based hashing.

J-Gamer
Quote:
J-Gamer said:

Thanks... I was wondering how you guys all do that :p

acc.js [github.com] :-X

I was actually talking about how to be able to copy both the text AND the link to the specific post ^^

I haven't studied Java yet, so I don't really understand the code ._.
I might look into it later, when I have some spare time to learn Java.

bamccaig said:

The object doesn't actually need to know what the image index refers to because (presumably) it will be passed in and set from the outside world by something that does know. Using indexes like that for your sprites isn't a terrible idea, but there are better ways to do it, especially in C++. For example, you could store boost::shared_ptr<BITMAP> and then store a copy of the sprite's smart pointer directly in your class. You could even load your sprites into a std::map<std::string, boost::shared_ptr<BITMAP> > so that you could later refer to them by name. That's generally how I have done it.

In the code we get to see, it's clear that he wants the function to know which number to return, probably based on some state parameters of the object itself.
I have to say I never used Boost, so I don't know how it works.

Thomas Fjellstrom
J-Gamer said:

I was actually talking about how to be able to copy both the text AND the link to the specific post ^^

The forum auto links it most times.

bamccaig
J-Gamer said:

I was actually talking about how to be able to copy both the text AND the link to the specific post ^^

That's actually specifically what it can do. :) Though it isn't perfect: it doesn't handle HTML properly [yet]. When it fails to quote, you can use a separate feature to just fill in the <quote name="user" src="uri"></quote> part though.

J-Gamer said:

I haven't studied Java yet, so I don't really understand the code ._.
I might look into it later, when I have some spare time to learn Java.

It's JavaScript, not Java. They are two completely different languages with little in common. In theory, you should be able to just drop it in and use it, but in practice having some JavaScript experience would come in handy because it isn't perfect. :) (ML also discourages its use because he doesn't want people abusing its convenience)

J-Gamer said:

In the code we get to see, it's clear that he wants the function to know which number to return, probably based on some state parameters of the object itself.

The object would just store its sprite index, or an animation, which itself would contain a set of indexes. That would be part of the object's state. The object doesn't physically need to know what those indexes mean. It can trust the outside world to give it the right indexes. Of course, it's not a perfect model, but it can work if you're careful.

A better model is probably storing an animation or a set of animations, each of which containing a set of smarter pointers to your sprites. :) That's a relatively complicated model though for beginner.

J-Gamer said:

I have to say I never used Boost, so I don't know how it works.

Boost is a very large C++ framework. The boost::shared_ptr<T> is a smart pointer that manages the memory for you automatically. Essentially, it just stores a copy-count/reference-count internally. When you make copies of it the count is incremented, and when those copies are destroyed the count is decremented. When the count reaches zero, the stored object is automatically destroyed, freeing the memory. It's entirely automatic.

#SelectExpand
1typedef boost::shared_ptr<int> IntPtr; 2typedef boost::shared_ptr<ALLEGRO_BITMAP> AlBitmapPtr; 3 4{ 5 { 6 IntPtr i(new int(5)); 7 } // The int is deleted here automatically. 8 9 AlBitmapPtr b; 10 11 { 12 AlBitmapPtr b2( 13 al_load_bitmap("./path/to/file.bmp"), 14 al_destroy_bitmap); 15 16 b = b2; 17 } 18} // The ALLEGRO_BITMAP is destroyed here automatically.

It's a bit like garbage collection, except that it works immediately instead of waiting some indeterminate amount of time and checking for objects that can be freed. The downside is that it can't handle cyclical references, so you do need to pay some attention if you end up creating those.

gnolam
I said:
gnolam said:

Also: the code you're giving us shouldn't even compile...

Quote:

masked_blit(Sprite[Object->GetImage()], Buffer, Object->GetFrame() * Object->GetW(); Object->GetStance() * Object->GetH(); Object->GetX() - Camera->GetX(); Object->GetY() - Camera->GetY(); Object->GetW(), Object->GetH());

I was referring to the semicolons. :P

J-Gamer
bamccaig said:

It's JavaScript, not Java.

:-[ I should have know that at least...

Gabriel Campos
gnolam said:

I was referring to the semicolons.

Oh..yes, I dont realized...
The function works nicely after I declared pure virtual...
if dont it says..undefined reference to vtable in cObject..or something like this...
Strange . ..

Edgar Reynaldo

The function works nicely after I declared pure virtual...
if dont it says..undefined reference to vtable in cObject..or something like this...

It's because every function you declare has to also be defined. Also, you should note that every base class that has virtual functions should also have a virtual destructor. This is so that the appropriate destructors get called for the derived classes.

/// In Base.hpp

class Base {
protected :
   Data d;
public :
   Base() : d() {}
   virtual ~Base() {}
   virtual void DoSomething();
};

/// In Base.cpp

void Base::DoSomething() {/*...*/}

Gabriel Campos

But why to put in the destructor??
I couldnt understand this part of the code

#SelectExpand
1/// In Base.hpp 2 3class Base { 4protected : 5 Data d; // Couldn understand 6public : 7 Base() : d() {} // Couldn understand 8 virtual ~Base() {} 9 virtual void DoSomething(); 10}; 11 12/// In Base.cpp 13 14void Base::DoSomething() {/*...*/}

Other thing I want to learn is..why use this implementation on the constructor code of some object, something like player..

#SelectExpand
1class cPlayer{ 2 cPlayer(int x, int y) : (x, y); // can someone explain to me?

I want to thanx evebody too.. Since this post I learned a lot about OOP.. ;D

Edgar Reynaldo

But why to put in the destructor??

This is so that the appropriate destructors get called for the derived classes.

I couldnt understand this part of the code

Data is just a made up class, used for an example.

#SelectExpand
1class Data { 2private : 3 int i; 4 float f; 5 char c; 6public : 7 Data(); 8 Data(int _integer , float _float , char _char); 9}; 10 11Data::Data() : 12 i(0), // call int constructor for integer type 13 f(0.0f), // call float constructor for float type 14 c('\0') // call char constructor for char type 15{} 16 17Data::Data(int _integer , float _float , char _char) : 18 i(_integer), 19 f(_float), 20 c(_char) 21{}

The code in the constructor after the semicolon and before the braces is called an initialization list. It gives the member variables of the class an initialization value. Always initialize the members of the class before using them. If you don't, then their starting values are undefined, and hold the value of whatever was left over in memory from before.

An example of what not to do :

Data::Data() {
   printf("i = %i , f = %f , c = %c" , i , f , c);// Could print anything
                                                  // because i , f , and c are
                                                  // uninitialized
}

Gabriel Campos

Well, couldnt understand yet...But I got a c++ book from a good university here, so I will study all this part. . . ;D
But lets go to another game concept question, How to make a lot of stages and add enemies there.. My solution is this, but I think its a little weird.. :P

#SelectExpand
1 2int main(){ 3 init(); 4 Stage01(); 5 Stage02(); 6 Stage03(); 7 deinit(); 8} 9END_OF_MAIN(); 10 11int Stage01(){ 12 // Here I create the objects 13 cPlayer Player(200, 200); // x, y, parameters 14 cEnemy Enemy[10]; // and on and on 15 16while(inGame){ 17 // the game code 18} 19} // end of Stage 20 21 22int Stage02(){ 23 // Here I create the objects again 24 cPlayer Player(100, 250); // x, y, parameters 25 cEnemy Enemy[6]; 26 27while(inGame){ 28 // the game code 29} 30} // end of Stage

So, this is the right way to do this??
Or should create all objects, lets say..make them global... and use it??
Create a method to put them in the right stage and position?? ???

Edgar Reynaldo

I would use something like this. You can set up the current stage in the CreateStage function, and then just run the current stage in main.

#SelectExpand
1class Stage { 2private : 3 BITMAP* stage_map; 4 BITMAP* buffer; 5 cPlayer Player; 6 vector<cEnemy*> Enemies; 7 cCamera Camera; 8 9public : 10 Stage() : stage_map() , Player() , Enemies() {} 11 ~Stage() {Free();} 12 void Free() { 13 if (buffer) { 14 destroy_bitmap(buffer); 15 buffer = 0; 16 } 17 if (stage_map) { 18 destroy_bitmap(stage_map); 19 stage_map = 0; 20 } 21 for (int i = 0 ; i < Enemies.size() ; ++i) {delete Enemies[i];} 22 Enemies.clear(); 23 } 24 void SetStageMap(BITMAP* bmp) { 25 if (!bmp) {return;} 26 if (stage_map) {destroy_bitmap(stage_map);} 27 stage_map = bmp; 28 } 29 bool Update(double tsec) { 30 // collision testing goes here 31 Player.Update(tsec); 32 for (int i = 0 ; i < Enemies.size() ; ++i) { 33 Enemies[i]->Update(tsec); 34 } 35 Camera.CenterOn(Player.CX() , Player.CY()); 36 } 37 void CheckInputs() { 38 Player.CheckInputs(); 39 for (int i = 0 ; i < Enemies.size() ; ++i) { 40 Enemies[i]->CheckInputs(); 41 } 42 } 43 void Draw(BITMAP* dest) { 44 int camx = Camera.X(); 45 int camy = Camera.Y(); 46 int camw = Camera.W(); 47 int camh = Camera.H(); 48 blit(stage_map , buffer , camx , camy , 0 , 0 , camw , camh); 49 Player.Draw(buffer , -camx , -camy); 50 for (int i = 0 ; i < Enemies.size() ; ++i) {Enemies[i]->Draw(buffer , -camx , -camy);} 51 blit(buffer , dest , 0 , 0 , 0 , 0 , buffer->w , buffer->h); 52 } 53 54 void SetPlayerStats(/*...*/); 55 void AddEnemy(cEnemy* enemy) { 56 Enemies.push_back(enemy); 57 } 58}; 59 60 61Stage* CreateStage(int stage_num) { 62 Stage* new_stage = 0; 63 switch (stage_num) { 64 case 1 : 65 return new Stage(/*... parameters ...*/); 66 break; 67 case 2 : 68 new_stage = new Stage(); 69 /* Alter the new stage here */ 70 return new_stage; 71 break; 72 default : 73 Error(); 74 break; 75 } 76 return new_stage; 77} 78 79/// In main 80 81int stage_num = 1; 82Stage* current_stage = CreateStage(stage_num); 83 84while (playing) { 85 current_stage->Draw(screen); 86 current_stage->CheckInputs(); 87 current_stage->Update(time_passed); 88 if (current_stage->StageComplete()) { 89 delete current_stage; 90 ++stage_num; 91 current_stage = CreateStage(stage_num); 92 } 93 if (current_stage->GameOver()) {playing = false;} 94} 95 96if (current_stage) {delete current_stage;}

Gabriel Campos

Hmm... So you are telling me to make all the game in a class and there make a system to load the maps and the enemies..??
So in the main function I only call the functions of this class...But I make my map based on tiles... I will look more detailed this in home..thanx

Thread #606117. Printed from Allegro.cc