[Concept and WIP] Undertale Pocket Battles

Hey… I’ve been having some trouble with animating sprites. I have a spritesheet, which is right here:
New%20Piskel%20copy%205
It’s already been turned into chars, but I have no idea how to make the character animate. When I try to display both sprites, they are the same. I have looked at a few other questions about animation, but they don’t make much sense to me.

This is my github repository, I couldn’t format the code here.

thanks in advance.

To animate the Sprite you’ll need to write a function to alternate which Sprite tile is being drawn. There’s a lot of different ways to go about that.

I looked at you code, and it doesn’t appear that you converted your Sprite sheet correctly. I’m assuming you just dumped that image you posted into craits converter?

What I believe is happening is you are drawing that whole image to the screen, then over drawing the right half with the left on the second draw call.

There is a number of ways to go about this, here are two examples.

Assuming you used a tool like team args Sprite sheet converter

  1. The Sprite tiles need to be oriented vertically, not horizontally like you have.
    The height needs to be some multiple of 8pixels
    I.e. 8,16,24 ect tall per image.

You can picture this in your head as an array of your Sprite tiles even though it’s one single char array you get out of the converter.

Afterwards you can use the methods specified on that manual page to draw the sprites.
drawSelfMasked(xPostion, yPosition, myTileSheet, tileNumber); . Where myTileSheet would be arudman and tile number would alternate between 0&1 for the first and second tile.

Another option would be to convert each Sprite tile separately, splitting the file into 2. So you would have say arduman1[], arduman2[].
Then alternate drawbitmap calls using those two bitmaps through an if statement or some other manner.


Moderator Note:
Links to Team ARG’s website have been removed due to malicious new owners.

The TeamARG spritesheet website doesn’t work for me. I drag the image over it, but nothing happens. That’s why I used craits.

Also, I’m sorry if i’m wrong, but when you say “oriented vertically”, do you mean the image has to be flipped 90 degrees or something?

You Sprite sheet is like this A,B. It has 2 ‘tiles’
It needs to be like
A
B

The arduman will be standing vertical one on top the other.

If you want to use drawbitmap and craits website I would break the image into two individual ones.

Oh, okay. I’ve decided to just break the image in half and go from there. Thank you for the help! I appreciate it.

Did you see this comment?


Not necessarily.
If masking is used (through Sprites::drawExternalMask, Sprites::drawPlusMask or Sprites::drawSelfMasked) then the excess won’t matter.

Thank you. I’ve got it moving now, I used the separate sprites and made chars out of them. Then i put them into an if statement that cycles through them. Only problem i’m having is that the animation is too fast. I tried everyXFrames but the image keeps blinking instead of staying there. I can’t limit the framerate, because there’s a little character that has to move as well. What do I do here? I’ve updated my github page with the new code.

I’m guessing you’re putting the drawing code inside the if(everyXFrames(fps)) block?
You have to draw the sprite outside of that so you draw every frame and just have a variable holding the frame number and only change that variable everyXFrames.

uint8_t spriteFrame = 0;
constexpr uint8_t firstSpriteFrame = 0;
constexpr uint8_t lastSpriteFrame = 1;
constexpr uint8_t updatesPerFrame = 15;

void updateSprite()
{
	if(arduboy.everyXFrames(updatesPerFrame))
	{
		if(spriteFrame < lastSpriteFrame)
			++spriteFrame;
		else
			spriteFrame = firstSpriteFrame;
	}
}

void drawSprite()
{
	Sprites::drawOverwrite(x, y, spriteSheet, spriteFrame);
}

Okay. I used the code that you gave me and it works! Except my sprite looks weird because a bit of the image from the frame before it appears in the bottom of the sprite. I got the dimensions correct, but I can’t seem to get it to display the sprite correctly.

If you update your code on GitHub then I’ll take a look,
but I might not get chance until tomorrow.

Are you definitely clearing the screen?
At the moment I notice you’re putting arduboy.clear() and arduboy.display() in every single state function.
Usually it makes more sense to just have them once in the loop function.
E.g.

void loop()
{
	// put your main code here, to run repeatedly:
	if(!arduboy.nextFrame())
		return;

	arduboy.pollButtons()
	arduboy.nextFrame();

	switch(gamestate)
	{
		case 0:
			//title screen start
			title();
			break;
		case 1:
			//begin game
			game();
			break;
	}

	arduboy.display();
}

Also I just noticed my code should have been using arduboy.everyXFrames rather than everyXFrames.
(That’s what I get for rushing code so late at night.)


Bonus tip, game state works better as an enum class:

enum class GameState
{
	TitleScreen,
	Gameplay,
};

GameState gameState;

Used in loop as:

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

	arduboy.pollButtons()
	arduboy.nextFrame();

	switch(gameState)
	{
		case GameState::TitleScreen:
			updateTitlescreen();
			break;
		case GameState::Gameplay:
			updateGame();
			break;
	}

	arduboy.display();
}

And the state is changed like:

gameState = GameState::TitleScreen;

The primary advantage of this is that your code becomes more self-descriptive,
but the other key advantage is that you can’t accidentally do this:

// Hard to find bug if using `int`
// But an easy to spot compilation error with enum class
gameState = 5;

One last thing, calling arduboy.clear() and arduboy.setFrameRate(60) in setup is redundant,
arduboy.begin() already calls both of those.

hi the sprite of arduman is toooooo fast you can fix it?

hello! thank you for trying out my game. I haven’t really done much with it since last month because i’m lazy, but i’m going to keep going now. Anyway, I updated the code on github and it should be able to slow down. It has a sprite glitch, which pharap was very helpful with. I’ll try to fix that soon

2 Likes

thanks you are a REALLY GOOD PERSON 0.0

1 Like

Remind me what the glitch is and I’ll see if I can help later.
(Unless you manage to fix it yourself before I get back.)

By the way, you don’t have to comment out your old code, you can remove it.
It won’t be lost because GitHub has a sort of ‘time travel’ feature that allows you to look back at your code as it was during previous commits.
Each commit is essentially a snapshot of the code’s history.

That’s the bit i’m talking about. Also yes I am responding 2 months after you did, sorry. i’m not very good at keeping focused on things, especially with school and everything.

I got the teamARG sprite converter working (i didn’t read the naming instructions clearly, arghh) but now the image corruption is worse, and it seems to be printing a small segment of my title screen??? I have no idea what is happening here.

Do you have the unconverted sprite(s)?

It’s hard to find the problem without knowing what the sprites are supposed to look like.

New%20Piskel%20copy%205

It looks like this, but the sprites are arranged vertically instead of horizontally. I’m not at home right now, but ill try to get a better image as well as an example of the corruption as soon as possible. Thank you for helping me!

1 Like

I found the problem and it’s exactly what I expected it would be.
For some reason your images weren’t formatted correctly.

I split the frames up and ran them through my personal image converter and then put the output in your code and it fixed the problem.

So here’s a version of the program that works:

#include <Arduboy2.h>
#include <ArduboyPlaytune.h>
Arduboy2 arduboy;
//variables declared
int gamestate = 0;
int health = 20;
int frame = 0;
const int spriteFrame1 = 0;
const int spriteFrame2 = 1;
const int frameUpdates = 30;
int heartX = 32;
int heartY = 32;

constexpr uint8_t ardumanWidth = 24;
constexpr uint8_t ardumanHeight = 28;

uint8_t const arduman[] PROGMEM =
{
	// Dimensions
	ardumanWidth, ardumanHeight,

	// Frame 0 - Frame0
	0x00, 0x00, 0x00, 0xFF, 0xFD, 0x03, 0x33, 0x33, 0x03, 0x03, 0x23, 0x43, 0x43, 0x23, 0x03, 0x03, 0x33, 0x33, 0x03, 0xFD, 0xFF, 0x00, 0x00, 0x00,
	0x1C, 0x02, 0x01, 0xFF, 0xFF, 0xFC, 0x3C, 0x3C, 0x38, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, 0xFF, 0xFF, 0x01, 0x02, 0x1C,
	0x00, 0x00, 0x00, 0xFF, 0x78, 0xF8, 0xE5, 0xE2, 0xE5, 0xF8, 0xF8, 0xFF, 0xFF, 0xE3, 0xE3, 0xE3, 0xFF, 0xF8, 0xF8, 0x78, 0xFF, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x09, 0x09, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x09, 0x09, 0x00, 0x00, 0x00,

	// Frame 1 - Frame1
	0x00, 0x00, 0x00, 0xFE, 0xFA, 0x06, 0x66, 0x66, 0x06, 0x06, 0x46, 0x86, 0x86, 0x46, 0x06, 0x06, 0x66, 0x66, 0x06, 0xFA, 0xFE, 0x00, 0x00, 0x00,
	0x70, 0x08, 0x04, 0xFF, 0xFF, 0xF8, 0x78, 0x78, 0x70, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, 0xFF, 0xFF, 0x04, 0x08, 0x70,
	0x00, 0x00, 0x00, 0xFF, 0xF1, 0xF1, 0xCA, 0xC4, 0xCA, 0xF1, 0xF1, 0xFF, 0xFF, 0xC7, 0xC7, 0xC7, 0xFF, 0xF1, 0xF1, 0xF1, 0xFF, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x0B, 0x0A, 0x0F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0F, 0x0A, 0x0B, 0x00, 0x00, 0x00,
};



//sprites declared
const unsigned char titleScreen[] PROGMEM = {
  0x00, 0x00, 0xf0, 0xf8, 0xfc, 0x00, 0x80, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x7c, 0xf8, 0xf0, 0xf8, 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x1c, 0xbc, 0xfc, 0xf8, 0xf8, 0x00, 0x00, 0xf8, 0xfc, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0xfc, 0xfc, 0xe4, 0xcc, 0xe4, 0xfc, 0x7c, 0x7c, 0x00, 0x00, 0x18, 0x18, 0x1c, 0xfc, 0xfc, 0xfc, 0x1c, 0x1c, 0x1c, 0x00, 0x00, 0xe0, 0xf8, 0x3c, 0x3c, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xf0, 0xf8, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xfc, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xfc, 0xfc, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x87, 0x87, 0x87, 0x87, 0x7, 0x7, 0x7, 0x00, 0x80, 0x87, 0x87, 0x80, 0x00, 0x1, 0x3, 0x7, 0x80, 0x80, 0x87, 0x87, 0x7, 0x7, 0x87, 0x87, 0x00, 0x00, 0x80, 0x83, 0x7, 0x7, 0x87, 0x87, 0x87, 0x87, 0x80, 0x80, 0x7, 0x7, 0x80, 0x80, 0x81, 0x87, 0x87, 0x86, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7, 0x87, 0x87, 0x80, 0x80, 0x80, 0x00, 0x00, 0x7, 0x7, 0x81, 0x81, 0x87, 0x7, 0x7, 0x00, 0x80, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x7, 0x2, 0x80, 0x80, 0x83, 0x87, 0x87, 0x87, 0x87, 0x7, 0x7, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x3, 0x7, 0x3, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0xd, 0xd, 0xf, 0x7, 0x00, 0x00, 0x3f, 0x7f, 0x61, 0x61, 0x7f, 0x3f, 0x00, 0x00, 0x3f, 0x7f, 0x61, 0x61, 0x61, 0x00, 0x00, 0x7f, 0x7f, 0x1e, 0x3f, 0x73, 0x61, 0x00, 0x00, 0x7f, 0x7f, 0x6d, 0x6d, 0x6d, 0x6d, 0x00, 0x00, 0x1, 0x1, 0x7f, 0x7f, 0x1, 0x1, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x4d, 0x4d, 0x7f, 0x33, 0x00, 0x00, 0x7e, 0x7f, 0x13, 0x7f, 0x7e, 0x00, 0x00, 0x1, 0x1, 0x7f, 0x7f, 0x1, 0x1, 0x1, 0x00, 0x00, 0x1, 0x1, 0x7f, 0x7f, 0x1, 0x1, 0x1, 0x00, 0x00, 0x7f, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x7f, 0x7f, 0x6d, 0x6d, 0x6d, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  
};


const unsigned char heart[] PROGMEM = {
  0x6, 0xf, 0x1e, 0xf, 0x6, 
};

void setup() {
  // put your setup code here, to run once:
  arduboy.begin();
  arduboy.clear();
  arduboy.setFrameRate(60);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(!arduboy.nextFrame()) {
    return;
  }
  switch(gamestate) {
    case 0:
      //title screen start
      title();
      break;
    case 1:
      //begin game
      game();
      break;
  }
}

void title() {
  arduboy.clear();
  
  arduboy.drawBitmap(0, 0, titleScreen, 128, 32, WHITE);
  arduboy.setCursor(2, 40);
  arduboy.print("PRESS A TO BEGIN");
  arduboy.display();

  if (arduboy.pressed(A_BUTTON)) {
    gamestate++;
  }
}

void game() {
  arduboy.clear();
  updateSprite();
  drawSprite();
  arduboy.print(frame);
  arduboy.drawRect(0, 8, 64, 40, WHITE);
  arduboy.drawBitmap(heartX, heartY, heart, 5, 5, WHITE);
  arduboy.display();

  if (arduboy.pressed(B_BUTTON)) {
    gamestate = 0;
  }
  
  if (arduboy.pressed(RIGHT_BUTTON) && heartX < 58) {
     heartX = heartX + 2;
  }
    
  if (arduboy.pressed(LEFT_BUTTON) && heartX > 2) {
    heartX = heartX - 2;
  }

  if (arduboy.pressed(UP_BUTTON) && heartY > 10) {
    heartY = heartY - 2;
  }

  if (arduboy.pressed(DOWN_BUTTON) && heartY < 42) {
    heartY = heartY + 2;
  }
}

void updateSprite() {
  if (arduboy.everyXFrames(frameUpdates)) {
    
    if (frame < spriteFrame2) {
      frame++;
    } else {
      frame = spriteFrame1;
    }

  }
}

void drawSprite() {
  Sprites::drawOverwrite(90, 10, arduman, frame);
}

No problem.

1 Like

New stuff added! There’s a new title screen, a health meter, and a bouncing test bubble that deals damage.

New%20Piskel%20copy%209

IMG_5080

Thank you pharap for helping with a lot of problems!

2 Likes