0

64x32 LED Matrix Arduino Mario Jumper
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

64x32 LED Matrix Arduino Mario Jumper

by FrozT on Tue Jul 24, 2018 4:27 pm

About:
As a project to teach my son coding for the Arduino we put together a little Mario jumping game. It may not be perfect but my interest in taking it any further is rapidly coming to a middle.

Ingredients:
64 x 32 LED Matrix
Arduino Mega (you might actually be able to do this on an Uno but I haven't tried.)
IR Sensor or Button (I'm using IR so people actually have to jump.)
the codez (see below)

Instructions:
Put IR sensor on Analog pin A4 and attach it to a stick above your head. Then jump to make Mario jump. Your score will increase for every obstacle that you successfully pass or brick that you break. Once dead, just jump to reset.

Arduino_Mario2.jpg
Arduino_Mario2.jpg (549.31 KiB) Viewed 678 times


The codez: (v1.0)
Code: Select all | TOGGLE FULL SIZE
#include <RGBmatrixPanel.h>

// Most of the signal pins are configurable, but the CLK pin has some
// special constraints.  On 8-bit AVR boards it must be on PORTB...
// Pin 8 works on the Arduino Uno & compatibles (e.g. Adafruit Metro),
// Pin 11 works on the Arduino Mega.  On 32-bit SAMD boards it must be
// on the same PORT as the RGB data pins (D2-D7)...
// Pin 8 works on the Adafruit Metro M0 or Arduino Zero,
// Pin A4 works on the Adafruit Metro M4 (if using the Adafruit RGB
// Matrix Shield, cut trace between CLK pads and run a wire to A4).

#define CLK 11 // USE THIS ON ARDUINO MEGA
#define OE   9
#define LAT 10
#define A   A0
#define B   A1
#define C   A2
#define D   A3
#define IR  A4

// Last parameter = 'true' enables double-buffering, for flicker-free,
// buttery smooth animation.  Note that NOTHING WILL SHOW ON THE DISPLAY
// until the first call to swapBuffers().  This is normal.
RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, true, 64);

static const byte marioWidth = 14;
static const byte marioHeight = 14;
static const byte groundY = 26;
static const word imageDataSize = marioWidth * marioHeight;
static const byte maxPipes = 3;
static const byte maxBricks = 4;
static const byte minimumDistanceBetweenPipes = 3;
static const byte brickSize = 8;
static const byte minimumHoleSize = marioWidth + 5;
static const byte pipeWidth = 10;

static const uint16_t PROGMEM  mario[4][2][imageDataSize] =
{
  { //Running anim
    { 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xf800, 0xf800, 0xf800, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x0000, 0x0000, 0x7225, 0x7225, 0x0000, 0x7225, 0x0000, 0x0000, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0xf48a, 0xf48a, 0x0000, 0x0000, 0xf48a, 0x2945, 0xf48a, 0xf48a, 0xfdd0, 0xf48a, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x0000, 0x0000, 0xf48a, 0xf48a, 0x0000, 0x7225, 0x7225, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0xf48a, 0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x7225, 0x7225, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xf800, 0xf800, 0x000e, 0x228e, 0xa000, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xf800, 0xf8c6, 0xf800, 0x000e, 0x228e, 0xa000, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xa000, 0xf800, 0x000e, 0x000e, 0x228e, 0x228e, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0xf48a, 0xf48a, 0x0000, 0x0000, 0xffdf, 0x228e, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0xaa60, 0xe405, 0xe405, 0x0000, 0x000e, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xaa60, 0xaa60, 0xaa60, 0xe405, 0xf645, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f },
    { 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xf800, 0xf800, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x0000, 0x0000, 0x7225, 0x7225, 0x0000, 0x7225, 0x0000, 0x0000, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0xf48a, 0xf48a, 0x0000, 0x0000, 0xf48a, 0x0000, 0xf48a, 0xf48a, 0xfdd0, 0xf48a, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x0000, 0x0000, 0xf48a, 0xf48a, 0x0000, 0x7225, 0x7225, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0xf48a, 0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x7225, 0x7225, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xf800, 0xf800, 0xf800, 0x000e, 0x228e, 0xa000, 0xf800, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0xfdd0, 0xfdd0, 0xa000, 0xf800, 0xf800, 0xa000, 0x000e, 0x228e, 0xa000, 0xf800, 0x0000, 0xf800, 0x001f, 0x001f, 0xf48a, 0xf48a, 0x7225, 0xa000, 0xa000, 0x0000, 0x228e, 0x228e, 0x228e, 0x228e, 0x0000, 0xa000, 0xf48a, 0x001f, 0x001f, 0x7225, 0x7225, 0x0000, 0x0000, 0x228e, 0x228e, 0xffdf, 0x228f, 0x228f, 0xffdf, 0x0000, 0x7225, 0x001f, 0x001f, 0x001f, 0x0000, 0x000e, 0x000e, 0x000e, 0x228e, 0x228e, 0x228e, 0x0000, 0xf645, 0xf645, 0x001f, 0x001f, 0x001f, 0xaa60, 0xaa60, 0x0000, 0x000e, 0x0000, 0x0000, 0x000e, 0x0000, 0xe405, 0xe405, 0xaa60, 0x001f, 0x001f, 0x001f, 0xaa60, 0xe405, 0xe405, 0x001f, 0x001f, 0x001f, 0x001f, 0xaa60, 0xaa60, 0xaa60, 0x001f, 0x001f, 0x001f }
  },
  { //Jumping
    { 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xc802, 0xf800, 0xf800, 0x001f, 0x001f, 0x7225, 0xf48a, 0xf48a, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xc802, 0xc802, 0xc802, 0xc802, 0xc802, 0xc802, 0x001f, 0x7225, 0x7225, 0x001f, 0x001f, 0x001f, 0x0000, 0x0000, 0x7225, 0x7225, 0x0000, 0x7225, 0x001f, 0x001f, 0x001f, 0xc802, 0x001f, 0x001f, 0x001f, 0xf48a, 0xf48a, 0x0000, 0x0000, 0xf48a, 0x2945, 0xf48a, 0xf48a, 0xfdd0, 0xf48a, 0xc802, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x0000, 0x0000, 0xf48a, 0xf48a, 0x0000, 0x7225, 0x7225, 0x7225, 0xc802, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0xf48a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x7225, 0x7225, 0x7225, 0x7225, 0xc802, 0x001f, 0x001f, 0x001f, 0x001f, 0xc802, 0xf800, 0xc802, 0x000e, 0x228e, 0xa000, 0xc802, 0x0000, 0xc802, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x0000, 0xa000, 0xf800, 0xc802, 0x000e, 0x228e, 0xa000, 0xc802, 0x0000, 0x001f, 0x001f, 0x001f, 0xfdd0, 0xfdd0, 0x7225, 0x0000, 0xa000, 0xa000, 0x0000, 0xffdf, 0x228e, 0x228e, 0xffdf, 0x001f, 0xf645, 0xaa60, 0xf48a, 0xf48a, 0x7225, 0x0000, 0xa000, 0x0000, 0x228e, 0x228e, 0x228e, 0x228e, 0x0000, 0xf645, 0xaa60, 0xaa60, 0x001f, 0xaa60, 0x0000, 0x0000, 0x0000, 0x228e, 0x000e, 0x000e, 0x000e, 0x000e, 0x0000, 0xe405, 0xaa60, 0x001f, 0xaa60, 0xaa60, 0xe405, 0x0000, 0x228e, 0x000e, 0x000e, 0x000e, 0x001f, 0x001f, 0x001f, 0xe405, 0xaa60, 0x001f, 0xaa60, 0xe405, 0x001f, 0x000e, 0x000e, 0x000e, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f }
  },
  { //Dead
    { 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xf800, 0xf800, 0xa000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xf48a, 0x001f, 0xa000, 0xf800, 0xf800, 0xf800, 0xf800, 0xa000, 0x001f, 0xf48a, 0x001f, 0x001f, 0xfdd0, 0xf48a, 0xf48a, 0x001f, 0x7225, 0x0000, 0x7225, 0x7225, 0x0000, 0x7225, 0x001f, 0xf48a, 0xf48a, 0xfdd0, 0xf48a, 0xf48a, 0xf800, 0x7225, 0xf48a, 0x2945, 0xf48a, 0xf48a, 0x2945, 0xf48a, 0x7225, 0xf800, 0xf48a, 0xf48a, 0x7225, 0xf800, 0xf800, 0x2945, 0x2945, 0xf48a, 0xfdd0, 0xfdd0, 0xf48a, 0x2945, 0x2945, 0xf800, 0xf800, 0x7225, 0x001f, 0x001f, 0xa000, 0xf48a, 0x0000, 0x7225, 0x7225, 0x7225, 0x7225, 0x0000, 0xf48a, 0xa000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0xf48a, 0x0000, 0x0000, 0x0000, 0x0000, 0xf48a, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0xf48a, 0x2945, 0x2945, 0xf48a, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x000e, 0x228e, 0x0000, 0x7225, 0x7225, 0x7225, 0x7225, 0x0000, 0x228e, 0x000e, 0x001f, 0x001f, 0x001f, 0xaa60, 0xf645, 0x0000, 0x228e, 0xa000, 0xf800, 0xf800, 0xa000, 0x228e, 0x0000, 0xf645, 0xaa60, 0x001f, 0x001f, 0xaa60, 0xaa60, 0xf645, 0x0000, 0x228e, 0xa000, 0xa000, 0x228e, 0x0000, 0xf645, 0xaa60, 0xaa60, 0x001f, 0x001f, 0xaa60, 0xaa60, 0xe405, 0x001f, 0xffdf, 0x228e, 0x228e, 0xffdf, 0x001f, 0xe405, 0xaa60, 0xaa60, 0x001f, 0x001f, 0xaa60, 0xaa60, 0xe405, 0x001f, 0x000e, 0x000e, 0x000e, 0x000e, 0x001f, 0xe405, 0xaa60, 0xaa60, 0x001f, 0x001f, 0x001f, 0xaa60, 0xe405, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xe405, 0xaa60, 0x001f, 0x001f }
  },
  { //Falling
    { 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xf800, 0xf800, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xa000, 0xa000, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x0000, 0x0000, 0x7225, 0x7225, 0x0000, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xf48a, 0xf48a, 0x0000, 0x0000, 0xf48a, 0x2945, 0xf48a, 0xf48a, 0xfdd0, 0xf48a, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x0000, 0x0000, 0xf48a, 0xf48a, 0x0000, 0x7225, 0x7225, 0x7225, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0xf48a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x7225, 0x7225, 0x7225, 0x7225, 0x7225, 0x0000, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xf800, 0xf800, 0xf800, 0x000e, 0x228e, 0xa000, 0xf800, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0xfdd0, 0x7225, 0xa000, 0xf800, 0xf800, 0xa000, 0x000e, 0x228e, 0xa000, 0xf800, 0x0000, 0xf800, 0xf48a, 0x001f, 0xf48a, 0xf48a, 0x7225, 0xa000, 0xa000, 0x0000, 0x000e, 0x228e, 0x0000, 0x0000, 0x0000, 0xa000, 0x7225, 0x001f, 0x001f, 0x7225, 0x7225, 0x0000, 0x0000, 0x000e, 0x228e, 0xffdf, 0x228e, 0x228e, 0xffdf, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x000e, 0x000e, 0x228e, 0x228e, 0x0000, 0xf645, 0xaa60, 0x001f, 0xe405, 0xaa60, 0x001f, 0x001f, 0x001f, 0x001f, 0x000e, 0x000e, 0x000e, 0x228e, 0xe405, 0xaa60, 0xaa60, 0x001f, 0xaa60, 0xaa60, 0x001f, 0x001f, 0x001f, 0x001f, 0x001f, 0x000e, 0x000e, 0x228e, 0xe405, 0xaa60, 0x001f, 0xe405, 0xaa60, 0x001f, 0x001f }
  }
};

bool everyOther = false;
byte animSequence = 0;
byte animFrame = 0;
byte numRects = 0;
int endSpace = matrix.width();
byte currentPipe = 1;
byte lFloor = groundY;
byte lCeiling = 0;
int marioPosX = -marioWidth;
int marioPosY = lFloor - marioHeight;
byte marioRight = marioPosX + marioWidth;
byte frameNum = 0;
int jumpVelocity = 0;
int marioLastPosX1;
int marioLastPosY1;
int marioLastPosX2;
int marioLastPosY2;
byte numBricks;
byte forwardSpeed = 1;
int score = 0;

struct PipeData
{
  int x;
  byte y;
  int width;
};

enum marioStates {
  Running,
  Jumping,
  Dead,
  Falling
};

enum marioStates marioState;
enum marioStates marioLastState;
enum marioStates marioLastFrameState;
enum marioStates marioLastState1;
enum marioStates marioLastState2;

PipeData pipes[maxPipes];
PipeData hole;
PipeData bricks[maxBricks];


void setup() {
  matrix.begin();
  reset();
  Serial.begin(9600);
}

void reset()
{
  // Set Sky and Ground
  matrix.fillScreen(31);
  drawGround();
  matrix.swapBuffers(false);
  matrix.fillScreen(31);
  drawGround();
  matrix.setTextSize(1);
  byte lFloor = groundY;
  marioPosX = -marioWidth;
  marioPosY = lFloor - marioHeight;
  pipes[0].x = matrix.width() - 1;
  pipes[0].y = lFloor - 6;
  pipes[0].width = pipeWidth;
  for (int i = 1; i < maxPipes; i++)
    pipes[i].width = 0;
  hole.width = 0;
  hole.y = groundY;
  numBricks = 0;
  for (int i = 0; i < maxBricks; i++)
    bricks[i].width = 0;
  marioState = Running;
  forwardSpeed = 1;
  score = 0;

  do
  {
    drawMario();
    matrix.drawLine(marioPosX - 1, marioPosY, marioPosX - 1, groundY - 1, 31); //this just helps to remove some artifacts
    matrix.drawLine(marioPosX, marioPosY, marioPosX, groundY - 1, 31); //this just helps to remove some artifacts
    matrix.swapBuffers(false);
    marioPosX++;
  } while (marioPosX < 20);
  matrix.drawLine(marioPosX - 1, marioPosY, marioPosX - 1, groundY - 1, 31); //this just helps to remove some artifacts
  matrix.drawLine(marioPosX, marioPosY, marioPosX, groundY - 1, 31); //this just helps to remove some artifacts
  marioRight = marioPosX + marioWidth;
}

void debugPrint(int txt)
{
  matrix.fillRect(0,0,23,7,31);
  matrix.setCursor(0,0);
  matrix.setTextSize(1);
  matrix.print(txt);
}

void scorePrint()
{
  byte x = 12;
  if (score > 99)
    x = 18;
  else if (score < 10)
    x = 6;
  else if (score > 999)
    x = 24;
  matrix.setCursor(matrix.width() - x,0);
  matrix.fillRect(matrix.width() - x,0,x,7,31);
  matrix.print(score);
}

void drawObstacles()
{
  int currentEndSpace = 0;
  int distanceBetweenPipes = 0;

  for (byte i = 0; i < maxPipes; i++)
  {
    if (pipes[i].width > 0)
    {
      int pipeRight = pipes[i].x + pipes[i].width;
      if (pipeRight == -2)
      {
        currentPipe = i;
        pipes[i].width = 0;
        score++;
      }
      else
      {
        pipes[i].x -= forwardSpeed;
        if (pipeRight - 1 > currentEndSpace)
          currentEndSpace = pipeRight;
      }
    }
  }

// Generate a new pipe if we can ******************************************************************************************************************************************************************* PIPE HOLE BRICK
  endSpace = matrix.width() - currentEndSpace;
  if (currentPipe < maxPipes && endSpace > minimumDistanceBetweenPipes && random(0,50) == 1 && (hole.width == 0 || (hole.width > 0 && hole.x + hole.width < matrix.width())) && (bricks[0].width == 0 || (bricks[0].width > 0 && bricks[0].x + (bricks[0].width * brickSize) + (marioWidth * 2) < matrix.width())))
  {
    pipes[currentPipe].x = matrix.width() - 1;
    pipes[currentPipe].y = groundY - random(4,7);
    pipes[currentPipe].width = pipeWidth;

    //A chance to draw a hole
    if (hole.width == 0 && random(0,5) == 1)
    {
      hole.x = pipes[currentPipe].x + pipes[currentPipe].width + random(0, 40);
      hole.width = minimumHoleSize + random(0, 5);
      if (hole.x < 10)
      {
        hole.x = 0;
        hole.width = minimumHoleSize;
      }
    }
    else if (numBricks == 0 && random(1,2) == 1)     //A chance to draw bricks
    {
      numBricks = random(1,4);
      byte offset = pipes[currentPipe].x + pipes[currentPipe].width + random(marioWidth * 2,(marioWidth * 2) + 25);
      for (byte i = 0; i < numBricks; i++)
      {
        bricks[i].x = offset + (i * brickSize);
        bricks[i].y = 1;
        bricks[i].width = brickSize;
      }
    }
    currentPipe++;
  }

  //Move the hole if it exists
  if (hole.width > 0)
  {
    if (hole.x + hole.width > 0)
      hole.x-=forwardSpeed;
    else
    {
      hole.width = 0;
      score++;
    }
  }

  //Move the bricks if they exist
  if (numBricks > 0)
  {
    bool haveBricks = false;
    for (byte i = 0; i < numBricks; i++)
    {
        if (bricks[i].x + brickSize > -2) //move bricks regardless if they exist or not because we need a correct x for cleanup
        {
          bricks[i].x-=forwardSpeed;
          if (bricks[i].width > 0) haveBricks = true;
        }
        else
          bricks[i].width = 0;
    }
    if (!haveBricks) numBricks = 0;
  }

  //Draw the pipes
  for (byte i = 0; i < maxPipes; i++)
  {
    if (pipes[i].width > 0)
    {
      //pipe stem
      drawGradientSquare(pipes[i].x, pipes[i].y + 3, pipeWidth, groundY - pipes[i].y - 3);
      matrix.drawLine(pipes[i].x + 1, pipes[i].y + 3, pipes[i].x + pipeWidth - 1, pipes[i].y + 3, 224); //add a little shadow under the pipe top

      //pipe top
      drawGradientSquare(pipes[i].x - 1, pipes[i].y, pipeWidth + 2, 3);
    }
  }

  //Draw any holes if they exist
  if (hole.width > 0)
  {
    matrix.fillRect(hole.x, hole.y, hole.width, matrix.height() - groundY, 31);
    //Draw the ground dirt
    matrix.fillRect(hole.x + hole.width - 2,groundY + 2, 2, 4, matrix.Color888(40, 25, 10));
    //Draw the grass
    matrix.fillRect(hole.x + hole.width - 2,groundY, 2, 2, matrix.Color333(0, 6, 0));
  }

  //Draw any bricks if they exist
  if (numBricks > 0)
    for (byte i = 0; i < numBricks; i++)
    {
      if (bricks[i].width > 0 && bricks[i].x + bricks[i].width > -3 && bricks[i].x < matrix.width())
      {
        //Regular brick
        matrix.fillRect(bricks[i].x, bricks[i].y + 1, brickSize - 1, brickSize - 1, 27362);
        matrix.drawLine(bricks[i].x, bricks[i].y, bricks[i].x + brickSize - 1, bricks[i].y, 0);
        matrix.drawLine(bricks[i].x, bricks[i].y + 4, bricks[i].x + brickSize - 1, bricks[i].y + 4, 0);
        matrix.drawLine(bricks[i].x + 4, bricks[i].y + 1, bricks[i].x + 4, bricks[i].y + 3, 0);
        matrix.drawLine(bricks[i].x + brickSize - 1, bricks[i].y + 5, bricks[i].x + brickSize - 1, bricks[i].y + brickSize - 1, 0);
        cleanupBricks(i);
      }
  }
}

void cleanupAllBricks()
{
  for (byte i = 0; i < numBricks; i++)
    cleanupBricks(i);
}

void cleanupBricks(byte i)
{
  if (i == maxBricks - 1 || bricks[i + 1].width == 0)
  {
    matrix.fillRect(bricks[i].x + brickSize - 1, bricks[i].y, brickSize, brickSize, 31);  //You have to use brickSize here because brick.width may have already been cleared
  }
}

void drawGradientSquare(int x, byte y, byte width, byte height)
{
    int endSquareX = x + width;
     
    //main part of the pipe
    matrix.fillRect(x,y, width, height, 992); //00000 011111 00000
   
    //shadow
    matrix.fillRect(x + 2, y, 2, height, 224);
   
    //highlight
    matrix.drawLine(endSquareX - 2, y, endSquareX - 2, y + height - 1, 8162); //00011 111111 00010

    //Outline
    matrix.drawLine(x, y, x, y + height - 1, 0);
   
    //Cleanup
    matrix.fillRect(x + width,y, 2, height, 31);
}

void drawGround()
{
  //Draw the ground dirt
  matrix.fillRect(0,groundY + 2, matrix.width(), matrix.height() - 1, matrix.Color888(40, 25, 10));
  //Draw the grass
  matrix.fillRect(0,groundY, matrix.width(), 2, matrix.Color333(0, 6, 0));
}

void drawLevel()
{
  //Draw pipes and holes
  drawObstacles();
  //Find the floor ************************************************************************************************************************************************************************************* FLOOR
  lFloor = matrix.height();
  for (byte i = 0; i < maxPipes; i++)
  {
    if (pipes[i].width > 0)
    {
      int pipeRight = pipes[i].x + pipes[i].width;
      if (marioRight >= pipes[i].x &&  marioPosX + 2 <= pipeRight) //+2 is a little boost to allow mario to fall off the pipe sooner because his sprite is a square but he isnt really
        if (pipes[i].y -1 < lFloor) lFloor = pipes[i].y;
    }
  }
  //Check if mario is NOT over a hole
  if (hole.width == 0 || !( marioPosX + 2 >= hole.x && marioRight <= hole.x + hole.width))
    if (lFloor > groundY) lFloor = groundY; // at this point weve verified the ground is the Floor

  //Find Ceiling
  lCeiling = 0;
  if (numBricks > 0)
    for (byte i = 0; i < numBricks; i++)
      if (marioRight >= bricks[i].x && marioPosX <= bricks[i].x + brickSize)
        if (lCeiling < bricks[i].y + brickSize) lCeiling = bricks[i].y + brickSize;
}

void drawMario()
{
  int x = 0;
  int y = 0;
  for(int i = 0; i < imageDataSize; i++)
  {
    matrix.drawPixel(x + marioPosX, y + marioPosY, pgm_read_word(&mario[marioState][animFrame][i]));
    x++;
    if (x == marioWidth)
    {
      x = 0;
      y++;
    }
  }
  if (marioState == Running)
  {
    if (frameNum == 4)
    {
      animFrame++;
      if (animFrame == 2) animFrame = 0;
      frameNum = 0;
    }
    if (everyOther)
    {
      if (marioLastState1 == Falling) cleanupMarioJump();
    }
    else
    {
      if (marioLastState2 == Falling) cleanupMarioJump();
    }
  }
  else if (marioState == Jumping || marioState == Falling || marioState == Dead)
  {
    cleanupMarioJump();
  }
  frameNum++;
}

void cleanupMarioJump()
{
  //cleanup
  if (marioState == Jumping)
  {
    if (everyOther)
      matrix.fillRect(marioPosX, marioPosY + marioHeight, marioWidth, marioLastPosY1 - marioPosY, 31);
    else
      matrix.fillRect(marioPosX, marioPosY + marioHeight, marioWidth, marioLastPosY2 - marioPosY, 31);
  }
  else// falling
  {
    if (everyOther)
      matrix.fillRect(marioLastPosX1, marioLastPosY1, marioWidth, marioPosY - marioLastPosY1 , 31);
    else
      matrix.fillRect(marioLastPosX2, marioLastPosY2, marioWidth, marioPosY - marioLastPosY2, 31);
  }

}

// *********************************************************************************************************************** Process inputs
void processInputs()
{
  if (marioState == Falling)
  {
    //debugPrint(frameNum);
    if (frameNum == 2)
    {
      jumpVelocity -= (marioLastState == Running)? 1 : 0.5;
      marioPosY -= jumpVelocity;
      if (marioPosY + marioHeight >= lFloor)
      { // End of fall
        if (hole.width > 0 && marioPosX >= hole.x && marioRight <= hole.x + hole.width)
        //He's fallen in to a hole
            marioState = Dead;
        else
        {//He's landed on the ground
          marioState = Running;
          jumpVelocity = 0;
          marioPosY = lFloor - marioHeight;
        }
      }
      frameNum = 0;
    }
  }
  else if (marioState == Jumping)
  {
    if (frameNum == 2)
    {
      frameNum = 0;
      marioPosY -= jumpVelocity;
      if (marioPosY < lCeiling + 1)  //Hits the ceiling
      {// Set Falling, hit a brick
        marioPosY = lCeiling + 1;
        lCeiling = 0;
        jumpVelocity = -1;
        marioState = Falling;
        frameNum = 0;
        for (byte i = 0; i < numBricks; i++)
          if (bricks[i].width > 0 && marioPosX < bricks[i].x + bricks[i].width - 2 && marioRight > bricks[i].x + 2) //Check if Mario hits a brick
          {
            score++;
            //Remove Brick
            matrix.fillRect(bricks[i].x, bricks[i].y, bricks[i].width, bricks[i].width, 31);
            matrix.swapBuffers(false);
            matrix.fillRect(bricks[i].x, bricks[i].y, bricks[i].width, bricks[i].width, 31);
            matrix.swapBuffers(false);
            //matrix.fillRect(0, 1, matrix.width(), 8, 31);
            bricks[i].width = 0;
          }
      }
      else  //Still jumping
      {
        jumpVelocity -= 0.5;
        if (jumpVelocity < 0)
        { //Now hes falling
          marioState = Falling;
        }
      }
      cleanupMarioJump();
    }
  }
  else if (marioState == Running)
  {
    if (lFloor > marioPosY + marioHeight)
    {
      marioState = Falling;
      jumpVelocity = -1;
      frameNum = 0;
      animFrame = 0;
    }
    if (marioPosY + marioHeight > lFloor || marioPosY <= lCeiling)
    {
      //debugPrint(marioState);
      //delay(3000);
      marioState = Dead;
    }
    if (analogRead(A4) > 270)
    {
      marioState = Jumping;
      jumpVelocity = 5;
      marioPosY-=6;
      //jumpDirectionUp = true;
      frameNum = 0;
      animFrame = 0;
    }
  }
  else if (marioState == Dead)
  {
    forwardSpeed = 0;
    frameNum = 0;
    animFrame = 0;
    //Will restart on next jump
    if (analogRead(A4) > 300)
      reset();
  }
}

void loop()
{
  drawLevel();

  processInputs();

  drawMario();

  scorePrint();
   
  // Update display
  matrix.swapBuffers(false);
  if (everyOther)
  {
    marioLastPosX1 = marioPosX;
    marioLastPosY1 = marioPosY;
    marioLastState1 = marioState;
  }
  else
  {
    marioLastPosX2 = marioPosX;
    marioLastPosY2 = marioPosY;
    marioLastState2 = marioState;
  }
  everyOther = !everyOther;

  if (marioLastFrameState != marioState)
    marioLastState = marioLastFrameState;
  marioLastFrameState = marioState;
}


Cheers!

FrozT
 
Posts: 1
Joined: Tue Jul 24, 2018 4:07 pm

Re: 64x32 LED Matrix Arduino Mario Jumper

by MikeBarela on Tue Jul 24, 2018 5:48 pm

Thank you for sharing your great project! I've posted it on the Adafruit blog at
https://blog.adafruit.com/2018/07/24/fr ... io-jumper/

Keep on Making! Best regards, Mike

MikeBarela
 
Posts: 715
Joined: Sat Mar 24, 2012 8:56 pm
Location: Mid-Atlantic

Re: 64x32 LED Matrix Arduino Mario Jumper

by marcmerlina on Wed Jul 25, 2018 12:51 pm

Cool.
For future reference, I've added code in GFX to let you display a whole image at once, you don't have to display it pixel by pixel :)
https://github.com/adafruit/RGB-matrix- ... 2.ino#L299
defined here:
https://github.com/adafruit/Adafruit-GF ... X.cpp#L642
marcmerlina
 
Posts: 13
Joined: Wed Jun 11, 2014 5:11 pm

Re: 64x32 LED Matrix Arduino Mario Jumper

by marcmerlina on Wed Jul 25, 2018 5:03 pm

Oh yeah, unless you know nothing about git and don't really want to learn (basics are pretty easy with github, they have online help), please put this on github :)
After I'm done building my 64x64 neopixel matrix, I can try to port your code to FastLED::Neomatrix which supports the same Adafruit::GFX backend, and should ideally just work.
marcmerlina
 
Posts: 13
Joined: Wed Jun 11, 2014 5:11 pm

Please be positive and constructive with your questions and comments.