//Platformer made by me, using lots of code made by myself with some code from various sources.
//if you are playing this game know that some of it is very difficult
#include <MD_MAX72xx.h>
#define MAX_DEVICES 2
#define CS_PIN 10
#define BUTTON_PIN 12
#define HORZ_PIN A1
//x and y is used for displaying to the dot matrix and the yreverse is used for the level collision vertically
float x = 0;
float y = 1;
float yreverse = 6;
//jumpvel and is used for jumping (not named yvel because nothing else affects it)
float jumpvel;
int level = 0;
int arrayoflevel;
const int buzzer = 9;
//i found this function from a guide https://www.instructables.com/two-ways-to-reset-arduino-in-software/
void(* resetFunc) (void) = 0;//declare reset function at address 0
MD_MAX72XX mx = MD_MAX72XX(MD_MAX72XX::PAROLA_HW, CS_PIN, MAX_DEVICES);
//this method of making levels is probably not optimal but its easy for me to understand
//0 = empty space, 1 = block
//the commented out array below is an example of a level array
/*
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
}
*/
//There is probably a way to make the levels take less memory,(low memory is why i cant i have too many levels)
//but i feel like 12 levels(my max with this system) is good enough anyways. Also, i dont want to change the way
//levels are implemented.
//game[] contains all of the levels in the game
bool game[12][8][16]=
{
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0},
{1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1},
{0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},
{0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},
{1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,1,0,0,1,1,1,1,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
{1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1}
},
{
{1,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0},
{1,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0},
{1,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0},
{0,0,1,1,1,1,0,0,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0},
{1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0},
{0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}
},
{
{0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
{0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1},
{0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1},
{0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1},
{1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1}
}
};
/*
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,0,0,1,1,0,0,1,0,0,0,1},
{0,1,0,1,0,0,1,0,0,1,0,0,1,0,1,0},
{0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
*/
//argument one should be an element of a level layout array
void renderline(bool row_of_level[], int row_of_screen){
for(int i = 0; i < 16; i++){
if (row_of_level[i] == true){
mx.setPoint(row_of_screen,i,true);
}
else{
mx.setPoint(row_of_screen,i,false);
}
}
}
void renderlevel(bool array[][16]){
for(int i = 0, o = 7; i < 8; i++, o--){
renderline(array[i],o);
}
}
void levelend(){
x = 0;
y = 1;
yreverse = 6;
level++;
renderlevel(game[level]);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
mx.begin();
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY / 2);
mx.clear();
renderlevel(game[level]);
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.print("Level ");
Serial.println(level + 1);
pinMode(buzzer, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
int horz = analogRead(HORZ_PIN);
int buttonvalue = digitalRead((BUTTON_PIN));
//gravity+collision
if (game[level][static_cast<int>(yreverse)+1][static_cast<int>(x)]==0||y>=7){
mx.setPoint(static_cast<int>(y+0.5),static_cast<int>(x),false);
y-=0.5;
yreverse+=0.5;
//Serial.println(F("in the air"));
}
else{
y=static_cast<int>(y+0.5);
yreverse=static_cast<int>(yreverse+0.5);}
//end of gravity+collision
if (buttonvalue == HIGH) {
}
if (buttonvalue == LOW) {
if (game[level][static_cast<int>(yreverse)+1][static_cast<int>(x)]==1 && game[level][static_cast<int>(yreverse)-1][static_cast<int>(x)]==0){jumpvel=2; tone(buzzer, 250);}
}
if (game[level][static_cast<int>(yreverse)+1][static_cast<int>(x)]==0 && jumpvel - 0.5 != -0.5){jumpvel-=0.5;}
mx.setPoint(static_cast<int>(y+0.5),static_cast<int>(x),false);
//this is a certified goto moment
before_y_up:
if(game[level][static_cast<int>(yreverse - jumpvel)][static_cast<int>(x)]==0){y += jumpvel; yreverse -= jumpvel;}
else if(jumpvel>0) {jumpvel-=0.5; goto before_y_up;}
if (horz < 400 && static_cast<int>(x) + 0.5 <= 15 && game[level][static_cast<int>(yreverse)][static_cast<int>(x)+1]==0){
mx.setPoint(static_cast<int>(y+0.5),static_cast<int>(x),false);
x += 0.5;}
if (horz > 600 && static_cast<int>(x) - 0.5 >= 0 && game[level][static_cast<int>(yreverse)][static_cast<int>(x)-1]==0){
mx.setPoint(static_cast<int>(y+0.5),static_cast<int>(x),false);
x -= 0.5;}
/*
//good code for testing position:
Serial.print("X:");
Serial.println(x);
Serial.print("Y:");
Serial.println(y);
Serial.print("Y REVERSE:");
Serial.println(yreverse);
*/
//somehow get inside a block
if (game[level][static_cast<int>(yreverse)][static_cast<int>(x)]==1){yreverse--;renderlevel(game[level]);}
//fall into pit
if (y <= 0){tone(buzzer,150);delay(200);tone(buzzer,100);delay(400);noTone(buzzer); mx.clear(); delay(500); resetFunc(); }
//beat level
if (x == 15 && horz < 400){
for (int i=0, o=300; i<16; i++){tone(buzzer, o); o+=20; delay(80); mx.setColumn(i,-1);}\
tone(buzzer, 640);
delay(400);
noTone(buzzer);
delay(400);
if(level!=-1){levelend();Serial.print("Level "); Serial.println(level + 1);};
}
mx.setPoint(static_cast<int>(y+0.5),static_cast<int>(x),true);
mx.update();
delay(50);
noTone(buzzer);
}