Skip to content

Instantly share code, notes, and snippets.

@technobly
Created November 17, 2019 21:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save technobly/f2db0b55af80116f22c8fa805b0bd226 to your computer and use it in GitHub Desktop.
Save technobly/f2db0b55af80116f22c8fa805b0bd226 to your computer and use it in GitHub Desktop.
Hadbadge 2019 Heartrate App
#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