![]() |
|
Timing of enemy arrival in shmup |
_jagged
Member #17,124
September 2019
|
Hello everyone, But... I'm not sure what is an efficient way to time when my waves of enemies should appear onscreen. Unlike my functions for collision I don't know how to use a function for spawning enemies unless they are all spawned at the same time. In a game like Rtype the enemies typically appear onscreen one by one with maybe 0.25 - 0.5 second delay. Currently I have a counter int the redraw block: 1if (redraw && al_is_event_queue_empty(event_queue))
2{
3 redraw = 0;
4 switch (gamestate)
5 {
6 case START_SCREEN:
7 al_draw_textf(font, al_map_rgb(255, 0, 255), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2,
8 ALLEGRO_ALIGN_CENTER, "C-Type");
9 al_draw_textf(font, al_map_rgb(255, 0, 255), SCREEN_WIDTH / 2, (SCREEN_HEIGHT /
10 2) + (SCREEN_HEIGHT / 8),
11 ALLEGRO_ALIGN_CENTER, "press spacebar to begin");
12 break;
13 case IN_GAME:
14 enemy_timer++;
And then in the event timer block I do this: 1if (enemy_timer == 240)
2init_enemy(&enemy_grunts[0], 1920, 300);
3
4if (enemy_timer == 270)
5init_enemy(&enemy_grunts[1], 1920, 300);
6
7if (enemy_timer == 300)
8init_enemy(&enemy_grunts[2], 1920, 300);
Which is obvious tiresome. Can I make this happen for ten enemies by using a function? Cheers!
|
Audric
Member #907
January 2001
|
For a continuously scrolling game, I would use the "level offset" (in pixels) as a time mark, instead of a number of (milli)seconds. This makes it easier for you to match the level graphics. First version would be to hard-code in an array of structs the "program" of your level: T_Schedule level1_schedule[] = { /* At T= 0 pixels, a squadron of three) */ {0, ENEMY_TYPE_BLUE_SHIP, 23, 200}, /* 23 pixels off the right edge, 200 pixels from bottom */ {0, ENEMY_TYPE_BLUE_SHIP, 23, 250}, {0, ENEMY_TYPE_BLUE_SHIP, 23, 300}, /* At T = 40 pixels, a single bonus ship */ {0, ENEMY_TYPE_BONUS, 45, 100}, };
Be sure to write everything in chronological order. Once you have such system working, you can consider externalizing the data in a file (raw text, xml, whatever is easiest for you to edit). Your code can then execute the loading once, when your program starts, and fill the exact same array of structure - the "schedule player" code is then unchanged! |
MikiZX
Member #17,092
June 2019
|
What Audric says is possibly the best and straight forward way of having this up and running while keeping control over what is happening during the level. My approach to this problem in a small shmup I did was to just do a modulo divide (integer reminder of a division) of the enemy_timer with different numbers (similar to what you are already doing) - so every 50 increases of the timer I would spawn one wave of weak enemies, every 73 increases a different type of wave, every 300 a stronger wave, and reset the timer every 10000 increases (sort of level complete thingy) etc. which as a system will lack character but is still playable and enjoyable. if (enemy_timer%50==0) init_enemy(&enemy_grunts[0], 1920, 300); if (enemy_timer%73==0) init_enemy(&enemy_grunts[1], 1920, 300); if (enemy_timer%300==0) init_enemy(&enemy_grunts[2], 1920, 300); As this is your first project, the following suggestion might be too much work and complex (so if you fancy the idea, you might want to keep this only for the version 2 of your game) - If you will want to extend your game to have decorative graphics like R-Type has (top and bottom of the screen) then as Audric suggests you might want to externalize your map data. And, possibly adapt to using a map editor such as 'Tiled' where one layer of the map could dictate the decorations to be drawn on the screen and another layer of the same map be used to tell your game when to trigger which type of enemy or introduce power-ups. Now, this would require quite a bit of planning, extra work and adapting your graphics to certain sizes (likely), creating tilesets for Tiled, etc. but it might be rewarding in the long run. One last thing, I am likely wrong as I cannot have all the insight in your code but, looking at it, I believe you would need to move the enemy_timer++; out of the redraw part and into the timer section of your code? (so the enemy_timer variable increases at regular intervals as opposed to increasing at different pace depending on if the game is running on slower computer or a faster one - unless this is the design you wish to have, naturally). |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
This is a perfect use case for an event based system. You can have events that cause enemies to spawn and make enemies appear based on an event that you can send whenever you want. 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 |
_jagged
Member #17,124
September 2019
|
Thank you all for your responses. But, I must admit... I'm a bit confused. What Audric has said makes a lot of sense; I should be spawning these enemies based on the position of the background/environment. But my first and only level is a repeating background and parallax foreground (not really sure how to explain this) that repeats. MikiZx, wouldn't your approach be less efficient than what I have now due to the modulus? I agree with your skepticism of the enemy_timer placement, but I was under the impression that this kind of game would have no problem emptying the event queue with ANY current hardware. Edgar, could you elaborate, please?
|
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Using an event system is quite similar to what you have. Basically, you monitor game time, and spawn events or enemies based on conditions. The way you're doing it now is fine, and others have made good suggestions. I would go with their solutions for now. 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 |
MikiZX
Member #17,092
June 2019
|
Actually regarding modulus suggestion you are right, it is inferior to Audric's and Edgar's suggestion (since using modulus result takes away almost all control from you in telling the game when to spawn the enemies). The only advantage I can think of for using modulus is that it is quick. Also, if you do not actually have a map but only repeating graphics then 'Tiled' suggestion I made is definitely an overkill. For your case I believe Audric's and Edgar's suggestions are much better fit. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Modulus works fine for the background offset, just keep the actual distance traversed and modulo that to get the offset. Then use the actual distance for spawning enemies. 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 |
|