Compare commits
3 Commits
master
...
spacemania
Author | SHA1 | Date | |
---|---|---|---|
a04954f57c | |||
d06f9986cb | |||
6ba29bb77c |
31
README.md
31
README.md
@ -1,5 +1,28 @@
|
||||
# Arduboy
|
||||
This is a repository for my projects with the Arduboy, a tiny arduino based gaming handheld.
|
||||
You can browse different projects by browsing through the branches.
|
||||
# Spacemania 2000
|
||||
This is the shooter game from the book HTML5 Games: Novice to Ninja by Sitepoint.
|
||||
[You can find the book here.](https://www.sitepoint.com/premium/books/html5-games-novice-to-ninja)
|
||||
|
||||
Screenshots and other info will be hosted on [ARNweb](https://arnweb.nl/projects/arduboy/ "Arduboy projects")
|
||||
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.
|
||||
|
||||
## 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
Normal file
303
arduboyTest.ino
Normal file
@ -0,0 +1,303 @@
|
||||
// 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
Normal file
BIN
data/baddie.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 248 B |
BIN
data/bullet.png
Normal file
BIN
data/bullet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 183 B |
BIN
data/gameover.png
Normal file
BIN
data/gameover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 473 B |
BIN
data/spaceship.png
Normal file
BIN
data/spaceship.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 271 B |
BIN
data/titlescreen.png
Normal file
BIN
data/titlescreen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 538 B |
Loading…
Reference in New Issue
Block a user