ExolonFX - shooter/platform game

Hello

I just finished my last game - ExolonFx - conversion game from zxspectrum.

Wikipedia: Exolon is a run and gun game programmed by Raffaele Cecco and published by Hewson in 1987 for the ZX Spectrum, Commodore 64, and Amstrad CPC. It was later converted to the Enterprise 128, Amiga, and Atari ST.

ArduboyCapture (5)

I mentioned about this game (demo version) here: ExolonFX - new project (demo version)

I added all 125 levels from zx spectrum version.
Some aspects of the game mechanics have been improved

How to play:
UP - jump
DOWN - crouch
LEFT - go to left
RIGHT - go to right
BUTTON A - fire
BUTTON A (hold) - launch rocket.
in the teleport - UP key takes you to the second teleport.
BUTTON B - return to title screen.

Options on the title screen:
LEFT or RIGHT - select level
DOWN - disable/enable sounds
UP - enable/disable cheat mode
ArduboyCapture (5)ArduboyCapture (6)
game1game2
ArduboyRecording (5)

Exolon.arduboy (61.5 KB)

10 Likes

This looks incredible! I use MrBlinky’s Arduboy Uploader GUI v1.12 and having trouble installing this on my genuine arduboy FX. I’m fairly sure it’s me and my own stupidity, but a little guidance would be appreciated if you have the time. I tried uploading the fxdata.bin file first and then the hex file after but didn’t seem to work. I notice the github link has a lot of files though so wondering if I’m uploading the wrong ones. Sorry to be an idiot/annoyance.

I made a tutorial for how to add games using Arduboy Toolset, another program to work with Arduboy data: Arduboy Toolset - #147 by haloopdy

Great ZX Spectrum game of my childhood! Thanks for being able to play it again and get nostalgic ) I will try to port it to ESPboy in the next few days of course

1 Like

Yes! It works on ESPboy!
But why does the astronaut look transparent and the levels don’t change automatically ? )

Hmm on Arduboy version levels are incremented automatically but always you see the title screen between levels.
In main loop:

    if (player.x > BOARD_GAME_WIDTH-3){
            player.clear_parameters = false;
            game_stage = STAGE_GAME_TITLE;
            Current_Level = Current_Leve+1;
            
    }

About astronaut ESP version - looks like on Arduboy version or different?

I just recompile the original version (using ported Arduboy libs for ESP8266) and getting the same Picture as on the Arduboy version (and the same as we see on the emulator).
Maybe add a score to the game like in the original Exolon?

I thought about score but there is one big problem - in arduboy version I cannot add any new code. My sketch uses 28996 bytes but available are only 29696 bytes :(. I think i would have to rewrite, a lot of part of code this game (and i still don’t know it will be enough). I also wanted add a lot of other things like animated mines, more and better sounds, but there is not enough memory for this.

There’s quite a few things you could do to save memory.

To select a few to start with:

  • You shouldn’t be calling audio.on() in setup() because that forces the sound on and ignores the user’s sound preferences.
  • You don’t need to call audio.begin() because arduboy.begin() already does that.
  • You don’t need an audio object at all, because arduboy already has one: arduboy.audio
    • (This actually won’t save you any memory because the compiler will be getting rid of the audio object anyway.)
  • You don’t need an enable_audio because you can use arduboy.audio.enabled() instead.
  • In cases where you are doing if(/*something*/) { tinyfont.print("something"); } else { tinyfont.print("something"); } it should be cheaper to replace that if-else with the conditional operator ?-:
    • E.g. instead of if (enable_audio) { tinyfont.print("Y"); } else { tinyfont.print("N"); } you can do: tinyfont.print(arduboy.audio.enabled() ? "Y" : "N");, which should use less memory. (I.e. 1 function call instead of 2.)
    • The same trick may apply in other circumstances, e.g. instead of if (player.is_super) { super_player_frame_position = 22; } else { super_player_frame_position = 0; } it may be cheaper to do super_player_frame_position = player.is_super ? 0 : 22;.
  • If you’re using the FX library then you shouldn’t be calling arduboy.display(), you should only be calling FX::display().
    • See here for more information.
  • If you’re using FX::display(CLEAR_BUFFER) instead of FX::display() then you don’t need to call arduboy.clear().
  • To save RAM instead of progmem, you should wrap your string literals (e.g. "Y", "N", "SOUND:", etc.) with the F macro (e.g.F("Y"), F("N"), F("SOUND:"), etc.). The reason for this is quite technical, but basically the F forces the string to stay in progmem.

The biggest saving you could possibly make would actually be to restructure your code so that you’re not doing while(!arduboy.nextFrame()) everywhere or calling FX::display(CLEAR_BUFFER) multiple times and instead using a proper state machine.

Basically instead of doing if(game_stage == STAGE_GAME_TITLE) and then title_screen() having a loop inside, you should be doing something more like:

void loop()
{
	// If it's not time to draw the next frame
	if(!arduboy.nextFrame())
		// Exit the loop function
		return;
		
	// Update the button states
	arduboy.pollButtons();
	
	// Check the current game state
	switch(game_stage)
	{
		// If the current game state is 'game title'
		case STAGE_GAME_TITLE:
			// Call the function that updates and draws the titlescreen
			title_screen();
			break;
			
		// If the current game state is 'play game'
		case STAGE_PLAY_GAME:
			// Call the function that updates and draws the gameplay
			play_game();
			break;
	}
	
	// Update the screen and clear the screen buffer
	FX::display(CLEAR_BUFFER);
}

Crucially those title_screen() and play_game() functions should not get stuck in a loop. They should:

  • Update the game logic
  • Draw all the things they need to draw
  • Return, either explicitly or by reaching the bottom of the function

By doing things that way, you should never need to call arduboy.nextFrame(), arduboy.pollButtons(), or FX::display() more than once.

(You may also find this post useful.)

If, after reading that, you’re wondering how you would adapt something like:

do {
// Blah blah blah
} while (!exit_loop);

And

if (arduboy.justPressed(A_BUTTON)) {
	exit_loop = true;
}

The answer is: with states.

Instead of having the do-while, you allow control to reach the bottom of the function so it goes back to loop(), and then when loop() is called again, control will go back to title_screen() and everything will happen again without title_screen() needing a loop inside it.

When you’re ready to leave that loop, you just do game_stage = STAGE_PLAY_GAME;.

In your case, it looks like you’re intending to only call prepare_level_parameters(); when the title screen has ended, so I think you would want:

if (arduboy.justPressed(A_BUTTON))
{
	game_stage = STAGE_PLAY_GAME;
	prepare_level_parameters();
}

By setting game_stage and reaching the end of title_screen() and then the end of loop(), the next time loop() begins, instead of going to title_screen() it goes to play_game(); because game_stage is then STAGE_PLAY_GAME, not STAGE_GAME_TITLE.


Does that all make sense?
Do you have any questions?

(Unfortunately I don’t know any Polish.)

4 Likes

Thanks. You advices are very helpful. I think i have to improve my code (but i not know when - this project took a lot of energy and tired me ;). But what you wrote will be very helpful for my next projects :slight_smile:

2 Likes

ExolonFX is available on http://www.bloggingadeadhorse.com/cart/Cart.html

obraz

Thank you @filmote !

3 Likes