|
[A5] Drawing a sprite to a display |
Havacore
Member #12,591
February 2011
|
Just as a little learning project, I want to make an allegro program that just has a sprite on the display, and it walks left when press left, right when I press right etc. Basically all I have done so far is make a pong game which just used primitive bitmaps, rather than loading an image. So basically I just need to know how sprites work. I need to know where does the sprite come from? Do I take a sprite sheet from google and load a section of that image file into the program? When the sprite moves, how exactly do I put in the animation? Do I time it so that while a keyboard event is occurring, the program cycles through a few different images on a sprite sheet? And if there is anything else I should know then I would appreciate any advice you all could give me
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Here's a very broad description of how I do it : 1class Animation {
2private :
3 BITMAP** frames;
4 double duration;
5 double current_time;
6 int num_frames;
7 int frame_number;
8
9public :
10 void SetFrameTime(double tsec);
11 void AdvanceFrameTime(double tsec) {SetFrameTime(current_time + tsec);}
12 void Draw(BITMAP* bmp , int x , int y);
13};
14
15class StateAnimation {
16private :
17 map<string , Animation*>
18 Animation* active_animation;
19public :
20 void SetState(string state);
21 void AdvanceFrameTime(double tsec) {
22 if (active_animation) {
23 active_animation->AdvanceFrameTime(tsec);
24 }
25 }
26 void Draw(BITMAP* bmp , int x , int y) {
27 if (active_animation) {
28 active_animation->Draw(bmp , x , y);
29 }
30 }
31/*...*/
32};
33
34class Character {
35private :
36 Animation move_left;
37 Animation move_right;
38 Animation crouch;
39 Animation stand_left;
40 Animation stand_right;
41 Animation jump_left;
42 Animation jump_right;
43 StateAnimation anim_state;
44/*...*/
45};
For an animation, you need to know how long it displays for, how many frames there are, how much time has passed so far, and whether it loops or is static. Then you also need to know the current state of the animation, and how to set that state based on what your character is doing. 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 |
Havacore
Member #12,591
February 2011
|
oh nice! Good thing my class just covered how to do OOP! But on a simpler scale. I don't even know how to draw a sprite to the display. I've looked through the allegro manual and I can't find any functions that take in an image file or anything to draw to the display. All I can think of is creating a bitmap, and filling it with a colour
|
jason perkins
Member #10,524
January 2009
|
You can go and grab a sprite sheet off google, or make one yourself that looks like this: This is the code I use to get a single tile off this sheet, and scroll through them over time. 1
2CPlayer::CPlayer()
3{
4 bmp = al_load_bitmap("player.bmp");
5 al_convert_mask_to_alpha(bmp, (al_map_rgb(255, 0, 255)));
6
7 animationWidth = al_get_bitmap_width(bmp)/32; //the tiles are 32/32
8 animationHeight = al_get_bitmap_height(bmp)/32;
9
10
11 for (int h = 0; h< animationHeight; h++)
12 {
13 for (int w = 0; w<animationWidth; w++)
14 {
15 pallet.push_back(al_create_sub_bitmap(bmp, w*TILE_SIZE, h*TILE_SIZE, TILE_SIZE, TILE_SIZE));
16 }
17 }
18
19 bmp = pallet[0];
20}
21
22
23void CPlayer::animate(int state, int cycleTime)
24{
25
26 animationCount++;
27 if (animationCount >= cycleTime)
28 {
29 animationCount = 0;
30
31 }
32 animationState = state;
33
34 if (state >= 0 && state <= 3)
35 {
36 direction = state;
37 }
38
39 bmp = pallet[state*animationWidth + (animationCount/(cycleTime/4))+1];
40
41}
To actually draw this I call the players' parent draw function. void CVisibleTile::draw() { if(x+ TILE_SIZE >= 0 && x < SCREEN_W && y + TILE_SIZE >= 0 && y< SCREEN_H) { al_draw_bitmap(bmp, x, y, 0); } } Hope that helps. There's a good tutorial on the wiki for the basics of displaying bitmaps as well. http://wiki.allegro.cc/index.php?title=Allegro_5_Tutorial/Input |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Havacore said: But on a simpler scale. I don't even know how to draw a sprite to the display. I've looked through the allegro manual and I can't find any functions that take in an image file or anything to draw to the display. Are you using Allegro 4 or Allegro 5? Allegro 4 : Allegro 5 : 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 |
Havacore
Member #12,591
February 2011
|
I'm using allegro 5. what is the pallet object you have at line 15 jason? I hope you don't mind, but I'm just copying down that code so that I can mess around with it later to get a better understanding of what's going on. Just to clarify, what does al_convert_mask_to_alpha do? I noticed that the rgb code in your function is magenta, so does that just make it so that magenta is transparent? And I have read all the tutorials so far. And I've implemented them into a little pong game (except font, which I can't get to work so far). The bitmap tutorial unfortunately just explains how to make a solid colored square, not an image. Or in this case, and image out of a bigger image like a sprite sheet.
|
SpectreNectar
Member #10,969
May 2009
|
Havacore said: so does that just make it so that magenta is transparent? Yes. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Havacore said: The bitmap tutorial unfortunately just explains how to make a solid colored square, not an image. Or in this case, and image out of a bigger image like a sprite sheet. Use al_load_bitmap to load your spritesheet, then create an array of ALLEGRO_BITMAP* and fill it in with al_create_bitmap and al_draw_bitmap_region or use al_create_sub_bitmap on your spritesheet. Then use al_draw_bitmap to draw your images. 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 |
Thomas Fjellstrom
Member #476
June 2000
|
I think I need to add a second example to that bitmap tutorial that uses the image addon. -- |
leixiong
Member #12,688
March 2011
|
Can we copy bitmap to new bitmap without display ? |
Neil Walker
Member #210
April 2000
|
I guess you've figured out from the posts above that there really isn't any such thing as a sprite. In the olden days, the Commodore 64 had sprites. A sprite is just a bitmap that appears to animate simply because you are replacing it with another bitmap, i.e. a sprite is a class you create to manage, control and show the graphics in order Forget about palettes. They are only used in 8 bit graphics and A5 doesn't support them. Regarding al_convert_mask_to_alpha(): A5 uses the alpha channel to support transparency. A4 didn't and instead usually relied on 'magic pink', i.e. 255,0,255 magenta. So, al_convert_mask_to_alpha will look at your bitmap and any magenta pixel will be converted to transparency. Neil. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
Havacore
Member #12,591
February 2011
|
Ok so first step, I just want to cut a section (the top left most) of the sprite sheet and put it on the display, just for starters. Now I've got a program that compiles, but it has a segmentation fault in there. Also I'm wondering if I'm doing this right. I'm just making a class for the sprite, and using a drawing method with al_draw_bitmap_region. (The rest of the code should be good, Its just copied from my pong game for the eventual keyboard input I will want to put in later) 1#include <stdio.h>
2#include <allegro5/allegro.h>
3#include <allegro5/allegro_image.h>
4
5
6
7/*
8CONSTANTS
9*/
10
11const int SCREEN_W = 640;
12const int SCREEN_H = 480;
13const float FPS = 60;
14
15enum MYKEYS {
16 KEY_UP, KEY_DOWN, KEY_W, KEY_S
17};
18
19/*
20FUNCTIONS
21*/
22
23/*
24OBJECTS
25*/
26
27class player
28{
29
30 private:
31
32 ALLEGRO_BITMAP *bmp;
33 ALLEGRO_BITMAP *animation;
34 int animationWidth;
35 int animationHeight;
36
37
38 public:
39
40 //Construtor
41 player();
42 //Draws the sprite from areas x and y from the sprite sheet
43 void draw(float x, float y);
44
45
46
47};
48
49 player::player()
50 {
51 //loads the entire spritesheet
52 bmp = al_load_bitmap("player.png");
53 //converts the sprite sheet's magenta background to transparent pixels
54 al_convert_mask_to_alpha(bmp, (al_map_rgb(255, 0, 255)));
55
56 //each animation in the sprite sheet is 32X32 pixels
57 animationWidth = al_get_bitmap_width(bmp)/32;
58 animationHeight = al_get_bitmap_height(bmp)/32;
59
60
61 }
62
63 void player::draw(float x, float y)
64 {
65 //draw section of sprite sheet
66 //target bitmap, region x, region y, width, height, destination x, destination y, flag(0)
67 al_draw_bitmap_region(bmp, 0, 0, animationWidth, animationHeight, x, y, 0);
68 }
69
70/*
71MAIN
72*/
73
74int main(int argc, char **argv)
75{
76 /*
77 ALLEGRO DECLARATIONS
78 */
79
80 ALLEGRO_DISPLAY *display = NULL;
81 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
82 ALLEGRO_TIMER *timer = NULL;
83
84
85 /*
86 VARIABLES
87 */
88
89 bool key[4] = {false, false, false, false };
90 bool redraw = true;
91 bool doexit = false;
92
93 float sprite_x = (SCREEN_W/2);
94 float sprite_y = (SCREEN_H/2);
95
96 player sprite;
97
98 /*
99 CONFIGURATION
100 */
101
102 if(!al_init()) {
103 fprintf(stderr, "failed to initialized allegro\n");
104 return -1;
105 }
106
107 if(!al_install_keyboard()) {
108 fprintf(stderr, "failed to install keyboard\n");
109 return -1;
110 }
111
112 //initialize display (w, h)
113 display = al_create_display(SCREEN_W, SCREEN_H);
114 if(!display) {
115 fprintf(stderr, "failed to create display\n");
116 return -1;
117 }
118
119 timer = al_create_timer(1.0/FPS);
120 if(!timer) {
121 fprintf(stderr, "failed to create timer\n");
122 return -1;
123 }
124
125 al_set_target_bitmap(al_get_backbuffer(display));
126
127 event_queue = al_create_event_queue();
128 if(!event_queue) {
129 fprintf(stderr, "failed to create event queue\n");
130 return -1;
131 }
132
133 al_register_event_source(event_queue, al_get_display_event_source(display));
134
135 al_register_event_source(event_queue, al_get_timer_event_source(timer));
136
137 al_register_event_source(event_queue, al_get_keyboard_event_source());
138
139 al_clear_to_color(al_map_rgb(0, 0, 0));
140
141 al_flip_display();
142
143 al_start_timer(timer);
144
145 /*
146 MAIN LOOP
147 */
148
149 while(!doexit)
150 {
151
152 ALLEGRO_EVENT ev;
153
154 al_wait_for_event(event_queue, &ev);
155
156 if(ev.type == ALLEGRO_EVENT_TIMER)
157 {
158
159
160 redraw = true;
161 }
162
163 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
164 {
165 break;
166 }
167 else if(ev.type == ALLEGRO_EVENT_KEY_UP)
168 {
169 switch(ev.keyboard.keycode)
170 {
171 case ALLEGRO_KEY_ESCAPE:
172 doexit = true;
173 break;
174 }
175 }
176
177 if(redraw && al_is_event_queue_empty(event_queue))
178 {
179 redraw = false;
180 al_clear_to_color(al_map_rgb(0,0,0));
181
182 //redraw bitmaps
183
184
185 //draw player
186 sprite.draw(sprite_x, sprite_y);
187
188 al_flip_display();
189
190 }
191
192
193 }
194
195 al_destroy_timer(timer);
196 al_destroy_display(display);
197 al_destroy_event_queue(event_queue);
198 //destroy bitmaps
199
200 return 0;
201 }
|
jason perkins
Member #10,524
January 2009
|
I've never used al_draw_bitmap_region(), but that looks a little off. because your changing units from pixels to pictures with this line: animationWidth = al_get_bitmap_width(bmp)/32; ... To get just the top left image with al_create_sub_bitmap(). you'd do this: bmp = al_load_bitmap("player.png") ALLEGRO_BITMAP* top_left_image = al_create_sub_bitmap(bmp, 0, 0, 32, 32); and draw with al_draw_bitmap(top_left_image, x, y, 0) It just makes more practical sense to create an entire array at once though. so if you have a 4x4 sheet and 32x32 tiles... bmp = al_load_bitmap("player.png") ALLEGRO_BITMAP* bmp_array[4][4]; for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { bmp_array[x][y] = al_create_sub_bitmap(bmp, 32*x, 32*y, 32, 32); } } sprite.bmp = bmp_array[0][0]; Also instead of creating the variables sprite_x, and sprite_y, you should just make them private members of your player class, and write public functions to modify the values. Same goes for the bitmap so you can switch which element in the bitmap array is getting drawn. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
@Havacore 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 |
Havacore
Member #12,591
February 2011
|
Ok I did it! I now have a program that draws a piece of the sprite sheet to the display! Now for animation, which is going to be quite the mountain for me to conquer @Edgar Also that map<string , Animation*> in the animationState class, what is that? Thanks for all the help so far btw everyone, this is awesome!
|
Desmond Taylor
Member #11,943
May 2010
|
Without giving you full code since you are doing it for a course of some sort. You can use al_create_timer( ALLEGRO_BPS_TO_SECS( 60 ) ); "60" being the FPS and use the Allegro Event system ALLEGRO_EVENT_TIMER. Hope this helps you. Edit: Havacore said: Also that map<string , Animation*> in the animationState class, what is that? It's an array. Similar to std::vector and array[10] |
Havacore
Member #12,591
February 2011
|
Desmond Taylor said: Without giving you full code since you are doing it for a course of some sort Just to clarify, this isn't for a class, allegro programming is something I'm just learning on my own time. The course I mentioned earlier is just a regular computer science course. On the other hand though, that is useful. I'll have to play around with events some more
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Havacore said: I just don't quite know how to keep track of time in a program. (whether in an allegro program or in a regular C++ program). The only thing I can think of is using my FPS constant with the allegro timer, making the animation state change every 15 frames or so. Would that be how you would go about tackling that problem? Use an ALLEGRO_TIMER, and set the the number of seconds between ticks using your FPS variable. You get the number of seconds per tick by taking the reciprocal of your FPS. Then for each timer event you receive, you call Animation::AdvanceFrameTime(seconds_per_tick). 1const float FPS = 60.0;// or whatever your monitors refresh rate is
2const float SPT = 1.0/FPS;// seconds per tick
3ALLEGRO_TIMER* timer = al_create_timer(SPT);
4
5//... Create display ...
6
7al_clear_to_color(al_map_rgb(0,0,0));
8al_flip_display();
9al_start_timer(timer);// start the timer just after a vsync (flip) so we always get the most amount of time for logic and drawing
10
11//... Logic ...
12while (!quit) {
13 while (1) {
14 ALLEGRO_EVENT ev;
15 al_wait_for_event(event_queue , &ev);
16 if (ev.type == ALLEGRO_EVENT_TIMER) {
17 animation.AdvanceFrameTime(SPT);
18 redraw = true;
19 }
20 if (al_is_event_queue_empty(event_queue)) {break;}
21 }
22 if (redraw) {
23 al_clear_to_color(al_map_rgb(0,0,0));
24 animation.Display(x,y);
25 al_flip_display();
26 }
27}
28// ... Clean up ...
29return 0;
Here is a working Allegro 4 based example of animation : If you download the zip file from that post you can view the source code I used for it and run the example I provided. The important functions from Animation.cpp are AnimationBase::AdvanceFrameTime, and AnimationBase::SetFrameTime, which I posted on the page I linked to. If you have any questions, feel free to ask. If I have time in the next few days, I may make a short version that works with A5. Desmond Taylor said:
Havacore said: Also that map<string , Animation*> in the animationState class, what is that? It's an array. Similar to std::vector and array[10]
No, it's not an array. At best, it is like a sorted linked list. I gave William Labbett a short explanation of how to use the std::map class here : 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 |
Havacore
Member #12,591
February 2011
|
Ok I'm trying to use the code you put in the first response with the animation, stateAnimation and character classes. I'm still trying to wrap my head around the map thing, but I'm wondering if I can get away without using it. I worked on it a bit today but this is about as far as I got sprite.h: 1#ifndef _SPRITE_H_
2#define _SPRITE_H_
3
4#include <allegro5/allegro.h>
5#include <stdio.h>
6#include <cstring>
7
8class animation
9{
10
11 private:
12 ALLEGRO_BITMAP *bmp;
13 ALLEGRO_BITMAP *bmp_array[8][5];
14 double duration;
15 double current_time;
16 int num_frames;
17 int frame_number;
18
19
20 public:
21 animation();
22 void setFrameTime(double tsec);
23 void advanceFrameTime(double tsec);
24 void draw(BITMAP* bmp, int x, int y);
25
26}
27
28class stateAnimation
29{
30
31 private:
32 //map?
33 Animation* active_animation;
34
35 public:
36 void setState(string state);
37 void advanceFrameTime(double tsec);
38 void draw(BITMAP* bmp, int x, int y);
39}
40
41class player
42{
43
44 private:
45
46 ALLEGRO_BITMAP *current_animation;
47 int animationWidth;
48 int animationHeight;
49 animation move_left;
50 animation move_right;
51 stateAnimation anim_state;
52
53 public:
54
55 //Construtor
56 player();
57
58};
59
60#endif
sprite.cc: 1#include "sprite.h"
2#include <stdio.h>
3#include <allegro5/allegro.h>
4
5
6/********************/
7/* animation class */
8/********************/
9
10animation::animation()
11{
12 //loads the entire spritesheet
13 bmp = al_load_bitmap("player.png");
14 //converts the sprite sheet's magenta background to transparent pixels
15 al_convert_mask_to_alpha(bmp, (al_map_rgb(255, 0, 255)));
16
17
18 for(int x = 0; x < 8; x++)
19 {
20 for(int y = 0; y < 5; y++)
21 {
22 bmp_array[x][y] = al_create_sub_bitmap(bmp, 32*x, 32*y, 32, 32);
23 }
24 }
25
26 num_frames = 40;
27 current_time = 0;
28}
29
30//sets the time for a frame
31void animation::setFrameTime(double tsec)
32{
33 duration = tsec;
34}
35
36//advances the frame time
37void animation::advanceFrameTime(double tsec)
38{
39 setFrameTime(current_time + tsec);
40}
41
42void animation::draw(BITMAP* bmp, int x, int y)
43{
44 al_draw_bitmap(bmp, x, y, 0);
45}
46
47/**************************/
48/* animation state class */
49/**************************/
50
51void stateAnimation::setState(string state)
52{
53
54}
55
56void stateAnimation::advanceFrameTime(double tsec)
57{
58
59}
60
61void stateAnimation::draw(BITMAP* bmp, int x, int y)
62{
63
64}
65
66/*****************/
67/* Player class */
68/*****************/
69
70
71//Constructor
72player::player()
73{
74
75}
I changes some stuff from the original post, and I haven't filled in the player or the animation state class yet. I haven't figured out what exactly the setFrameTime and advanceFrameTime functions should do. One second I'm thinking that setFrameTime will set the duration, but then I think why wouldn't you just do that in the constructor... Maybe it's just because I need to step away from this for a second..
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Havacore said: I haven't figured out what exactly the setFrameTime and advanceFrameTime functions should do. SetFrameTime should take a time value and turn it into a frame number. AdvanceFrameTime should take the current value, add the delta time to it, and then use that value in a call to SetFrameTime. I'll go over the basics of a forward playing looped animation : 1
2class Animation {
3protected :
4 ALLEGRO_BITMAP** frames;
5 double duration;
6 double frames_per_sec;
7 double frametime;
8 int num_frames;
9 int frame_num;
10
11public :
12 Animation() :
13 frames(0),
14 duration(0.0),
15 frames_per_sec(0.0),
16 frametime(0.0),
17 num_frames(0),
18 frame_num(0)
19 {}
20 ~Animation() {Free();}
21
22 void Free() {
23 if (frames) {
24 delete [] frames;
25 frames = 0;
26 }
27 }
28
29 void Setup(double play_duration , int number_of_frames) {
30 Free();
31 assert(number_of_frames > 0);
32 assert(play_duration > 0.0);
33 duration = play_duration;
34 num_frames = number_of_frames;
35 frames = new ALLEGRO_BITMAP*[num_frames];
36 frames_per_sec = (double)num_frames / duration;
37 SetFrameTime(0.0);
38 }
39 void AdvanceFrameTime(double delta_time) {
40 SetFrameTime(frametime + delta_time);
41 }
42 void SetFrameTime(double new_frame_time) {
43 while(new_frame_time < 0.0) {new_frame_time += duration;}
44 while(new_frame_time >= duration) {new_frame_time -= duration;}
45 frametime = new_frame_time;
46 frame_num = (int)(frametime*frames_per_sec);
47 }
48 void SetBitmap(ALLEGRO_BITMAP* bmp, int frame_number) {
49 assert(frames);
50 assert((frame_number >= 0) && (frame_number < num_frames));
51 frames[frame_number] = bmp;
52 }
53 void Display(int x , int y) {
54 assert(frames);
55 assert(frames[frame_num]);
56 al_draw_bitmap(frames[frame_num] , (float)x , (float)y , 0);
57 }
58
59};
And that's it. It gets slightly more complicated if you want more features, but it's a good place to start. Use it like this : 1double duration = 10.0;
2int number_of_frames = 40;
3Animation anime;
4anime.Setup(duration , number_of_frames);
5
6ALLEGRO_BITMAP* bmp = al_load_bitmap("player.png");
7//converts the sprite sheet's magenta background to transparent pixels al_convert_mask_to_alpha(bmp, (al_map_rgb(255, 0, 255)));
8int i = 0;
9ALLEGRO_BITMAP* bmp_array[40];
10for(int x = 0; x < 8; x++) {
11 for(int y = 0; y < 5; y++) {
12 bmp_array[x][y] = al_create_sub_bitmap(bmp, 32*x, 32*y, 32, 32);
13 anime.SetBitmap(bmp_array[x][y] , i);
14 ++i;
15 }
16}
17
18// Event loop
19 while (1) {
20 ALLEGRO_EVENT ev;
21 al_wait_for_event(event_queue , &ev);
22 if (ev.type == ALLEGRO_EVENT_TIMER) {
23 anime.AdvanceFrameTime(SECONDS_PER_TICK);
24 redraw = true;
25 }
26 if (al_is_event_queue_empty(event_queue)) {break};
27 }
28 if (redraw) {
29 al_clear_to_color(al_map_rgb(0,0,0));
30 anime.Draw(400 - al_get_bitmap_width(bmp)/2 , 300 - al_get_bitmap_height(bmp)/2);
31 al_flip_display();
32 }
33}
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 |
|