Created
November 17, 2019 21:37
-
-
Save technobly/f2db0b55af80116f22c8fa805b0bd226 to your computer and use it in GitHub Desktop.
Hadbadge 2019 Heartrate App
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include "mach_defines.h" | |
#include "sdk.h" | |
#include "gfx_load.h" | |
#include "cache.h" | |
#include "libsynth.h" | |
#include "synth_utils.h" | |
#include "midi_note_increments.h" | |
#include "badgetime.h" | |
//The bgnd.png image got linked into the binary of this app, and these two chars are the first | |
//and one past the last byte of it. | |
extern char _binary_bgnd_png_start; | |
extern char _binary_bgnd_png_end; | |
extern char _binary_heartrate_tileset_png_start; | |
extern char _binary_heartrate_tileset_png_end; | |
//Pointer to the framebuffer memory. | |
uint8_t *fbmem; | |
#define FB_WIDTH 512 | |
#define FB_HEIGHT 320 | |
#define FB_PAL_OFFSET 256 | |
extern volatile uint32_t MISC[]; | |
#define MISC_REG(i) MISC[(i)/4] | |
extern volatile uint32_t GFXREG[]; | |
#define GFX_REG(i) GFXREG[(i)/4] | |
#define GPIO_01 (1<<0) | |
#define GPIO_02 (1<<1) | |
#define GPIO_03 (1<<2) | |
#define GPIO_04 (1<<3) | |
#define GPIO_05 (1<<4) | |
#define GPIO_06 (1<<5) | |
#define GPIO_07 (1<<6) | |
#define GPIO_08 (1<<7) | |
#define GPIO_09 (1<<8) | |
#define GPIO_10 (1<<9) | |
#define GPIO_11 (1<<10) | |
#define GPIO_12 (1<<11) | |
#define GPIO_13 (1<<12) | |
#define GPIO_14 (1<<13) | |
#define GPIO_15 (1<<14) | |
#define GPIO_16 (1<<15) | |
#define GPIO_17 (1<<16) | |
#define GPIO_18 (1<<17) | |
#define GPIO_19 (1<<18) | |
#define GPIO_20 (1<<19) | |
#define GPIO_21 (1<<20) | |
#define GPIO_22 (1<<21) | |
#define GPIO_23 (1<<22) | |
#define GPIO_24 (1<<23) | |
#define GPIO_25 (1<<24) | |
#define GPIO_26 (1<<25) | |
#define GPIO_27 (1<<26) | |
#define GPIO_28 (1<<27) | |
#define GPIO_29 (1<<28) | |
//Manually point to sprites memory location | |
uint32_t *GFXSPRITES = (uint32_t *)0x5000C000; | |
//Define some tilemap data | |
#define FLAPPY_GROUND_INDEX 247 | |
#define FLAPPY_GROUND_Y 19 | |
#define FLAPPY_BRICK_INDEX 136 | |
#define FLAPPY_PLAYER_INDEX 184 | |
#define FLAPPY_PLAYER_JUMP_INDEX 191 | |
//Define game parameters | |
#define FLAPPY_PIPE_GAP 7 | |
#define FLAPPY_PIPE_BOTTOM 19 | |
#define FLAPPY_PIPE_HEIGHT_MIN 2 | |
#define FLAPPY_PIPE_HEIGHT_MAX 9 | |
#define FLAPPY_SPEED 1.8 | |
#define FLAPPY_PLAYER_X 4 | |
#define FLAPPY_GRAVITY 2.0 | |
#define FLAPPY_JUMP (-17) | |
#define FLAPPY_BOTTOM_EXTENT 290 | |
int m_player_y = 11; | |
float m_player_velocity = 0.0; | |
uint32_t m_score = 0; | |
int m_pipe_1_x = 11; | |
int m_pipe_1_height = 3; | |
int m_pipe_2_x = 27; | |
int m_pipe_2_height = 5; | |
int m_pipe_3_x = 43; | |
int m_pipe_3_height = 7; | |
int m_pipe_4_x = 59; | |
int m_pipe_4_height = 4; | |
//Borrowed this from lcd.c until a better solution comes along :/ | |
static void __INEFFICIENT_delay(int n) { | |
for (int i=0; i<n; i++) { | |
for (volatile int t=0; t<(1<<11); t++); | |
} | |
} | |
static void __delay_us(int n) { | |
for (int i=0; i<n; i++) { | |
for (volatile int t=0; t<(1<<5); t++); | |
} | |
} | |
//Wait until all buttons are released | |
static inline void __button_wait_for_press() { | |
while (MISC_REG(MISC_BTN_REG) == 0); | |
} | |
//Wait until all buttons are released | |
static inline void __button_wait_for_release() { | |
while (MISC_REG(MISC_BTN_REG)); | |
} | |
static inline void __sprite_set(int index, int x, int y, int size_x, int size_y, int tile_index, int palstart) { | |
x+=64; | |
y+=64; | |
GFXSPRITES[index*2]=(y<<16)|x; | |
GFXSPRITES[index*2+1]=size_x|(size_y<<8)|(tile_index<<16)|((palstart/4)<<25); | |
} | |
//Helper function to set a tile on layer a | |
static inline void __tile_a_set(uint8_t x, uint8_t y, uint32_t index) { | |
GFXTILEMAPA[y*GFX_TILEMAP_W+x] = index; | |
} | |
//Helper function to set a tile on layer b | |
static inline void __tile_b_set(uint8_t x, uint8_t y, uint32_t index) { | |
GFXTILEMAPB[y*GFX_TILEMAP_W+x] = index; | |
} | |
//Helper function to move tile layer 1 | |
static inline void __tile_a_translate(int dx, int dy) { | |
GFX_REG(GFX_TILEA_OFF)=(dy<<16)+(dx &0xffff); | |
} | |
//Helper function to move tile layer b | |
static inline void __tile_b_translate(int dx, int dy) { | |
GFX_REG(GFX_TILEB_OFF)=(dy<<16)+(dx &0xffff); | |
} | |
static inline void __create_pipe(int x, int h) { | |
//Generate a full pipe including gap | |
for (uint8_t y=0; y<FLAPPY_PIPE_BOTTOM; y++) { | |
//TOP | |
if (y < FLAPPY_PIPE_BOTTOM-FLAPPY_PIPE_GAP-h) { | |
__tile_a_set(x,y,FLAPPY_BRICK_INDEX); | |
__tile_a_set(x+1,y,FLAPPY_BRICK_INDEX+1); | |
__tile_a_set(x+2,y,FLAPPY_BRICK_INDEX+1); | |
__tile_a_set(x+3,y,FLAPPY_BRICK_INDEX+2); | |
} | |
//MIDDLE | |
else if (y < FLAPPY_PIPE_BOTTOM-h) { | |
__tile_a_set(x,y,0); | |
__tile_a_set(x+1,y,0); | |
__tile_a_set(x+2,y,0); | |
__tile_a_set(x+3,y,0); | |
} | |
//BOTTOM | |
else { | |
__tile_a_set(x,y,FLAPPY_BRICK_INDEX); | |
__tile_a_set(x+1,y,FLAPPY_BRICK_INDEX+1); | |
__tile_a_set(x+2,y,FLAPPY_BRICK_INDEX+1); | |
__tile_a_set(x+3,y,FLAPPY_BRICK_INDEX+2); | |
} | |
__tile_a_set(x+4,y,0); | |
} | |
} | |
/** | |
* Check for collision with a pipe with true screen x coordinate and height value | |
* Sadly units do not match. If I find time to fix it I will. | |
* x is in absolute screen coordinate (pixels) | |
* h is the height of the bottom pipe in tiles | |
* | |
* This is compared against the player position which is stored statically. | |
* YOLO | |
* | |
* Returns 0 if no collision, non-zero if collision | |
*/ | |
static int __collision_test(int x, int h) { | |
//Easiest test is if player has not reached pipe | |
if (x > ((FLAPPY_PLAYER_X* 16)+32)) { | |
return 0; | |
} | |
//If player is past the pipe there can be no collision | |
if ((x + 4) * 16 < (FLAPPY_PLAYER_X * 16)) { | |
return 0; | |
} | |
//We only reach this point if player is at the pipe | |
//Top is the minimum y extent the player can be as they're passing through the pipe | |
int top = (FLAPPY_PIPE_BOTTOM - FLAPPY_PIPE_GAP - h) * 16; | |
//Bottom is the maximum y extent he player can be as they're passing through the pipe | |
int bottom = ((FLAPPY_PIPE_BOTTOM - h) * 16) - 32; | |
//Test if player y is valid | |
if (m_player_y < top || m_player_y > bottom) { | |
return -1; | |
} | |
//We got this far, must be clear | |
return 0; | |
} | |
// Sound FX | |
void synth_play_game_over(void){ | |
synth_queue->voice_force = (1 << 2); | |
for (uint32_t pitch = midi_table[64] ; pitch > midi_table[64-36] ; pitch=(pitch*15/16)){ | |
synth_queue->voice[2].phase_inc = pitch; | |
synth_queue->cmd_wait = 1250; | |
} | |
synth_queue->voice_force = 0; | |
} | |
void synth_play_flap(void){ | |
synth_queue->voice_force = 3; | |
synth_queue->voice[0].phase_inc = midi_table[80]; | |
synth_queue->voice[1].phase_inc = midi_table[80]; | |
for (uint16_t i=0; i<100; i=i+1){ | |
synth_queue->cmd_wait = 50; | |
synth_queue->voice[0].phase_inc = midi_table[85]+i*16; | |
synth_queue->voice[1].phase_inc = midi_table[85]+i*16; | |
} | |
synth_queue->voice_force = 0; | |
} | |
static inline void __pulse_heart(int x, int y) { | |
// __tile_a_set(x,y,HEART_PULSE_INDEX); | |
} | |
int get_heart_beat(void) { | |
/** General I/O input register. Bits 29-0 reflect the values of the corresponding lines on the cartridge I/O connector. */ | |
// MISC_GENIO_IN_REG | |
/** General I/O output register. Bits 29-0 set the values of the cartridge lines that are selected as outputs. */ | |
// MISC_GENIO_OUT_REG | |
/** General I/O output enable registers. Set 1 to any of the bits 29-0 to make the corresponding line into an output. */ | |
// MISC_GENIO_OE_REG | |
// * Master Slave | |
// * CS GEN12 <-------> D5 CS (19) | |
// * MISO GEN10 <-------> D4 MISO (21) | |
// * MOSI GEN08 <-------> D3 MOSI (23) | |
// * SCK GEN06 <-------> D2 SCK (25) | |
// pinMode(A2, OUTPUT); // CS | |
// pinMode(A3, OUTPUT); // CLK | |
// pinMode(A4, INPUT); // MISO | |
// pinMode(A5, OUTPUT); // MOSI | |
// GPIO_06 OUTPUT - SCK | |
// GPIO_08 OUTPUT - MOSI | |
// GPIO_10 INPUT - MISO | |
// GPIO_12 OUTPUT - CS | |
MISC_REG(MISC_GENIO_W2C_REG) = GPIO_19; // CS LOW | |
// __delay_us(1000); | |
delay(1); | |
uint8_t data_byte; | |
// for (char i = 2; i; i--) { // number of bytes | |
data_byte = 55; | |
for (char bits = 8; bits; bits--) { | |
if (data_byte & 0x80) { | |
MISC_REG(MISC_GENIO_W2S_REG) = GPIO_23; // MOSI HIGH | |
// MISC_REG(MISC_GENIO_OUT_REG) |= GPIO_23; | |
// __delay_us(10); | |
delay(1); | |
} else { | |
MISC_REG(MISC_GENIO_W2C_REG) = GPIO_23; // MOSI LOW | |
// __delay_us(10); | |
delay(1); | |
} | |
data_byte <<= 1; | |
// MISC_REG(MISC_GENIO_W2S_REG) = GPIO_25; // SCK HIGH | |
MISC_REG(MISC_GENIO_OUT_REG) |= GPIO_25; | |
// __delay_us(1000); | |
delay(1); | |
if (MISC_REG(MISC_GENIO_IN_REG) & GPIO_21) { | |
data_byte |= 0x01; | |
} | |
// MISC_REG(MISC_GENIO_W2C_REG) = GPIO_25; // SCK LOW | |
MISC_REG(MISC_GENIO_OUT_REG) &= ~(GPIO_25); | |
// __delay_us(1000); | |
delay(1); | |
} | |
// printf("Heart beat %d %u", i, data_byte); | |
// } // number of bytes | |
// __INEFFICIENT_delay(1); | |
delay(1); | |
MISC_REG(MISC_GENIO_W2S_REG) = GPIO_19; // CS HIGH | |
return data_byte; | |
} | |
void main(int argc, char **argv) { | |
//Allocate framebuffer memory | |
fbmem=malloc(320*512/2); | |
// MISC_REG(PIC_OFFSET_REGS) |= PIC_CTL_PASSTHRU; | |
// delay(1); | |
// MISC_REG(PIC_OFFSET_REGS) &= ~PIC_CTL_RESET; | |
// delay(1); | |
// /** Control register for the PIC. It allows you to reset it, send it an | |
// interrupt, and to enable it to control the LEDs. */ | |
// #define PIC_CTL_REG 0x0 | |
// /** Reset bit. Setting this to 1 keeps the PIC in reset, setting it to 0 | |
// allows it to run. */ | |
// #define PIC_CTL_RESET (1<<0) | |
// * This bit is directly connected to the INT0 IRQ line. Use this to | |
// send an interrupt to the PIC | |
// #define PIC_CTL_INT0 (1<<1) | |
// /** LED passthrough. If 1, the RiscV controls the LEDs. If 0, the desired | |
// LED state is available to the pic to read, but it can control the | |
// outputs to the LED itself. */ | |
// #define PIC_CTL_PASSTHRU (1<<2) | |
// Setup cartridge for SPI Master | |
MISC_REG(MISC_GENIO_OE_REG) = GPIO_23 | GPIO_19 | GPIO_25; | |
// MISC_REG(MISC_GPEXT_OE_REG) = 0xffffffff; | |
// MISC_REG(MISC_GPEXT_OUT_REG) = 0xffffffff; | |
for (uint8_t i=0; i<32;i++) { | |
MISC_REG(MISC_LED_REG)=(1<<i); | |
delay(30); | |
} | |
MISC_REG(MISC_LED_REG) = 0xFFFFFFFF; | |
delay(500); | |
//Set up the framebuffer address. | |
GFX_REG(GFX_FBADDR_REG)=((uint32_t)fbmem)&0xFFFFFF; | |
//We're going to use a pitch of 512 pixels, and the fb palette will start at 256. | |
GFX_REG(GFX_FBPITCH_REG)=(FB_PAL_OFFSET<<GFX_FBPITCH_PAL_OFF)|(512<<GFX_FBPITCH_PITCH_OFF); | |
//Blank out fb while we're loading stuff. | |
GFX_REG(GFX_LAYEREN_REG)=0; | |
//Load up the default tileset and font. | |
//ToDo: loading pngs takes a long time... move over to pcx instead. | |
printf("Loading tiles...\n"); | |
int gfx_tiles_err = | |
gfx_load_tiles_mem(GFXTILES, &GFXPAL[0], | |
&_binary_heartrate_tileset_png_start, | |
(&_binary_heartrate_tileset_png_end - &_binary_heartrate_tileset_png_start)); | |
printf("Tiles initialized err=%d\n", gfx_tiles_err); | |
//The IPL leaves us with a tileset that has tile 0 to 127 map to ASCII characters, so we do not need to | |
//load anything specific for this. In order to get some text out, we can use the /dev/console device | |
//that will use these tiles to put text in a tilemap. It uses escape codes to do so, see | |
//ipl/gloss/console_out.c for more info. | |
//Note that without the setvbuf command, no characters would be printed until 1024 characters are | |
//buffered. | |
FILE *console=fopen("/dev/console", "w"); | |
setvbuf(console, NULL, _IONBF, 0); //make console unbuffered | |
if (console==NULL) { | |
printf("Error opening console!\n"); | |
} | |
//we tell it to start writing from entry 0. | |
//Now, use a library function to load the image into the framebuffer memory. This function will also set up the palette entries, | |
//PAL offset changes the colors that the 16-bit png maps to? | |
gfx_load_fb_mem(fbmem, &GFXPAL[FB_PAL_OFFSET], 4, 512, &_binary_bgnd_png_start, (&_binary_bgnd_png_end-&_binary_bgnd_png_start)); | |
//Flush the memory region to psram so the GFX hw can stream it from there. | |
cache_flush(fbmem, fbmem+FB_WIDTH*FB_HEIGHT); | |
//Copied from IPL not sure why yet | |
GFX_REG(GFX_LAYEREN_REG)=GFX_LAYEREN_FB|GFX_LAYEREN_TILEB|GFX_LAYEREN_TILEA|GFX_LAYEREN_SPR; | |
GFXPAL[FB_PAL_OFFSET+0x100]=0x00ff00ff; //Note: For some reason, the sprites use this as default bgnd. ToDo: fix this... | |
GFXPAL[FB_PAL_OFFSET+0x1ff]=0x40ff00ff; //so it becomes this instead. | |
__button_wait_for_release(); | |
//Set map to tilemap B, clear tilemap, set attr to 0 | |
//Not sure yet what attr does, but tilemap be is important as it will have the effect of layering | |
//on top of our scrolling game | |
fprintf(console, "\0331M\033C\0330A"); | |
//Clear both tilemaps | |
memset(GFXTILEMAPA,0,0x4000); | |
memset(GFXTILEMAPB,0,0x4000); | |
//Clear sprites that IPL may have loaded | |
memset(GFXSPRITES,0,0x4000); | |
//Draw the ground on the tilemap, probably inefficient but we're learning here | |
//Tilemap is 64 wide. Fille the entire bottom row with grass | |
// for (uint8_t x=0; x<64; x++) { | |
// __tile_a_set(x, FLAPPY_GROUND_Y, FLAPPY_GROUND_INDEX); | |
// } | |
//The user can still see nothing of this graphics goodness, so let's re-enable the framebuffer and | |
//tile layer A (the default layer for the console). | |
//Normal FB enabled (vice 8 bit) because background is loaded into the framebuffer above in 4 bit mode. | |
//TILEA is where text is printed by default | |
GFX_REG(GFX_LAYEREN_REG)=GFX_LAYEREN_FB|GFX_LAYEREN_TILEA|GFX_LAYEREN_TILEB|GFX_LAYEREN_SPR; | |
//Draw the player as a brick. Need to use our custome tilemap so we have a real sprite or figure | |
//out how sprites work in the graphics engine | |
#if 1 | |
//Primary game loop | |
float dy=0; | |
float dx=0; | |
int game_over = 0; | |
int hb = 60; | |
while(!game_over) { | |
// static int i = 0; | |
// static int dir = 1; | |
// if (MISC_REG(MISC_BTN_REG)) { | |
// while (MISC_REG(MISC_BTN_REG)); // wait | |
// __INEFFICIENT_delay(500); | |
// if (dir) { | |
// i++; | |
// if (i > 16) { | |
// dir = 0; | |
// } | |
// } else { | |
// i--; | |
// if (i < 0) { | |
// dir = 1; | |
// } | |
// } | |
// MISC_REG(MISC_LED_REG) = (1<<i); | |
// __INEFFICIENT_delay(500); | |
// } | |
#if 0 | |
for (int x=0; x<4; x++) { | |
for (int i=0; i<=5; i++) { | |
MISC_REG(MISC_LED_REG) = (1<<i) + 0x700; | |
delay(hb*1000/60/2/5/4); | |
} | |
// for (int i=8; i<=10; i++) { | |
// MISC_REG(MISC_LED_REG) = (1<<i); | |
// __INEFFICIENT_delay(10); | |
// } | |
// for (int i=9; i>=8; i--) { | |
// MISC_REG(MISC_LED_REG) = (1<<i); | |
// __INEFFICIENT_delay(10); | |
// } | |
for (int i=5; i>=0; i--) { | |
MISC_REG(MISC_LED_REG) = (1<<i) + 0x700; | |
delay(hb*1000/60/2/5/4); | |
} | |
} | |
MISC_REG(MISC_LED_REG) = 0x700; | |
#endif | |
#if 1 | |
// /^^\__/^^\___________________ | |
// for (int x=0; x<4; x++) { | |
// MISC_REG(MISC_LED_REG) = (3<<2) + 0x700; | |
// delay(hb*1000/60/2/12); | |
// MISC_REG(MISC_LED_REG) = (9<<1) + 0x700; | |
// delay(hb*1000/60/2/12); | |
// MISC_REG(MISC_LED_REG) = (33<<0) + 0x700; | |
// delay(hb*1000/60/2/12); | |
// MISC_REG(MISC_LED_REG) = (3<<2) + 0x700; | |
// delay(hb*1000/60/2/20); | |
// MISC_REG(MISC_LED_REG) = (15<<1) + 0x700; | |
// delay(hb*1000/60/2/20); | |
// MISC_REG(MISC_LED_REG) = (63<<0) + 0x700; | |
// delay(hb*1000/60/2/20); | |
// MISC_REG(MISC_LED_REG) = (15<<1) + 0x700; | |
// delay(hb*1000/60/2/20); | |
// MISC_REG(MISC_LED_REG) = (3<<2) + 0x700; | |
// delay(hb*1000/60/2/20); | |
// } | |
MISC_REG(MISC_LED_REG) = (3<<2) + 0x700; | |
delay(hb*1000/60/4/5); | |
MISC_REG(MISC_LED_REG) = (15<<1) + 0x700; | |
delay(hb*1000/60/4/5); | |
MISC_REG(MISC_LED_REG) = (63<<0) + 0x700; | |
delay(hb*1000/60/4/5); | |
MISC_REG(MISC_LED_REG) = (15<<1) + 0x700; | |
delay(hb*1000/60/4/5); | |
MISC_REG(MISC_LED_REG) = (3<<2) + 0x700; | |
delay(hb*1000/60/4/5); | |
MISC_REG(MISC_LED_REG) = 0x700; | |
delay(hb*1000/60/4); | |
#endif | |
// MISC_REG(MISC_LED_REG) = 0b11100010101; | |
// delay(hb*1000/60/4); | |
// MISC_REG(MISC_LED_REG) = 0x700; | |
// delay(hb*1000/60/4); | |
hb = get_heart_beat(); | |
fprintf(console, "\0335X\03310Y "); | |
if (hb == 0 | hb == 255 | hb == 60) { | |
hb = 60; | |
// fprintf(console, "\0332X\03310YYOU DEAD!"); | |
} else { | |
fprintf(console, "\0335X\03310Y%d BPM ", hb); | |
} | |
// fprintf(console, "\0335X\03315Y%x ", count); | |
if (MISC_REG(MISC_BTN_REG)) { | |
game_over = 1; | |
return; | |
} | |
continue; | |
//Move the tile layer b, each 1024 of dx is equal to one tile (or 16 pixels) | |
__tile_a_translate((int)dx, (int)dy); | |
dx += FLAPPY_SPEED; | |
//Calculate true screen coordinates x coordinate of pipes | |
int x1 = (((m_pipe_1_x << 10) - (int)dx) & 0xFFFF) >> 6; | |
int x2 = (((m_pipe_2_x << 10) - (int)dx) & 0xFFFF) >> 6; | |
int x3 = (((m_pipe_3_x << 10) - (int)dx) & 0xFFFF) >> 6; | |
int x4 = (((m_pipe_4_x << 10) - (int)dx) & 0xFFFF) >> 6; | |
//Periodically update user y position and check for jumping | |
if ((m_score % 300) == 0) { | |
m_player_y += m_player_velocity; | |
//Collision detection | |
if (m_player_y >= FLAPPY_BOTTOM_EXTENT) { | |
game_over = 1; | |
m_player_y = 272; | |
} | |
//Jump when user presses button | |
if (MISC_REG(MISC_BTN_REG)) { | |
m_player_velocity = 0; | |
m_player_y += FLAPPY_JUMP; | |
__sprite_set(0, FLAPPY_PLAYER_X*16, m_player_y, 32, 32, FLAPPY_PLAYER_JUMP_INDEX, 0); | |
synth_play_flap(); | |
} else { | |
m_player_velocity += FLAPPY_GRAVITY; | |
__sprite_set(0, FLAPPY_PLAYER_X*16, m_player_y, 32, 32, FLAPPY_PLAYER_INDEX, 0); | |
} | |
//Test collision against any pipes, but use our made up minimum score values to only test after the pipes | |
//are created | |
if (m_score > 8000) { | |
game_over |= | |
__collision_test(x3, m_pipe_3_height) || | |
__collision_test(x4, m_pipe_4_height); | |
} | |
if (m_score > 25000) { | |
game_over |= | |
__collision_test(x1, m_pipe_1_height) || | |
__collision_test(x2, m_pipe_2_height); | |
} | |
} | |
//Generate 4 pipes with fixed heights so it's easy to get started | |
//Only generate the pipes as they make progress | |
//The 8000 and 25000 values are arbitrary but defer pipe creation _just_ enough | |
if (m_score == 8000) { | |
__create_pipe(m_pipe_3_x, m_pipe_3_height); | |
__create_pipe(m_pipe_4_x, m_pipe_4_height); | |
} else if (m_score == 25000) { | |
__create_pipe(m_pipe_1_x, m_pipe_1_height); | |
__create_pipe(m_pipe_2_x, m_pipe_2_height); | |
} | |
//Detect a pipe about to enter from right side of screen, in this case generate | |
//A new pipe at that same tile x coord so it appears we have infinite scrolling | |
//Screen is 480 wide so 500 is good enough | |
if (x1 == 500) { | |
// m_pipe_1_height = (rand() % (FLAPPY_PIPE_HEIGHT_MIN - FLAPPY_PIPE_HEIGHT_MAX)) + FLAPPY_PIPE_HEIGHT_MIN; | |
__create_pipe(m_pipe_1_x, m_pipe_1_height); | |
} | |
if (x2 == 500) { | |
// m_pipe_2_height = (rand() % (FLAPPY_PIPE_HEIGHT_MIN - FLAPPY_PIPE_HEIGHT_MAX)) + FLAPPY_PIPE_HEIGHT_MIN; | |
__create_pipe(m_pipe_2_x, m_pipe_2_height); | |
} | |
if (x3 == 500) { | |
// m_pipe_3_height = (rand() % (FLAPPY_PIPE_HEIGHT_MIN - FLAPPY_PIPE_HEIGHT_MAX)) + FLAPPY_PIPE_HEIGHT_MIN; | |
__create_pipe(m_pipe_3_x, m_pipe_3_height); | |
} | |
if (x4 == 500) { | |
// m_pipe_4_height = (rand() % (FLAPPY_PIPE_HEIGHT_MIN - FLAPPY_PIPE_HEIGHT_MAX)) + FLAPPY_PIPE_HEIGHT_MIN; | |
__create_pipe(m_pipe_4_x, m_pipe_4_height); | |
} | |
//Print score at 0,0 | |
//NOTE: this seems to be a *very* slow operation. Adding a second fprintf will have a noticeable | |
//slowdown effect. Removing this fprintf will put the game into ludicrous speed mode. Need to fix! | |
// fprintf(console, "\0330X\0330Y%dm\03324XBW", (m_score >> 10)); | |
//Flappy score increases with distance which is simply a function of time | |
m_score++; | |
} | |
synth_play_game_over(); | |
//Print game over | |
fprintf(console, "\03315X\03320YGG!\nScore: %dm", (m_score/1000)); | |
//Wait for user to release whatever buttons they were pressing and to press a new one | |
__button_wait_for_release(); | |
__INEFFICIENT_delay(200); | |
__button_wait_for_press(); | |
//Clear both tilemaps | |
memset(GFXTILEMAPA,0,0x4000); | |
memset(GFXTILEMAPB,0,0x4000); | |
//Clear sprites that IPL may have loaded | |
memset(GFXSPRITES,0,0x4000); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment