Compare commits
2 Commits
spacemania
...
master
Author | SHA1 | Date | |
---|---|---|---|
265714771e | |||
d01ea24148 |
31
README.md
31
README.md
@ -1,28 +1,5 @@
|
|||||||
# Spacemania 2000
|
# Arduboy
|
||||||
This is the shooter game from the book HTML5 Games: Novice to Ninja by Sitepoint.
|
This is a repository for my projects with the Arduboy, a tiny arduino based gaming handheld.
|
||||||
[You can find the book here.](https://www.sitepoint.com/premium/books/html5-games-novice-to-ninja)
|
You can browse different projects by browsing through the branches.
|
||||||
|
|
||||||
I rewrote the game in C++ because I want to learn a new programming language and this seemed to be a nice way to practice.
|
Screenshots and other info will be hosted on [ARNweb](https://arnweb.nl/projects/arduboy/ "Arduboy projects")
|
||||||
|
|
||||||
## Getting it yourself
|
|
||||||
The game is very unfinished at this point, but you can try it anyway. You'll have to compile it yourself.
|
|
||||||
### Requirements
|
|
||||||
* Arduboy, Arduboy compatible device or emulator
|
|
||||||
* Arduino IDE
|
|
||||||
* Arduboy2 library
|
|
||||||
* Computer
|
|
||||||
Start the Arduino IDE and load up arduboyTest.ino and send the game to your device.
|
|
||||||
|
|
||||||
### Controls
|
|
||||||
* A = Start, shoot and restart
|
|
||||||
* B = Spawn enemy
|
|
||||||
* D-Pad = Move
|
|
||||||
* A + B = Reset game
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
* Automatic spawning of enemies
|
|
||||||
* Pauze menu
|
|
||||||
* Different stages of difficulty
|
|
||||||
* Music
|
|
||||||
* Background image
|
|
||||||
* Cleaner code
|
|
303
arduboyTest.ino
303
arduboyTest.ino
@ -1,303 +0,0 @@
|
|||||||
// Arne van Iterson 2019
|
|
||||||
|
|
||||||
// Include all the stuff
|
|
||||||
#include <Arduboy2.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
// Setup instance of arduboy
|
|
||||||
Arduboy2 arduboy;
|
|
||||||
|
|
||||||
// Define all bitmaps
|
|
||||||
//// Spacemania 2000 titlescreen
|
|
||||||
const unsigned char PROGMEM titlescreen[] =
|
|
||||||
{
|
|
||||||
// width, height,
|
|
||||||
102, 22,
|
|
||||||
0x3f, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xf3, 0xf3, 0x00, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0x00, 0xff, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x03, 0x03, 0x03, 0x03, 0x00, 0xff, 0xff, 0x03, 0x03, 0xff, 0xff, 0x03, 0x03, 0xff, 0xff, 0x00, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0x00, 0xff, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xff, 0xff,
|
|
||||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0xf3, 0xf3, 0x03, 0xf3, 0xf3, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0xf3, 0x03, 0x03, 0xf3, 0xf3, 0x30, 0x33, 0x33, 0x30, 0x30, 0x33, 0xf3, 0x00, 0x00, 0xf3, 0xf3, 0x30, 0x33, 0x33, 0x30, 0x30, 0x30, 0xf0, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3f, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
//// Gameover screen
|
|
||||||
const unsigned char PROGMEM gameover[] =
|
|
||||||
{
|
|
||||||
// width, height,
|
|
||||||
102, 22,
|
|
||||||
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xff, 0xff, 0xc0, 0xc0, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0xfc, 0x00, 0xff, 0xff, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0x30, 0x30, 0xc0, 0xc0, 0x30, 0x30, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xff, 0xff, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x3c, 0xcf, 0xcf, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
//// Player spaceship
|
|
||||||
const unsigned char PROGMEM spaceship[] =
|
|
||||||
{
|
|
||||||
// width, height,
|
|
||||||
16, 16,
|
|
||||||
0x00, 0xfe, 0xfc, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0x80, 0xfe, 0x80, 0xfc, 0x80, 0xf0, 0x80, 0x00,
|
|
||||||
0x00, 0x43, 0x6f, 0x77, 0x7b, 0x3d, 0x5f, 0x6f, 0x77, 0x7b, 0x3d, 0x3f, 0x1f, 0x0f, 0x03, 0x00,
|
|
||||||
};
|
|
||||||
//// Player bullets
|
|
||||||
const unsigned char PROGMEM bullet[] =
|
|
||||||
{
|
|
||||||
// width, height,
|
|
||||||
8, 8,
|
|
||||||
0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c, 0x00,
|
|
||||||
};
|
|
||||||
//// Enemy spaceship
|
|
||||||
const unsigned char PROGMEM baddie[] =
|
|
||||||
{
|
|
||||||
// width, height,
|
|
||||||
16, 16,
|
|
||||||
0xc0, 0xf0, 0xf8, 0xbc, 0xde, 0xce, 0xe7, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xfe, 0xf6, 0xc1,
|
|
||||||
0x03, 0x0f, 0x19, 0x3f, 0x61, 0x7f, 0xc1, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x7f, 0x6f, 0x83,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define Variables
|
|
||||||
//// System
|
|
||||||
const int screen[] = { 128, 64 };
|
|
||||||
|
|
||||||
//// Timing
|
|
||||||
float dt = 0;
|
|
||||||
|
|
||||||
//// Game Setup
|
|
||||||
const int framerate = 60;
|
|
||||||
int gamestate = 0;
|
|
||||||
bool reset = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
//// Game Variables
|
|
||||||
float playerPos[] = { 0, ((screen[1] / 2) - (spaceship[1] / 2)) };
|
|
||||||
float playerSpeed = 1;
|
|
||||||
float bulletSpeed = 1.5;
|
|
||||||
const int bulletAmount = 5;
|
|
||||||
float baddieSpeed = 0.8;
|
|
||||||
const int baddieAmount = 16;
|
|
||||||
|
|
||||||
// Setup code
|
|
||||||
void setup() {
|
|
||||||
// Random number generator
|
|
||||||
arduboy.initRandomSeed();
|
|
||||||
// Start arduboy
|
|
||||||
arduboy.begin();
|
|
||||||
// Set framerate
|
|
||||||
arduboy.setFrameRate(framerate);
|
|
||||||
// Clear screen
|
|
||||||
arduboy.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Game loop
|
|
||||||
void loop() {
|
|
||||||
// Only loop if it is time for the next frame
|
|
||||||
if (!arduboy.nextFrame())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Clear screen
|
|
||||||
arduboy.clear();
|
|
||||||
// Keep track of buttons
|
|
||||||
arduboy.pollButtons();
|
|
||||||
|
|
||||||
// Switch between gamestates
|
|
||||||
switch (gamestate)
|
|
||||||
{
|
|
||||||
//// Titlescreen
|
|
||||||
case 0:
|
|
||||||
Sprites::drawOverwrite(((screen[0] - titlescreen[0]) / 2), ((screen[0] - titlescreen[0]) / 2), titlescreen, 0);
|
|
||||||
arduboy.setCursor(16, 40);
|
|
||||||
arduboy.print("Press A to start");
|
|
||||||
arduboy.setCursor(36, 57);
|
|
||||||
arduboy.print("McArn 2019");
|
|
||||||
if (arduboy.justPressed(A_BUTTON))
|
|
||||||
{
|
|
||||||
gamestate = 1;
|
|
||||||
reset = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//// Game
|
|
||||||
case 1:
|
|
||||||
if ( arduboy.pressed(A_BUTTON) && arduboy.pressed(B_BUTTON) ) {
|
|
||||||
gamestate = 0;
|
|
||||||
}
|
|
||||||
game();
|
|
||||||
break;
|
|
||||||
|
|
||||||
//// Game over
|
|
||||||
case 2:
|
|
||||||
Sprites::drawOverwrite(((screen[0] - gameover[0]) / 2), ((screen[0] - gameover[0]) / 2), gameover, 0);
|
|
||||||
arduboy.setCursor(12, 40);
|
|
||||||
arduboy.print("Press A to restart");
|
|
||||||
if (arduboy.justPressed(A_BUTTON))
|
|
||||||
{
|
|
||||||
gamestate = 1;
|
|
||||||
reset = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Display everything
|
|
||||||
arduboy.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bullet class
|
|
||||||
class Bullet
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
float pos[2];
|
|
||||||
bool dead = true;
|
|
||||||
void update() {
|
|
||||||
if (pos[0] >= (screen[0] + bullet[0]))
|
|
||||||
{
|
|
||||||
dead = true;
|
|
||||||
pos[0] = 0 - bullet[0];
|
|
||||||
} else {
|
|
||||||
pos[0] = pos[0] + (1 * bulletSpeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Max amount of bullets = 5;
|
|
||||||
Bullet bullets[bulletAmount];
|
|
||||||
|
|
||||||
// Enemy class
|
|
||||||
class Baddie
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
float pos[2];
|
|
||||||
bool dead = true;
|
|
||||||
void update() {
|
|
||||||
if (pos[0] <= (0 - baddie[0]))
|
|
||||||
{
|
|
||||||
dead = true;
|
|
||||||
gamestate = 2;
|
|
||||||
pos[0] = screen[0] + baddie[0];
|
|
||||||
} else {
|
|
||||||
pos[0] = pos[0] - (1 * baddieSpeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Baddie baddies[baddieAmount];
|
|
||||||
|
|
||||||
void game() {
|
|
||||||
// Reset game if coming from title or gameover screen
|
|
||||||
if (reset)
|
|
||||||
{
|
|
||||||
for (i = 0; i < (baddieAmount - 1); i++)
|
|
||||||
{
|
|
||||||
baddies[i].pos[0] = screen[0] + baddie[0];
|
|
||||||
baddies[i].pos[1] = random(screen[1] - baddie[1]);
|
|
||||||
baddies[i].dead = true;
|
|
||||||
}
|
|
||||||
for (i = 0; i < (bulletAmount - 1); i++)
|
|
||||||
{
|
|
||||||
bullets[i].dead = true;
|
|
||||||
}
|
|
||||||
playerPos[0] = 0;
|
|
||||||
playerPos[1] = (screen[1] / 2) - (spaceship[1] / 2);
|
|
||||||
reset = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move Player
|
|
||||||
if ( arduboy.pressed(UP_BUTTON) && !(playerPos[1] <= 0) ) {
|
|
||||||
playerPos[1] = playerPos[1] - 1 * playerSpeed;
|
|
||||||
}
|
|
||||||
if ( arduboy.pressed(DOWN_BUTTON) && !(playerPos[1] >= (screen[1] - spaceship[1])) ) {
|
|
||||||
playerPos[1] = playerPos[1] + 1 * playerSpeed;
|
|
||||||
}
|
|
||||||
if ( arduboy.pressed(LEFT_BUTTON) && !(playerPos[0] <= 0) ) {
|
|
||||||
playerPos[0] = playerPos[0] - 1 * playerSpeed;
|
|
||||||
}
|
|
||||||
if ( arduboy.pressed(RIGHT_BUTTON) && !(playerPos[0] >= (screen[0] - spaceship[0])) ) {
|
|
||||||
playerPos[0] = playerPos[0] + 1 * playerSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn Bullet
|
|
||||||
if ( arduboy.justPressed(A_BUTTON)) {
|
|
||||||
for (i = 0; i < (bulletAmount - 1); i++)
|
|
||||||
{
|
|
||||||
if (bullets[i].dead)
|
|
||||||
{
|
|
||||||
bullets[i].pos[0] = playerPos[0];
|
|
||||||
bullets[i].pos[1] = playerPos[1] + (spaceship[1] / 2) - (bullet[1] / 2);
|
|
||||||
bullets[i].dead = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn baddie for debug
|
|
||||||
if ( arduboy.justPressed(B_BUTTON)) {
|
|
||||||
for (i = 0; i < (baddieAmount - 1); i++)
|
|
||||||
{
|
|
||||||
if (baddies[i].dead)
|
|
||||||
{
|
|
||||||
baddies[i].dead = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update and show non-dead bullets
|
|
||||||
for (i = 0; i < (bulletAmount - 1); i++)
|
|
||||||
{
|
|
||||||
if (!bullets[i].dead)
|
|
||||||
{
|
|
||||||
bullets[i].update();
|
|
||||||
Sprites::drawSelfMasked(round(bullets[i].pos[0]), round(bullets[i].pos[1]), bullet, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update and show non-dead baddies
|
|
||||||
for (i = 0; i < (baddieAmount - 1); i++)
|
|
||||||
{
|
|
||||||
if (!baddies[i].dead)
|
|
||||||
{
|
|
||||||
baddies[i].update();
|
|
||||||
Sprites::drawSelfMasked(round(baddies[i].pos[0]), round(baddies[i].pos[1]), baddie, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw player
|
|
||||||
Sprites::drawSelfMasked(round(playerPos[0]), round(playerPos[1]), spaceship, 0);
|
|
||||||
checkCollision();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables for collision detection
|
|
||||||
float distance = 0;
|
|
||||||
float difference[2];
|
|
||||||
int a;
|
|
||||||
|
|
||||||
// Check collisions
|
|
||||||
void checkCollision() {
|
|
||||||
for (i = 0; i < (baddieAmount - 1); i++)
|
|
||||||
{
|
|
||||||
// Collision baddie x bullet
|
|
||||||
for (a = 0; a < (bulletAmount - 1); a++)
|
|
||||||
{
|
|
||||||
//// Difference x
|
|
||||||
difference[0] = (baddies[i].pos[0] + (baddie[0] / 2)) - (bullets[a].pos[0] + (bullet[0] / 2));
|
|
||||||
//// Difference y
|
|
||||||
difference[1] = (baddies[i].pos[1] + (baddie[1] / 2)) - (bullets[a].pos[1] + (bullet[1] / 2));
|
|
||||||
|
|
||||||
// Calculate diffence
|
|
||||||
distance = sqrt(pow(difference[0], 2) + pow(difference[1], 2));
|
|
||||||
if (!baddies[i].dead && !bullets[a].dead && distance <= 11)
|
|
||||||
{
|
|
||||||
bullets[a].dead = true;
|
|
||||||
baddies[i].dead = true;
|
|
||||||
baddies[i].pos[0] = screen[0] + baddie[0];
|
|
||||||
baddies[i].pos[1] = random(screen[1] - baddie[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collision baddie x player
|
|
||||||
//// Difference x
|
|
||||||
difference[0] = (baddies[i].pos[0] + (baddie[0] / 2)) - (playerPos[0] + (spaceship[0] / 2));
|
|
||||||
//// Difference y
|
|
||||||
difference[1] = (baddies[i].pos[1] + (baddie[1] / 2)) - (playerPos[1] + (spaceship[1] / 2));
|
|
||||||
|
|
||||||
// Calculate diffence
|
|
||||||
distance = sqrt(pow(difference[0], 2) + pow(difference[1], 2));
|
|
||||||
if (!baddies[i].dead && distance <= 15)
|
|
||||||
{
|
|
||||||
gamestate = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
BIN
data/baddie.png
BIN
data/baddie.png
Binary file not shown.
Before Width: | Height: | Size: 248 B |
BIN
data/bullet.png
BIN
data/bullet.png
Binary file not shown.
Before Width: | Height: | Size: 183 B |
Binary file not shown.
Before Width: | Height: | Size: 473 B |
Binary file not shown.
Before Width: | Height: | Size: 271 B |
Binary file not shown.
Before Width: | Height: | Size: 538 B |
Loading…
Reference in New Issue
Block a user