Advertisement
Jhynjhiruu

Untitled

Apr 12th, 2019
366
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.99 KB | None | 0 0
  1. #include "pm.h" // read this library if you don't recognise anything in capital letters
  2.  
  3. #include "sprites.h" // 16x16 b/w + transparency bird sprite
  4. #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
  5.  
  6. #include "input.h" // library for input - useful
  7.  
  8. #include "rng.h" // randomness
  9.  
  10. // defines
  11.  
  12. #define SCREEN_SIZE 96 // height of screen (really width, but flappy bird is portrait)
  13.  
  14. #define NUM_PIPES 3 // number of pipes, duh
  15.  
  16. #define MIN_SHIFT 4 // lowest pipe position
  17.  
  18. #define GAP 32 // gap between top and bottom of pipe
  19.  
  20. #define MAX_SHIFT SCREEN_SIZE - MIN_SHIFT
  21.  
  22. // structs
  23.  
  24. struct Pipe {
  25.   unsigned char y;
  26.   unsigned char position;
  27.   unsigned char width;
  28.   unsigned char enabled;
  29. };
  30.  
  31. // global variables
  32.  
  33. int yspeed = 0; // variable storing bird's y speed
  34.  
  35. int next_sprite = 2; // holds the next free sprite for the drawing function (0 is bird, 1 is game over graphic)
  36.  
  37. struct Pipe pipe[NUM_PIPES]; // PIPES
  38.  
  39. // stuff for running once per frame
  40.  
  41. int frame_counter = 0; // used to count the number of frames that have passed
  42.  
  43. int trigger = 0;
  44.  
  45. void __interrupt irq_1_prc_done(void) // interrupt that is triggered after a frame is drawn
  46. {
  47.     IRQ_ACT1 |= IRQ1_PRC_COMPLETE; // acknowledge interrupt
  48.    
  49.     trigger = 1;
  50. }
  51.  
  52. void draw_pipe(int index)
  53. {
  54.     struct Pipe current_pipe = pipe[index];
  55.    
  56.     if(!current_pipe.enabled)
  57.     {
  58.         next_sprite += 7;
  59.         return;
  60.     }
  61.    
  62.     for(int i = 0; i < 7; i++)
  63.     {
  64.         OAM[next_sprite + i].y = current_pipe.y;
  65.         OAM[next_sprite + i].ctrl = OAM_ENABLE;
  66.     }
  67.    
  68.     OAM[next_sprite].x = current_pipe.position + 0x10;
  69.     OAM[next_sprite + 1].x = current_pipe.position + GAP + 0x10;
  70.    
  71.     for(int i = 2; i < 7; i++)
  72.     {
  73.         OAM[next_sprite + i].x = (i * 0x10 + current_pipe.position + GAP + 0x10);
  74.         if(OAM[next_sprite + i].x >= 0x70)
  75.             OAM[next_sprite + i].x = (i * 0x10 + current_pipe.position);
  76.     }
  77.    
  78.     OAM[next_sprite].tile = PIPE_END;
  79.     OAM[next_sprite + 1].tile = PIPE_END;
  80.    
  81.     for(int i = 2; i < 7; i++)
  82.         OAM[next_sprite + i].tile = PIPE_SECTION;
  83.    
  84.     OAM[next_sprite + 1].ctrl |= OAM_FLIPH;
  85.    
  86.     next_sprite += 7;
  87. }
  88.  
  89. int main(void) // main function
  90. {
  91.    
  92.     // screen initialisation
  93.    
  94.     PRC_MODE = COPY_ENABLE|SPRITE_ENABLE|MAP_ENABLE|MAP_16X12;
  95.     PRC_RATE = RATE_36FPS; // set up PRC to enable sprites, and a 16x12 tile background
  96.    
  97.     // interrupts
  98.    
  99.     IRQ_ENA1 |= IRQ1_PRC_COMPLETE; // enable the frame complete interrupt to do fun stuff (see irq_1_prc_done)
  100.     IRQ_PRI1 = PRI1_PRC(1); // give this high priority
  101.    
  102.     // tilemap initialisation
  103.    
  104.     for(int i = 0; i < 16 * 12; i++)
  105.         TILEMAP[i] = 0; // initialise the 16x12 tilemap with tile 0 (the chequerboard)
  106.    
  107.     PRC_SCROLL_X = 0;
  108.     PRC_SCROLL_Y = 0; // reset the background scroll values
  109.    
  110.     // sprites and tiles
  111.    
  112.     PRC_SPR = (long)sprites; // load in sprite tiles
  113.     PRC_MAP = (long)map; // load in map tiles
  114.    
  115.     // OAM definitions and initialisation
  116.    
  117.     #define BIRD OAM[0]
  118.  
  119.     BIRD.x = 0x40;
  120.     BIRD.y = 0x10;
  121.     BIRD.tile = BIRD_TILE_0; // initialise the first and only sprite with position (32, 32), the bird sprite and enable it
  122.     BIRD.ctrl = OAM_ENABLE;
  123.    
  124.     #define GAME_OVER OAM[1]
  125.  
  126.     GAME_OVER.x = 56;
  127.     GAME_OVER.y = 40;
  128.     GAME_OVER.tile = GAME_OVER_TILE;
  129.     GAME_OVER.ctrl = 0;
  130.    
  131.     // testing purposes only
  132.    
  133.     OAM[2].x = 0xF0;
  134.     OAM[2].y = 0xF0;
  135.     OAM[2].tile = PIPE_SECTION;
  136.     OAM[2].ctrl = 0;
  137.    
  138.     OAM[3].x = 0xF0;
  139.     OAM[3].y = 0xF0;
  140.     OAM[3].tile = PIPE_SECTION;
  141.     OAM[3].ctrl = 0;
  142.    
  143.     OAM[4].x = 0xF0;
  144.     OAM[4].y = 0xF0;
  145.     OAM[4].tile = PIPE_SECTION;
  146.     OAM[4].ctrl = 0;
  147.    
  148.     for(int i = 0; i < NUM_PIPES; i++)
  149.     {
  150.         pipe[i].y = 0x50;
  151.         pipe[i].position = 0;
  152.         pipe[i].width = 16;
  153.         pipe[i].enabled = 0;       
  154.     }
  155.    
  156.     for(;;) // do this infinitely:
  157.     {
  158.         while(!trigger)
  159.             ; // wait till the last frame has been drawn
  160.         trigger = 0;
  161.    
  162.         frame_counter++; // increment the frame counter
  163.    
  164.         if(!(frame_counter % 4)) // every 4 frames,
  165.         {
  166.             PRC_SCROLL_Y++; // increment the map x scroll by 1
  167.             PRC_SCROLL_Y &= 0x1F; // equivalent to % 32; makes it appear to scroll infinitely
  168.            
  169.             for(int i = 0; i < NUM_PIPES; i++)
  170.             {
  171.                 if(pipe[i].enabled && pipe[i].y > 0x00)
  172.                     pipe[i].y--;
  173.                 else
  174.                 {
  175.                     pipe[i].enabled = 0;
  176.                     pipe[i].y = 0x50;
  177.                 }
  178.             }
  179.        
  180.         }
  181.        
  182.         if(!(frame_counter % 128) && !pipe[NUM_PIPES - 1].enabled)
  183.             for(int i = 0; i < NUM_PIPES; i++)
  184.                 if(!pipe[i].enabled)
  185.                 {
  186.                     int rand_position = (rand() % (MAX_SHIFT - GAP - MIN_SHIFT)) + MIN_SHIFT;
  187.                     pipe[i].y = 0x50;
  188.                     pipe[i].position = rand_position;
  189.                     pipe[i].enabled = 1;
  190.                     break;
  191.                 }
  192.        
  193.         /*
  194.         ----------------PHYSICS----------------
  195.         */
  196.        
  197.         if(BIRD.x + yspeed > 0x00) // if the bird won't be killed by the next move,
  198.         {
  199.             BIRD.x += yspeed; // add the y speed to the bird's y position (screen is rotated so x is y)
  200.             if(!(frame_counter % 3))
  201.                 yspeed -= 1;
  202.         }
  203.         else
  204.         {
  205.             yspeed = 2;
  206.             /*IRQ_ENA1 &= ~IRQ1_PRC_COMPLETE; // disable the frame end interrupt
  207.             BIRD.ctrl &= ~OAM_ENABLE; // disable the bird sprite
  208.             break; // break this infinite loop*/
  209.         }
  210.        
  211.         if(BIRD.x > 0x60) // if the bird goes off the top of the screen,
  212.         {
  213.             yspeed = 0; // kill the y speed
  214.             BIRD.x = 0x60; // lock the height
  215.         }
  216.        
  217.         if(get_key(KEY_RIGHT))
  218.         {
  219.             yspeed = 2; // if the right key is pressed, jump
  220.         }
  221.        
  222.         // pipe drawing
  223.        
  224.         next_sprite = 2; // 0 is bird, 1 is game over graphic
  225.        
  226.         for(int i = next_sprite; i < 21; i++)
  227.         {
  228.             OAM[i].ctrl = 0;
  229.         }
  230.        
  231.         for(int i = 0; i < NUM_PIPES; i++)
  232.         {
  233.             draw_pipe(i);
  234.         }
  235.        
  236.     }
  237.    
  238.     // this happens when the bird dies
  239.    
  240.     IO_DATA |= BIT4; // write 1 to rumble data line to start rumbling
  241.     for(int j = 0; j < 5000; j++) // wait for a bit
  242.         ;
  243.     IO_DATA &= ~BIT4; // write 0 to rumble data line to stop rumbling
  244.    
  245.     GAME_OVER.ctrl = OAM_ENABLE; // display the lose sprite
  246.     for(int i = 0; i < 12; i++)
  247.     {
  248.         GAME_OVER.ctrl ^= OAM_INVERT; // flash it a few times
  249.         for(int j = 0; j < 1000; j++)
  250.             ;          
  251.     }
  252.    
  253.     return 0; // good practice
  254. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement