Help me with C++ for my game

I was gonna say:

I don’t think you’ve understood what I meant. The bug only happens when walking right or walking left, and it’s only 1 pixel, but not always in the same spot that, that is black (as if a white pixel of the sprite wasn’t being drawn)

But I did what you said and it works flawlessly

1 Like

That’s because this is the sort of thing masks are designed for.
Masks are the most flexible way to implement transparency on the Arduboy.

If I knew what spr_human_outline actually looked like I could probably determine why the other approach wasn’t working.

I have many talents, but reading an array full of hexadecimal and figuring out what the original image looked like is not one of them. :P

But frankly using masks is a better option, and you only need one function instead of two, so it might just be best to switch to doing that and forget about why it was breaking before.

1 Like

My approach is to use 16 tiles (so, uint8_t). So the tiles themselves are just numbers with a corresponding frame from the sprite

Anything equal to or greater than 4 is considered solid. For caverns and houses I’m thinking of simply using a different spritesheet, but stick to 16 tiles. So everything could be stored as a uint8_t

I have watched this video so I’m aware of some strategies https://youtu.be/ZWQ0591PAxM?t=376
But let’s pretend I don’t compress anything and put everything in one giant array on PROGMEM, how many sections of 16 tiles by 8 tiles high could I have?

(I know you can’t be very precise about this because it will depend on how many sprites I have and my code, but any approximation would be good to know)

EDIT: I guess my question might become irrelevent because of how much it can be compressed with the meta-tiles and meta-meta-tile technique. I think the answer is simply pretty big"

If it’s all in progmem without compression so it’s one tile per byte, then it depends on how much code you end up with, because code eats into progmem too.

16x8 = 128, there’s 28672 bytes of progmem in total.
I can’t remember how much you’re using at the moment, but it’s probably something like 30-50%, so you could probably fit a few hundred of those in.

In that case you can fit two tiles per byte, which will half your memory usage (i.e. 16x8 will fit in 64 bytes).

enum class TileType : uint8_t
{
	None,
	Grass,
	Path,
	Wall,
	// Etc
};

struct TilePair
{
private:
	uint8_t value;
	
public:
	TilePair(TileType high, TileType low)
		: value(static_cast<uint8_t>(high) << 4 | static_cast<uint8_t>(low))
	{
	}
	
	TileType getHigh() const
	{
		return static_cast<TileType>((this->value >> 4) & 0x0F);
	}
	
	TileType getLow() const
	{
		return static_cast<TileType>((this->value >> 0) & 0x0F);
	}
};

True, though meta tiles can be quite fiddly.

That’s the third time I’ve seen someone post that same video. :P

Here’s something more impressive: all the original zelda dungeons are actually just a second overworld - the pieces fit together like a jigsaw puzzle:

2 Likes

Before I brick my Arduboy, could you make sure with me I’m not gonna screw it up? (meaning I don’t want to brick my Arduboy). I’m 99% sure I have to use the PROGMEM keyword otherwise it loads in the 2500 bytes or so instead of the big old 28000 something bytes of storage

Here’s my code:

World.h

#pragma once

constexpr uint8_t TOTAL_WORLD_WIDTH = 48;
constexpr uint8_t TOTAL_WORLD_HEIGHT = 32;
extern uint8_t world[TOTAL_WORLD_WIDTH*TOTAL_WORLD_HEIGHT];

constexpr uint8_t WORLD_SECTION_WIDTH = 16;
constexpr uint8_t WORLD_SECTION_HEIGHT = 8;
extern uint8_t loaded_world_section[WORLD_SECTION_WIDTH*WORLD_SECTION_HEIGHT];

int8_t x_on_grid(int16_t x);
int8_t y_on_grid(int16_t y);
uint8_t get_tile(uint8_t xIndex, uint8_t yIndex);
bool is_tile_solid(int16_t x, int16_t y);
void draw_world();
bool detect_wall(int8_t x, int8_t y);

World.cpp

#include <Arduboy2.h>
#include "World.h"
#include "Images.h"

extern Arduboy2 arduboy;

constexpr uint8_t TILE_WIDTH = 8;

uint8_t world[TOTAL_WORLD_WIDTH*TOTAL_WORLD_HEIGHT] {
    0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,
    1,12,13,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,12,13,0,0,0,0,0,1,1,1,1,0,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,
    1,14,15,0,0,0,1,1,1,12,13,0,0,0,0,1,1,1,14,15,0,0,0,0,0,1,5,5,5,0,0,11,11,11,11,0,0,0,0,0,0,0,12,13,0,0,0,0,
    0,1,0,0,0,1,1,1,1,14,15,0,0,0,11,0,1,1,1,1,1,0,0,0,0,0,5,5,5,1,0,11,11,11,0,0,1,1,0,0,1,1,14,15,0,0,0,0,
    0,0,0,0,0,1,12,13,1,1,1,0,0,1,11,11,0,1,1,0,0,0,1,1,1,1,6,7,6,1,0,11,11,0,1,1,1,0,0,0,1,1,1,1,1,0,0,0,
    0,0,0,0,0,1,14,15,1,1,0,0,1,11,11,11,0,0,0,0,0,2,2,2,2,2,2,2,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,
    0,0,0,0,0,0,1,1,0,0,0,0,1,0,11,0,0,1,1,0,1,2,1,0,1,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,1,0,0,0,0,0,1,1,0,0,0,1,5,5,5,0,0,0,0,0,0,0,0,0,
    0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,2,0,0,1,1,0,12,13,1,1,1,0,0,1,5,5,5,5,1,0,0,0,0,0,0,0,0,
    0,0,12,13,0,1,1,1,1,12,13,1,1,1,1,0,0,5,5,5,0,2,1,12,13,4,4,4,15,0,11,11,0,0,1,5,5,5,6,1,0,0,0,0,1,1,0,0,
    0,1,14,15,1,0,0,1,1,14,15,1,1,0,0,0,0,5,5,5,5,2,1,14,15,4,4,4,1,0,11,11,11,0,0,6,7,6,1,0,0,0,1,1,1,1,0,0,
    0,1,0,0,0,12,13,0,1,1,1,0,0,0,0,0,1,6,5,5,5,2,1,1,0,6,7,6,1,1,1,11,0,0,0,0,2,1,1,1,0,0,1,1,1,1,0,0,
    0,0,1,1,1,14,15,1,1,1,1,0,0,1,1,1,1,1,6,7,6,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,1,1,1,1,1,1,
    0,0,0,1,1,1,1,1,1,0,0,1,1,2,2,2,2,2,2,2,2,2,1,1,1,11,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,0,
    0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,1,11,11,11,11,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
    0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,2,1,0,11,11,1,1,1,1,1,1,0,1,12,13,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,1,0,0,0,0,1,1,1,1,0,0,0,14,15,1,1,1,0,0,0,0,0,0,0,0,0,
    0,1,1,0,1,0,0,12,13,1,1,1,0,0,0,12,13,0,0,0,1,2,1,4,4,4,0,0,0,0,0,0,0,0,1,1,1,0,12,13,1,0,0,0,0,0,0,0,
    0,12,13,1,1,0,0,14,15,1,1,1,1,0,1,14,15,0,0,0,1,2,1,4,4,4,0,5,5,5,1,0,0,1,0,0,0,1,14,15,1,0,0,0,1,0,0,0,
    0,14,15,1,1,0,1,1,1,1,12,13,1,0,1,1,1,0,0,0,1,2,0,4,4,4,1,5,5,5,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,
    1,0,1,1,1,0,0,0,1,1,14,15,0,1,1,1,1,12,13,0,1,2,0,6,7,6,1,5,5,5,1,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,
    0,1,0,0,12,13,0,0,1,1,1,1,0,1,1,1,1,14,15,0,1,2,0,0,2,1,1,6,7,6,1,0,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,
    0,0,0,0,14,15,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,2,2,2,2,2,2,2,2,2,2,1,0,1,0,0,1,0,1,1,1,0,0,1,1,1,1,1,
    0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,
    0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,
    0,0,0,12,13,0,0,0,1,1,12,13,1,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,12,13,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
    0,0,1,14,15,0,0,12,13,1,14,15,0,0,0,0,0,12,13,0,0,1,0,0,1,1,1,1,14,15,1,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,0,0,
    0,0,0,1,1,1,1,14,15,1,1,0,0,1,1,1,1,14,15,0,0,0,0,0,1,12,13,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,1,0,0,0,0,
    0,0,1,0,0,1,1,1,0,0,0,0,0,12,13,1,1,1,0,0,0,0,0,0,1,14,15,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
    0,1,12,13,1,1,0,0,0,0,0,0,0,14,15,1,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,
    0,0,14,15,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};

//9928 - 9796 = 132
uint8_t loaded_world_section[WORLD_SECTION_WIDTH*WORLD_SECTION_HEIGHT] = {
    1,1,0,0,0,2,0,0,0,0,0,12,13,1,1,1,
    0,5,5,5,0,2,1,12,13,4,4,4,15,0,11,1,
    0,5,5,5,5,2,1,14,15,4,4,4,1,0,11,11,
    1,6,5,5,5,2,1,1,0,6,7,6,1,1,1,0,
    1,1,6,7,6,2,2,2,2,2,2,2,2,2,2,2,
    2,2,2,2,2,2,1,1,1,11,0,1,1,1,0,0,
    1,1,1,1,1,1,0,11,11,11,11,0,0,0,0,1,
    1,1,1,0,0,0,0,0,11,11,1,1,1,1,1,1,
};


int8_t x_on_grid(int16_t x) {
    x = (x / TILE_WIDTH);
    x = max(x, 0);
    x = min(x, WORLD_SECTION_WIDTH-1);
    
    return x;
}

int8_t y_on_grid(int16_t y) {
    y = (y / TILE_WIDTH);
    y = max(y, 0);
    y = min(y, WORLD_SECTION_HEIGHT-1);
    
    return y;
}

uint8_t get_tile(uint8_t xIndex, uint8_t yIndex) {
    return loaded_world_section[WORLD_SECTION_WIDTH * yIndex + xIndex];  
}

bool is_tile_solid(int16_t x, int16_t y) {
    return (4 <= get_tile(x, y));
}

bool detect_wall(int8_t x, int8_t y) {
    int8_t x1 = x_on_grid(x);
    int8_t x2 = x_on_grid(x+TILE_WIDTH-1);
    int8_t y1 = y_on_grid(y);
    int8_t y2 = y_on_grid(y+TILE_WIDTH-1);
    
    return ((is_tile_solid(x1, y1) || is_tile_solid(x2, y1) || is_tile_solid(x2, y2) || is_tile_solid(x1, y2)));
}

void draw_world() {
    for(uint8_t x = 0; x < WORLD_SECTION_WIDTH; x++) {
        for(uint8_t y = 0; y < WORLD_SECTION_HEIGHT; y++) {
            uint8_t frame = get_tile(x, y);
            //Sprites::drawOverwrite(x*8, y*8, spr_world, frame); 
            Sprites::drawSelfMasked(x*8, y*8, spr_world, frame);
        }
    }
}

If you overload the RAM at compile time, I think the IDE will refuse to upload.
(Or at least I sincerely hope it would.)

But yes, to put things in progmem you must use the PROGMEM macro.

E.g.

uint8_t world[TOTAL_WORLD_WIDTH*TOTAL_WORLD_HEIGHT] PROGMEM =
{
    0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,
    1,12,13,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,12,13,0,0,0,0,0,1,1,1,1,0,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,
    1,14,15,0,0,0,1,1,1,12,13,0,0,0,0,1,1,1,14,15,0,0,0,0,0,1,5,5,5,0,0,11,11,11,11,0,0,0,0,0,0,0,12,13,0,0,0,0,
    0,1,0,0,0,1,1,1,1,14,15,0,0,0,11,0,1,1,1,1,1,0,0,0,0,0,5,5,5,1,0,11,11,11,0,0,1,1,0,0,1,1,14,15,0,0,0,0,
    0,0,0,0,0,1,12,13,1,1,1,0,0,1,11,11,0,1,1,0,0,0,1,1,1,1,6,7,6,1,0,11,11,0,1,1,1,0,0,0,1,1,1,1,1,0,0,0,
    0,0,0,0,0,1,14,15,1,1,0,0,1,11,11,11,0,0,0,0,0,2,2,2,2,2,2,2,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,
    0,0,0,0,0,0,1,1,0,0,0,0,1,0,11,0,0,1,1,0,1,2,1,0,1,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,1,0,0,0,0,0,1,1,0,0,0,1,5,5,5,0,0,0,0,0,0,0,0,0,
    0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,2,0,0,1,1,0,12,13,1,1,1,0,0,1,5,5,5,5,1,0,0,0,0,0,0,0,0,
    0,0,12,13,0,1,1,1,1,12,13,1,1,1,1,0,0,5,5,5,0,2,1,12,13,4,4,4,15,0,11,11,0,0,1,5,5,5,6,1,0,0,0,0,1,1,0,0,
    0,1,14,15,1,0,0,1,1,14,15,1,1,0,0,0,0,5,5,5,5,2,1,14,15,4,4,4,1,0,11,11,11,0,0,6,7,6,1,0,0,0,1,1,1,1,0,0,
    0,1,0,0,0,12,13,0,1,1,1,0,0,0,0,0,1,6,5,5,5,2,1,1,0,6,7,6,1,1,1,11,0,0,0,0,2,1,1,1,0,0,1,1,1,1,0,0,
    0,0,1,1,1,14,15,1,1,1,1,0,0,1,1,1,1,1,6,7,6,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,1,1,1,1,1,1,
    0,0,0,1,1,1,1,1,1,0,0,1,1,2,2,2,2,2,2,2,2,2,1,1,1,11,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,0,
    0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,1,11,11,11,11,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
    0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,2,1,0,11,11,1,1,1,1,1,1,0,1,12,13,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,1,0,0,0,0,1,1,1,1,0,0,0,14,15,1,1,1,0,0,0,0,0,0,0,0,0,
    0,1,1,0,1,0,0,12,13,1,1,1,0,0,0,12,13,0,0,0,1,2,1,4,4,4,0,0,0,0,0,0,0,0,1,1,1,0,12,13,1,0,0,0,0,0,0,0,
    0,12,13,1,1,0,0,14,15,1,1,1,1,0,1,14,15,0,0,0,1,2,1,4,4,4,0,5,5,5,1,0,0,1,0,0,0,1,14,15,1,0,0,0,1,0,0,0,
    0,14,15,1,1,0,1,1,1,1,12,13,1,0,1,1,1,0,0,0,1,2,0,4,4,4,1,5,5,5,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,
    1,0,1,1,1,0,0,0,1,1,14,15,0,1,1,1,1,12,13,0,1,2,0,6,7,6,1,5,5,5,1,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,
    0,1,0,0,12,13,0,0,1,1,1,1,0,1,1,1,1,14,15,0,1,2,0,0,2,1,1,6,7,6,1,0,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,
    0,0,0,0,14,15,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,2,2,2,2,2,2,2,2,2,2,1,0,1,0,0,1,0,1,1,1,0,0,1,1,1,1,1,
    0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,
    0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,
    0,0,0,12,13,0,0,0,1,1,12,13,1,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,12,13,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
    0,0,1,14,15,0,0,12,13,1,14,15,0,0,0,0,0,12,13,0,0,1,0,0,1,1,1,1,14,15,1,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,0,0,
    0,0,0,1,1,1,1,14,15,1,1,0,0,1,1,1,1,14,15,0,0,0,0,0,1,12,13,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,1,0,0,0,0,
    0,0,1,0,0,1,1,1,0,0,0,0,0,12,13,1,1,1,0,0,0,0,0,0,1,14,15,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
    0,1,12,13,1,1,0,0,0,0,0,0,0,14,15,1,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,
    0,0,14,15,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};

And then to read from progmem you must pass an address/pointer to pgm_read_byte (to read a uint8_t) or pgm_read_word (to read a uint16_t).

In case you don’t know what that looks like:

return pgm_read_byte(&world[index]);

(Related thread here, official documentation here, relevant Arduino topic here.)

1 Like

Thank you, two quick questions

  1. Do I need the PROGMEM keyword and the CONST keyword in both the header file and the cpp file?
  2. It seems that the world doesn’t use any memory… when I compile it says this:

Sketch uses 9928 bytes (34%) of program storage space. Maximum is 28672 bytes.

Shouldn’t it be using more? it says the exact same thing if I comment it out in both the header and the .cpp file

That’s actually a simplification, there’s more to it than that. But that is the overall result in the end.

It’s what I did for Ardynia

I actually regretted doing it and won’t do it again for Ardynia 2. Having to fit your dungeons into a rectangle really limits how interesting they can be.

2 Likes

just a heads up, you will do this eventually. It’s just part of programming for this platform, you can’t be perfect 100% of the time :slight_smile: Learning how to reset it using the reset button is well worth doing.

1 Like

I thought bricking it meant that there was nothing to do to fix it, I didn’t know that the reset button worked for that. That’s good news!

I suppose it’s good to know this before I make my game, thanks for the heads up

Yeah you can pretty much always recover. It is possible to truly brick it, but that involves using custom bootloaders and other advanced stuff that most people don’t get involved with.

But with that said, not laying them out in a rectangle and still being efficient with progmem is quite the challenge.

1 Like

I’m looking into ways to store my world in PROGMEM properly and read from it, and this library seems promising…
http://arduiniana.org/libraries/flash/

That library looks fine if you want to use it. But honestly reading and writing from progmem isn’t hard. pgm_read_byte and pgm_read_word are about all you need, maybe pgm_read_ptr sometimes. They are easy to use.

I just figured it out literally 5 seconds ago! I’m feeling pretty good. You’re right, no need for the library
And I think I might be able to just put the whole overworld in there without needing to load it in RAM. At least it works for a 16x8 tiles level

Here’s my code to read it:

uint8_t get_tile_progmem(uint8_t xIndex, uint8_t yIndex) {
    return pgm_read_byte(&(loaded_world_section[WORLD_SECTION_WIDTH * yIndex + xIndex]));
}

Something I’m wondering about, how do I make sure not to store PROGMEM stuff over save data or things I don’t want to overwrite?

progmem and eeprom are separate. The compiler will ensure they never cross paths. No need to worry.

1 Like

Okay so I have a 48x32 world right now and a ‘view’ or ‘camera’ that follows the player, for now I made it move at intervals of a screen (like Ardynia)

Collision and sprite drawing works, and I do it straight from the program data (PROGMEM), I had planned on loading the data on a 16x8 area, and I might still do it if I find it necessary later, but for now the colision detection and the tile rendering is straight from PROGMEM.

Now would be a good time to upload it on your Arduboys and check out what’s been done so far, because it’s already pretty cool https://github.com/TheProgrammer163/arduboy

1 Like

Does look pretty cool.

I would spend some time and try to make the screen scroll with the player rather than update a ‘page’ at a time. This might make the game flow a little better.

2 Likes

Thank you!

Yes I’ve planned to try it out, it shouldn’t be too difficult to set up. A big advantage of making everything 8x8 is that you can see further up and further down (I’m making a hack-and-slash so it’s important to see the enemies before they reach you)

I’ll be going to bed, have a good night and good night everyone

1 Like

You can just put it all in the header file, you don’t need to keep separating things into a .h and a .cpp unless you want the separation for some reason.

It won’t use memory unless you’re actually referencing it somewhere.

In C++ you don’t pay for what you don’t use - any functions/arrays you don’t use don’t end up in the final .hex.

Like what exactly?

In the original I’m pretty sure that’s exactly how it worked,
they just shoved the dungeons into a different RAM bank from the overworld and treated it the same as the overworld,
thus bank-switching only happened when entering and exiting dungeons.

So far nobody has 100% bricked their Arduboy.
Worst case scenario you overwrite the bootloader and have to reburn it using either another Arduino board or (from what I’ve heard the easier option) a specialised ISP programmer.

Overwriting the bootloader during normal use shouldn’t be possible, but the factor has been known to forget to set the protection fuses from time to time.

Reminds me of that time I wrote a ‘progmem pointer’ class.
You could use it just like a normal pointer, but it read from progmem and you obviously couldn’t write to it.
Such is the power of C++.

I thought you were going to be using loaded_world_section as a buffer in RAM to read world data into?

This isn’t an issue, progmem, RAM and EEPROM all have different address spaces.
If they didn’t, you wouldn’t need special functions to read from them.

For example, on the ARM Cortex chip you don’t need any special instructions for accessing the read-only memory area,
the ROM area is in the same address space as the RAM area,
so it can be accessed with a normal pointer dereference.

1 Like

I thought so too and I still might, but for now it works well straight from PROGMEM.

When I add the interior of houses and caves then it might become necessary, or maybe I can put everything in the same array. For caverns/dungeons. I’m also hesitant about wether or not the view should be as it is now (like Ardynia or the first Zelda on the NES) or make it follow with the player always in the center

I’ll also have to figure out a way to to know which door brings to which house. Depending on how all of this gets solved I might goback to loading a section of the world (I kept all my functions so it’s easy to revert back)