|
Game Crashing and I'm not sure why? |
childski
Member #17,771
June 2020
|
Hi. I am very new to Allegro and trying to make an RPG game. In game_run(), I intend to show a couple of dialogues before continuing the game in the if(dialogue) bit. Though for some reason after the dialogue ends, the game will crash and the console says: Process returned -1073741819 (0xC0000005) I'm not sure what I did wrong, can somebody point out my mistakes? Please take a look at my really messy code and bear with me: 1#include <stdio.h>
2#include <allegro5/allegro_native_dialog.h>
3#include <allegro5/allegro.h>
4#include <allegro5/allegro_font.h>
5#include <allegro5/allegro_ttf.h>
6#include <allegro5/allegro_audio.h>
7#include <allegro5/allegro_acodec.h>
8#include <allegro5/allegro_primitives.h>
9#include <allegro5/allegro_image.h>
10#include <string>
11#define GAME_TERMINATE -1
12
13
14ALLEGRO_TIMER* timer = NULL;
15ALLEGRO_TIMER* timer2 = NULL;
16ALLEGRO_DISPLAY* display = NULL;
17ALLEGRO_FONT* font = NULL;
18ALLEGRO_SAMPLE* song = NULL;
19ALLEGRO_BITMAP* player = NULL;
20ALLEGRO_BITMAP* bg = NULL;
21ALLEGRO_BITMAP* title = NULL;
22ALLEGRO_BITMAP* papa = NULL;
23ALLEGRO_BITMAP* shadow = NULL;
24ALLEGRO_BITMAP* titlejohnny = NULL;
25ALLEGRO_BITMAP* textbox = NULL;
26
27//new bitmaps for window 2 here
28ALLEGRO_BITMAP* papa_1 = NULL;
29ALLEGRO_BITMAP* door = NULL;
30ALLEGRO_BITMAP* frame = NULL;
31ALLEGRO_BITMAP* family = NULL;
32
33ALLEGRO_EVENT_QUEUE *event_queue = NULL;
34
35enum KEYS { DOWN, LEFT, RIGHT, UP};
36enum STATE {IDLE, DIALOGUE, FRAME, DOOR1};
37
38const char *gametitle = "johnny johnny";
39const int width = 1280;
40const int height = 720;
41int window = 1;
42int state;
43bool next_window = false;
44bool draw = true;
45bool active = false;
46
47int pos_x = width / 2 - 50; //starting pos_x
48int pos_y = height / 2 + 200; //starting pos_y
49int dir = DOWN, sourcex = 0, sourcey = 0;
50float movespeed = 5;
51
52void show_err_msg(int msg);
53void game_init();
54void game_begin();
55void game_destroy();
56int game_run();
57int process_event();
58
59//dialogue stuff
60
61int dialogueindex = 0;
62char* dialogue1[12] = {"papa: johnny, johnny...","johnny: yes papa?","papa: eating sugar?","johnny: no, papa...","papa: telling lies?","johnny: no, papa...","papa: well, then. prove it.","johnny: 'i really did not eat sugar.", "what should i say to convince him?'","johnny: 'oh, i know... i will give","papa's favorite letters.'","hint: find papa's favorite letters."};
63
64char* door1text= "what's papa's favorite word?";
65
66typedef struct character
67{
68 int x = 10;
69 int y = 10;
70 ALLEGRO_BITMAP *image_path;
71
72} Character;
73
74Character character1;
75
76bool Collision(float x, float y, float ex, float ey, int width, int height)
77{
78 if(x + width < ex || x > ex + width || y + height < ey || y > ey + height)
79 {
80 return false;
81 }
82 return true;
83}
84
85void stopmoving()
86{
87 if(dir == DOWN)
88 character1.y-= movespeed;
89 if (dir == LEFT)
90 character1.x+=movespeed;
91 if(dir == RIGHT)
92 character1.x-=movespeed;
93 if(dir == UP)
94 character1.y+=movespeed;
95}
96
97
98int main(int argc, char *argv[])
99{
100 int msg = 0;
101
102 printf("Loading...\n");
103 game_init();
104 game_begin();
105
106 while (msg != GAME_TERMINATE)
107 {
108 msg = game_run();
109 if (msg == GAME_TERMINATE)
110 printf("Bye\n");
111 }
112 game_destroy();
113 return 0;
114}
115
116
117void show_err_msg(int msg)
118{
119 fprintf(stderr, "unexpected msg: %d", msg);
120 game_destroy();
121 exit(9);
122}
123
124void game_init()
125{
126 if (!al_init())
127 show_err_msg(-1);
128
129 //Initialize Timer
130 float FPS = 60.0;
131 timer = al_create_timer(1.0/FPS);
132 al_start_timer(timer);
133
134 event_queue = al_create_event_queue();
135 display = al_create_display(width,height);
136
137 al_set_window_position(display, 0, 0);
138 al_set_window_title(display, gametitle);
139 al_init_font_addon();
140 al_init_ttf_addon();
141 al_init_primitives_addon();
142 al_init_image_addon();
143 al_init_acodec_addon();
144 al_install_audio();
145 al_install_keyboard();
146
147 al_register_event_source(event_queue,al_get_display_event_source(display));
148 al_register_event_source(event_queue,al_get_keyboard_event_source());
149 al_register_event_source(event_queue,al_get_timer_event_source(timer));
150
151
152}
153
154
155void game_begin()
156{
157 song = al_load_sample("liar.ogg");
158 if (!song){
159 printf( "Audio clip sample not loaded!\n" );
160 show_err_msg(-6);
161 }
162 // Loop the song until the display closes
163 al_play_sample(song, 1,0,1,ALLEGRO_PLAYMODE_LOOP, NULL);
164 ALLEGRO_COLOR al_map_rgb(unsigned char r, unsigned char g, unsigned char b);
165 font = al_load_ttf_font("Wildy-Sans.ttf", 40, 0);
166 player = al_load_bitmap("spritejohnny.png");
167 al_draw_bitmap(player,0, 0, 0); //for character
168 bg = al_load_bitmap("title_bg.png");
169 title = al_load_bitmap("title.png");
170 shadow = al_load_bitmap("shadow.png");
171 papa = al_load_bitmap("papa.png");
172 titlejohnny = al_load_bitmap("title_johnny.png");
173
174 //for window 2
175 papa_1 = al_load_bitmap("papa_1.png");
176 textbox = al_load_bitmap("textbox.png");
177 family = al_load_bitmap("family.png");
178 frame = al_load_bitmap("frame.png");
179 door = al_load_bitmap("door.png");
180 bg = al_load_bitmap("title_bg.png");
181
182
183 al_draw_bitmap(bg, 0, 0, 0);
184 al_draw_bitmap(shadow, 55, 10, 0);
185 al_draw_bitmap(papa, 150, 0, 0);
186 al_draw_bitmap(title, 500, 250, 0);
187 al_draw_bitmap(titlejohnny, 220, 350, 0);
188 al_draw_text(font,al_map_rgb(255,255,255),800,500,0,"press enter to start");
189 al_flip_display();
190
191}
192
193int process_event()
194{
195 ALLEGRO_EVENT event;
196 ALLEGRO_KEYBOARD_STATE keystate;
197 al_wait_for_event(event_queue, &event);
198 al_get_keyboard_state(&keystate);
199 al_get_keyboard_event_source();
200 al_get_timer_event_source(timer);
201
202 bool hitframe = false;
203
204 if(al_key_down(&keystate, ALLEGRO_KEY_ENTER))
205 next_window = true;
206
207 if(al_key_down(&keystate, ALLEGRO_KEY_ESCAPE))
208 return GAME_TERMINATE;
209
210 active = true;
211 if(al_key_down(&keystate, ALLEGRO_KEY_DOWN))
212 {
213 character1.y += movespeed;
214 dir = DOWN;
215 }
216 else if(al_key_down(&keystate, ALLEGRO_KEY_UP))
217 {
218 character1.y -= movespeed;
219 dir = UP;
220 }
221 else if(al_key_down(&keystate, ALLEGRO_KEY_RIGHT))
222 {
223 character1.x += movespeed;
224 dir = RIGHT;
225 }
226 else if(al_key_down(&keystate, ALLEGRO_KEY_LEFT))
227 {
228 character1.x -= movespeed;
229 dir = LEFT;
230 }
231 else
232 active = false;
233
234 if(active)
235 sourcex += al_get_bitmap_width(player) / 3;
236 else
237 sourcex = 100;
238
239 if(sourcex >= al_get_bitmap_width(player))
240 sourcex = 0;
241 sourcey = dir;
242 draw = true;
243
244 if(Collision(character1.x, character1.y,260,160, al_get_bitmap_width(frame)/2+10, al_get_bitmap_height(frame)/2))
245 {
246 state = FRAME;
247 printf("frame");
248 stopmoving();
249 }
250
251 if(Collision(character1.x, character1.y,950,280, al_get_bitmap_width(papa_1)/2+10, al_get_bitmap_height(papa_1)/2))
252 {
253 printf("dad");
254 stopmoving();
255 }
256
257 if(Collision(character1.x, character1.y,585,0, al_get_bitmap_width(door)/2-10, al_get_bitmap_height(door)/2))
258 {
259 state = DOOR1;
260 printf("door1");
261 stopmoving();
262 }
263
264 if(event.type == ALLEGRO_EVENT_KEY_DOWN)
265 {
266 if(event.keyboard.keycode == ALLEGRO_KEY_Z)
267 {
268 switch(state)
269 {
270 case DIALOGUE:
271 dialogueindex++;
272 break;
273 /*case FRAME:
274 al_draw_bitmap(family,300,200,0);
275 break;
276 case DOOR1:
277 al_draw_bitmap(textbox,300,200,0);
278 al_draw_text(font,al_map_rgb(255,255,255),600,250,ALLEGRO_ALIGN_CENTER,door1text);
279 break;*/
280 }
281
282 }
283 }
284
285 /*if(event.type == ALLEGRO_EVENT_KEY_CHAR && door1)
286 {
287 const int inputChar = event.keyboard.unichar;
288 if
289 (
290 (inputChar >= 48 && inputChar <= 57) //is a number
291 || ( inputChar >= 65 && inputChar <= 90) //is a capital letter
292 || ( inputChar >= 97 && inputChar <= 122) //is a lower-case letter
293 || ( inputChar == 95) //is an underscore
294 ){
295 keyboard_string += inputChar;
296 }
297 }*/
298
299 return 0;
300}
301
302
303int game_run()
304{
305 int error = 0;
306 al_play_sample(song,5,0,1,ALLEGRO_PLAYMODE_LOOP,0);
307 if(window == 1)
308 {
309 if (!al_is_event_queue_empty(event_queue))
310 {
311 error = process_event();
312 if(next_window)
313 {
314 window++;
315 character1.x = pos_x;
316 character1.y = pos_y;
317 character1.image_path = player;
318 //bg = al_load_bitmap("title_bg.png"); --> moved to game-begin
319 }
320 }
321 }
322 // Second window(Main Game)
323 else if(window == 2)
324 {
325 al_draw_bitmap(bg, 0,0,0);
326 al_draw_bitmap(papa_1,950,250,0);
327 al_draw_bitmap(frame,290,220,0);
328 al_draw_bitmap(door,550,0,0);
329
330 // Change Image for animation
331 if(draw)
332 {
333 al_draw_bitmap_region(character1.image_path, sourcex, sourcey * al_get_bitmap_height(character1.image_path) / 4, 100, 100, character1.x, character1.y, 0);
334 }
335
336 state = DIALOGUE;
337
338 switch(state)
339 {
340 case IDLE:
341 al_draw_bitmap(bg, 0,0,0);
342 al_draw_bitmap(papa_1,950,250,0);
343 al_draw_bitmap(frame,290,220,0);
344 al_draw_bitmap(door,550,0,0);
345 break;
346 case DIALOGUE:
347 if(dialogueindex<sizeof(dialogue1)-1)
348 {
349 al_draw_bitmap(textbox,300,200,0);
350 al_draw_text(font,al_map_rgb(255,255,255),600,250,ALLEGRO_ALIGN_CENTER,dialogue1[dialogueindex]);
351 }
352 else state = IDLE;
353 break;
354 case FRAME:
355 al_draw_bitmap(family,300,200,0);
356 break;
357 case DOOR1:
358 al_draw_bitmap(textbox,300,200,0);
359 al_draw_text(font,al_map_rgb(255,255,255),600,250,ALLEGRO_ALIGN_CENTER,door1text);
360 break;
361 default:
362 al_draw_bitmap_region(character1.image_path, sourcex, sourcey * al_get_bitmap_height(character1.image_path) / 4, 100, 100, character1.x, character1.y, 0);
363 }
364
365 al_flip_display();
366
367 // Listening for new event
368 if (!al_is_event_queue_empty(event_queue))
369 {
370 error = process_event();
371 }
372 }
373 return error;
374}
375
376void game_destroy()
377{
378 al_destroy_display(display);
379 al_destroy_font(font);
380 al_destroy_event_queue(event_queue);
381 al_destroy_timer(timer);
382 al_destroy_timer(timer2);
383 al_destroy_bitmap(player);
384 al_destroy_bitmap(papa);
385 al_destroy_bitmap(title);
386 al_destroy_bitmap(bg);
387 al_destroy_bitmap(titlejohnny);
388 al_destroy_bitmap(papa_1);
389 al_destroy_bitmap(textbox);
390 al_destroy_bitmap(family);
391 al_destroy_bitmap(frame);
392 al_destroy_bitmap(door);
393 al_uninstall_keyboard();
394 al_destroy_sample(song);
395}
Thank you so much! |
pmprog
Member #11,579
January 2010
|
Can you not step through it with a debugger and see the stack trace... That would help you loads
|
MikiZX
Member #17,092
June 2019
|
I believe you need to move your: timer = al_create_timer(1.0/FPS); al_register_event_source(event_queue, al_get_timer_event_source(timer)) ; al_start_timer(timer); outside of the game loop (possibly to your init function) - right now I believe you are creating a new timer each iterration of the loop. EDIT: Also, your process_event(); function does not contain the part that would be processing the timer events. Have a look at https://github.com/liballeg/allegro5/blob/master/examples/ex_timer.c lines from 141-161 for an example of an event processing loop. |
childski
Member #17,771
June 2020
|
Hi, thank you for all the replies. @pmprog: sorry, what is a stack trace? @MikiZX: thank you for the reference and suggestions. I've moved the timer to init now. From the sample code that I've seen, they only used the timer to animate some sprites. I'm still confused about the timer concept; is it to make sure that the game runs on a stable FPS? --- From the source codes that I've seen in Allegro game development, it's either too complicated that I can't understand the structure or too basic. As my function if(dialogue) causes the game to crash due to infinite loop, I want to ask: is there a way to show a dialogue text box like in most RPG style games? Again, thanks for the feedback and guidance. |
LennyLen
Member #5,313
December 2004
|
childski said: I'm still confused about the timer concept; is it to make sure that the game runs on a stable FPS? The main purpose of timers is to ensure that your game runs at the same speed on different computers.
|
pmprog
Member #11,579
January 2010
|
@childski, A stack trace is a list of functions that the current execution leading up to your crash. Personally, i think debugging is just as important as coding, so I'd honestly recommend learning how to use a debugger. Depending on what language/toolchain you're using, they're all a little different, but the concepts are generally consistent
|
childski
Member #17,771
June 2020
|
@LennyLen thanks! that cleared me up a bit. I'll just have to somehow implement it... @pmprog Ok, so I've found that my problem is in the if(dialogue) part, which now I've cleaned up a bit, but still have problems with. In my game_run() function, I understand that it loops until the game stops. The problem arises when I set dialogue=false (i.e the dialogueindex reaches 12), and then the game crashes. Until today, I'm still not sure why and what could be done to actually fix it |
MikiZX
Member #17,092
June 2019
|
I had a second look at your source and possibly you need to test this line: My programming skill is not that good (and I'm too lazy to test) but maybe sizeof(char* x) will not return the number of elements in the array? As for displaying the dialogue there is no special way - you choose how to do it (you can just print text to the screen). Some people here that understand C++ better can also confirm if your code is C or C++ since you are using #include <string> .. I am not sure if this changes anything. As for timers.... Hm.. I'll try to explain part of the situation. I have had a look at your game code and your game actually does not have a fixed speed at which it is executed because at the moment you only make things happen when there is some input to your game (like a keypresses for example) - the main loop of your game is executed as fast as your computer/operating system can run it. Even if this is OK for a game to run only when there is input - this is not what majority of game devs do. You can create multiple timers that can run in parallel - one timer to be executed 60 times a second, another that executes only once every 5 minutes, etc... Each time the timer ticks (is executed) there will be a new ALLEGRO_EVENT_TIMER in the event queue and your main loop can be designed to do something when it this event appears. On the other hand, you will have to add processing for different events in your loop (like window managment for example). If your game was just running in a loop without a timer (as it is doing so now) then you will need to calculate time elapsed between two frames (two iterrations of the loop) of the game and move and animate the game assets using this delta time in order for the movement and animation to be done at the same speed/rate on different computers. Using a fixed timer simplyfies things in this regard as you can always use the same values to advance animation or change position. Do not take all this I have written as 100% true (as I am learning Allegro as well) but it is there to give you some general idea of why timers could be usefull for you (or not needed at all). Please let me know if there is any particuar reason you wish to create your game without a fixed timer - or if you see no problem to re-arranging your main loop so it fits the 30 or 60 ticks per second type of executing as I can eventually (if you get stuck) change your code so it runs at fixed rate using a timer. |
pmprog
Member #11,579
January 2010
|
I think i know what your problem is, but seriously, invest some time into a debugger. Failing that... I used to be taught what was called a dryrun. Where you run line by line through your head, keeping track of the variables on a bit of paper I really just want to say the problem i see, but part of me hopes you'll try the debugging Edit: A hint is that you are actually overflowing your dialogue array, which is why it's crashing
|
childski
Member #17,771
June 2020
|
@MikiZX That was very helpful and eye-opening! Thanks a lot for the explanation. And yes, I've now implemented the correct way to calculate the elements of the char* array, now it's fixed! :') It's not that I do not want to use a timer, it's just that I probably have no idea how to correctly use one. Though I am currently trying to incorporate it into my game loop. I do wish my game can be run consistently on every computer, just... figuring it out. Again, thanks for the great help --- I'm not sure if you're referring to another type of debugger/debugging? I'm confused. |
pmprog
Member #11,579
January 2010
|
@childski: Then yes, you were overrunning the array. Whilst that in itself doesn't error, it leads you to access incorrect/invalid memory, which is what causes the error. Also line 336 always sets your state to DIALOGUE, you'll never be able move on from the dialogue section
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
There are multiple ways to use a debugger. CB is just handling the interface for you. Setting breakpoints, stepping, so on.... There's a little guide I wrote to gdb here : (you'll notice there is a terminal in CB for talking to gdb) 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 |
|