Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "pm.h" // read this library if you don't recognise anything in capital letters
- #include "sprites.h" // 16x16 b/w + transparency bird sprite
- #include "map.h" // 8x8 b/w chequerboard map tile - formats for both of these can be found at https://wiki.sublab.net/index.php/PM_PRC
- #include "input.h" // library for input - useful
- #include "rng.h" // randomness
- // defines
- #define SCREEN_SIZE 96 // height of screen (really width, but flappy bird is portrait)
- #define NUM_PIPES 3 // number of pipes, duh
- #define MIN_SHIFT 4 // lowest pipe position
- #define GAP 32 // gap between top and bottom of pipe
- #define MAX_SHIFT SCREEN_SIZE - MIN_SHIFT
- // structs
- struct Pipe {
- unsigned char y;
- unsigned char position;
- unsigned char width;
- unsigned char enabled;
- };
- // global variables
- int yspeed = 0; // variable storing bird's y speed
- int next_sprite = 2; // holds the next free sprite for the drawing function (0 is bird, 1 is game over graphic)
- struct Pipe pipe[NUM_PIPES]; // PIPES
- // stuff for running once per frame
- int frame_counter = 0; // used to count the number of frames that have passed
- int trigger = 0;
- void __interrupt irq_1_prc_done(void) // interrupt that is triggered after a frame is drawn
- {
- IRQ_ACT1 |= IRQ1_PRC_COMPLETE; // acknowledge interrupt
- trigger = 1;
- }
- void draw_pipe(int index)
- {
- struct Pipe current_pipe = pipe[index];
- if(!current_pipe.enabled)
- {
- next_sprite += 7;
- return;
- }
- for(int i = 0; i < 7; i++)
- {
- OAM[next_sprite + i].y = current_pipe.y;
- OAM[next_sprite + i].ctrl = OAM_ENABLE;
- }
- OAM[next_sprite].x = current_pipe.position + 0x10;
- OAM[next_sprite + 1].x = current_pipe.position + GAP + 0x10;
- for(int i = 2; i < 7; i++)
- {
- OAM[next_sprite + i].x = (i * 0x10 + current_pipe.position + GAP + 0x10);
- if(OAM[next_sprite + i].x >= 0x70)
- OAM[next_sprite + i].x = (i * 0x10 + current_pipe.position);
- }
- OAM[next_sprite].tile = PIPE_END;
- OAM[next_sprite + 1].tile = PIPE_END;
- for(int i = 2; i < 7; i++)
- OAM[next_sprite + i].tile = PIPE_SECTION;
- OAM[next_sprite + 1].ctrl |= OAM_FLIPH;
- next_sprite += 7;
- }
- int main(void) // main function
- {
- // screen initialisation
- PRC_MODE = COPY_ENABLE|SPRITE_ENABLE|MAP_ENABLE|MAP_16X12;
- PRC_RATE = RATE_36FPS; // set up PRC to enable sprites, and a 16x12 tile background
- // interrupts
- IRQ_ENA1 |= IRQ1_PRC_COMPLETE; // enable the frame complete interrupt to do fun stuff (see irq_1_prc_done)
- IRQ_PRI1 = PRI1_PRC(1); // give this high priority
- // tilemap initialisation
- for(int i = 0; i < 16 * 12; i++)
- TILEMAP[i] = 0; // initialise the 16x12 tilemap with tile 0 (the chequerboard)
- PRC_SCROLL_X = 0;
- PRC_SCROLL_Y = 0; // reset the background scroll values
- // sprites and tiles
- PRC_SPR = (long)sprites; // load in sprite tiles
- PRC_MAP = (long)map; // load in map tiles
- // OAM definitions and initialisation
- #define BIRD OAM[0]
- BIRD.x = 0x40;
- BIRD.y = 0x10;
- BIRD.tile = BIRD_TILE_0; // initialise the first and only sprite with position (32, 32), the bird sprite and enable it
- BIRD.ctrl = OAM_ENABLE;
- #define GAME_OVER OAM[1]
- GAME_OVER.x = 56;
- GAME_OVER.y = 40;
- GAME_OVER.tile = GAME_OVER_TILE;
- GAME_OVER.ctrl = 0;
- // testing purposes only
- OAM[2].x = 0xF0;
- OAM[2].y = 0xF0;
- OAM[2].tile = PIPE_SECTION;
- OAM[2].ctrl = 0;
- OAM[3].x = 0xF0;
- OAM[3].y = 0xF0;
- OAM[3].tile = PIPE_SECTION;
- OAM[3].ctrl = 0;
- OAM[4].x = 0xF0;
- OAM[4].y = 0xF0;
- OAM[4].tile = PIPE_SECTION;
- OAM[4].ctrl = 0;
- for(int i = 0; i < NUM_PIPES; i++)
- {
- pipe[i].y = 0x50;
- pipe[i].position = 0;
- pipe[i].width = 16;
- pipe[i].enabled = 0;
- }
- for(;;) // do this infinitely:
- {
- while(!trigger)
- ; // wait till the last frame has been drawn
- trigger = 0;
- frame_counter++; // increment the frame counter
- if(!(frame_counter % 4)) // every 4 frames,
- {
- PRC_SCROLL_Y++; // increment the map x scroll by 1
- PRC_SCROLL_Y &= 0x1F; // equivalent to % 32; makes it appear to scroll infinitely
- for(int i = 0; i < NUM_PIPES; i++)
- {
- if(pipe[i].enabled && pipe[i].y > 0x00)
- pipe[i].y--;
- else
- {
- pipe[i].enabled = 0;
- pipe[i].y = 0x50;
- }
- }
- }
- if(!(frame_counter % 128) && !pipe[NUM_PIPES - 1].enabled)
- for(int i = 0; i < NUM_PIPES; i++)
- if(!pipe[i].enabled)
- {
- int rand_position = (rand() % (MAX_SHIFT - GAP - MIN_SHIFT)) + MIN_SHIFT;
- pipe[i].y = 0x50;
- pipe[i].position = rand_position;
- pipe[i].enabled = 1;
- break;
- }
- /*
- ----------------PHYSICS----------------
- */
- if(BIRD.x + yspeed > 0x00) // if the bird won't be killed by the next move,
- {
- BIRD.x += yspeed; // add the y speed to the bird's y position (screen is rotated so x is y)
- if(!(frame_counter % 3))
- yspeed -= 1;
- }
- else
- {
- yspeed = 2;
- /*IRQ_ENA1 &= ~IRQ1_PRC_COMPLETE; // disable the frame end interrupt
- BIRD.ctrl &= ~OAM_ENABLE; // disable the bird sprite
- break; // break this infinite loop*/
- }
- if(BIRD.x > 0x60) // if the bird goes off the top of the screen,
- {
- yspeed = 0; // kill the y speed
- BIRD.x = 0x60; // lock the height
- }
- if(get_key(KEY_RIGHT))
- {
- yspeed = 2; // if the right key is pressed, jump
- }
- // pipe drawing
- next_sprite = 2; // 0 is bird, 1 is game over graphic
- for(int i = next_sprite; i < 21; i++)
- {
- OAM[i].ctrl = 0;
- }
- for(int i = 0; i < NUM_PIPES; i++)
- {
- draw_pipe(i);
- }
- }
- // this happens when the bird dies
- IO_DATA |= BIT4; // write 1 to rumble data line to start rumbling
- for(int j = 0; j < 5000; j++) // wait for a bit
- ;
- IO_DATA &= ~BIT4; // write 0 to rumble data line to stop rumbling
- GAME_OVER.ctrl = OAM_ENABLE; // display the lose sprite
- for(int i = 0; i < 12; i++)
- {
- GAME_OVER.ctrl ^= OAM_INVERT; // flash it a few times
- for(int j = 0; j < 1000; j++)
- ;
- }
- return 0; // good practice
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement