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.
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!