forked from Michel2/LoLshield
315 lines
8.4 KiB
Arduino
315 lines
8.4 KiB
Arduino
/*
|
|
Space Invader, a shoot-them-up game for LOL Shield for Arduino
|
|
Copyright 2009/2010 Benjamin Sonntag <benjamin@sonntag.fr> http://benjamin.sonntag.fr/
|
|
|
|
History:
|
|
2009-12-30 - V0.0 Initial code at Berlin during 26C3
|
|
2009-12-31 - V1.0 Score Drawing, at Berlin after 26C3 ;)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "Charliplexing.h"
|
|
#include "Figure.h"
|
|
#include "Font.h"
|
|
|
|
#if defined(ARDUINO) && ARDUINO >= 100
|
|
#include "Arduino.h"
|
|
#else
|
|
#include "WProgram.h"
|
|
#endif
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/* ----------------------------------------------------------------- */
|
|
/* SPACE INVADER CODE !!! */
|
|
/* ----------------------------------------------------------------- */
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
|
|
// Number of fire we can use before having to wait
|
|
#define MAXFIRE 3
|
|
// Number of lives you have :
|
|
#define STARTLIVES 4
|
|
// Maximum number of ennemies at one :
|
|
#define MAXENNEMIES 8
|
|
// Speed of ennemies arrival : (between 0 & 20, 20 = rare, 0 = often )
|
|
#define ENNEMIESRATE 6
|
|
|
|
|
|
/** The score of the user (number of points = speed of each killed ennemy - number of ennemies missed) */
|
|
int score=0;
|
|
/** Position of the ship between 1 & 7 */
|
|
byte shippos=4;
|
|
/** Number of lives of the user */
|
|
byte lives;
|
|
|
|
/** Position of the bullets of the ship, [0]=x [1]=y */
|
|
byte firepos[9][2]={
|
|
{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}
|
|
};
|
|
/** Position and speed of the ennemies [0]=x [1]=y [2]=speed [3]=speed counter */
|
|
byte ennemypos[8][4]={
|
|
{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}
|
|
};
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Draw the ship at its current position.
|
|
* @param set 1 or 0 to set or clear the led.
|
|
*/
|
|
void drawShip(uint8_t c=1) {
|
|
LedSign::Set(0,shippos-1,c);
|
|
LedSign::Set(0,shippos ,c);
|
|
LedSign::Set(0,shippos+1,c);
|
|
LedSign::Set(1,shippos ,c);
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Draw the number of lives remaining at the top left of the screen
|
|
*/
|
|
void drawLives() {
|
|
for(byte i=0;i<STARTLIVES;i++) {
|
|
LedSign::Set(13-i,0,(i<lives)?1:0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** end of the game, draw the Scores using a scrolling
|
|
*/
|
|
void endGame() {
|
|
for(byte x=4;x<=8;x++)
|
|
for(byte y=0;y<=8;y++)
|
|
LedSign::Set(x,y,0);
|
|
|
|
Figure::Scroll90(score);
|
|
|
|
for(byte i=0;i<30;i++) {
|
|
drawShip(0);
|
|
delay(5*(30-i));
|
|
drawShip(0);
|
|
delay(5*(30-i));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Initialize a new game (lives, screen, score, ship ...)
|
|
*/
|
|
void initGame() {
|
|
lives=STARTLIVES;
|
|
score=0;
|
|
shippos=4;
|
|
LedSign::Clear();
|
|
drawLives();
|
|
drawShip();
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Check the variator to know the position of the ship.
|
|
* Move and redraw the ship in case of change.
|
|
*/
|
|
void moveShip()
|
|
{
|
|
// Ship have 7 positions. Let's use a third of the variator position.
|
|
int newshpos=7-(analogRead(5)/72); // we reverse the command (variator wrongly connected ;) )
|
|
if (newshpos>7) newshpos=7;
|
|
if (newshpos<1) newshpos=1;
|
|
if (newshpos!=shippos) {
|
|
drawShip(0);
|
|
for(byte i=0;i<8;i++)
|
|
LedSign::Set(0,i,0);
|
|
shippos=newshpos;
|
|
drawShip(1);
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Check the fire button and fire if it has been pushed.
|
|
* Please note that we use a static status to check that the user
|
|
* pull the button between each fire.
|
|
*/
|
|
void fireShip()
|
|
{
|
|
static byte status=0;
|
|
if (status==0) {
|
|
// Ship may fire 10 times (not more...)
|
|
if (analogRead(4)>1000) {
|
|
// FIRE !
|
|
status=1;
|
|
for(byte i=0;i<MAXFIRE;i++) {
|
|
if (firepos[i][0]==0) {
|
|
firepos[i][0]=2; firepos[i][1]=shippos;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (analogRead(4)<1000) status=0;
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Crash : called when an ennemy touched the ship (failure!)
|
|
*/
|
|
void crash() {
|
|
drawShip(1);
|
|
delay(150);
|
|
drawShip(0);
|
|
delay(150);
|
|
drawShip(1);
|
|
delay(150);
|
|
drawShip(0);
|
|
delay(150);
|
|
|
|
for(byte i=0;i<MAXENNEMIES;i++)
|
|
if (ennemypos[i][0]!=0) {
|
|
LedSign::Set(ennemypos[i][0],ennemypos[i][1],0);
|
|
ennemypos[i][0]=0;
|
|
}
|
|
for(byte i=0;i<MAXFIRE;i++)
|
|
firepos[i][0]=0;
|
|
|
|
lives--;
|
|
if (lives==0) {
|
|
endGame();
|
|
initGame();
|
|
} else {
|
|
LedSign::Clear();
|
|
drawLives();
|
|
drawShip();
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Add ennemies at the top randomly, with random speed too
|
|
*/
|
|
void addEnnemies()
|
|
{
|
|
if (random(0,ENNEMIESRATE)==0) {
|
|
// ENNEMY COMING !
|
|
for(byte i=0;i<MAXENNEMIES;i++) {
|
|
if (ennemypos[i][0]==0) {
|
|
ennemypos[i][0]=13; ennemypos[i][1]=random(1,8);
|
|
ennemypos[i][2]=random(2,5); // Speed of ennemies between 1 and 5 (5=slower)
|
|
ennemypos[i][3]=0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Move the ennemies, and check the collision with the ship
|
|
*/
|
|
void moveEnnemies()
|
|
{
|
|
for(byte i=0;i<MAXENNEMIES;i++) {
|
|
if (ennemypos[i][0]!=0) {
|
|
ennemypos[i][3]++;
|
|
if (ennemypos[i][2]==ennemypos[i][3]) {
|
|
ennemypos[i][3]=0;
|
|
LedSign::Set(ennemypos[i][0],ennemypos[i][1],0);
|
|
ennemypos[i][0]--;
|
|
// collision with the top of the ship
|
|
if (ennemypos[i][0]==1 && shippos==ennemypos[i][1]) {
|
|
crash();
|
|
} else {
|
|
if (ennemypos[i][0]==0) { // Collision detection
|
|
ennemypos[i][0]=0;
|
|
if (score>0) score-=1;
|
|
if (shippos==ennemypos[i][1] || shippos-1==ennemypos[i][1] || shippos+1==ennemypos[i][1]) {
|
|
crash();
|
|
} else {
|
|
LedSign::Set(ennemypos[i][0],ennemypos[i][1],0);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
LedSign::Set(ennemypos[i][0],ennemypos[i][1],1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Move the bullets, draw them, and check the collision with
|
|
* ennemies.
|
|
*/
|
|
void moveFires()
|
|
{
|
|
for(byte i=0;i<MAXFIRE;i++) {
|
|
if (firepos[i][0]!=0) {
|
|
LedSign::Set(firepos[i][0],firepos[i][1],0);
|
|
firepos[i][0]++;
|
|
// Let's detect collision with ennemies :
|
|
for(byte j=0;j<MAXENNEMIES;j++) {
|
|
if (ennemypos[j][0]!=0) {
|
|
if ((ennemypos[j][0]==firepos[i][0] || ennemypos[j][0]==firepos[i][0]+1) && ennemypos[j][1]==firepos[i][1]) {
|
|
// Ennemy destroyed
|
|
LedSign::Set(ennemypos[j][0],ennemypos[j][1],0);
|
|
ennemypos[j][0]=0;
|
|
firepos[i][0]=0;
|
|
score+=(6-ennemypos[j][2]); // Change it in case of ennemy speed change ;) score is 5-speed
|
|
}
|
|
}
|
|
}
|
|
if (firepos[i][0]==14) {
|
|
firepos[i][0]=0;
|
|
} else {
|
|
LedSign::Set(firepos[i][0],firepos[i][1],1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** MAIN program Setup
|
|
*/
|
|
void setup() // run once, when the sketch starts
|
|
{
|
|
LedSign::Init();
|
|
randomSeed(analogRead(2));
|
|
|
|
initGame();
|
|
drawShip();
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** MAIN program Loop
|
|
*/
|
|
void loop() // run over and over again
|
|
{
|
|
moveShip();
|
|
fireShip();
|
|
moveFires();
|
|
moveEnnemies();
|
|
addEnnemies();
|
|
delay(100);
|
|
}
|