Milona Games/Milona Software: "Project Scarlet" development

At the very least we need to know if you’re using Sprites or arduboy.drawBitmap for drawing.

Chances are you’ve got the width and height of an image wrong.
Depending on which function you’re using, the width and height will either be an argument to the function or part of the image data.

Without seeing the actual code that’s the best guess I can offer.

The other alternative is that you’ve passed an invalid image pointer to one of the drawing functions,
but that seems somewhat less likely.


https://bulbapedia.bulbagarden.net/wiki/MissingNo.

I used the Sprites:: namespace and the sprites have masks.
The animation frames are all 16x16.

So can we see the code?

1 Like

It’s actually a class, not a namespace.


As I said before, without seeing the code all we can do is guess.

The more specifics you give the better the guesses will be,
but only seeing the actual code will be enough to actually pinpoint the issue.

Here’s the code. The bug lies in the file called “player.h”:

    #ifndef PLAYER_H
    #define PLAYER_H
    #include "scroll.h"
    int direction = 0;
    int walkframe = -1;
    int idleframe = 0;
    int ground = 0;
    int pole = 0;
    void player() {
      //arduboy.fillCircle(playerx, playery, 32, WHITE);
        if(arduboy.pressed(LEFT_BUTTON))
        {
          playerx = playerx - 1;
          direction = 1;
          walkframe = walkframe+1;
          idleframe = 0;
        }
        if(arduboy.pressed(RIGHT_BUTTON))
        {
          playerx = playerx + 1;
          direction = 0;
          walkframe = walkframe+1;
          idleframe = 0;
        }
        if(!arduboy.pressed(LEFT_BUTTON) || !arduboy.pressed(RIGHT_BUTTON))
        {
          walkframe = -1;
        }
        
        if((arduboy.pressed(UP_BUTTON)) && pole>0)
        {
          playery = playery - 1;
        }
        if (pole<=0){
        playery = playery + 1;
        }
    if (playerx<8) {
        playerx = 8;
      }
    if (playerx>208) {
        playerx = 208;
      }
    if (walkframe>15) {
        walkframe = 0;
      }
    if (walkframe<0) {
        idleframe = idleframe + 1;
      }
      arduboy.print(direction);
    }
    void playergfx() {
      if(direction = 0 && ground>=1)
      {
        Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunright_plus_mask,(walkframe/4));
      }
      if(direction = 1 && ground>=1)
      {
        Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunleft_plus_mask,(walkframe/4));
      }
      if(direction = 0 && ground<=0)
      {
        Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunright_plus_mask,0);
      }
      if(direction = 1 && ground<=0)
      {
        Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunleft_plus_mask,0);
      }
      /*if(arduboy.pressed(LEFT_BUTTON) && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunleft_plus_mask,(walkframe/4));
        }
        if(arduboy.pressed(RIGHT_BUTTON) && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunright_plus_mask,(walkframe/4));
        }
        if (direction = 0 && walkframe<0 && idleframe <40 && ground>=1) 
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxstandright_plus_mask,(walkframe/4));
        }
        if (direction = 1 && walkframe<0 && idleframe <40 && ground>=1) 
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxstandleft_plus_mask,(walkframe/4));
        }
        if (direction = 0 && ground<=0) 
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunright_plus_mask,0);
        }
        if (direction = 1 && ground<=0) {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunleft_plus_mask,0);
        }
        if (direction = 0 && idleframe>=40 && ground>=1) 
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxidle_plus_mask,0);
        }
        if (direction = 1 && idleframe>=40 && ground>=1) 
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxidle_plus_mask,0);
        }
    /*if (direction == 0) {
      if (walkframe>=0 && idleframe<40 && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunright_plus_mask,(walkframe/4));
        }
      if (walkframe<0 && idleframe<40 && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxstandright_plus_mask,0);
        }
      else if (idleframe>=40 && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxidle_plus_mask,0);
        }
      else if (ground<=0)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunright_plus_mask,0);
        }
      }
    if (direction == 1) {
      if (walkframe>=0 && idleframe<40 && ground>=1) 
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunleft_plus_mask,(walkframe/4));
        }
        if (walkframe<0 && idleframe<40 && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxstandleft_plus_mask,0);
        }
      else if (idleframe>=40 && ground>=1)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxidle_plus_mask,0);
        }
      else if (ground<=0)
        {
          Sprites::drawPlusMask((playerx-8)-(camerax-64),(playery-8)-cameray,maxrunleft_plus_mask,0);
        }
      }
    */
    }
    #endif

I commented the animation commands until I could find a way to fix it.
The “MissingNo. Body Disease” bug in action:
A Scarlet Tower Missingno 2ScarletAnimationBugDemo.hex (36.3 KB)

@Mypka_MaxCat,
You didn’t follow my request that you enclose posted code in markdown code tags. I’ve done this for you in your last post but please do it yourself for future posts.

Okay… Sorry if it bothers you.

You didn’t consider that it might have been ArdBitmap? :stuck_out_tongue: :wink:

The player was rendered by the “Sprites” class. The boxes and the tiles meanwhile were rendered by “arduboy.drawBitmap”.

I assume all of the images and the frames render correctly? You are using the drawPlusMask() function - how are you generating the image data - from memory this format is interlaced image data / mask data / image data / … and so on.

1 Like

It’s interlaced? Not to sound stupid, the word “interlaced image” makes me think of CRT monitors and television sets.
So it’s interlaced. Is there still a way to animate this sprite and get rid of that mess?
P.S.: The gravity works surprisingly well for how I coded it. Except since it is subtracting 1 from the player’s position and Max was supposed to have ground animations for when he’s on the floor and air animations for when he’s aloft.

It’s statistically unlikely. (To the point I often forget that library exists…)

I think ‘interleaved’ would be a better term to avoid confusion with interlaced video which functions quite differently.

At the moment, based on the new information from the code you posted I have two theories:

  • The image data is broken somehow - something that can’t be confirmed without access to the image data
  • The drawPlusMask bug that we thought was fixed wasn’t completely fixed

All the parameters seem correct.

Just to confirm: are you using an official Arduboy or a clone?
(And if you’re using a clone, are you using Mr Blinky’s port of the Arduboy2 library?)

ProjectABE emulator.

Hence my use of “might” instead of “may”, and the emojis trying to convey sarcasm.


@Mypka_MaxCat,
If you could post the code for a stripped down minimum example, including the image arrays that you’re using, it would help us try to re-create it and determine the issue.

1 Like

If you were unaware of the sprite format that has the embedded mask, how did you manage to get the other graphics at the start of playergfx() to work? Did you borrow these graphics from somewhere else?


No. I am comfortable with interlaced.

I drew the graphics myself.

How did you convert them?

Can you render all the frames individually? Is it just your code that is wrong or the converted graphics?

There’s a tool by Crait that converts monochrome images into hexadecimal code, and also a tool by Team ARG for sprites.
To render the frames individually, you can replace “maxrunright_plus_mask” and “maxrunleft_plus_mask” with a different animation, except I should’ve provided the animation names for this.

I could but I haven’t got all of the images and code.

AFAIK neither of these do sprite + mask in the same output.

Here you go.

#ifndef MAXSPR_H
#define MAXSPR_H
const unsigned char PROGMEM maxstandright_plus_mask[] =
{
// width, height,
16, 16,
// FRAME 00
0x00, 0x00, 0x30, 0x30, 0xcc, 0xfc, 0x02, 0xfe, 0xc1, 0xff, 0xc1, 0xff, 0xe1, 0xff, 0xf1, 0xff, 
0x92, 0xfe, 0xf2, 0xfe, 0x90, 0xff, 0xe1, 0xff, 0x12, 0x1e, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x81, 0xc6, 0xdf, 0xdb, 0xff, 0x99, 0xff, 0x05, 0x7f, 
0x9d, 0xff, 0xdd, 0xff, 0xc9, 0xc9, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char PROGMEM maxstandleft_plus_mask[] =
{
// width, height,
16, 16,
// FRAME 00
0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x12, 0x1e, 0xe1, 0xff, 0x90, 0xff, 0xf2, 0xfe, 0x92, 0xfe, 
0xf1, 0xff, 0xe1, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x02, 0xfe, 0xcc, 0xfc, 0x30, 0x30, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc9, 0xc9, 0xdd, 0xff, 0x9d, 0xff, 
0x05, 0x7f, 0x99, 0xff, 0xdb, 0xff, 0xc6, 0xdf, 0x81, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char PROGMEM maxidle_plus_mask[] =
{
// width, height,
16, 16,
// FRAME 00
0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x12, 0x1e, 0xe1, 0xff, 0xf0, 0xff, 0x92, 0xfe, 0xf2, 0xfe, 
0xf1, 0xff, 0x91, 0xff, 0xe1, 0xff, 0xc1, 0xff, 0x02, 0xfe, 0xcc, 0xfc, 0x30, 0x30, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0xd9, 0xd9, 0xdd, 0xff, 0x9d, 0xff, 
0x1d, 0x7f, 0x85, 0xff, 0xd9, 0xff, 0xda, 0xff, 0x81, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char PROGMEM maxrunright_plus_mask[] =
{
// width, height,
16, 16,
// FRAME 00
0x00, 0x00, 0x30, 0x30, 0xcc, 0xfc, 0x02, 0xfe, 0xc1, 0xff, 0xc1, 0xff, 0xe1, 0xff, 0xf1, 0xff, 
0x92, 0xfe, 0xf2, 0xfe, 0x90, 0xff, 0xe1, 0xff, 0x12, 0x1e, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xe2, 0xe3, 0xdd, 0xff, 0x1d, 0x7f, 0x05, 0x7f, 
0x19, 0x7f, 0x19, 0x3f, 0x61, 0x79, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

// FRAME 01
0x00, 0x00, 0x30, 0x30, 0xcc, 0xfc, 0x02, 0xfe, 0xc1, 0xff, 0xc1, 0xff, 0xe1, 0xff, 0xf1, 0xff, 
0x92, 0xfe, 0xf2, 0xfe, 0x90, 0xff, 0xe1, 0xff, 0x12, 0x1e, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x1d, 0x3f, 0xc5, 0xff, 0xd9, 0xff, 
0xd9, 0xff, 0x85, 0xbf, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

// FRAME 02
0x00, 0x00, 0x60, 0x60, 0x98, 0xf8, 0x04, 0xfc, 0x82, 0xfe, 0x82, 0xfe, 0xc2, 0xfe, 0xe2, 0xfe, 
0x24, 0xfc, 0xe4, 0xfc, 0x20, 0xfe, 0xc2, 0xfe, 0x24, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0xc5, 0xf7, 0xb3, 0xff, 0x33, 0xff, 0x0b, 0xff, 
0x3b, 0xff, 0x3b, 0xff, 0xd3, 0xd3, 0xe1, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

// FRAME 03
0x00, 0x00, 0x30, 0x30, 0xcc, 0xfc, 0x02, 0xfe, 0xc1, 0xff, 0xc1, 0xff, 0xe1, 0xff, 0xf1, 0xff, 
0x92, 0xfe, 0xf2, 0xfe, 0x90, 0xff, 0xe1, 0xff, 0x12, 0x1e, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x62, 0x63, 0xf1, 0xff, 0x8d, 0xbf, 0x0d, 0x3f, 
0x11, 0x3f, 0xdd, 0xff, 0xc1, 0xc1, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const unsigned char PROGMEM maxrunleft_plus_mask[] =
{
// width, height,
16, 16,
// FRAME 00
0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x12, 0x1e, 0xe1, 0xff, 0x90, 0xff, 0xf2, 0xfe, 0x92, 0xfe, 
0xf1, 0xff, 0xe1, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x02, 0xfe, 0xcc, 0xfc, 0x30, 0x30, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70, 0x61, 0x79, 0x19, 0x3f, 0x19, 0x7f, 
0x05, 0x7f, 0x1d, 0x7f, 0xdd, 0xff, 0xe2, 0xe3, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

// FRAME 01
0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x12, 0x1e, 0xe1, 0xff, 0x90, 0xff, 0xf2, 0xfe, 0x92, 0xfe, 
0xf1, 0xff, 0xe1, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x02, 0xfe, 0xcc, 0xfc, 0x30, 0x30, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x85, 0xbf, 0xd9, 0xff, 
0xd9, 0xff, 0xc5, 0xff, 0x1d, 0x3f, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

// FRAME 02
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x24, 0x3c, 0xc2, 0xfe, 0x20, 0xfe, 0xe4, 0xfc, 0x24, 0xfc, 
0xe2, 0xfe, 0xc2, 0xfe, 0x82, 0xfe, 0x82, 0xfe, 0x04, 0xfc, 0x98, 0xf8, 0x60, 0x60, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xe1, 0xd3, 0xd3, 0x3b, 0xff, 0x3b, 0xff, 
0x0b, 0xff, 0x33, 0xff, 0xb3, 0xff, 0xc5, 0xf7, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 

// FRAME 03
0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x12, 0x1e, 0xe1, 0xff, 0x90, 0xff, 0xf2, 0xfe, 0x92, 0xfe, 
0xf1, 0xff, 0xe1, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x02, 0xfe, 0xcc, 0xfc, 0x30, 0x30, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0xc1, 0xc1, 0xdd, 0xff, 0x11, 0x3f, 
0x0d, 0x3f, 0x8d, 0xbf, 0xf1, 0xff, 0x62, 0x63, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif