daily pastebin goal
70%
SHARE
TWEET

How to write a simple side scrolling game in GBDK...

a guest Sep 12th, 2010 6,465 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. How To Write a Simple Side Scrolling Game in GBDK Written Really Fucking Simply
  2. Version 1.2
  3. By Jason
  4. drunk-ass@beer.com
  5.  
  6. Thanks go to Darren Reid and Chris Larken for the bug reports.
  7.  
  8. Newbies have been seriously complaining lately about a lack of documents out there that explain to them what to do step by step. Personally, I think they're either looking for people to write the code for them or aren't smart enough to code. It's not a bad thing. I can't compose music or draw worth shit. Either way, here's another gift to all the coders out there.
  9.  
  10. This is far from optimized. This is partially caused by myself creating bad code, and partially done to make it easier to describe what is going on.
  11.  
  12. All information is valid with GBDK (SDCC) version 2.93.
  13.  
  14. Procedure 1 - Make.bat
  15.  
  16. Many people say you should plan your game before you code it. This is just stupid. If you waste time planning, you're not working. Not working means you're not being productive. You can always redo whatever you fuck up.
  17. You need a make.bat in order to compile your game. While there's plenty of ways to do this, include a make file, I prefer a make.bat due to the fact I like DOS and it's just easier that way.
  18. We make our make.bat using MS-DOS 6.22 Edit. We do not use notepad, as notepad will save it as make.bat.txt, which is not make.bat. Comprende?
  19. So let's look at our make.bat...
  20.  
  21.         echo off
  22. This line tells DOS to supress the lines written when the batch file is called.
  23.  
  24.         d:\gbdk\bin\lcc -Wa-l -Wl-m -Wl-j -c -o newbie.o newbie.c
  25. This compiles the bank 0 C file newbie.c into a GBDK object file called newbie.o
  26.  
  27.         d:\gbdk\bin\lcc -Wa-l -Wl-m -Wl-j -Wf-bo2 -c -o bank2.o bank2.c
  28. This compiles the bank 2 file bank2.c into a GBDK object file called bank2.o. Notice the
  29. -Wf-bo2 flag. This is very important as it tells GBDK to put all the shit it compiles from this file into bank 2.
  30.  
  31.         d:\gbdk\bin\lcc -Wa-l -Wl-m -Wl-j -Wf-bo3 -c -o bank3.o bank3.c
  32. This compiles the bank 3 file bank3.c into a GBDK object file called bank3.o. Notice the
  33. -Wf-bo3 flag. This is very important as it tells GBDK to put all the shit it compiles from this file into bank 3.
  34.  
  35.         d:\gbdk\bin\lcc -Wa-l -Wl-m -Wl-j -Wl-yt0x01 -Wl-yo4 -Wl-yp0x143=0x80 -o newbie.gbc newbie.o bank2.o bank3.o
  36. This builds the actual ROM image, newbie.gbc from the object files newbie.o, bank2.o, and bank3.o.
  37. The -Wl-yt0x01 indicates which cartridge type we will be using. We picked 0x01, or a ROM + MBC 1 memory controller. Select one from the following table taken from Pan of Anthrox's GBSPEC.TXT.
  38. 0147 Cartridge type:
  39. 0 - ROM ONLY                    12 - ROM+MBC3+RAM
  40. 1 - ROM+MBC1                    13 - ROM+MBC3+RAM+BATT
  41. 2 - ROM+MBC1+RAM                19 - ROM+MBC5
  42. 3 - ROM+MBC1+RAM+BATT   1A - ROM+MBC5+RAM
  43. 5 - ROM+MBC2                    1B - ROM+MBC5+RAM+BATT
  44. 6 - ROM+MBC2+BATTERY    1C - ROM+MBC5+RUMBLE
  45. 8 - ROM+RAM                     1D - ROM+MBC5+RUMBLE+SRAM
  46. 9 - ROM+RAM+BATTERY             1E - ROM+MBC5+RUMBLE+SRAM+BATT
  47. B - ROM+MMM01                   1F - Pocket Camera
  48.  
  49. The -Wl-yp0x143=0x80 indicates that this will be a Gameboy Color compatible title. replacing 0x80 with 0xC0 will indicate a Gameboy Color Only title, and 0x00 will represent everything else.
  50. The -Wl-yo4 indicates how many ROM banks we will be using. We selected 4, thus equalling a 64 kilobyte ROM. The following are common bank sizes taken from Pan of Anthrox's GBSPEC.TXT.
  51.         256Kbit = 32KByte = 2 banks
  52.         512Kbit = 64KByte = 4 banks
  53.         1Mbit = 128KByte = 8 banks
  54.         2Mbit = 256KByte = 16 banks
  55.         4Mbit = 512KByte = 32 banks
  56.         8Mbit = 1MByte = 64 banks
  57.         16Mbit = 2MByte = 128 banks
  58.  
  59.  
  60.         pause
  61. This DOS command waits until a key is pressed before continuing. This allows us to see any errors if applicable.
  62.  
  63.         d:\no\dboy d:\gbdev\newbie\newbie.gbc
  64. This runs the ROM newbie.gbc with the emulator DBOY. This allows us to test the rom to see if it does what it is supposed to.
  65.  
  66.         cd d:\gbdev\newbie
  67. This makes sure that the directory the batch file ends up at is d:\gbdev\newbie. No$gmb changes the directory if it was selected over dboy above.
  68.  
  69.         d:
  70. This switches the drive to D:, which is a secondary 540 meg harddrive in my computer that is dedicated to gameboy development.
  71.  
  72.         del *.lst        
  73. This deletes the .LST files since I don't use them, thus freeing up disk space.
  74.  
  75. And that completes your make.bat file. Good for you!
  76.  
  77. Procedure 2 - GBTK
  78.  
  79. 1) Start Megaman X's Gameboy Toolkit. (Version used V0.013A)
  80. 2) There is a big rectangle entitled Source. Click on there and an Open File dialogue will appear.
  81. 3) Load whatever picture you want to load by finding it on your computer, highlighting it, and double clicking it.
  82. 4) We need to make it so that it is under 256 tiles. This is because the original gameboy's hardware only supports 256 tiles at a time loaded into video RAM. There is a work around for the Gameboy Color only, however this is just a beginner document, so we will not go into detail about it. A good size would be either 18x13 or 13x18, both use ~234 tiles. Multiplied out that is either 144x104 or 104x144 of the Gameboy's 160x144 display.  In the upper right corner is a section entitled Picture/Video Size. The 3rd Radio Button allows you to enter your size. The first box is for the X, the second box is for the Y. For our sake we'll use 104x144. Click the 3rd Radio Dial. Fill in the boxes. Click the unmarked gray box directly to the right of the 2 size boxes.
  83. 5) If the picture does not look perfect, adjust it by moving the dials in the GameBoy Thresholds.
  84. 6) When satisfied, click File.
  85. 7) Click Save As.
  86. 8) Change the Save As Type to Gameboy Development Kit (*.h)
  87. 9) Change the directory to your project directory.
  88. 10) Type in titlepic.h
  89. 11) Click Save.
  90.  
  91.  
  92.  
  93. Procedure 3 - GBTD
  94.  
  95. Background Tile
  96. 1) Launch Gameboy Tile Designer
  97. 2) With Tile 0, draw the tile that you want to fill the screen with during gameplay.
  98. 3) Click on File.
  99. 4) Click on Export To....
  100. 5) Under File [ Type ] Select GBDK C file (*.c)
  101. 6) In the File [ Filename ] Type in the path to your project and bgtile.c
  102. 7) Under Settings [ Label ] Type in BGTile
  103. 8) Click OK
  104. 9) Click File.
  105. 10) Click Export.
  106.  
  107.  
  108.  
  109. Sprite Tiles
  110. 1) Launch Gameboy Tile Designer
  111. 2) With Tile 0, draw the tile that you want for the player.
  112. 3) With Tile 1 (click on the white box next to the 1 right below the small graphic containing the picture of the player with the number 0 next to it.), draw the BadGuy.
  113. 4) With Tile 2 (click on the white box next to the 2 right below the small graphic containing the picture of the BadGuy with the number 1 next to it.), draw the Player's Shot.
  114. 5) Click on File.
  115. 6) Click on Export To....
  116. 7) Under File [ Type ] Select GBDK C file (*.c)
  117. 8) In the File [ Filename ] Type in the path to your project and sprtiles.c
  118. 9) Under Settings [ Label ] Type in SpriteTiles
  119. 10) Here's the difference. Where it says Settings [ From ] [0] to [0], change the 2nd zero to a two so it reads Settings [ From ] [0] to [2].
  120. 10) Click OK
  121. 11) Click File.
  122. 12) Click Export.
  123.  
  124.  
  125.  
  126. Procedure 4 - Enemy AI
  127.  
  128. Enemy AI can easily be accomplished using Pan of Anthrox's Roller Coaster v.1.3.
  129. 1) Start Roller Coaster.
  130. 2) Fill in the following information.
  131.         Start Angle is the beginning of the sine wave.
  132.         End Angle is the end angle of the sine wave.
  133.         # of values is the number of positions to make on the wave.
  134.         Min. Value is the minimum value the variable can equal.
  135.         Max. Value is the maximum value the variable can equal.
  136.                 For the sake of our demonstration, we will use the default configuration.
  137. 3) Under the A section, press Sine. A sine wave should be created.
  138. 4) Under the C section, press A. The sine wave should be recreated in the C window.
  139. 5) Click on the Save To Clipboard button.
  140.  
  141.  
  142. Figure 1 - Rollercoaster
  143.  
  144. 6) Open up bank2.c
  145. 7) Paste in the data you copied to the clipboard.
  146. 8) Save bank2.c
  147. 9) Close Rollercoaster.
  148.  
  149.  
  150. Procedure 5 - Newbie.C
  151.  
  152. As easy as above seems, that's not programming. That's a batch file. You can't make a game from just a batch file.
  153.  
  154. Enter Newbie.C
  155. We have already established that this game will be 4 banks. Bank 0 is nonswitchable, so we want to try and keep this bank as uncluttered as possible. We will stash the game engine itself inside of bank 02, and try to get all the games data- graphic tiles and the non-game engine like inside of bank 03.
  156. Time to get coding.
  157.  
  158. We need to include our header files.
  159.  
  160.         #include <gb\gb.h>
  161. If you don't know what #include means, you shouldn't be reading this. Includes open another file for integration into the current c file. The header file gb.h contains gameboy specific routines.
  162.  
  163.         #include <rand.h>
  164. If you don't know what #include means, you shouldn't be reading this. Includes open another file for integration into the current c file. The header file rand.h contains routines for generating random numbers.
  165.  
  166. We now need to list our procedures. We define them in bank 0 so that we can access them from bank 0 if we are so inclined to do so.
  167.  
  168.         // bank 0
  169. This line is just commentary. It tells us that the following procedures are located inside bank 0.
  170.  
  171.         void vblint(void);
  172. This line defines our vertical blank interrupt handler.
  173.  
  174.         // bank 2
  175. This line is just commentary. It tells us that the following procedures are located inside bank 2. This helps us later on, since bankswitching is not automatic with GBDK.
  176.  
  177.         void UpdateGraphics(void);
  178. This routine updates all the sprites and the background. It is located inside of bank 2, so bank 2 must be selected before you call it.
  179.  
  180.         void DoGameplay(void);
  181. The game's actual gameplay lies inside of here.
  182.  
  183.         void UpdateJoypad(void);
  184. This procedure reads the joypad, and reacts to the gameplay accordingly.
  185.  
  186.         void UpdateBadGuy(void);
  187. This procedure updates the Bad Guy.
  188.  
  189.         void CollisionDetection(void);
  190. This procedure checks to make sure no sprites have collided, and does action if sprites have.
  191.  
  192.  
  193.         // bank 3
  194. This line is just commentary. It tells us that the following procedures are located inside bank 3. This helps us later on, since bankswitching is not automatic with GBDK.
  195.  
  196.         void DrawTitleScreen(void);
  197. The first procedure in bank 3 is DrawTitleScreen. As you can hopefully guess, this procedure draws the title screen.
  198.  
  199.         void LoadGameTiles(void);
  200. This procedure loads the game's tiles from bank 3 into the gameboy's video ram so that we may access them later on during the game.
  201.  
  202. We now need to list our variables.
  203.  
  204.         fixed seed;
  205. This creates a fixed (data type) seed (name) used for random number generation. Don't think too much, just cut and paste.
  206.  
  207. Time to start coding the actual procedures.
  208.  
  209.         main()
  210. This creates the main procedure. The main procedure is what is called at the beginning of the ROM.
  211.  
  212.         {
  213. This { thing. No. I'm not going to describe this every time I have to. But I will describe this once. This thing is what signifies the start of a section of code specific to the line preceding it.
  214.  
  215. First we will do what has to be initialized.
  216.  
  217.                 seed.b.l = DIV_REG;
  218. This line loads whatever is in the DIV_REG into seed.b.l. This is for random number generation. Don't worry too much about it.
  219.  
  220. Now let us display our title screen.
  221.  
  222.                 SWITCH_ROM_MBC1(3);
  223. This line switches the memory bank controller to bank 3, which contains our data.
  224.  
  225.                 DrawTitleScreen();
  226. That draws the title screen. It's that simple. At least for bank 0.
  227.  
  228. Now prepare to get the game playing.
  229.  
  230.                 seed.b.h = DIV_REG;
  231. Load DIV_REG into seed.b.h. For Random number generation.
  232.  
  233.                 initrand(seed.w);
  234. Initialize the random number generator.
  235.  
  236.                 LoadGameTiles();
  237. This procedure loads the tiles from bank 3 that we want to use in our game located in bank 2.
  238.  
  239.                 disable_interrupts();
  240. This prevents interrupts from happening until an enable_interrupts(); is called.
  241.  
  242.                 add_VBL(vblint);
  243. This adds our procedure void vblint(void); as the VBL interrupt handler, so that when a vblank interrupt is triggered, the CPU jumps to that procedure.
  244.  
  245.                 SWITCH_ROM_MBC1(2);
  246. This line switches the memory bank controller to bank 2, which contains our game code.
  247.  
  248.                 DoGameplay();
  249. This procedure plays the game. Seeing as how it is in bank 2, we called the SWITCH_ROM_MBC1(bank #2); above.
  250.  
  251.  
  252.                 reset();
  253. This line resets the gameboy. This is much nicer than having the gameboy color just crash.
  254.  
  255.         }
  256. Remember our friend {? This line does the opposite, completing the section of code.
  257.  
  258. Now we code our void vblint(void); and any other previously defined bank 0 procedures.
  259.  
  260.         void vblint(void)
  261. Tell the compiler that we are starting code on the section for vblint.
  262.  
  263.         {
  264.  
  265.                 SWITCH_ROM_MBC1(2);
  266. Make sure that we are switched to Bank 2, since this is our game code bank.
  267.  
  268.                 UpdateGraphics();
  269. Call the graphical update. We do this during vertical blank since it is the time that the screen is not being updated. Otherwise graphical errors are bound to happen since you are updating the areas while you are coding.
  270.  
  271.         }
  272. End vblint.
  273.  
  274. And thus ends bank 0. There is still plenty of space free, so if we ever want to add more to the game, such as interrupt-driven routines, we have room.
  275.  
  276. Procedure 6 - Bank02.C
  277.  
  278.         #include <gb\gb.h>
  279. First thing to do is to include gb.h
  280.  
  281.         #include <rand.h>
  282. And rand.h
  283.  
  284. When we open this, we start out with this (or a variant if the options were tweaked) that we pasted in from Pan's RollerCoaster.
  285.  
  286. db  32,  32,  33,  34,  35,  35,  36,  37
  287. db  38,  38,  39,  40,  41,  41,  42,  43
  288. db  44,  44,  45,  46,  46,  47,  48,  48
  289. db  49,  50,  50,  51,  51,  52,  53,  53
  290. db  54,  54,  55,  55,  56,  56,  57,  57
  291. db  58,  58,  58,  59,  59,  60,  60,  60
  292. db  61,  61,  61,  61,  62,  62,  62,  62
  293. db  62,  63,  63,  63,  63,  63,  63,  63
  294. db  63,  63,  63,  63,  63,  63,  63,  63
  295. db  62,  62,  62,  62,  62,  61,  61,  61
  296. db  61,  60,  60,  60,  59,  59,  59,  58
  297. db  58,  57,  57,  56,  56,  55,  55,  54
  298. db  54,  53,  53,  52,  52,  51,  50,  50
  299. db  49,  49,  48,  47,  47,  46,  45,  44
  300. db  44,  43,  42,  42,  41,  40,  39,  39
  301. db  38,  37,  36,  36,  35,  34,  33,  33
  302. db  32,  31,  30,  29,  29,  28,  27,  26
  303. db  26,  25,  24,  23,  23,  22,  21,  20
  304. db  20,  19,  18,  18,  17,  16,  16,  15
  305. db  14,  14,  13,  12,  12,  11,  11,  10
  306. db  9,  9,  8,  8,  7,  7,  6,  6
  307. db  6,  5,  5,  4,  4,  4,  3,  3
  308. db  3,  2,  2,  2,  1,  1,  1,  1
  309. db  1,  1,  0,  0,  0,  0,  0,  0
  310. db  0,  0,  0,  0,  0,  0,  0,  0
  311. db  1,  1,  1,  1,  1,  1,  2,  2
  312. db  2,  3,  3,  3,  4,  4,  4,  5
  313. db  5,  5,  6,  6,  7,  7,  8,  8
  314. db  9,  9,  10,  11,  11,  12,  12,  13
  315. db  14,  14,  15,  16,  16,  17,  18,  18
  316. db  19,  20,  20,  21,  22,  23,  23,  24
  317. db  25,  26,  26,  27,  28,  29,  29,  30
  318.  
  319. Now we need to change this into C code.
  320.  
  321.         const UBYTE EnemyAI[] = {
  322. First write this line that defines a constant (unchangeable by program. This saves alot of RAM later on.) unsigned byte array called EnemyAI.
  323.         32,  32,  33,  34,  35,  35,  36,  37,
  324. Remove all the dbs. Add a comma to the end
  325.         38,  38,  39,  40,  41,  41,  42,  43,
  326. Remove all the dbs. Add a comma to the end
  327.         44,  44,  45,  46,  46,  47,  48,  48,
  328. Remove all the dbs. Add a comma to the end
  329.         49,  50,  50,  51,  51,  52,  53,  53,
  330. Remove all the dbs. Add a comma to the end
  331.         54,  54,  55,  55,  56,  56,  57,  57,
  332. Remove all the dbs. Add a comma to the end
  333.         58,  58,  58,  59,  59,  60,  60,  60,
  334. Remove all the dbs. Add a comma to the end
  335.         61,  61,  61,  61,  62,  62,  62,  62,
  336. Remove all the dbs. Add a comma to the end
  337.         62,  63,  63,  63,  63,  63,  63,  63,
  338. Remove all the dbs. Add a comma to the end
  339.         63,  63,  63,  63,  63,  63,  63,  63,
  340. Remove all the dbs. Add a comma to the end
  341.         62,  62,  62,  62,  62,  61,  61,  61,
  342. Remove all the dbs. Add a comma to the end
  343.         61,  60,  60,  60,  59,  59,  59,  58,
  344. Remove all the dbs. Add a comma to the end
  345.         58,  57,  57,  56,  56,  55,  55,  54,
  346. Remove all the dbs. Add a comma to the end
  347.         54,  53,  53,  52,  52,  51,  50,  50,
  348. Remove all the dbs. Add a comma to the end
  349.         49,  49,  48,  47,  47,  46,  45,  44,
  350. Remove all the dbs. Add a comma to the end
  351.         44,  43,  42,  42,  41,  40,  39,  39,
  352. Remove all the dbs. Add a comma to the end
  353.         38,  37,  36,  36,  35,  34,  33,  33,
  354. Remove all the dbs. Add a comma to the end
  355.         32,  31,  30,  29,  29,  28,  27,  26,
  356. Remove all the dbs. Add a comma to the end
  357.         26,  25,  24,  23,  23,  22,  21,  20,
  358. Remove all the dbs. Add a comma to the end
  359.         20,  19,  18,  18,  17,  16,  16,  15,
  360. Remove all the dbs. Add a comma to the end
  361.         14,  14,  13,  12,  12,  11,  11,  10,
  362. Remove all the dbs. Add a comma to the end
  363.         9,  9,  8,  8,  7,  7,  6,  6,
  364. Remove all the dbs. Add a comma to the end
  365.         6,  5,  5,  4,  4,  4,  3,  3,
  366. Remove all the dbs. Add a comma to the end
  367.         3,  2,  2,  2,  1,  1,  1,  1,
  368. Remove all the dbs. Add a comma to the end
  369.         1,  1,  0,  0,  0,  0,  0,  0,
  370. Remove all the dbs. Add a comma to the end
  371.         0,  0,  0,  0,  0,  0,  0,  0,
  372. Remove all the dbs. Add a comma to the end
  373.         1,  1,  1,  1,  1,  1,  2,  2,
  374. Remove all the dbs. Add a comma to the end
  375.         2,  3,  3,  3,  4,  4,  4,  5,
  376. Remove all the dbs. Add a comma to the end
  377.         5,  5,  6,  6,  7,  7,  8,  8,
  378. Remove all the dbs. Add a comma to the end
  379.         9,  9,  10,  11,  11,  12,  12,  13,
  380. Remove all the dbs. Add a comma to the end
  381.         14,  14,  15,  16,  16,  17,  18,  18,
  382. Remove all the dbs. Add a comma to the end
  383.         19,  20,  20,  21,  22,  23,  23,  24,
  384. Remove all the dbs. Add a comma to the end
  385.         25,  26,  26,  27,  28,  29,  29,  30,
  386. Remove all the dbs. Add a comma to the end
  387.         };
  388. End EnemyAI
  389.  
  390.         UBYTE Playing, Joy;
  391. UBYTEs are unsigned 8 bit variables capable of a number between 0 and 255, or 0x00 to 0xFF hex. Playing determines whether or not the game is playing. Joy is the unsigned byte that we will be using to read the joypad and see if the pad is pressed in a certain direction.
  392.  
  393.         UBYTE PlayerX, PlayerY;
  394. UBYTEs are unsigned 8 bit variables capable of a number between 0 and 255, or 0x00 to 0xFF hex. PlayerX refers to the Player's X coordinates. PlayerY refers to the Player's Y coordinates.
  395.  
  396.         UBYTE BadGuyX, BadGuyY, BadGuyZ, BadGuyOffset;
  397. UBYTEs are unsigned 8 bit variables capable of a number between 0 and 255, or 0x00 to 0xFF hex. BadGuyX refers to the Bad Guy's X coordinates. BadGuyY refers to the Bad Guy's Y coordinates. BadGuyZ will be the spot in reference to where he is AI wise. BadGuyOffset is the Y offset for the AI.
  398.  
  399.         UBYTE PlayerShotX, PlayerShotY, PlayerShotZ;
  400. UBYTEs are unsigned 8 bit variables capable of a number between 0 and 255, or 0x00 to 0xFF hex. PlayerShotX refers to the Player's Shot's X coordinates. PlayerShotY refers to the Player's Shot's Y coordinates. PlayerShotZ determines whether or not the player has shot.
  401.  
  402.  
  403.         void UpdateGraphics(void)
  404. This routine is the routine that updates the graphics the player sees on the screen. It is called by the VBLINT handling routine, so every vblint the graphics are updated.
  405.  
  406.         {
  407.                 disable_interrupts();
  408. Disable the interrupts. This way if another interrupt occurs, we will not lose our place inside the vblint.
  409.  
  410.                 scroll_bkg(1,0);
  411. This moves the background 1 pixel on the X-axis. By doing this, the background scrolls continually.
  412.  
  413.                 move_sprite(0,PlayerX,PlayerY);
  414. This moves the player's sprite to its current X-Y axis.
  415.  
  416.                 move_sprite(1,BadGuyX,BadGuyY);
  417. This moves the Bad Guy's sprite to its current X-Y axis.
  418.  
  419.                 move_sprite(2,PlayerShotX,PlayerShotY);
  420. This moves the Player's Shots' sprite to its current X-Y axis.
  421.  
  422.                 enable_interrupts();
  423. This enables interrupts so that come next vblint, the vblint handler will be called which will call this.
  424.  
  425.         }
  426. End UpdateGraphics.
  427.  
  428.  
  429.         void DoGameplay(void)
  430. this procedure contains the gameplay loop.
  431.         {
  432.                 playing = 1;
  433. Sets the UBYTE playing to 1, indicating that the game is playing.
  434.  
  435.                 while(playing == 1) {
  436. This starts a loop so that while playing is equal to 1, the loop will continue to loop. If playing does not equal 1, the loop will stop.
  437.  
  438. Repeat the following steps for the game to play.
  439.  
  440.                         UpdateJoypad();
  441. This procedure checks the joypad, and moves the players ship according to the results. It also updates the player's shot, if it has been shot, for lack of a better place of sticking it.
  442.  
  443.                         UpdateBadGuy();
  444. This procedure moves the enemy.
  445.                        
  446.                         CollisionDetection();
  447. This is one of the most important procedures. It checks to see if the player has collided with the enemy, along with the player's shot colliding with the badguy.
  448.        
  449.                         delay(10);
  450. This is the game's master speed control. It doesn't affect the background scrolling, but does affect the badguy's speed, as well as how responsive the controls are.
  451.  
  452.                 }
  453. end while loop
  454.  
  455.         }
  456. End DoGameplay.
  457.  
  458.         void UpdateJoypad(void)
  459. Begin the code for the checking the joypad.
  460.         {
  461.                 Joy = joypad();
  462. Read the joypad. Store what we read into unsigned byte Joy.
  463.  
  464. Now there's 2 ways you can do this. A switch is more efficient, but for ease of use we will use ifs.
  465.  
  466.                 if(Joy & J_LEFT) {
  467. J_LEFT is defined in gb.h. Joy is the returned buttons pressed byte. If the bit defined by J_LEFT and the corresponding bit in Joy are both 1, then the if statement is true, thus all the code in the {} brackets will be ran.
  468.  
  469.                         if(PlayerX > 0) PlayerX--;
  470. This checks to make sure that the PlayerX can be decreased without making the sprite go completely off of the screen. The number 0 might need to be replaced with a different number such as 8 in order to keep the sprite on screen.
  471.  
  472.                 }
  473. End IF Joy & J_LEFT statement.
  474.  
  475.                 if(Joy & J_RIGHT) {
  476. J_RIGHT is defined in gb.h. Joy is the returned buttons pressed byte. If the bit defined by J_RIGHT and the corresponding bit in Joy are both 1, then the if statement is true, thus all the code in the {} brackets will be ran.
  477.  
  478.                         if(PlayerX < 152) PlayerX++;
  479. This checks to make sure that the PlayerX can be increased without making the sprite go completely off of the screen. The number 152 might need to be replaced with a different number such as 160 in order to keep the sprite on screen.
  480.  
  481.                 }
  482. End IF Joy & J_RIGHT statement.
  483.  
  484.                 if(Joy & J_UP) {
  485. J_UP is defined in gb.h. Joy is the returned buttons pressed byte. If the bit defined by J_UP and the corresponding bit in Joy are both 1, then the if statement is true, thus all the code in the {} brackets will be ran.
  486.  
  487.                         if(PlayerY > 0) PlayerY --;
  488. This checks to make sure that the PlayerY can be decreased without making the sprite go completely off of the screen. The number 0 might need to be replaced with a different number such as 8 in order to keep the sprite on screen.
  489.  
  490.                 }
  491. End IF Joy & J_UP statement.
  492.  
  493.  
  494.                 if(Joy & J_DOWN) {
  495. J_DOWN is defined in gb.h. Joy is the returned buttons pressed byte. If the bit defined by J_DOWN and the corresponding bit in Joy are both 1, then the if statement is true, thus all the code in the {} brackets will be ran.
  496.  
  497.                         if(PlayerY < 136) PlayerY++;
  498. This checks to make sure that the PlayerY can be increased without making the sprite go completely off of the screen. The number 136 might need to be replaced with a different number such as 144 in order to keep the sprite on screen.
  499.  
  500.                 }
  501. End IF Joy & J_DOWN statement.
  502.  
  503.                 if(Joy & J_A) {
  504. J_A is defined in gb.h. Joy is the returned buttons pressed byte. If the bit defined by J_A and the corresponding bit in Joy are both 1, then the if statement is true, thus all the code in the {} brackets will be ran.
  505.  
  506.                         if(PlayerShotZ == 0) {
  507. This checks to see if a shot has been fired. If there is no shot being shot, then you can go ahead and shoot.
  508.  
  509.                                 PlayerShotZ = 1;
  510. This is done to signify that a shot has been fired.
  511.  
  512.                                 PlayerShotX = PlayerX;
  513. This is done to move the shot to where the player is. Since the player has a lower sprite number (zero as opposed to two for the shot), the player is drawn on top of the shot, thus making it look like the shot is coming from the player.
  514.  
  515.                                 PlayerShotY = PlayerY;
  516. This is done to move the shot to where the player is. Since the player has a lower sprite number (zero as opposed to two for the shot), the player is drawn on top of the shot, thus making it look like the shot is coming from the player.
  517.  
  518.                         }
  519. End if PlayerShotZ = 0 statement.
  520.  
  521.                 }
  522. End if Joy & J_A statement.
  523.  
  524.                 if(PlayerShotZ == 1) {
  525. If the player has shot, do the following.
  526.  
  527.                         PlayerShotX = PlayerShotX + 2;
  528. Increase the Player's Shot's X axis by 2 in order to make the bullet faster than the player.
  529.  
  530.                         if(PlayerShotX > 240) {
  531. If the shot has moved past the 240 mark, do the following.
  532.  
  533.                                 PlayerShotX = 250;
  534. This moves the sprite off of the screen so that a stationary bullet is not displayed on the gameboy.
  535.  
  536.                                 PlayerShotY = 250;
  537. This moves the sprite off of the screen so that a stationary bullet is not displayed on the gameboy.
  538.  
  539.                                 PlayerShotZ = 0;
  540. This tells the game that the player has not shot. The reset in PlayerShotZ allows the player to shoot come next game loop call if A is being pressed.
  541.  
  542.                         }
  543. End if PlayerShotX > 240 statement.
  544.  
  545.                 }
  546. End if PlayerShotZ = 1 statement.
  547.                
  548.         }
  549. End UpdateJoypad
  550.  
  551.         void UpdateBadGuy(void)
  552. This routine updates the BadGuy so he's not a gay stationary object.
  553.         {
  554.                 BadGuyX = BadGuyX - 1;
  555. Decrease the BadGuy's X coordinate.
  556.                 if(BadGuyX > 240) {
  557. When the BadGuyX counter is decreased from 0, it resets to 255. When this happens, do the following.
  558.  
  559.                         BadGuyOffset = rand();
  560. Load a random number into the BadGuy's AI Offset.
  561.  
  562.                         while(BadGuyOffset > 134) {
  563. Loop until we get a BadGuyY that is less than 134 (so we see the badguy).
  564.  
  565.                                 BadGuyOffset = rand();
  566. Load a random number into the BadGuy's AI Offset.
  567.  
  568.                         }
  569. End while BadGuyY > 134 loop
  570.  
  571.                         BadGuyX = 239;
  572. Move the BadGuy's X axis so that the greater than 240 does not keep getting called.
  573.  
  574.                 }
  575. End BadGuyX > 240 Loop
  576.  
  577.                 BadGuyY = BadGuyOffset + BadGuyAI[BadGuyZ];
  578. Load the new BadGuyY. Do this by taking the Offset value and adding the current AI value to it. This creates the sine wave effect we used RollerCoaster to create.
  579.  
  580.                 BadGuyZ++;
  581. Increase the BadGuyAI counter.
  582.         }
  583. End UpdateBadGuy
  584.  
  585.         void CollisionDetection(void)
  586. Check to see if sprites collide
  587.         {
  588.  
  589. The following set numbers in each if statement (the 4) need to be adjusted depending on how the sprites are drawn.
  590.  
  591.                 if(PlayerShotY > BadGuyY - 4) {
  592. Check to see if the Y axis is great enough to trigger a collision.
  593.  
  594.                         if(PlayerShotY < BadGuyY + 4) {
  595. Check to see if the Y axis is small enough to trigger a collision.
  596.  
  597.                                 if(PlayerShotX > BadGuyX - 4) {
  598. Check to see if the X axis is great enough to trigger a collision.
  599.                                         if(PlayerShotX < BadGuyX + 4) {
  600. Check to see if the X axis is small enough to trigger a collision.
  601.  
  602. If all of these have occured, we have a hit.
  603.                                                 PlayerShotZ = 0;
  604. Reset the unsigned byte that determines if the player has shot or not.
  605.  
  606.                                                 PlayerShotX = 250;
  607. Move the Player's Shot's X axis off of the screen.
  608.  
  609.                                                 PlayerShotY = 250;
  610. Move the Player's Shot's Y axis off of the screen.
  611.  
  612.                                                 EnemyX = 255;          
  613. Move the Enemy's X axis so that it is far enough off of the screen that the next UpdateBadguy will reset it.
  614.  
  615.                                         }
  616. End if PlayerShotX < BadGuyX + 4
  617.                                 }
  618. End if PlayerShotX > BadGuyX - 4
  619.  
  620.                         }
  621. End if PlayerShotY < BadGuyY + 4
  622.  
  623.                 }
  624.  End If PlayerShotY > BadguyY - 4 Statement
  625.  
  626.  
  627.                 if(PlayerY > BadGuyY - 4) {
  628. Check to see if the Y axis is great enough to trigger a collision.
  629.  
  630.                         if(PlayerY < BadGuyY + 4) {
  631. Check to see if the Y axis is small enough to trigger a collision.
  632.  
  633.                                 if(PlayerX > BadGuyX - 4) {
  634. Check to see if the X axis is great enough to trigger a collision.
  635.                                         if(PlayerX < BadGuyX + 4) {
  636. Check to see if the X axis is small enough to trigger a collision.
  637.  
  638. If all of these have occured, we have a hit.
  639.                                                 Playing = 0;
  640. A collision with your ship has occured. Thus you are dead, and the game ceases to play.
  641.  
  642.                                         }
  643. End if PlayerShotX < BadGuyX + 4
  644.                                 }
  645. End if PlayerShotX > BadGuyX - 4
  646.  
  647.                         }
  648. End if PlayerShotY < BadGuyY + 4
  649.  
  650.                 }
  651.  End If PlayerShotY > BadguyY - 4 Statement
  652.  
  653.  
  654.         }
  655. End CollisionDetection
  656.  
  657. Procedure 7 - Bank03.C
  658.  
  659. The game is done. The only thing we have left really is all the data to load into a bank, and to display the title picture.
  660.  
  661.         #include <gb\gb.h>
  662. Include gb.h. We can skip rand.h since we aren't going to be calling random numbers.
  663.  
  664.         #include "titlepic.h"
  665. This loads the information we converted with GBTK.
  666.  
  667.         #include "bgtile.c"
  668. This loads the background tile we drew with GBTD.
  669.  
  670.         #include "sprtiles.c"
  671. This loads the sprite tiles we drew with GBTD.
  672.  
  673.         const UBYTE gamemap[] = {
  674. const to save ram, unsigned byte, gamemap is its name. This is used to clear the map of the title screen data.
  675.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  676.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  677.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  678.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  679.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  680.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  681.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  682.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  683.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  684.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  685.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  686.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  687.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  688.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  689.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  690.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  691.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  692.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  693.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  694.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  695.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  696.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  697.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  698.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  699.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  700.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  701.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  702.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  703.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  704.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  705.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  706.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  707.         };
  708.  
  709.         const UWORD titlepal[] = {
  710. The palette to load for the title screen. It is constant to save on ram, UWORD as in unsigned 16 bit data type, and titlepal is its name.
  711.                 RGB(0,0,0),RGB(10,10,10),RGB(20,20,20),RGB(30,30,30),
  712. RGB is a color define. The first number refers to red, 2nd green, 3rd blue. so RGB(red,green,blue), where the values can be anywhere from 0 to 31.
  713.         };
  714. end titlepal
  715.  
  716.         const UWORD bgpal[] = {
  717. The palette to load for the background of the game. It is constant to save on ram, UWORD as in unsigned 16 bit data type, and bgpal is its name.
  718.                 RGB(0,0,0),RGB(10,10,10),RGB(20,20,20),RGB(30,30,30),
  719. RGB is a color define. The first number refers to red, 2nd green, 3rd blue. so RGB(red,green,blue), where the values can be anywhere from 0 to 31.
  720.         };
  721. end titlepal
  722.  
  723.         const UWORD spritepal[] = {
  724. The palette to load for the game's sprites. It is constant to save on ram, UWORD as in unsigned 16 bit data type, and spritepal is its name.
  725.                 RGB(0,0,0),RGB(10,10,10),RGB(20,20,20),RGB(30,30,30),
  726. RGB is a color define. The first number refers to red, 2nd green, 3rd blue. so RGB(red,green,blue), where the values can be anywhere from 0 to 31.
  727.         };
  728. end titlepal
  729.  
  730.         void DrawTitleScreen(void)
  731. Time to display the title screen, and wait until a button is pressed.
  732.  
  733.         {
  734.  
  735.                 wait_vbl_done();
  736. Wait until the screen is not being updated.
  737.  
  738.                 DISPLAY_OFF;
  739. Turn the display off.
  740.  
  741.                 set_bkg_data(0,235,title_tiledata);
  742. Set the background tile data so that it loads from the title_tiledata from title.h. The 0 indicates the tile to start with. The 235 indicates how many tiles to load, and the title_tiledata tells where to load the tiles from.
  743.  
  744.                 set_bkg_tiles(2,0,13,18,title_tilemap);
  745. Set the background tile map so that it displays the title_tilemap from title.h. The 2 shows where to start displaying the tiles from x-wise. the 0 shows where to start drawing the title picture from y-wise. The 13 shows how many tiles horizontally to draw. The 18 shows how many tiles vertically to draw. title_tilemap tells it where to load the map from.
  746.  
  747.                 set_bkg_palette(0,1,&titlepal[0]);
  748. set_bkg_palette sets the background palette. the 0 states to start with palette # 0. the 1 states to load 1 palette. the &titlepal[0] states to load the palette from titlepal.
  749.  
  750.                 SHOW_BKG;
  751. Show the background.
  752.  
  753.                 HIDE_WIN;
  754. Hide the window since we are not using it.
  755.  
  756.                 HIDE_SPRITES;
  757. Hide the sprites since we are not using them.
  758.  
  759.                 wait_vbl_done();
  760. Wait until the screen is not being updated.
  761.  
  762.                 DISPLAY_ON;
  763. Turn the display on.
  764.  
  765.                 waitpad(255);
  766. Wait until anything is pressed. 255 is all 8 bits, which means if any of the 8 buttons on the gameboy are pressed, continue.
  767.  
  768.         }
  769. End DrawTitleScreen
  770.  
  771.         void LoadGameTiles(void)
  772. Load the game's data.
  773.         {
  774.                 wait_vbl_done();
  775. Wait until the gameboy is not updating the display.
  776.  
  777.                 DISPLAY_OFF;
  778. Turn the display off.
  779.  
  780.                 set_bkg_data(0,1,BGTile);
  781. Set the background data to load the 1 bg tile. 0 = start tile, 1 = tiles to load, bgtile = where to load tile from.
  782.  
  783.                 set_bkg_tiles(0,0,32,32,gamemap);
  784. Set the background map to clear it of everything. 0 = x start, 0 = y start, 32 = width, 32 = height.
  785.  
  786.                 set_bkg_palette(0,1,&bgpal[0]);
  787. Set the background palette to the game's palette. 0 = start palette, 1 = palettes to load. &bgpal[0] = where to load palette from.
  788.  
  789.                 set_sprite_data(0,3,SpriteTiles);
  790. Load the sprite tiles. 0 = first tile. 3 = tiles to load. SpriteTiles = where to load tiles from
  791.  
  792.                 set_sprite_tile(0,0);
  793. Set display-sprite #0 to sprite-in-ram # 0
  794.  
  795.                 set_sprite_tile(1,1);
  796. Set display-sprite #1 to sprite-in-ram # 1
  797.  
  798.                 set_sprite_tile(2,2);
  799. Set display-sprite #2 to sprite-in-ram # 2
  800.  
  801.                 SPRITES_8x8;
  802. Use 8x8 sprites.
  803.  
  804.                 SHOW_SPRITES;
  805. Show the sprites.
  806.  
  807.                 SHOW_BKG;
  808. Show the background.
  809.  
  810.                 DISPLAY_ON;
  811. Turn the display on.
  812.  
  813.         }
  814.  
  815. Now, we are done coding, however we need to open up the following files -
  816.         TITLEPIC.H
  817.         BGTILE.C
  818.         SPRTILES.C
  819.  
  820.         In TITLEPIC.H -
  821. Find where it says
  822.         unsigned char titlepic_tiledata[] = {
  823. and change it to
  824.         const unsigned char titlepic_tiledata[] = {
  825. And then find
  826.         unsigned char titlepic_tilemap[] = {
  827. and change it to
  828.         const unsigned char titlepic_tilemap[] = {
  829.  
  830.         In BGTILE.C
  831. Find where it says
  832.         unsigned char BGTile[] = {
  833. and change it to
  834.         const unsigned char BGTile[] = {
  835.  
  836.         In SPRTILES.C
  837. Find where it says
  838.         unsigned char SpriteTiles[] = {
  839. and change it to
  840.         const unsigned char SpriteTiles[] = {
  841.  
  842.  
  843. Procedure 8 - Compile and assemble the ROM
  844.  
  845. This is the easiest procedure. Since we already have a make.bat file, run it. And if you did everything correctly, you should have a lame little sidescroller ROM compiled. Enjoy.
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top