Need help testing code


(Thomas) #1

Since I don’t own an Arduboy as of yet I need some code testing however cant test it because I lack the hardware and I cant seem to find an emulator that runs on Windows if anyone could help that would be appreciated.


(Pharap) #2

It won’t work because you’re trying to draw a sprite from a buffer in RAM instead of from a predefined sprite in ROM (a.k.a. progmem).

Also the whole GETKEYS function is redundant because Arduboy2 has a function called justPressed that tells you if a button has been pressed since the last call to pollButtons (which you normally place near the start of your loop) and justReleased which tells you if a button has been released since the last call to pollButtons.

I don’t think GETKEYS does what you intend it to anyway.

It sets Pressed[i] after the key has been released and it doesn’t store Keys in a place where it will live past the end of the function, so Keys will be destroyed when the function ends and thus the else if block will never be executed anyway.

Sorry if that disappoints you.

On the bright side, most of your syntax looks correct.

I moved on to trying to compile it and apart from misspelling true as ‘True’ it compiled, so that’s not too bad considering.


(Thomas) #3

XD kinda expected it to be wrong to be honest with you being my first C++ program for the Arduboy.

Thank you for testing it regardless.


(Pharap) #4

Do you have any prior experience with other languages?
E.g. other Arduino stuff or maybe Python?


(Thomas) #5

I do have prior experience using Python aswell as pascal however I only know the basic syntax of C


(Thomas) #6

Just a Quick question why wouldn’t the buffer work? I thought you were just passing an array of bytes into the drawBitmap() function


(Pharap) #7

I thought so.
I would be incredibly surprised if someone who didn’t have prior programming experience was able to get functions right on their ‘first program’ :P.

Python was just a lucky guess because people are always recommending it to beginners.
I’m surprised at seeing Pascal mentioned though, it’s generally considered to be quite an old language and I haven’t encountered many people who know it.

Ah, that’s one of the nuances of working with an Arduino board.
Arduino has three different kinds of memory:

  • Flash memory, typically called ‘ROM’ or ‘progmem’, which stores the program code and any constant data. It can be read to using special macros like pgm_read_byte and pgm_read_word, but cannot be written to.

  • SRAM, typically called ‘work RAM’ or just ‘RAM’, which is where variables (and the stack and the heap if you know what they are) get stored.

  • EEPROM, which is a limited amount of persistant memory that can be used for saving things for later executions, like how you’d normally use files.

The drawBitmap function expects the bitmap pointer to point to a block of progmem and handles the reading for you, so reading your bitmap into a buffer isn’t necessary.

If you don’t already know, the Arduboy has 32KB of progmem (4KB is used by the bootloader), 2.5KB of SRAM, and 1KB of EEPROM. (When you come to using EEPROM, remember that the first 16 bytes are reserved for use by the Arduboy2 library.)


(Thomas) #8

Thanks for the help on this I do believe there is a sprite-sheet bitmap drawing function so ill take a look at that.

P.S. Pascal is quite an obsolete language but it is easier to understand than my spaghetti code in python.


(Thomas) #9

Implemented the justPressed() function as well as exchanging the draw bitmap function for drawSelfMasked() Should work now (Theoretically)


(Pharap) #10

It compiles but it doesn’t quite work yet.

There’s a few flaws (I’ve spoilerised them in case you’d rather have the challenge of figuring them out, I’ll un-spoiler later if you want to know anyway):

  1. The while loop is unnecessary because loop gets run infinitely (i.e. when it reaches the end, it runs again almost immediately). And frankly the while loop overcomplicates the code.
  1. You need a if(!ard.nextFrame()) return; near the top of loop to make sure you’re not trying to draw until it’s time to draw.
  1. You missed ard.diplay(); to actually display the screen.
  1. Choice isn’t persistant, it needs to be a global variable or a static variable.
  1. You don’t need an instance of Sprites, you can just call its functions like Sprites::drawSelfMasked.
  1. The ard.pressed(UP_BUTTON)||ard.pressed(DOWN_BUTTON) check is kind of redundant. It would theoretically speed the code up, but on the Arduboy you don’t have to worry about speed as much as you do about using up the progmem. I’ve heard many people say they’ve hit the memory bottleneck but few saying ‘my code isn’t fast enough’.
  1. There is no Sprites.h, Sprites is a part of Arduboy2.
  1. Sprite 18 looks broken, I’m guessing there is no sprite 18 and your logic is off by 1.

I’ve adapted it into a version that works, but I won’t show you if you’d rather work it out on your own.


(Thomas) #11

To my understanding this should work:
void MainMenu(){
byte Choice = 0;
while(!(ard.justPressed(A_BUTTON))) {
while(!ard.nextFrame()){}
ard.pollButtons();
if (ard.pressed(UP_BUTTON)||ard.pressed(DOWN_BUTTON)){
if (ard.justPressed(UP_BUTTON) && (Choice < 18)) {
Choice += 1;
}
if (ard.justPressed(DOWN_BUTTON) && (Choice > 0)) {
Choice -= 1;
}
ard.clear();
ard.print(Choice);
ard.display();
}
}
sprites.drawSelfMasked(20,20,BackgroundEnviroment,Choice);
ard.display();
}

There might be something wrong with how I defined the sprites

Choice doesn’t need to be persistent since the function is only displaying the sprite when the “A” button is pressed.

The reason why I have a loop in Main menu is because It is going to have different game options rather than just displaying a sprite.

Feel free to post your own code I don’t mind.

I have added the .png image to the Github repository for convinence.

EDIT:Re-compiled the images for the tile set putting it on Github
RE-EDIT:Tile 18 was reading out of program memory so it probably displayed as garbled junk


(Pharap) #12

It does work as intended, though it’s an odd way to do things.

You can do it as

Sprites sprites;
...
sprites.drawSelfMasked(...);

But you don’t have to make an object, you can just do:

Sprites::drawSelfMasked(...);

Odd choice, but ok.

Normally people tackle that sort of problem by using a state machine.
E.g.

enum class GameState { MainMenu, Settings, Game };

GameState gameState = GameState::MainMenu;

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

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

  switch(gameState)
  {
    case GameState::MainMenu: UpdateMainMenu(); break;
    case GameState::Settings: UpdateSettings(); break;
    case GameState::Game: UpdateGame(); break;
  }

  arduboy.display();
}

So the loop picks what to run based on the gameState variable and there’s no duplication of the pollButtons, clear or display logic.

Easy fix:

if (ard.justPressed(UP_BUTTON) && (Choice < 17)) {
  Choice += 1;
}

I rewrote it as this:

#include <Arduboy2.h>
#include "Bitmaps.h"

Arduboy2 ard;

byte Choice = 0;

void MainMenu()
{    
	if (ard.justPressed(UP_BUTTON) && (Choice < 18))
	{
		Choice += 1;
	}
	if (ard.justPressed(DOWN_BUTTON) && (Choice > 0))
	{
		Choice -= 1;
	} 
    
	ard.print(Choice);
    Sprites::drawSelfMasked(20,20,BackgroundEnviroment,Choice);
}

void setup()
{
  ard.begin();
  ard.clear();
}

void loop()
{
	if(!ard.nextFrame())
		return;
		
	ard.pollButtons();
	ard.clear();
	
	MainMenu();
	
	ard.display();
}

But it changes the behaviour to what I originally thought was the intended behaviour.


(Thomas) #13

Yea that other method does look a whole lot easier

LOGO:

Logo

SPRITESHEET:

BackgroundTiles 16x16


(Thomas) #14

Edit: I have edited the Github repository with the updated code


(Pharap) #15

I had looked at the code yesterday I just didn’t have time to check and comment (and then forgot to check - I’ve been working on various other things).

There’s five issues:

  • You’re mising a curly brace to end your second if in UpdateMainMenu.
  • You’re drawing the logo over the arrow.
  • The arrow isn’t really lasting long enough, but otherwise it’s functional.
  • The arrow doesn’t show up properly.
  • You’re still using the redundant sprites object to draw rather than just using Sprites. I.e. you can get rid of Sprites sprites; in Global.h and just use Sprites::drawSelfMasked instead of sprites.drawSelfMasked.

I’m not quite sure what the arrow’s supposed to look like so I’m not sure what the problem is with it.


(Scott) #16

Using either way generates the same code. There’s no guarantee that Sprites functions will remain static in the future, so it’s better to create a Sprites object.


(Thomas) #17

I Have fixed these problems now and have recompiled the github repository

EDIT:Arrow has been fixed (Timings were off)


(Pharap) #18

It wasn’t just the timings though, the arrow itself doesn’t draw because of the way the masks work.

Your arrow is black on white (with some padding), and its using itself as a mask. With a mask, white means ‘draw’ and black means ‘don’t draw’, so you’re not drawing the part you want to draw and you are drawing the part you don’t want to draw, if that makes sense.

Ideally you need to make a white arrow to use as a mask.

The timing is indeeed better than before though.
It could be simplified though, like this:

bool ShouldDrawArrow = false;

void UpdateMainMenu(){
  sprites.drawSelfMasked(1,1,Logo,0);
  if (ShouldDrawArrow){
   sprites.drawOverwrite(21,56,Arrow,0);
  }
  if (ard.justPressed(A_BUTTON)){
    gameState = GameState::Game;
  }
  if (ard.everyXFrames(30)) {
      ShouldDrawArrow = !ShouldDrawArrow;
  }
}

(Thomas) #19

Ah right Now fixed The problem didn’t know about the inverted sprites.

EDIT: First graphics test for the game is now available.


(Thomas) #20