Added code and data files.

This commit is contained in:
Miguel Astor
2013-08-13 13:41:57 -04:30
parent 250421bb7f
commit 42d7007a35
10 changed files with 488 additions and 1 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Ignore NXT executable files, RIC edit data and Gedit backup files.
*.rxe
*.RPA
*~

25
LICENSE
View File

@@ -0,0 +1,25 @@
A Space Invaders clone for the Mindstorms NXT.
Copyright (c) 2013, Miguel Angel Astor Romero
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*) Redistributions of source code must retain the above
copyright notice, this list of conditions and the following disclaimer.
*) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITSOR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

5
Makefile Normal file
View File

@@ -0,0 +1,5 @@
all: NXTInvaders.nxc
nbc NXTInvaders.nxc -O=NXTInvaders.rxe -sm+ -d -S=usb
clean:
rm -f NXTInvaders.rxe

449
NXTInvaders.nxc Normal file
View File

@@ -0,0 +1,449 @@
/*------------------------------------------------------------------------------
; File : NXTInvaders.nxc
; Description : A Space Invaders clone for the Mindstorms NXT.
; Programmed by : Miguel Angel Astor, sonofgrendel@gmail.com
; Version: 1.0
; Date: 8/13/2013
;-----------------------------------------------------------------------------*/
#download "ship.ric"
#download "splash.ric"
#download "invader.ric"
#download "victory.ric"
#download "defeat.ric"
#define X_MAX 99
#define Y_MAX 63
#define X_MID (X_MAX + 1) / 2
#define Y_MID (Y_MAX + 1) / 2
#define DRAW_PARAMS DRAW_OPT_NORMAL | DRAW_OPT_LOGICAL_XOR | DRAW_OPT_FILL_SHAPE
#define ALIEN_WIDTH 11
#define BASE_ALIEN_X 2
#define BASE_ALIEN_Y 32
#define ALIENS 6
/*******************
* Data structures *
*******************/
struct PLAYER_T{
int x;
int lives;
int score;
};
struct BULLET_T{
int x, y;
bool alive;
};
struct ALIEN_T{
int x, y;
bool alive;
};
/****************
* Global data. *
****************/
const int alien_update_speed[] = {50, 72, 95,
118, 140, 163,
186, 209, 231,
254, 277, 300 };
int dead_aliens;
bool victory;
// keys[0] -> Left button; keys[1] -> Right button; keys[2] -> Center button.
bool keys[3];
// State: 0 -> Splash screen; 1 -> Game; 2 -> Hall of fame screen.
int state, alien_frame, alien_x_offset;
bool alien_x_forward, done;
long then, then2;
PLAYER_T player;
BULLET_T p_bullets[3];
ALIEN_T aliens1[ALIENS];
ALIEN_T aliens2[ALIENS];
BULLET_T a_bullets1[ALIENS];
BULLET_T a_bullets2[ALIENS];
/*******************
* Game functions. *
*******************/
/**
* Catch the 3 possible player inputs.
*/
void input(){
if(ButtonPressed(BTNLEFT, false)){
keys[0] = true;
}else{
keys[0] = false;
}
if(ButtonPressed(BTNRIGHT, false)){
keys[1] = true;
}else{
keys[1] = false;
}
if(ButtonPressed(BTNCENTER, false)){
keys[2] = true;
}else{
keys[2] = false;
}
}
/**
* Processes player input, moves game objects and updates the game's state.
*/
void update(){
long now, delta_t, fire;
if(state == 0){
if(keys[2]){
state = 1;
}
}else if(state == 1){
// Move the player.
if(keys[0]){
if(player.x - 1 >= 3){
player.x -= 1;
}
}
if(keys[1]){
if(player.x + 1 <= X_MAX - 4){
player.x += 1;
}
}
// If the center button was pressed, fire a bullet.
if(keys[2]){
now = CurrentTick();
delta_t = now - then;
if(delta_t >= 500){
// One bullet every 500 miliseconds.
for(int i = 0; i < 3; i++){
if(!p_bullets[i].alive){
p_bullets[i].x = player.x;
p_bullets[i].y = 0;
p_bullets[i].alive = true;
PlayTone(262, 100);
break;
}
}
then = now;
}
}
// Update the player's bullets.
for(int i = 0; i < 3; i++){
if(p_bullets[i].alive){
p_bullets[i].y += 1;
if(p_bullets[i].y >= Y_MAX + 2){
p_bullets[i].alive = false;
}
}
}
// Update the aliens.
now = CurrentTick();
delta_t = now - then2;
if(delta_t >= alien_update_speed[11 - dead_aliens]){
// Change the frame.
if(alien_frame == 0){
alien_frame = 11;
}else{
alien_frame = 0;
}
// Move in the correct direction.
if(alien_x_forward){
alien_x_offset += 1;
if(alien_x_offset >= 15){
// Change direction 2 pixels before the edge of the screen.
alien_x_offset -= 1;
alien_x_forward = false;
}
}else{
alien_x_offset -= 1;
if(alien_x_offset <= 0){
// Change direction 2 pixels before the edge of the screen.
alien_x_offset += 1;
alien_x_forward = true;
}
}
// Fire on the player.
for(int i = 0; i < ALIENS; i++){
// First row.
if(aliens1[i].alive && !a_bullets1[i].alive){
fire = rand() % 100;
if(fire < 25){
// 0.25 probability of firing.
a_bullets1[i].alive = true;
a_bullets1[i].x = aliens1[i].x + alien_x_offset + 5;
a_bullets1[i].y = aliens1[i].y;
PlayTone(400, 100);
}
}
// Second row.
if(aliens2[i].alive && !a_bullets2[i].alive){
fire = rand() % 100;
if(fire > 75){
// 0.25 probability of firing.
a_bullets2[i].alive = true;
a_bullets2[i].x = aliens2[i].x + alien_x_offset + 5;
a_bullets2[i].y = aliens2[i].y;
PlayTone(400, 100);
}
}
}
then2 = now;
}
// Update the alien's bullets.
for(int i = 0; i < ALIENS; i++){
// First row.
if(a_bullets1[i].alive){
a_bullets1[i].y -= 1;
if(a_bullets1[i].y < -2){
a_bullets1[i].alive = false;
}
}
// Second row.
if(a_bullets2[i].alive){
a_bullets2[i].y -= 1;
if(a_bullets2[i].y < -2){
a_bullets2[i].alive = false;
}
}
}
// Check if any bullet shot by the player hit an alien.
for(int i = 0; i < 3; i++){
if(p_bullets[i].alive){
if(p_bullets[i].y >= 22 && p_bullets[i].y <= 30){
// Check the second row first.
for(int j = 0; j < ALIENS; j++){
if(aliens2[j].alive){
if(p_bullets[i].x >= aliens2[j].x + alien_x_offset &&
p_bullets[i].x <= aliens2[j].x + alien_x_offset + 11){
aliens2[j].alive = false;
p_bullets[i].alive = false;
player.score += 100;
dead_aliens += 1;
PlayTone(100, 250);
break;
}
}
}
}else if(p_bullets[i].y >= 32 && p_bullets[i].y <= 40){
// Check the first row last.
for(int j = 0; j < ALIENS; j++){
if(aliens1[j].alive){
if(p_bullets[i].x >= aliens1[j].x + alien_x_offset &&
p_bullets[i].x <= aliens1[j].x + alien_x_offset + 11){
aliens1[j].alive = false;
p_bullets[i].alive = false;
player.score += 150;
dead_aliens += 1;
PlayTone(100, 250);
break;
}
}
}
}
}
}
// Check alien bullet collisions with player.
// First row.
for(int i = 0; i < ALIENS; i++){
if(a_bullets1[i].alive && a_bullets1[i].y <= 2){
if(a_bullets1[i].x >= player.x - 3 && a_bullets1[i].x <= player.x + 4){
// If the bullet hit the player, reset the game.
player.x = X_MID;
player.lives -= 1;
alien_x_offset = 0;
alien_x_forward = true;
for(int j = 0; j < ALIENS; j++){
a_bullets1[i].alive = false;
a_bullets2[i].alive = false;
}
PlayTone(100, 250);
break;
}
}
}
// Second row
for(int i = 0; i < ALIENS; i++){
if(a_bullets2[i].alive && a_bullets2[i].y <= 2){
if(a_bullets2[i].x >= player.x - 3 && a_bullets2[i].x <= player.x + 4){
// If the bullet hit the player, reset the game.
player.x = X_MID;
player.lives -= 1;
alien_x_offset = 0;
alien_x_forward = true;
for(int j = 0; j < ALIENS; j++){
a_bullets1[i].alive = false;
a_bullets2[i].alive = false;
}
PlayTone(100, 250);
break;
}
}
}
// Check victory/defeat conditions.
if(dead_aliens == 12){
state = 2;
victory = true;
PlayTone(500, 1000);
ClearScreen();
}else if(player.lives < 0){
state = 2;
victory = false;
PlayTone(100, 1000);
ClearScreen();
}
}else{
if(keys[2]){
done = true;
}
}
}
/**
* Draws all game objects to the LCD screen of the robot.
*/
void render(){
int params[3] = {0, 0, 0};
if(state == 0){
// Render the splash screen.
GraphicOut(0, 0, "splash.ric");
}else if(state == 1){
ClearScreen();
// Render informative text.
TextOut(0, LCD_LINE1, "LIVES:");
//NumOut(35, LCD_LINE1, player.lives);
params[0] = 35;
GraphicOutEx(0, LCD_LINE1 + 1, "ship.ric", params);
if(player.lives > 1){
params[0] = 44;
GraphicOutEx(0, LCD_LINE1 + 1, "ship.ric", params);
if(player.lives > 2){
params[0] = 53;
GraphicOutEx(0, LCD_LINE1 + 1, "ship.ric", params);
}
}
TextOut(0, LCD_LINE2, "SCORE:");
NumOut(35, LCD_LINE2, player.score);
// Render the player's sprite.
params[0] = player.x - 3;
GraphicOutEx(0, 0, "ship.ric", params);
// Render the player's bullets.
for(int i = 0; i < 3; i++){
if(p_bullets[i].alive){
RectOut(p_bullets[i].x, p_bullets[i].y, 0, 2, DRAW_PARAMS);
}
}
// Render the aliens.
for(int i = 0; i < ALIENS; i++){
if(aliens1[i].alive){
// First row.
params[0] = alien_frame;
params[1] = aliens1[i].x + alien_x_offset;
params[2] = aliens1[i].y;
GraphicOutEx(0, 0, "invader.ric", params);
}
if(aliens2[i].alive){
// Second row.
params[0] = alien_frame;
params[1] = aliens2[i].x + alien_x_offset;
params[2] = aliens2[i].y;
GraphicOutEx(0, 0, "invader.ric", params);
}
}
// Render the aliens's bullets.
for(int i = 0; i < ALIENS; i++){
if(a_bullets1[i].alive){
RectOut(a_bullets1[i].x, a_bullets1[i].y, 0, 2, DRAW_PARAMS);
}
if(a_bullets2[i].alive){
RectOut(a_bullets2[i].x, a_bullets2[i].y, 0, 2, DRAW_PARAMS);
}
}
}else{
// Render the hall of fame.
if(victory){
params[0] = player.score;
GraphicOutEx(0, 0, "victory.ric", params);
}else{
GraphicOut(0, 0, "defeat.ric");
}
}
}
/**
* The heart of the game.
*/
void game_loop(){
while(!done){
input();
update();
render();
Wait(50);
}
}
/**
* Initializes all game data and call the game loop.
*/
task main(){
// Initialize game data.
state = 0;
done = false;
alien_frame = 0;
alien_x_offset = 0;
alien_x_forward = true;
// Initialize the player and bullets.
player.x = X_MID;
player.lives = 3;
player.score = 0;
for(int i = 0; i < 3; i++){
p_bullets[i].x = 0;
p_bullets[i].y = 0;
p_bullets[i].alive = false;
}
// Initialize the aliens.
dead_aliens = 0;
for(int i = 0; i < ALIENS; i++){
// First row.
aliens1[i].x = BASE_ALIEN_X + (i * 14);
aliens1[i].y = BASE_ALIEN_Y;
aliens1[i].alive = true;
// Second row.
aliens2[i].x = BASE_ALIEN_X + (i * 14);
aliens2[i].y = BASE_ALIEN_Y - 10;
aliens2[i].alive = true;
// Alien bullets, first row.
a_bullets1[i].x = 0;
a_bullets1[i].y = 0;
a_bullets1[i].alive = false;
// Second row.
a_bullets2[i].x = 0;
a_bullets2[i].y = 0;
a_bullets2[i].alive = false;
}
// Initialize time variables.
then = CurrentTick();
then2 = CurrentTick();
// Start the game!
PlayTone(500, 1000);
game_loop();
}

View File

@@ -1,4 +1,8 @@
NXTInvaders
===========
An Space Invaders clone for the Lego Mindstorms NXT
A Space Invaders clone for the Lego Mindstorms NXT.
This game is written in the NXC language. To compile on Windows use the BricxCC
IDE avaliable at http://bricxcc.sourceforge.net/nbc/. On Linux systems install
the NBC compiler available on the same page and run make.

BIN
defeat.ric Normal file

Binary file not shown.

BIN
invader.ric Normal file

Binary file not shown.

BIN
ship.ric Normal file

Binary file not shown.

BIN
splash.ric Normal file

Binary file not shown.

BIN
victory.ric Normal file

Binary file not shown.