Make Your Own Arduboy Game: Part 9 - Mapping DinoSmasher

Tell me please, when i try to replace the black square with a sprite i have nothing showing on the map. But that nothing can move around the map. So, how to make the image visible?
my try:

void drawplayer() {
  const unsigned char PROGMEM noname[] =
  {
    // width, height,
    16, 16,
    // TILE 00
    0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xb9, 0xb1, 0xb1, 0xb9, 0x83, 0x1f, 0xff, 0xff, 0xff, 0xff, 
    0xff, 0x07, 0x73, 0x7b, 0x7b, 0x78, 0x3f, 0x9f, 0xdf, 0x9f, 0xbf, 0x38, 0x79, 0x39, 0xb3, 0x87, 
  };
}

@NoobGeek,
Welcome to the Arduboy Forum!

First:
When you post code in this forum, please enclose it in markdown code tags:

Start with a line containing three backticks followed by cpp .
Insert your code starting on the following line.
On the line following you code, put another three backticks.
The backtick character is commonly on the key below the Esc key at the top left of a U.S. keyboard. If you can’t find it on your keyboard, you can copy and paste from the tags here:

```cpp
The first line of your code
More code
The last line of your code
```

I’ve added the tags to your post above but please do it yourself in the future.


You’ll have to be more specific and/or provide more code showing how you’re trying to display and move your sprite. I wrote a simple sketch that draws and allows you to move your sprite using the D-pad. It may provide information that helps you.

#include <Arduboy2.h>

Arduboy2 arduboy;

const unsigned char PROGMEM noname[] =
{
  // width, height,
  16, 16,
  // TILE 00
  0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xb9, 0xb1, 0xb1, 0xb9, 0x83, 0x1f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x07, 0x73, 0x7b, 0x7b, 0x78, 0x3f, 0x9f, 0xdf, 0x9f, 0xbf, 0x38, 0x79, 0x39, 0xb3, 0x87,
};

int16_t xPos = 0;
int16_t yPos = 0;

void setup() {
  arduboy.begin();
  arduboy.setFrameRate(45);
}

void loop() {
  if(!arduboy.nextFrame()) {
    return;
  }

  arduboy.pollButtons();
  arduboy.clear();

  if (arduboy.justPressed(UP_BUTTON)) {
    --yPos;
  }
  if (arduboy.justPressed(DOWN_BUTTON)) {
    ++yPos;
  }
  if (arduboy.justPressed(LEFT_BUTTON)) {
    --xPos;
  }
  if (arduboy.justPressed(RIGHT_BUTTON)) {
    ++xPos;
  }

  Sprites::drawOverwrite(xPos, yPos, noname, 0);

  arduboy.display();
}

NoobGeek1.hex (19.5 KB)

1 Like

I had a closer look at @crait’s “completed code” and now know what you’re trying to do.

The spite that you’ve created for the player is just data. You need to draw it with one of the Sprites functions. Since the bitmap array you’ve provided doesn’t include a mask, the drawOverwrite() function is likely the best to use.

You need to put your noname array in the sketch as “global” data. For my testing, I put it before the tiles array

[...]
int mapx = 0;
int mapy = 0;

const unsigned char PROGMEM noname[] = {
  // width, height,
  16, 16,
  // TILE 00
  0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xb9, 0xb1, 0xb1, 0xb9, 0x83, 0x1f, 0xff, 0xff, 0xff, 0xff, 
  0xff, 0x07, 0x73, 0x7b, 0x7b, 0x78, 0x3f, 0x9f, 0xdf, 0x9f, 0xbf, 0x38, 0x79, 0x39, 0xb3, 0x87, 
};

const unsigned char tiles[] PROGMEM  = {
// width, height,
16, 16,
[...]

Then, you need to replace the fillRect() function in drawplayer() with the function to draw the sprite

#define PLAYER_SIZE      16
#define PLAYER_X_OFFSET    WIDTH / 2 - PLAYER_SIZE / 2
#define PLAYER_Y_OFFSET    HEIGHT / 2 - PLAYER_SIZE / 2
void drawplayer() {
//  arduboy.fillRect(PLAYER_X_OFFSET, PLAYER_Y_OFFSET, PLAYER_SIZE, PLAYER_SIZE, BLACK);
  Sprites::drawOverwrite(PLAYER_X_OFFSET, PLAYER_Y_OFFSET, noname, 0);
}

You should now have your noname sprite drawn instead of a black rectangle.


Without masking, all of the pixels in your sprite are drawn over the background. So, the next thing you’ll probably want to do is create a sprite with a mask and use drawPlusMask() to draw it.

Edit:
Here’s the array (I renamed it to player) and drawplayer() functions with the outside of the image masked

// player in drawPlusMask() format (mask included in image)
const unsigned char PROGMEM player[] = {
  // width, height,
  16, 16,
  // FRAME 00
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xb8, 0xfe, 0xb4, 0xfe,
  0xb4, 0xfe, 0xb8, 0xfe, 0x80, 0xfc, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xf8, 0x70, 0xfc, 0x78, 0xfc, 0x78, 0xfc, 0x78, 0xff, 0x3f, 0xff, 0x1f, 0x7f,
  0x1f, 0x3f, 0x1f, 0x7f, 0x3f, 0x7f, 0x38, 0xff, 0x78, 0xfe, 0x38, 0xfe, 0x30, 0x7c, 0x00, 0x78
};

void drawplayer() {
  Sprites::drawPlusMask(PLAYER_X_OFFSET, PLAYER_Y_OFFSET, player, 0);
}

NoobGeek2.hex (26.5 KB)

2 Likes

Thanks, it worked! I am surprised that you answered my question so quickly, and with a detailed answer. I am very grateful to you for that! From now on I will ask questions in the correct form. And I will try even more to delve into the software part before asking the community! Thanks again!

3 Likes

2 posts were split to a new topic: How do I create and control multiple objects (bullets)

There’s no part 10 is there :’( @crait

You can head over to @filmote’s more advanced tutorial:

Or you can:

  • Look up C++ tutorials online
  • Read through some of the other forum topics, particularly in the help sections since there’s lots of people asking common “How do I do X?” programming questions dotted around
  • Ask other people for help and advice
  • Just experiment
1 Like

There should be an Arduboy tutorial jam where everyone shares one simple thing they know how to do, or a broader project like these. Be a nice way to gather resources.

Im def gonna check out the c++ site, never seen that one before.

2 Likes

How would one even draw a rect for collisions over the specific tiles that contain a rock piece in this example? I can figure out the player, but honestly the whole drawing the player in world space and camera situation is too much for me.
Is there an easier way to draw a map for a top down style like this?
I’ve looked through…but most seem over my skill level at the moment.
Anyone have any resources on beginning C/C++ style game logic like this? Even Pico 8 abstracts some of the important bits :/.

You could technically draw a single image, but that would be a horrible waste of memory.

Either way you’d need a camera for the map to be scrollable.
No camera, no scrolling.

But really all a camera is (for a 2D game), is an amount by which the map should be offset.

Here’s a really simple diagram that might help with the idea.
(I don’t have a better one to hand.)

Coordinates

And here’s a very simple code example I wrote for someone else a few weeks/months ago:

It’s got lots of comments so hopefully you’ll be able to make some sense of it.

Drawing a rectangle and handling collisions are two separate matters that should be handled separately and actually don’t have to be correlated.

I don’t know what you mean by a ‘building piece’.
There are no buildings in the sample code, just grass, water, trees and stone.

If you’re just wanting basic tile collisions, have a look at some of the posts over in this recent topic:

(This is why I said have a read through some other forum topics as well. Sometimes you’ll find someone else has already asked a similar question.)

1 Like

I’ll check em out, thanks for being so helpful! Gonna try and unpack your example code, I’m obviously not up on everything. Know any good resources on just 2d c/c++ game logic?

1 Like

Not much in way of ‘the basics’, and not much that would be immediately applicable to Arduboy.

But honestly, if you just follow a tutorial that tells you how to make a game, you’ll probably only learn how to make that game, and without the skills and knowledge to modify it you’ll only be able to make that game.

To be able to make the games you want to make, you have to learn bits and pieces of how to do things and how to tie them together. Programming is very much about learning individual techniques and combining them to produce something new.

(It’s a bit like cooking - you learn what the ingredients do and then you put them together to make something, and you tweak the recipe as you go, discovering what works and what doesn’t. The recipe is the source code, the game is the food.)

It’s also about looking at large problems and breaking them down into smaller problems that are easier to solve. (It’s also more about solving problems than it is about telling the computer what to do.)

You can ask if you don’t understand something and want more information.

(Though perhaps it would be best to start a new topic rather than continue to reply to this one.)

You want C++ resources, not C. C++ is not C, and C is not C++.

The two are related but distinct languages, and Arduboy programming uses C++.

1 Like

Working through this and got to a part that’s a little confusing. I understand what’s happening in thje code here but the instructions seem to be wrong and there’s an alternate version of the code that doesn’t work and I’m not sure why.

I’m in the last part of “3. Moving the map”

it tells us to change this code:

Sprites::drawOverwrite(x * TILE_SIZE, y * TILE_SIZE, tiles, world[y][x]);

in ‘void drawworld()’ with this code:

arduboy.drawBitmap(x * TILE_SIZE + mapx, y * TILE_SIZE + mapy, tiles[world[y][x]], TILE_SIZE, TILE_SIZE, WHITE);

That code creates something that slightly resembles what we’re looking for but not quite right. Instead of the sprite graphics we are meant to have moving around the screen, it’s a bunch of characters that just look like nonsense but slightly represent the layout. The following code works fine and is presented in the example code below the previous instruction but it’s not clear why the code is different and why the code in the instruction was wrong.

Sprites::drawOverwrite(x * TILE_SIZE + mapx, y * TILE_SIZE + mapy, tiles, world[y][x]);

Presumably the example originally used arduboy.drawBitmap and was then updated to use Sprites::drawOverwrite but not everything was updated properly.

arduboy.drawBitmap and Sprites::drawOverwrite expect their image data to be in different formats. The Sprites functions expect the image data to be prefixed with the width and height of the image (and optionally have multiple ‘frames’ of image data), whereas arduboy.drawBitmap expects the width and height to be passed along with the function call and the image passed to contain only the image data.

But even then, the way tiles is being used implies that for the drawBitmap version it would actually have to be an array of pointers to image data (if it were just a 2D array it would be used as &tiles[world[y][x]] instead).

Sprites::drawOverwrite on the other hand is relying on Sprites’ ability to handle image data with multiple ‘frames’. I.e. a single image array actually contains multiple individual images (called ‘frames’), implicitly numbered from 0 onwards, and the last parameter of drawOverwrite (and some of the other Sprites functions) is the index of the frame to use.


For the record, you can actually draw a Sprites-format image with arduboy.drawBitmap by doing:

arduboy.drawBitmap(x, y, &image[2], pgm_readbyte(&image[0]), pgm_readbyte(&image[1])]);

arduboy.drawBitmap behaves slightly differently to Sprites::drawOverwrite though. I think arduboy.drawBitmap behaves more like Sprites::drawSelfMasked, but I can’t remember quite how arduboy.drawBitmap works because I’ve never really used it.

For drawing a tile map it won’t make much difference anyway since the tile map is always drawn below everything else. The difference will only be important when drawing entities on top of the tile map, in which case you won’t want to use Sprites::drawOverwrite and something like Sprites::drawSelfMasked or Sprites::drawPlusMask would be more appropriate.

Either way, be sure to check the documentation:


When that happens it usually means the address/pointer you’ve given to a drawing/printing function doesn’t actually point to valid image/text data and instead points to some other area of memory which is then being misinterpreted.

Sometimes it happens because data stored in progmem is being used as if it were data stored in RAM (or vice versa), which can lead to the wrong data being read.

(That might not make sense to you until you’ve learnt more about pointers and how memory works.)

In this case it’s probably because tiles is stored in progmem and tiles[world[y][x]] attempts to read tiles as if it were in RAM, which leads to unrelated data being read.

2 Likes

So since I’ve got as far as exists for this tutorial I’m going to check out the next sideways scroller one.

Just wondering if anyone’s ever tried to finish this game into something final and if the results are out there somewhere to play what this might have become? Since I’m assuming it isn’t going to be finished after all this time.

As far as I’m aware there isn’t.

Perhaps that’s something you’d like to attempt?

(Though you may need permission to use @crait’s graphics assuming he’s the artist.)

1 Like

Heh, maybe if I learn enough.

6 posts were split to a new topic: Overheating Display?

No. When the USB stack is removed, you need to manually enter bootloader mode. This is commonly done by holding the DOWN button during boot.

1 Like

Obviously, that’s not normal!