Skip to content

Instantly share code, notes, and snippets.

@TheV360
Created April 10, 2018 02:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheV360/39d4b0baa9ee9c378334aed433c6beef to your computer and use it in GitHub Desktop.
Save TheV360/39d4b0baa9ee9c378334aed433c6beef to your computer and use it in GitHub Desktop.
A small Arduboy platformer I was working on a while ago, may return some day, but for now, have this spaghetti code.
// Platformer
// By V360 (@TheV360gameDev)
//TODO: Pressing up shows how many keys you have and cuts off the map renderer to save CPU (except for dark mode)
// UI overhaul (more than the title screen!)
// Level titles
#include <Arduboy2.h>
#include <ArduboyTones.h>
Arduboy2 arduboy;
ArduboyTones sound(arduboy.audio.enabled);
#define ARDBITMAP_SBUF arduboy.getBuffer()
#include <ArdBitmap.h>
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
#define LVLWIDTH 32
#define LVLHEIGHT 16
#define LVLNUMBER 3
#define COLSTEP 4
#define TILEBLOCK 1
#define TILEEXIT 2
#define TILEMINE 3
#define TILEWATERS 4
#define TILEWATER 5
#define TILEKEY 6
#define TILELOCKBLOCK 7
#define TILELCONVEYOR 8
#define TILERCONVEYOR 9
#define TILEORB 10
#define TILESPRING 11
#define TILESWITCH 12
#define TILESWITCHBLOCKOFF 13
#define TILESWITCHBLOCKON 14
#define TILEPLAYER 15
byte state = 0;
const unsigned char titleTitle[] PROGMEM = {
0x7d,0x8f,0xbb,0x6b,0x6b,0xb5,0xda,0x91,0x9c,0x3a,0x66,0xb3,0x73,0x52,0x2f,0x92,
0x4b,0x8e,0x92,0x3d,0xe8,0xf6,0x2a,0x5d,0x0b,0x89,0x2a,0xd4,0x29,0x5e,0xd4,0xcb,
0x78,0xba,0x4e,0xe8,0xc5,0xeb,0x3a,0xa1,0x97,0x71,0x43,0x2f,0xe3,0xca,0x51,0xbc,
0xa8,0x97,0x71,0xcd,0x25,0x70,0x52,0xff,0xd8,0xf3,0x80,0x1d,0xa2,0x3d,0xc0,0x10,
0x00,0x81,0x70,0x1a,0x02,0x05,0xf1,0xc0,0x19,0x90,0x0c,0x84,0x23,0x70,0x93,0x21,
0x41,0x18,0xdb,0x1d,0x28,0x8c,0x52,0x2e,0x94,0x0b,0x65,0x05,0x0a,0xa3,0x94,0x11,
0x29,0x54,0xa1,0x48,0x02,0x85,0x51,0xca,0x52,0x0a,0x03,0x61,0x39,0xd5,0xb5,0x32,
0x0f,0x5c,0x28,0x4e,0x28,0x58,0xa1,0xa0,0x91,0x12,0x07,0x85,0x50,0x28,0x65,0x50,
0x2e,0x14,0x42,0xa1,0x94,0x41,0x21,0x14,0x4a,0x19,0x14,0x42,0xa1,0x94,0x41,0x71,
0x42,0x41,0x44,0x28,0x88,0x08,0x65,0x05,0x0a,0xa3,0x94,0x0b,0xe5,0x42,0xb9,0x50,
0x2e,0x94,0x0b,0xe5,0x42,0xb9,0x50,0x2e,0x94,0x0b,0xe5,0x42,0xb9,0x50,0x2e,0x94,
0x0b,0xe5,0x42,0xb9,0x50,0x2e,0x74,0x0d,0x0a,0x05,0x80,0x82,0x30,0x28,0x91,0x40,
0x89,0x83,0x72,0xa1,0x18,0x85,0x62,0x06,0x05,0x0a,0x40,0xa1,0x83,0x42,0x01,0xa0,
0x90,0x45,0xa1,0x01,0x0a,0x05
};
const unsigned char titlePlay[] PROGMEM = {
0x1f,0x9f,0xbf,0x8b,0xab,0xf7,0x3d,0x30,0x80,0x89,0x7b,0x20,0x5c,0xc0,0x3d,0x30,
0x80,0x03,0x77,0x22,0x69,0xe2,0x7c,0x90,0x56,0xe4,0x06,0x5c,0xd5,0x8b,0x27,0xcf,
0xc9,0xf8,0x33,0x41,0x26,0x9b,0xc5,0x64,0xb3,0xd8,0x0c,0x2e,0x94,0x4b,0x7e,0x47,
0x0f,0xe3,0xc8,0xbb,0xc3,0x72,0xb9,0x5c,0x2e,0xd7,0x8b,0xe5,0x72,0xb9,0x5c,0xae,
0x17,0xcb,0xe5,0x72,0xb9,0x5c,0x87,0x7d,0xce,0x69,0x16,0x8f
};
const unsigned char titleEdit[] PROGMEM = {
0x1f,0x9f,0x97,0x2c,0x36,0xaf,0xd8,0xac,0x7c,0x72,0x0f,0x04,0x00,0x09,0xb8,0x07,
0x42,0x48,0x74,0x13,0x90,0x21,0x01,0x37,0x43,0x86,0x0c,0xe7,0x31,0x72,0xe1,0x0d,
0x17,0xcc,0xe0,0xea,0x11,0xfc,0x33,0x72,0x08,0xb6,0x47,0xe4,0x46,0x28,0x04,0x6a,
0x0f,0xcb,0xe5,0x72,0xb9,0x5c,0x87,0x9d,0xd3,0xb8,0xac,0x93,0xfb,0xb0,0x5c,0x2e,
0x97,0xcb,0xf5,0x62,0xb9,0x5c,0x2e,0x97,0xeb,0xc5,0x72,0xb9,0x5c,0x2e,0xd7,0xe1,
0xcc,0xe1,0x7a,0xe0,0x0c
};
const unsigned char titleThanks[] PROGMEM = {
0x1f,0x9f,0x1f,0xde,0x0c,0x19,0x32,0xdc,0x03,0x43,0x07,0xee,0x81,0x01,0x1c,0xb8,
0x07,0x0e,0x52,0xdc,0x03,0x43,0x45,0xdc,0x01,0x04,0x00,0x21,0x38,0x37,0xb1,0x86,
0x0b,0xa0,0x02,0x05,0x54,0x60,0xa1,0x02,0x05,0x64,0x50,0xce,0x5c,0x28,0x17,0xca,
0x85,0x5f,0x8a,0xaa,0xca,0x01,0x00,0x0c,0x20,0x41,0x00,0x40,0x00,0x40,0x82,0x00,
0x08,0x00,0x08,0xc0,0x11,0x40,0xd8,0x40,0x81,0xcd,0x17,0x39,0xf6,0x98,0x5b,0x5e,
0x79,0xe7,0xc6,0x0b,0xfe,0x16,0x6b,0x9e,0xc6,0xe1,0x22
};
// 64 bytes
const unsigned char tiles[16][4] PROGMEM = {
{B0101,B0010,B0101,B0000}, // Nothing
{B1111,B1001,B1001,B1111}, // Block
{B1110,B1111,B1011,B1110}, // Exit door
{B1001,B0110,B0110,B1001}, // Mine
{B0100,B0010,B0100,B0010}, // Water surface
{B1010,B0000,B0101,B0000}, // Water
{B0000,B0110,B0110,B0000}, // Key
{B1111,B1011,B1101,B1111}, // Locked block
{B1111,B1011,B0101,B1111}, // Left conveyor
{B1111,B0101,B1011,B1111}, // Right conveyor
{B0110,B1111,B1101,B0110}, // Gravity Orb
{B1001,B1111,B1111,B1001}, // Spring
{B1100,B1000,B1000,B1100}, // Toggle switch
{B0101,B1000,B0001,B1010}, // Off switch block
{B0111,B1001,B1001,B1110}, // On switch block
{B1111,B1101,B1111,B1101} // Player
};
const unsigned char arrow[4] PROGMEM = {
B0010,B0110,B0110,B0010
};
const unsigned char tileInfo[2] PROGMEM = {
B10000010,
B01000011
};
// 257 bytes per level, but this doesn't matter because it's in PROGMEM
const unsigned char levels[LVLNUMBER][257] PROGMEM = {
{
B00000000,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x01,0x14,0x44,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x01,0x11,0x15,0x55,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0xF0,0x00,0x01,0x11,0x11,0x15,0x55,0x51,0x00,0x00,0x00,0x00,0x00,0x02,0x01,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11
},
{
B00000000,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x01,0x14,0x44,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x01,0x11,0x15,0x55,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0xF0,0x00,0x01,0x11,0x11,0x15,0x55,0x51,0x00,0x00,0x00,0x00,0x00,0x02,0x01,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11
},
{
B00000000,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x11,0x11,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0x00,0x00,0x00,0x00,0x01,0x11,0x51,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x51,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x51,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x30,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x18,0x88,0x99,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x10,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x41,
0x10,0x10,0x00,0x00,0x11,0x11,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x05,0x51,
0x10,0x00,0x00,0x11,0x31,0x10,0x00,0x10,0x00,0x00,0xED,0x00,0x00,0x00,0x05,0x51,
0x11,0xF0,0x11,0x11,0x00,0x00,0x00,0xC0,0x0A,0x00,0xDE,0x00,0x20,0x00,0x05,0x51,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x77,0x11,0x11
}
};
// ugh, this reminds me of my early petit computer days with my awful programming
// but this is apparently how it's done?
const unsigned char title0[] PROGMEM = "Welcome";
const unsigned char title1[] PROGMEM = "Locked door";
const unsigned char title2[] PROGMEM = "test";
const unsigned char* const levelTitles[] PROGMEM = {
title0,title1,title2
};
const unsigned char mode0[] PROGMEM = "Flip mode";
const unsigned char mode1[] PROGMEM = "Dark mode";
const unsigned char mode2[] PROGMEM = "L Wind mode";
const unsigned char mode3[] PROGMEM = "R Wind mode";
const unsigned char mode4[] PROGMEM = "Switch mode";
const unsigned char mode5[] PROGMEM = "Water mode";
const unsigned char mode6[] PROGMEM = "Volatile mode";
const unsigned char mode7[] PROGMEM = "Void mode";
const unsigned char* const modeTitles[] PROGMEM = {
mode0,mode1,mode2,mode3,mode4,mode5,mode6,mode7
};
char textBuffer[22];
// 512 bytes for an unsquished level
unsigned char tileMap[32][16];
// All the stuff needed for the platforming
float x = 0;
float y = 0;
float ax = 0;
float ay = 0;
bool gr = false;
bool dead = false;
unsigned char levelModes = 0;
/*
* Level modes:
* b0: *flip mode, flips gravity instead of jumping
* b1: *dark mode, can't see more than a 3 tile radius around you
* b2: *left conveyor mode, constantly moving left
* b3: *right conveyor mode, idk lol
* b4: *switch mode, when you jump, the switch tiles toggle
* b5: *water mode, water pulls you down when gravity is flipped
* b6: *volatile mode, don't fall too fast!
* b7: *void mode: don't render the normal solid block (challenging!)
*/
int flip = 1;
unsigned char timer;
// Stuff for tiles that do things
unsigned char touchedTileL;
unsigned char touchedTileM;
unsigned char touchedTileR;
unsigned char prevX;
unsigned char prevY;
int keys; // for those people that will fill the level with coins... >:( i would put a limit but that would just mean more wasted space
// Menu variables!
unsigned char sel;
unsigned char currMap;
bool showDebug = false;
// Editor variables!
bool editor = false;
bool switched = false;
bool placedPlayer = false;
unsigned char cursorX;
unsigned char cursorY;
unsigned char cursorT;
void setup() {
// This stuff will run once!
//Start your Arduboys...
arduboy.begin();
arduboy.setFrameRate(60); //60 fps
//Serial.begin(9600);
}
void loop() {
// I don't want to go on without waiting a frame first!
if (!(arduboy.nextFrame()))
return;
arduboy.pollButtons();
arduboy.clear();
// State zero is the title screen!
// State one is the level select!
// State two is the game,
// three is the pause screen,
// four is the level editor,
// five is the editor menu,
// six is the mode select menu,
// and seven is the credits!
switch (state) {
case 0:
ardbitmap.drawCompressed(1,0,titleTitle,WHITE,ALIGN_NONE,MIRROR_NONE);
if (arduboy.justPressed(LEFT_BUTTON) && sel > 0) {
sel--;
}
if (arduboy.justPressed(RIGHT_BUTTON) && sel < 2) {
sel++;
}
arduboy.fillRect(10 + (39 * sel),22,32,32,WHITE);
for (byte i = 0; i < 3; i++) {
arduboy.drawRect(8 + (39 * i),20,36,36);
}
ardbitmap.drawCompressed(10,22,titlePlay ,WHITE * (sel != 0),ALIGN_NONE,MIRROR_NONE);
ardbitmap.drawCompressed(49,22,titleEdit ,WHITE * (sel != 1),ALIGN_NONE,MIRROR_NONE);
ardbitmap.drawCompressed(88,22,titleThanks,WHITE * (sel != 2),ALIGN_NONE,MIRROR_NONE); // dangit
if (arduboy.justReleased(A_BUTTON)) {
if (sel == 0) {
state = 2;
editor = false;
loadMap(currMap);
}
if (sel == 1) {
state = 4;
editor = true;
fixMap();
}
if (sel == 2) {
state = 7;
}
}
break;
case 2:
// First, logic...
if (arduboy.pressed(LEFT_BUTTON)) {
ax -= .4;
}
if (arduboy.pressed(RIGHT_BUTTON)) {
ax += .4;
}
if (arduboy.justPressed(A_BUTTON) && gr) {
if (bitRead(levelModes,0)) {
flip = -flip;
sound.tone(NOTE_C5,24);
} else {
if (bitRead(levelModes,6)) {
ay = -2 * flip;
} else {
ay = -3 * flip;
}
if (bitRead(levelModes,4))
useSwitch();
sound.tone(NOTE_F4,24);
}
}
if (arduboy.justReleased(B_BUTTON)) {
state = 3;
sound.tone(NOTE_F4,32,NOTE_F5,32);
}
ax *= .7;
ay = ((ay + (.2 * flip)) * .9);
gr = false;
for (byte col = 0; col < COLSTEP; col++) { // Collisions and special blocks
if (!isTileSolid(x,y)) {
prevX = floor(x / 4);
prevY = floor(y / 4);
x = modFloat(x + (ax / COLSTEP),128.0);
y = modFloat(y + (ay / COLSTEP), 64.0);
// Locked blocks (have to put this here)
if (keys > 0) { // this is a mess, why did i write this
if (pixelTile(x - 2,y) == TILELOCKBLOCK) {
keys -= 1;
tileMap[(byte)floor((x - 2) / 4)][(byte)floor(y / 4)] = TILELOCKBLOCK << 4;
sound.tone(NOTE_C6,16,NOTE_C5,16);
}
if (pixelTile(x + 2,y) == TILELOCKBLOCK) {
keys -= 1;
tileMap[(byte)floor((x + 2) / 4)][(byte)floor(y / 4)] = TILELOCKBLOCK << 4;
sound.tone(NOTE_C6,16,NOTE_C5,16);
}
if (pixelTile(x,y - 2) == TILELOCKBLOCK) {
keys -= 1;
tileMap[(byte)floor(x / 4)][(byte)floor((y - 2) / 4)] = TILELOCKBLOCK << 4;
sound.tone(NOTE_C6,16,NOTE_C5,16);
}
if (pixelTile(x,y + 2) == TILELOCKBLOCK) {
keys -= 1;
tileMap[(byte)floor(x / 4)][(byte)floor((y + 2) / 4)] = TILELOCKBLOCK << 4;
sound.tone(NOTE_C6,16,NOTE_C5,16);
}
}
// Spring
if ((pixelTile(x - 2,y) == TILESPRING || pixelTile(x + 2,y) == TILESPRING) && (prevX != floor(x / 4) || prevY != floor(y / 4))) {
if (abs(ay) > 1) {
ay = -ay * 2.5;
sound.tone(NOTE_C6,16,NOTE_C5,16);
}
}
// Too fast?
if ((abs(ay) > 1.62) && bitRead(levelModes,6)) {
dead = true;
}
// Collisions
// Ceiling
if (isTileSolid(x - 1,y - 2) || isTileSolid(x + 1,y - 2)) {
ay = 0;
y = ( ceil(y / 4) * 4) - 2;
gr = flip < 0;
}
// Floor
if (isTileSolid(x - 1,y + 2) || isTileSolid(x + 1,y + 2)) {
ay = 0;
y = (floor(y / 4) * 4) + 2;
gr = flip > 0;
}
// Walls
if (isTileSolid(x - 2,y - 1) || isTileSolid(x - 2,y + 1)) {
ax = 0;
x = ( ceil(x / 4) * 4) - 2;
}
if (isTileSolid(x + 2,y - 1) || isTileSolid(x + 2,y + 1)) {
ax = 0;
x = (floor(x / 4) * 4) + 2;
}
// Special blocks
touchedTileL = pixelTile(x - 2,y);
touchedTileM = pixelTile(x,y);
touchedTileR = pixelTile(x + 2,y);
// Water
if ((touchedTileL == TILEWATERS) || (touchedTileR == TILEWATERS)) {
ay += .05 * (float)((bitRead(levelModes,5) * 2) - 1);
gr = true;
}
if ((touchedTileL == TILEWATER) || (touchedTileR == TILEWATER)) {
ay += .07 * (float)((bitRead(levelModes,5) * 2) - 1);
gr = true;
}
// Mine
if ((touchedTileL == TILEMINE) || (touchedTileR == TILEMINE)) {
dead = true;
}
// Conveyors
if ((pixelTile(x,y + 2) == TILELCONVEYOR) || (pixelTile(x,y - 2) == TILELCONVEYOR)) {
ax -= .05;
}
if ((pixelTile(x,y + 2) == TILERCONVEYOR) || (pixelTile(x,y - 2) == TILERCONVEYOR)) {
ax += .05;
}
// Wind
if (bitRead(levelModes,2)) {
ax -= .05;
}
if (bitRead(levelModes,3)) {
ax += .05;
}
// Orb
if (touchedTileL == TILEORB) {
flip = -flip;
tileMap[(byte)floor((x - 2) / 4)][(byte)floor(y / 4)] = TILEORB << 4;
sound.tone(NOTE_F4,16,NOTE_C5,16,NOTE_F5,16);
}
if (touchedTileR == TILEORB) {
flip = -flip;
tileMap[(byte)floor((x + 2) / 4)][(byte)floor(y / 4)] = TILEORB << 4;
sound.tone(NOTE_F4,16,NOTE_C5,16,NOTE_F5,16);
}
// Key
if (touchedTileL == TILEKEY) {
keys += 1;
tileMap[(byte)floor((x - 2) / 4)][(byte)floor(y / 4)] = TILEKEY << 4;
sound.tone(NOTE_C5,16,NOTE_C6,16);
}
if (touchedTileR == TILEKEY) {
keys += 1;
tileMap[(byte)floor((x + 2) / 4)][(byte)floor(y / 4)] = TILEKEY << 4;
sound.tone(NOTE_C5,16,NOTE_C6,16);
}
// Switch
if (touchedTileM == TILESWITCH && (prevX != floor(x / 4) || prevY != floor(y / 4))) {
useSwitch();
sound.tone(NOTE_C5,16,NOTE_E5,16);
}
// Dead
if (dead) {
dead = false;
if (editor) {
fixMap();
loadMap(0);
} else {
loadMap(currMap);
}
sound.tone(NOTE_F5,16,NOTE_D4,16);
}
// Exit
if ((touchedTileL == TILEEXIT) || (touchedTileR == TILEEXIT)) {
if (editor) {
fixMap();
state = 4;
} else {
currMap += 1;
loadMap(currMap);
}
sound.tone(NOTE_C3,32,NOTE_C4,32,NOTE_C5,32);
}
}
}
// Now draw!
if (bitRead(levelModes,1)) {
drawMap(floor(x / 4) + 29,floor(y / 4) + 13,7,7);
} else {
drawMap(0,0,32,16);
}
arduboy.drawBitmap(x - 2,y - 2,tiles[TILEPLAYER],4,4);
if (timer > 0) {
arduboy.setCursor(0,0);
arduboy.println(strcpy_P(textBuffer, (char*)pgm_read_word(&(levelTitles[currMap]))));
timer--;
}
break;
case 3:
sel = 0;
arduboy.setCursor(0,0);
arduboy.println(F("Paused"));
arduboy.print(F("Keys: "));
arduboy.println(keys);
arduboy.println(F("A: Menu"));
arduboy.println(F("B: Back"));
if (arduboy.justReleased(A_BUTTON)) {
if (editor) {
fixMap();
state = 4;
} else {
state = 0;
}
}
if (arduboy.justReleased(B_BUTTON)) {
state = 2;
}
break;
case 4:
if (arduboy.justPressed(UP_BUTTON)) {
cursorY--;
}
if (arduboy.justPressed(DOWN_BUTTON)) {
cursorY++;
}
if (arduboy.justPressed(LEFT_BUTTON)) {
cursorX--;
}
if (arduboy.justPressed(RIGHT_BUTTON)) {
cursorX++;
}
cursorX %= 32;
cursorY %= 16;
if (arduboy.pressed(A_BUTTON) && cursorT != TILEPLAYER) {
if (tileMap[cursorX][cursorY] == TILEPLAYER) {
placedPlayer = false;
}
tileMap[cursorX][cursorY] = cursorT;
} else if (arduboy.justReleased(A_BUTTON) && cursorT == TILEPLAYER) {
tileMap[cursorX][cursorY] = cursorT;
if (!placedPlayer) {
placedPlayer = true;
cursorT = 1;
}
}
if (arduboy.justReleased(B_BUTTON)) {
state = 5;
}
drawMap(0,0,32,16);
if (timer < 10) {
arduboy.drawBitmap(cursorX*4,cursorY*4,tiles[cursorT],4,4,INVERT);
} else {
arduboy.drawBitmap(cursorX*4,cursorY*4,tiles[cursorT],4,4,WHITE);
}
timer = (timer + 1) % 20;
break;
case 5:
arduboy.setCursor(0,0);
arduboy.println(F("Select tile"));
if (placedPlayer)
arduboy.println(F("Player placed!"));
arduboy.drawBitmap(cursorT*6,52,arrow,4,4);
for (byte i = 0; i < (16 - (byte)placedPlayer); i++) {
arduboy.drawBitmap(i*6,58,tiles[i],4,4);
}
if (arduboy.justPressed(LEFT_BUTTON)) {
cursorT--;
}
if (arduboy.justPressed(RIGHT_BUTTON)) {
cursorT++;
}
cursorT %= 16 - (byte)placedPlayer;
if (arduboy.justReleased(A_BUTTON) && placedPlayer) {
state = 2;
if (showDebug)
outputMap();
loadMap(0); // dont need id
}
if (arduboy.justReleased(B_BUTTON)) {
state = 4;
}
if (arduboy.justReleased(UP_BUTTON)) {
state = 0;
}
if (arduboy.justReleased(DOWN_BUTTON)) {
/*for (byte j = 0; j < LVLHEIGHT; j++) {
for (byte i = 0; i < LVLWIDTH; i++) {
tileMap[i][j] = 0;
}
}
placedPlayer = false;*/
sel = 0;
state = 6;
}
break;
case 6:
arduboy.setCursor(0,0);
arduboy.println(F("Select mode"));
arduboy.println(strcpy_P(textBuffer, (char*)pgm_read_word(&(modeTitles[sel]))));
arduboy.drawBitmap(sel * 6,52,arrow,4,4);
for (byte i = 0; i < 8; i++) {
arduboy.drawBitmap(i * 6,58,tiles[3 - (bitRead(levelModes,i) * 2)],4,4);
}
if (arduboy.justPressed(LEFT_BUTTON)) {
sel--;
}
if (arduboy.justPressed(RIGHT_BUTTON)) {
sel++;
}
sel %= 8;
if (arduboy.justReleased(A_BUTTON)) {
bitWrite(levelModes,sel,!bitRead(levelModes,sel));
}
if (arduboy.justReleased(B_BUTTON)) {
sel = 0;
state = 5;
}
break;
case 7:
arduboy.setCursor(0,0);
arduboy.println(F("~thanks for playing~"));
arduboy.println(F("Thanks to Nathan,"));
arduboy.println(F("Arduboy forum,"));
arduboy.println(F("and you!"));
if (arduboy.justReleased(A_BUTTON)) {
state = 0;
}
break;
default:
arduboy.setCursor(0,0);
arduboy.println(F("whoops"));
arduboy.println(F("there's no state here!"));
break;
}
if (arduboy.pressed(UP_BUTTON) && arduboy.justPressed(DOWN_BUTTON)) {
showDebug = !showDebug;
}
if (showDebug) {
arduboy.setCursor(0,50 * ((byte)floor(y / 4) < 8));
arduboy.print(arduboy.cpuLoad());
}
arduboy.display(); // Actually make the stuff I drew visible
}
bool isTileSolid(byte x, byte y) {
return isSolid(pixelTile(x,y));
}
byte pixelTile(byte x, byte y) {
return tileMap[(byte)floor(x / 4) % 32][(byte)floor(y / 4) % 16] & 15;
}
bool isSolid(byte tileID) {
return (bool)bitRead(pgm_read_byte(&(tileInfo[(byte)floor(tileID / 8)])),tileID % 8);
}
void loadMap(byte mapIndex) {
keys = 0;
ax = 0;
ay = 0;
flip = 1;
timer = 120 * (byte)!editor;
switched = false;
if (mapIndex >= LVLNUMBER) {
mapIndex = 0;
state = 7;
}
if (!editor)
levelModes = pgm_read_byte(&(levels[mapIndex][0]));
for (byte j = 0; j < LVLHEIGHT; j++) {
for (byte i = 0; i < LVLWIDTH; i++) {
if (!editor) {
if (i % 2 == 0) {
tileMap[i][j] = pgm_read_byte(&(levels[mapIndex][1 + (i / 2) + (j * 16)])) >> 4;
} else {
tileMap[i][j] = pgm_read_byte(&(levels[mapIndex][1 + (i / 2) + (j * 16)])) & 15;
}
}
if (tileMap[i][j] == TILEPLAYER) {
x = (i*4)+2;
y = (j*4)+2;
tileMap[i][j] = TILEPLAYER << 4;
placedPlayer = true;
}
}
}
}
void drawMap(byte x,byte y,byte w,byte h) {
for (byte j = y; j < y + h; j++) {
for (byte i = x; i < x + w; i++) {
if ((tileMap[i % 32][j % 16] & 15) > (bitRead(levelModes,7) * (state == 2))) {
arduboy.drawBitmap((i % 32)*4,(j % 16)*4,tiles[tileMap[i % 32][j % 16] & 15],4,4);
}
}
}
}
void fixMap() {
for (byte j = 0; j < LVLHEIGHT; j++) {
for (byte i = 0; i < LVLWIDTH; i++) {
if ((tileMap[i][j] >> 4) > 0) {
tileMap[i][j] = tileMap[i][j] >> 4;
}
if ((tileMap[i][j] == TILESWITCHBLOCKOFF || tileMap[i][j] == TILESWITCHBLOCKON) && switched) {
useSwitch();
switched = false;
}
}
}
}
void outputMap() {
/* Serial.print("{\n");
for (byte j = 0; j < LVLHEIGHT; j++) {
for (byte i = 0; i < LVLWIDTH; i+=2) {
Serial.print("0x");
Serial.print(tileMap[i][j],HEX);
Serial.print(tileMap[i+1][j],HEX);
Serial.print(",");
}
Serial.print("\n");
}
Serial.print("};");*/
}
void useSwitch() {
for (byte j = 0; j < LVLHEIGHT; j++) {
for (byte i = 0; i < LVLWIDTH; i++) {
if (tileMap[i][j] == TILESWITCHBLOCKOFF) {
tileMap[i][j] = TILESWITCHBLOCKON;
} else if (tileMap[i][j] == TILESWITCHBLOCKON) {
tileMap[i][j] = TILESWITCHBLOCKOFF;
}
}
}
switched = !switched;
}
float modFloat(float n, float m) {
while (n < 0) {
n += m;
}
while (n >= m) {
n -= m;
}
return n;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment