|
|
| Looking for a Game Tutorial |
|
jhetfield21
Member #12,379
November 2010
|
i hadn't thought of it like that....interesting
|
|
bamccaig
Member #7,536
July 2006
|
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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
|
Audric
Member #907
January 2001
|
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
Member #10,065
August 2008
|
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: 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. TranslatorHack 2010, a human translation chain in a.cc. |
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Gabriel Campos said: 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{ 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. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|
bamccaig
Member #7,536
July 2006
|
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. 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! 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. 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... 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
-- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
|
Gabriel Campos
Member #12,034
June 2010
|
Edgar Reynaldo said: 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 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
|
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Gabriel Campos said: 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. 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};
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|
J-Gamer
Member #12,491
January 2011
|
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: I had this problem a lot when learning C++ after I had been programming in a BASIC language for a long time. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
|
Thomas Fjellstrom
Member #476
June 2000
|
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
Member #907
January 2001
|
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
Member #12,034
June 2010
|
My Solution: 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.. 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();
|
|
gnolam
Member #2,030
March 2002
|
Gabriel Campos said: 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(). -- |
|
Gabriel Campos
Member #12,034
June 2010
|
Ok..but when a put size it doesnt draw anything on screen...
|
|
bamccaig
Member #7,536
July 2006
|
You're either showing us parts of your program or you're forgetting to actually initialize your objects and draw to the screen. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
|
gnolam
Member #2,030
March 2002
|
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
Member #12,034
June 2010
|
gnolam said: Also: the code you're giving us shouldn't even compile...
Why?? I couldnt realize . . . well,
|
|
J-Gamer
Member #12,491
January 2011
|
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 Gabriel Campos said: 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... " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
|
Gabriel Campos
Member #12,034
June 2010
|
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
So when I create a object...lets supose...Player I will refer his sprite with the number of this array... gnolam said: Also: the code you're giving us shouldn't even compile...
Maybe because I wrote
|
|
J-Gamer
Member #12,491
January 2011
|
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). Gabriel Campos said: 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)... " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
|
Dario ff
Member #10,065
August 2008
|
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: J-Gamer said: When compiling, the compiler wants to know how much memory it should allocate for each instance of a class...
TranslatorHack 2010, a human translation chain in a.cc. |
|
J-Gamer
Member #12,491
January 2011
|
Thanks... I was wondering how you guys all do that :p " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
|
Gabriel Campos
Member #12,034
June 2010
|
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.... 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
Member #12,491
January 2011
|
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. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
|
bamccaig
Member #7,536
July 2006
|
J-Gamer said: Thanks... I was wondering how you guys all do that :p 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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
|
|
|