Maze Runner [V1]

MazeRider.hex (46.8 KB)

I’ve been continuing to work on my maze game and have reached the point where its ready for a post. @Vampirics has been a huge help providing tiles and art so this wouldn’t be nearly as attractive looking without him.
spash

Each level has 5 unicycle parts that you must collect to advance to the next level. At this point there’s very little coding left for my final scope, just saving and scoring left.
However there are only 3 levels right now as they are the most time consuming aspect to make. Part of why I’m posting now is one: If anyone would like to make a level the engine is very simple, each floor is saved as a simple char array and then converted. I use excel to plan my levels then export it to a csv I can copy over.
Two: If anyone would be up to making a sound loop I have plenty of memory left to implement it. I am not musically inclined enough to do this myself unfortunately.

    The important info:

    Character: SnailGuy  

    Buttons:
    --------
    DPad: move in that direction
    A: select/ pause menu ingame
    B: exit pause menu
    A + B: return to level select while in game

    Move between floor tiles:
    -------------------------
    Upstairs: U
    Downstairs: D
    
    Move through in one direction tiles:
    ------------------------------------
    Left Gate: <
    Right Gate: >
    Upwards Gate: ^
    Downwards Gate: v
    
    Special Tiles: 
    --------------
    Closed Gate: * (Can't move through)
    Open Gate: # (Can move through)
    Gate Button: @ (Toggles gate state)

    Part tiles:
    -----------
    Parts:
    Seat: ~
    Stem: l
    Crank: z
    wheel: o
    Pedals: =

Here’s a few screens shots of the game:

MazeScreen

pause

And the release:

Source here.

Also @Pharap provided me some advice early on in development and would like to thank him again for the help.

9 Likes

Good job, it’s nice to see all this working that well. Might want to change the repo and filename to reflect the real name of the game maybe?

What kind of music would you want? Sounds effects?

Background music. TBH it was too much effort to change the ino and folder that’s why I just dumped it in src lol.

1 Like

I still think the player sprite should not have a mask and keep the black background, we lose the sprite when it’s over something else. And the player should be displayed over everything else I think.

That should help in seeing clearly where we are. It’s all so small that’s it’s important.

Level 4 is corrupted or something. Half the screen. Is showing random gibberish like is some parts are out of the array?

You could alter the mask so that the player has an outline.
That would give it a kind of ‘cardboard cut-out’ effect.

(And yes, that’s genuinely the best example I could find.)
(And the story behind it is even funnier than the image.)

1 Like

There’s no mask for the player Sprite.

Also there’s only 3 levels, I know what’s wrong but I won’t be able to fix that till tomorrow. I thought I had removed all my magic numbers but the win screen must still have one. I’m surprised it isn’t 100% scrambles tbh.

Something like this?
image

1 Like

If there was no mask and the player was drawn over everything, we would be able to see the player all the time as the 6x7 tile for the player had a black background…

This is the snippit for drawing the character. It doesn’t seem the black rectangle I wanted to draw behind the character does anything though.

void Character::printChar() {
  arduboy.drawRect(xFromQuadIndex(index), yFromQuadIndex(index), 6, 7, BLACK);
  arduboy.drawBitmap(xFromQuadIndex(index), yFromQuadIndex(index), snail, 6, 7, WHITE);
}

Yup, like that.

It does. drawRect draws an outline of a rectangle. I believe what you wanted was fillRect.

To be honest though, you’re better off just switching to Sprites format and using Spritess::drawOverwrite instead.
It would probably work out cheaper in the long run.

3 Likes

Sorry it’s been so long. If I learned anything from this project its that level design can be much more time consuming and tedious than writing the actual games,

I’ve added 3 easy stages in the beginning to help introduce some of the mechanics and one hard level at the end.

The last level has dead ends in the bottom maze. I’m unsure if I want to keep that in as a mechanic for the hardest levels or not. You can now return to the level select using A+B so getting stuck ins’t a hard reset.

I still need to implement EEPROM saving as well but otherwise I think after I make a couple more level packs this should be pretty good to go.

Edit:
Is there a current memory map of the standard EEPROM used with the Arduboy2 or is it just the

#define EEPROM_STORAGE_SPACE_START   16

In the arduboy2 library docs?
I only need to save 2 arrays, but as I add more levels the size of those two arrays will increase.

1 Like

There’s been lots of discussion but nothing has ever come of it, beyond allowing you to indicate what you use if you create a .arduboy file. So, you can do whatever you want as long as you don’t go below EEPROM_STORAGE_SPACE_START.

It’s best if you use #defines in an obvious spot, or some other way that makes it easy to change the location(s), in case someone wants to change it and re-compile so it doesn’t interfere with another of their favourite game(s).

Here’s one of the more popular threads:

That’s what I thought but wasn’t entirely sure. What exactly is the 16 that EEPROM_STORAGE_SPACE_START is set too? 16 bytes? Also what would the last location be 1000 then?

Would this be correct for the locations to store my two arrays?

arrayOneSaveLocation = EEPROM_STORAGE_SPACE_START;
array2SaveLocation = arrayOneSaveLocation + sizeOf(arrayOne);

Any EEPROM address below that contains values used by the library that pertain to the overall system and should be carried across sketches, such as the audio mute state and your Arduboy’s unit name should you decide to give it one. You shouldn’t read or write this area directly in a sketch as there’s no guarantee that the layout won’t change in a new library release. There are library calls provided to read or write any values that are deemed allowable for a sketch to change.

The EEPROM is 1K in size, addressed from 0 to 1023. EEPROM_STORAGE_SPACE_START is the first address and 1023 is the last address that a sketch can safely change.

That would work but, unless you need all of it, you might want to add an offset to locate it somewhere farther up in the space.

#define MY_EEPROM_OFFSET 567 // <- some arbitrary value that will still allow the data to fit 

arrayOneSaveLocation = EEPROM_STORAGE_SPACE_START + MY_EEPROM_OFFSET;
array2SaveLocation = arrayOneSaveLocation + sizeOf(arrayOne);

Many existing sketches start right at EEPROM_STORAGE_SPACE_START. By picking a higher address range, you are less likely to clobber or be clobbered by other sketches’ usage of EEPROM space.

1 Like

How does this look?

#pragma once
#include "GameEngine.h"
constexpr uint8_t EEPROM_START_C1                 EEPROM_STORAGE_SPACE_START +373
constexpr uint8_t EEPROM_START_C2                 EEPROM_START_C1 + 1
constexpr uint8_t EEPROM_arrayOneSaveLocationClears = EEPROM_START_C2 + 1;
constexpr uint8_t EEPROM_arrayTwoSaveLocationSteps = arrayOneSaveLocation + sizeOf(arrayOne);

void initEEPROM() {

  unsigned char c1 = EEPROM.read(EEPROM_START_C1);
  uint8_t c2 = EEPROM.read(EEPROM_START_C2);

  if (c1 != ‘V’ || c2 != 93) {    
    EEPROM.update(EEPROM_START_C1, ‘V’);
    EEPROM.update(EEPROM_START_C2, ‘93’);
    EEPROM.put(EEPROM_arrayOneSaveLocationClears, levelsCleared); //bool array of levels beaten
    EEPROM.put(EEPROM_arrayTwoSaveLocationSteps, minSteps);       //uint16_t array of number of steps taken  
  }
}

void saveEEPROMLevel(){
  EEPROM.update(EEPROM_arrayOneSaveLocationClears, levelsCleared);
}

void saveEEPROMSteps(){
  EEPROM.update(EEPROM_arrayTwoSaveLocationSteps, minSteps);
}

Also could you update individual members of a saved array? Something like:

//minSteps is an uint16_t array of length 7
EEPROM.update(EEPROM_arrayTwoSaveLocationSteps + (indexNumber * (*minsteps[1] - *minSteps[0]), minSteps[index]);

You should make those uint16_t since the addresses can be greater than 256.

EEPROM.update will write any single byte to EEPROM wherever you tell it to (if the value saved would change).

You probably already know this but, just in case:

EEPROM has a limited number of times that any given location can be written to before it might start failing to save the correct value. It’s a pretty large number of times, but you don’t want to be writing different values at something like once per second.

For the processor used by the Arduboy it’s specified as minimum 100000 write cycles. You may actually get far more than this but it’s not guaranteed. You can read EEPROM as often and as fast as you wish without risk of damage, though.

there’s a minor risk of c1 and c2 being ‘V’ and 93 from a previous game. It’s very minor, mind you, but just good to be aware of. My games do the same thing. But there’s that teeny risk of someone not being able to save correctly.

1 Like

Woops

I meant more along the lines if that was the right expression. I guess sizeof(minsteps[0]) would work too for the offset.

That’s why I asked about a specific spot. Will EEPROM.update() only write new values to an address or will it always write over whats there? I only intend to call the save functions after a level is completed.

I think the two values will be sufficient enough. They’re more for keeping track of the version, as when I add more maps the two arrays wont line up in EEPROM anymore and need to be changed.