Got missiles moving (though not correctly) and figured out how to draw more then one on the screen. Cities draw based on health, and automatically space themselves evenly (though it'll be capped at five after i figure out what's wrong with the enemy missiles).
missiles are all saved in an array (to be shared between enemy and ally missiles, currently) As are cities, and (some century) explosions to stop the enemy missiles.
Here's the main body of the code.
- Code: Select all
//imports the SPI library (needed to communicate with Gamebuino's screen)
#include <SPI.h>
//imports the Gamebuino library
#include <Gamebuino.h>
#include <stdlib.h>
//imports the header to make this blasted game work.
#include "MISCMD.h"
//creates a Gamebuino object named gb
Gamebuino gb;
// drawing functions
void drawTarget(int x,int y){
gb.display.drawFastHLine(x-5, y,4);
gb.display.drawFastHLine(x+1, y,4);
gb.display.drawFastVLine(x,y-5,4);
gb.display.drawFastVLine(x,y+1,4);
};
// missile controllers
boolean cpuFireRandomMissile(){
int missileID; // the index of the chosen missile in the array, used to make sure there's one avaible
while (missileID <= MISSILEARRAYSIZE - 1){
if (missileArray[missileID].active == true){
// missileid is already taken
missileID += 1;
}else{
// missileID isn't taken, set new values, set missile active, select random target
missileArray[missileID].active = true;
missileArray[missileID].start_x = random(LCDWIDTH); // random starting point, sans the very edges
missileArray[missileID].start_y = 0.0;
missileArray[missileID].target_y = LCDHEIGHT - 8;
missileArray[missileID].target_x = random(LCDWIDTH); // random target point, sans the very edges
missileArray[missileID].rel_frame = 0;
missileArray[missileID].num_frames = 10; /*(float) abs(sqrt(sq(missileArray[missileID].target_x - missileArray[missileID].start_x) + sq(missileArray[missileID].target_y - missileArray[missileID].start_y))) / 5; */ // number of frames of travel, based on speed
missileArray[missileID].player = false; // this is a CPU missile, after all
missileArray[missileID].velocity_x = (float)(missileArray[missileID].target_x - missileArray[missileID].start_x) / missileArray[missileID].num_frames;
missileArray[missileID].velocity_y = (float)(missileArray[missileID].target_y - missileArray[missileID].start_y) / missileArray[missileID].num_frames;
// plug into the init function, most of these values are simply reset, but this calculates the velocity of x and y
// init_missile(missileArray[missileID], missileArray[missileID].start_x, missileArray[missileID].start_y, missileArray[missileID].target_x, missileArray[missileID].target_y, missileArray[missileID].num_frames);
return true;
break;
};
};
return false;
};
void missileStep(){
// calculates the motion of all currently active missiles, calculate collisions or detonations (for player-fired missiles)
int missileID = 0;
while (missileID <= (MISSILEARRAYSIZE - 1)){
// scan and update all missile ID positions, if active.
missileArray[missileID].current_x += missileArray[missileID].velocity_x;
missileArray[missileID].current_y += missileArray[missileID].velocity_y;
missileID += 1;
};
};
// Drawing functinos.
void drawCity(int citycount){
// Draws the cities. takes the number of cities currently being used
// pick sprite based on percentage of city health
int cityx;
for (int curCity = 0; curCity <= citycount - 1; curCity++){
// sprite location is based on number of cities
cityx = (int) (LCDWIDTH/(citycount + 1)) * (curCity + 1); // determine spacing for the cities to draw
switch (cityArray[curCity].hp){
case 2:
gb.display.drawBitmap(cityx - 4, LCDHEIGHT - 16, sprCityFull); // Two hits left, full health
break;
case 1:
gb.display.drawBitmap(cityx - 4, LCDHEIGHT - 16, sprCityHalf); // One hit left, half health
break;
case 0:
gb.display.drawBitmap(cityx - 4, LCDHEIGHT - 16, sprCityDestroyed); // And these residents will need to move.
break;
default:
gb.display.drawBitmap(cityx - 4, LCDHEIGHT - 16, sprCityFull); // Two hits left, full health
break;
};
};
gb.display.drawFastHLine(0,LCDHEIGHT - 8, LCDWIDTH);
};
void drawMissiles(){
// draws all active missiles
int curMissile;
while (curMissile <= (MISSILEARRAYSIZE - 1)){
if (missileArray[curMissile].active == true){
// missile is active, draw the missile!
gb.display.drawLine(missileArray[curMissile].start_x, missileArray[curMissile].start_y, missileArray[curMissile].current_x, missileArray[curMissile].current_y);
//gb.display.drawPixel((int) missileArray[curMissile].current_x, (int) missileArray[curMissile].current_y);
};
curMissile += 1;
};
};
// the setup routine runs once when Gamebuino starts up
void setup(){
// initialize the Gamebuino object
gb.begin();
//display the main menu:
gb.titleScreen(F("Missle Command"));
gb.setFrameRate(1);
gb.pickRandomSeed();
// initialize memory space
}
// the loop routine runs over and over again forever
void loop(){
//updates the gamebuino (the display, the sound, the auto backlight... everything)
//returns true when it's time to render a new frame (20 times/second)
if(gb.update()){
while (cpuFireRandomMissile() == false){};
//if (gb.frameCount % 5 == 1){
missileStep();
// };
drawMissiles();
drawCity(3);
gb.display.cursorX = 0;
gb.display.cursorY = LCDHEIGHT - 7;
gb.display.setFont(font3x5);
gb.display.print(missileArray[1].start_x);
gb.display.print(" ");
gb.display.print(missileArray[1].start_y);
gb.display.print(" ");
gb.display.print(missileArray[1].target_x);
gb.display.print(" ");
gb.display.print(missileArray[1].target_y);
gb.display.print(" ");
gb.display.print(missileArray[1].current_x);
gb.display.print(" ");
gb.display.print(missileArray[1].current_y);
gb.display.print(" ");
gb.display.print(missileArray[1].active);
};
};
It has test values where the number of missiles left in each city should go, but alas.
Here's the header file, where the bitmaps and Myndale's original functions are stored.
- Code: Select all
// header file for the game, which saves all of the sprites, data structures, and other things needed for the game to work.
//City Sprites
static unsigned char PROGMEM sprCityFull[] =
{
8,8,
B00000000,
B00000000,
B00001000,
B00011000,
B01011100,
B01111110,
B11111111,
B11111111,
};
static unsigned char PROGMEM sprCityHalf[] =
{
8,8,
B00000000,
B00010100,
B00101010,
B00010100,
B00101100,
B01111110,
B11111111,
B11111111,
};
static unsigned char PROGMEM sprCityDestroyed[] =
{
8,8,
B00000000,
B00010100,
B00101010,
B00010100,
B00101001,
B01010110,
B01101010,
B11111111,
};
// struct for cities;
typedef struct {
// hit points of the city.
int hp;
// how many missiles the city has left
int mis;
} city;
// structure for missiles
typedef struct {
int start_x, start_y; // The starting positions of the missile
int target_x, target_y; // The Target of the missile
float current_x, current_y; // current position of the missile
float velocity_x, velocity_y; // horizonatal and vertical speed of the missile, used for calculating current x and y
int num_frames; // The number of frames to move the missile in, calculated from linear distance and speed.
int rel_frame; //relitive frame since missile fired
boolean player; // is this a player missile?
boolean active; // is this missile active?
} missile;
// structure for a 'level'
typedef struct{
int citycount; // how many cities
int mismax; // how many missiles in each city 0 is unlimited
int emiscount; // how many missiles will the CPU try and fire?
int emisvolleycount; // how many missiles AT ONCE will the CPU try and fire.
int volleytime; // average time in frames between missile volleys
} mission;
// constants
const int MISSILEARRAYSIZE = 3;
const int CITYARRAYSIZE = 5;
// array for the cities
static city cityArray[CITYARRAYSIZE];
// array of all the missiles
static missile missileArray[MISSILEARRAYSIZE];
// motion functions
void init_missile(missile & mis, int start_x, int start_y, int target_x, int target_y, int num_frames)
{
mis.start_x = mis.current_x = start_x;
mis.start_y = mis.current_y = start_y;
mis.target_x = target_x;
mis.target_y = target_y;
mis.velocity_x = (float)(target_x - start_x) / num_frames;
mis.velocity_y = (float)(target_y - start_y) / num_frames;
mis.num_frames = num_frames;
};
void update_missile(missile & mis)
{
mis.current_x += mis.velocity_x;
mis.current_y += mis.velocity_y;
};
void resetMissile(int id){
missileArray[id].active = false;
missileArray[id].start_x = 0;
missileArray[id].start_y = 0;
missileArray[id].target_y = 0;
missileArray[id].target_x = 0;
missileArray[id].rel_frame = 0;
missileArray[id].num_frames = 0; // number of frames of travel, based on speed
missileArray[id].player = true; // this is a CPU missile, after all
missileArray[id].velocity_x = 0.0;
missileArray[id].velocity_y = 0.0;
};
// Drawing functions
extern const byte font3x5[];
I'd stick up A HEX and ELF file, but it crashes after three (slowed down for testing) frames.
I'm completing this out of dogged determination at this point. XD I think I'll be happy to never play/touch it again once it works.