Fixed a bug when rendering the player's remaining number of lives.

This commit is contained in:
2013-08-18 10:58:03 -04:30
parent 42d7007a35
commit a5a8650836

View File

@@ -1,449 +1,450 @@
/*------------------------------------------------------------------------------
; 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();
}
/*------------------------------------------------------------------------------
; 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:");
params[0] = 35;
if(player.lives > 0){
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();
}