Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411423 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 19, 2024, 06:36:11 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Homebrew Creator's Club: Meeting One
Pages: [1] 2
Print
Author Topic: Homebrew Creator's Club: Meeting One  (Read 13208 times)
Cthulhu32
Level 6
*


Brawp


View Profile WWW
« on: February 01, 2010, 03:55:00 PM »


The TigForums Homebrew Creator's Club Presents
Meeting 1: Gameboy/Gameboy Color
Compiling a legal Nintendo rom, introduction to hardware registers and tile sets

[LOGO NEEDED]



Introduction:

    The Nintendo Gameboy, first introduced to the states in 1989, was a marvelous little hand held device. Many people remember the blips and bleeps of the sound chip, the costly 4 AA batteries, the horrible green screen that was impossible to see under anything except a jewelers light or a "Light Boy". But many of the games were simply amazing, and you absolutely could not get anything like it. Seeing Mario blowing up Sphinxes on an airplane, watching
 
    The Homebrew Creator's Club will be examining and compiling roms using both C and Assembly language, and everyone involved will have made at least one .gb file that runs on an emulator. All members are welcome to write quick blurbs, tutorials, moments of excitement, and general love/hate over the Nintendo Gameboy system. Members are also incouraged to release source with their demos, no matter what the rom does.

Goals:

Easy mode
  • Create a Nintendo Gameboy rom that displays a background/moves sprites on the screen via the d-pad. [C]
  • Create a VBlank interrupt driven program that moves sprites on the screen according to each VBlank. [C]
  • Create a simple Nintendo Gameboy Color rom that displays a colored background. [C]
 
Normal Mode
  • Create a Nintendo Gameboy game using a single screen background, several moving sprites, and a score counter. [C]
  • Create a simple melody and play it back while moving several sprites on the screen. [C]
  • Create a tool to convert 4 color bitmaps to Gameboy backgrounds. [Any Language]
  • Port any of the C examples in GBDK to Assembly. [ASM]
 
Hard Mode
  • Create a dynamic scrolling tile example on the Nintendo Gameboy using the VBlank interrupts to draw to the VRAM. [ASM]
  • Create a music algorithm/program using as few cycles as possible. [ASM]
  • Create a one-screen puzzle game with full leader-boards. [ASM]

Extreme Mode
  • Create an entire full-blown Gameboy game in Assembly. [ASM]

Tools:

   Note: I will personally be compiling everything I do in GBDK. Although WLA and RGBDS compile only Assembly, I enjoy GBDK's assembly in that you do not have to declare many of the headers and function calls you do in the other compilers.
  
Compilers
   GBDK - Gameboy Developer's Kit : http://gbdk.sourceforge.net/
   RGBDS - Rednex Gameboy Development System : http://www.otakunozoku.com/1999/08/01/rednex-gameboy-development-system/
   WLA DX - Yet Another ... Multi Platform Cross Assembler Package : http://www.villehelin.com/wla.html
  
Helpful Tools
   GBTD - Gameboy Tile Designer : (original url is down) http://www.snakeyes.org/util/files/gbtd22.zip
   GBMB - Gameboy Map Builder : (original url is down) http://www.snakeyes.org/util/files/gbmb18.zip
  
Emulators
   BGB - http://bgb.bircd.org/bgb.zip (my favorite, has a debugger, VRAM viewer, ram hacker, etc.)
   VBA-M - Visualboy Advance Merge : http://vba-m.com/index.php?ind=downloads&op=section_view&idev=3
   No$GMB - http://nocash.emubase.de/no$gmb.zip
  
Resources
   GBDK Function Descriptions - http://mitglied.multimania.de/petersieg/gb/gbdk.htm
   PDARoms - One of the best sources of legal roms : http://www.pdroms.de/files/gameboy/
   Oh! GameBoy Demo -

(fucking mind boggling)
   Gameboy Technical Programming - http://fms.komkon.org/GameBoy/Tech/Software.html
   
Nostalgic Motivation
   100 Game Boy Games in 10 Minutes :


   Gameboy Commercial :


   Metroid 2 stop-animation Japanese Commercial : http://www.youtube.com/watch?v=wTEn14TsK0s

Tigsource Created Tools
   Will add user-created tools as people make them.

---------------------------------------------------

As the month goes on, I'll be writing various tutorials to get everyone started. I encourage everyone to jump on in and start trying different challenges. Please post questions and comments in this thread, and we'll get some freaking homebrew creation going!
« Last Edit: February 02, 2010, 09:46:15 AM by Cthulhu32 » Logged

skyy
Level 2
**


[ SkyWhy ]


View Profile
« Reply #1 on: February 01, 2010, 03:59:34 PM »

I'm _IN_. I've been intending to start on some random bits of homebrew ages age. Currently already working on GP2X, all though that will be completed to the stage it should be pretty soon so need new challenges.

But yeah, definitely looking forward to what's happening on this thread.
 Coffee

It might get even more interest if the actual tool chain is fairly easy to setup and use. Because usually that's where the homebrew stuff lacks a lot. And please, if you are a hardcore linux nerd, please dont say they are "piss easy" to get working. It basically means that unless you are born with a keyboard in your hand and know _EVERYTHING_ there is to know about computers and use your linux only via command line, there is pretty much 0.005% of change of you getting the devchain working properly. Yes, I'm slightly bitter.  Giggle
« Last Edit: February 01, 2010, 04:03:34 PM by skyy » Logged

skaldicpoet9
Level 10
*****


"The length of my life was fated long ago "


View Profile
« Reply #2 on: February 01, 2010, 04:01:15 PM »

Sweetness, I am so ready to brew some games. I have been inching my way through this C++ class so hopefully it won't be completely jarring going back to C for a little while.
Logged

\\\\\\\"Fearlessness is better than a faint heart for any man who puts his nose out of doors. The date of my death and length of my life were fated long ago.\\\\\\\"
Absurdist
Level 0
***

Waiting for VBLANK


View Profile WWW
« Reply #3 on: February 01, 2010, 08:30:25 PM »

I'm not planning on doing any of the ASM related stuff, but do you have any recommended resources on learning Assembly in general?
Logged
curby
Level 0
**

bacon grills


View Profile WWW
« Reply #4 on: February 02, 2010, 02:35:40 AM »

Have to say this is a lovely idea.  I dabbled briefly with some DS homebrew and am eager to play around with the GB.  Count I in.  Well, hello there!
Logged

curby: Twitter

beatnik:  Plain Sight
skyy
Level 2
**


[ SkyWhy ]


View Profile
« Reply #5 on: February 02, 2010, 05:38:12 AM »

I'm definitely skipping the extreme ones already, cannot be arsed to start write anything completely in ASM. I've had my fair share of that when I've been programming micro controllers... Just.. no more... My brain just cannot handle it.

But the C bits, yum. Looking forward.  Noir
Logged

r.kachowski
Level 5
*****

and certainly no love below


View Profile WWW
« Reply #6 on: February 02, 2010, 07:43:54 AM »

can some enlightened individual tell me how to clear the screen when drawing in all points addressable mode?

it seems that operations are cumulative and I regularly end up with a mess. (also you get a crazy cool glitch effect when you try to draw outside of the screen)
Logged
skyy
Level 2
**


[ SkyWhy ]


View Profile
« Reply #7 on: February 02, 2010, 08:16:20 AM »

EDIT #1: I was full of shit, the site contained ZERO useful information.
Logged

Cthulhu32
Level 6
*


Brawp


View Profile WWW
« Reply #8 on: February 02, 2010, 09:42:57 AM »

can some enlightened individual tell me how to clear the screen when drawing in all points addressable mode?

it seems that operations are cumulative and I regularly end up with a mess. (also you get a crazy cool glitch effect when you try to draw outside of the screen)

One very simple way is to disable interrupts, write over the entire VRAM tile data area with 00s (blank out all pixels), and enable interrupts again. This way you won't miss a VBlank interrupt because that is bound to happen with such a big write in C.

Code:
UBYTE blankTile[] =
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

....
UWORD idx;

...
// During whenever you want to clear the background VRAM
disable_interrupts();
for(idx=0; idx < 0xFF; idx++)
    set_bkg_data(idx, 0x01, blankTile);
enable_interrupts();

If you need that in ASM let me know, it will look similar but you can do raw writes to 0x8000 instead of calling the GBDK functions.

Logged

r.kachowski
Level 5
*****

and certainly no love below


View Profile WWW
« Reply #9 on: February 04, 2010, 01:24:15 AM »

hmm, I don't quite appear to have the hang of it.

i've tried to implement it here, but it appears to only clear part of the screen.  Shrug
Logged
Cthulhu32
Level 6
*


Brawp


View Profile WWW
« Reply #10 on: February 04, 2010, 07:46:38 AM »

hmm, I don't quite appear to have the hang of it.

i've tried to implement it here, but it appears to only clear part of the screen.  Shrug

Ahhh I see, the drawing.h actually takes over part of your update loop when you include it. It probably sets up a timer or an interrupt to make sure its drawing properly. Anyway, using the drawing calls, I just made a white box.

Code:
      if ( joy & J_A )//clear screen
      {
        if(clean ==0)
        {
 color(WHITE, WHITE, M_NOFILL);
 box(0,0,GRAPHICS_WIDTH-1,GRAPHICS_HEIGHT-1,M_FILL);
 clean=1;
        }
      }

If you want to make a serious drawing application, I'd highly suggest looking into writing these functions yourself, because they must be setting up a VBlank interrupt or something. The reason you can tell is because when you do draw a box, you can see the tiles being overwritten. This means there has to be some kind of timer/interrupt watching function.
Logged

ITS_Mike
Level 3
***


Programmer


View Profile WWW
« Reply #11 on: February 04, 2010, 08:34:53 AM »

I am IN!  This is so exciting, I have been wanting an excuse to work on GameBoy games, and this is the perfect thing.  I can't wait to start!  Thanks for this.
Logged

Cthulhu32
Level 6
*


Brawp


View Profile WWW
« Reply #12 on: February 04, 2010, 03:42:05 PM »

Tutorial 1
Understanding the Gameboy


Introduction:

    Nintendo's Gameboy has several key features that make it both accessible, and incredibly easy to use for programmers. The background and window layer allow complex scrolling and overlays, and the sprites are easy to modify and manipulate. There are only 4 possible colors in a palette, but that is more than enough to make a sweet looking game, just look at Zelda! However, because the 8-bit Sharp lR35902 processor is only 4.19 MHz, we really need to push our code to be lean and mean. This is a very old school system, so we have to think old school. Most people are not used to dropping their C blanket and moving to ASM (me included), so we'll start in C using GBDK, and switch over to ASM after the system becomes more comfortable.

Lesson 1:

    The Gameboy is a hardware device, so as such you have access to anywhere inside of the system. Take a look here: http://fms.komkon.org/GameBoy/Tech/Software.html  You will notice that every register, memory map, and drawing point is a 16-bit number.

Code:
    Important 16-bit ranges:
      0xFF00-0xFFFF : I/O ports & Internal Ram
      0x8000-0x9FFF : Beginning of VRAM, where all of our drawing and tiles go

    These are the only access points we'll need to create a game. All of our drawing, positioning, and map data will go into VRAM, and all of our hardware settings and polling will come/go from the I/O. So for example, when you want to draw a Zelda map on the screen, you will draw your tiles into the correct VRAM data position, and then draw your map of which tile goes where on the screen.

    Next is understanding the hardware interrupts. The Gameboy has several triggers that will break into a function. These interrupts are extremely useful, because you have the ability to patch in your own function call, or to wait for interrupts to pass. Probably the most important interrupt is the VBlank, which indicates when the screen is ready to draw again. This is essentially a hardware frames per second, and dictates when certain hardware actions can occur such as writes to the VRAM.

Code:
    Imporant 16-bit number:
----------------------------------------------+---------------+---------------
FF0F -- IFLAGS [RW] Interrupt Flags           | when set to 1 | when set to 0
Bit4  Transition High->Low on pins P10-P13    | OCCURED       | NO
Bit3  End of serial I/O transfer              | OCCURED       | NO
Bit2  Timer overflow                          | OCCURED       | NO
Bit1  LCD controller interrupt [see LCDSTAT]  | OCCURED       | NO
Bit0  LCD vertical blanking impulse           | OCCURED       | NO
----------------------------------------------+---------------+---------------

    So, now that we have a way to limit our frames, and a way to render our tiles, lets make a simple application. I'm assuming you have GBDK installed to C:/GBDK/ and you have compiled the example programs without a problem.



First, lets make some simple tiles. Lets just have each tile be a solid block of color, and all four colors. So our tiles would look like:

Code:
const unsigned char paletteTiles[] = {
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // 4th color
  0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, // 3rd color
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF, // 2nd color
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00  // 1st color
};

This will be the raw pixel data that goes into our VRAM at 0x9000. We can actually dictate two sections of VRAM data for the background and window layer, but for now we'll leave things simple. As you do more demos, you will become more comfortable with manipulating raw pixels and messing with backgrounds/tiles, but for now lets just get this understanding out of the way.

Next, we'll need to copy these pixels to the VRAM. GBDK has a function built in, but I will also show you the raw way of doing it.

Code:
   set_bkg_data(0,4,paletteTiles);

This is a very simple one line function, but we don't learn anything from it so lets do this ourselves!

Code:
for(idx=0; idx < 0x40; idx++)
  *(unsigned char*)(0x9000+idx) = paletteTiles[idx];

This will write out the raw pixel data from paletteTiles into our VRAM space. 0x9000 is the point at which the background asks for its tiles inside of the tile map.

Next, we'll want to make a tile map, or a lookup index of each tile from our 0x9000 space. The easy way is to use the gbdk built in function.

Code:
   set_bkg_tiles(0,0,20,18,mapTiles);

Okay, enough of the easy, lets do it our own way.

Code:
for(idx=0; idx < 0x400; idx++)
   *(unsigned char*)(0x9800+idx) = idx%3; // pattern fill

This will fill in the every background tile with a tile from 0-3, and make a cool pattern. So lets put this into a c file.

Code:
#include <gb/gb.h>

const unsigned char paletteData[] = {
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

void main()
{
  UWORD idx; // our index counter
  disable_interrupts(); // Do not allow interrupts during INIT
  DISPLAY_OFF; // GBDK macro
  LCDC_REG = 0x47; // Set some hardware registers for various things like enabling background
  BGP_REG = OBP0_REG = OBP1_REG = 0xE4U;// Set the palette to binary: 11100100 or all 4 colors
  for(idx=0; idx < 0x40; idx++)
    *(unsigned char*)(0x9000+idx) = paletteData[idx]; // copy palette data
  for(idx=0;idx<0x400;idx++)
*(unsigned char*)(0x9800+idx) = idx%3; // create map data
  DISPLAY_ON; // GBDK macro
  enable_interrupts();   // allow interrupts as we're out of our INIT stage

  while(1) {
    wait_vbl_done(); // wait for VBlank
  }
}

Compile that in GBDK via a batch file or by hand. For me it looks like:

Code:
c:\gbdk\bin\lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -c -o main.o main.c
c:\gbdk\bin\lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -o FirstProject.gb main.o

And voila, your first gameboy rom! Load that bad boy up in BGB, and watch the patterns fly!

Exercises for the Reader

  • Modify the example program to display different map patterns
  • Create map data via the Gameboy Map Builder
  • Examine the Gameboy Tech guide to read about the LCDC Register

Do people want to see this sort of thing? Or are we just jammin and trying to get the challenges and our own learning done? I'm cool just working on my own Gameboy project, and if there's only a handful of us I'll just leave questions to PM.
Logged

CatStack
Level 0
***


View Profile
« Reply #13 on: February 06, 2010, 05:23:08 PM »

Awesome tutorial, really helped me get started. Personally I'd quite like to see more in the way of things like that.

Also, has anybody managed to get anything to animate? I've managed to get a sprite to display and have managed to get it to move around the screen - however, I'm a bit stuck as far as getting anything to animate goes. If I try to change this sprite's data during the update loop the gameboy (well, VBA I suppose) basically tells me where to shove it and doesn't display the sprite properly - either it'll flicker or not display at all, regardless, it never shows the new frame.  Facepalm


Anyway, this is what I've got:
Code:
#include <gb/gb.h>
#include <stdio.h>
#include <gb/cgb.h>
 
const unsigned char paletteData[] = {
  0x00,0xFF,0x40,0x91,0x68,0x91,0x00,0xFF,
  0x64,0x89,0x36,0xC9,0x16,0xE9,0x00,0xFF
};

const unsigned char mapData[] = {
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,
};

//first frame
const unsigned char smileyFaceData[] =
{
  0x7A,0x7E,0xFF,0xE5,0xFE,0xC3,0xBF,0xE9,
  0x9F,0xE1,0xDB,0x7F,0x67,0xFF,0xFF,0x7F,
  0xC7,0xB9,0xA5,0xFF,0xE7,0xBD,0xA5,0xFF,
  0x7E,0x7E,0x2C,0x34,0x2C,0x34,0x3C,0x3C
};

//second frame
const unsigned char mouseData1[] =
{
  0x08,0x08,0x1C,0x1C,0x3E,0x2A,0x3E,0x36,
  0x26,0x3A,0x1C,0x14,0x1C,0x14,0x2E,0x32,
  0x2E,0x32,0x26,0x3A,0x22,0x3E,0x1C,0x1C,
  0x08,0x08,0x0C,0x0C,0x04,0x04,0x04,0x04
};



//sprite attributes
unsigned char smileyFace[] =  
{
  50, 50, 0, 0x12
};

void main()
{

  int gencounter = 0;
  UWORD idx;
// our index counter
  disable_interrupts(); // Do not allow interrupts during INIT
  DISPLAY_OFF; // GBDK macro
  LCDC_REG = 0x47; // Set some hardware registers for various things like enabling background
  BGP_REG = OBP0_REG = OBP1_REG = 0xE4U;// Set the palette to binary: 11100100 or all 4 colors

  for(idx=0; idx < 16; idx++)
    *(unsigned char*)(0x9000+idx) = paletteData[idx]; // copy palette data
  for(idx=0;idx<0x400;idx++)
*(unsigned char*)(0x9800+idx) = mapData[idx%18]; // create map data
  
   for(idx=0; idx < 64; ++idx)
*(unsigned char*)(0x8000+idx) = smileyFaceData[idx]; //write sprite data to memory

  
  DISPLAY_ON; // GBDK macro
  enable_interrupts();   // allow interrupts as we're out of our INIT stage
  

  while(1) {

   static int y = 60; //coordinates
static int x = 60;
static UINT8 joy = 0;
static int frame = 0;
disable_interrupts();
if(frame == 0)
{
  for(idx=0; idx < 64; ++idx)
*(unsigned char*)(0x8000+idx) = mouseData1[idx]; //attempt to update frame.
  frame = 1;
}

else if(frame == 1)
{
  for(idx=0; idx < 64; ++idx)
*(unsigned char*)(0x8000+idx) = smileyFaceData[idx]; //attempt to update frame.
  frame = 0;
}
enable_interrupts();

*(unsigned char*)(0xFF00) = 0x20; //request input data
joy = *(unsigned char*)(0xFF00); //retrieve input data

joy = joy&0x0F; //get the relevant 4 bits

if(joy&J_LEFT) ++x;
if(joy&J_RIGHT) --x;
if(joy&J_UP) ++y;
if(joy&J_DOWN) --y;

 *(unsigned char*)(0xFF10) = 0xFF;
smileyFace[0] = y; //set Y position of character
smileyFace[1] = x; //set X position of character
  
 for(idx=0; idx < 4; ++idx)
*(unsigned char*)(0xFE00+idx) = smileyFace[idx]; //set sprite attributes

     wait_vbl_done(); // wait for VBlank

  }
}

I will fully admit I have absolutely no idea as to what I'm doing here. Help would be appreciated!
Logged

salade
Level 4
****



View Profile
« Reply #14 on: February 06, 2010, 07:41:21 PM »

I haven't been able to really look at the GB stuff that well, but from a quick read through it looks like it is incorrect to try and keep changing the data in the tile map to make sprites animate, which is what you are doing. try putting both the smiley face and the mouse in your tile map first, then changing the pattern number (byte2) of your sprite:
Code:
smileyFace[2] = 0; //for smiley, which you had
smileyFace[2] = 1; //for mouse

if you aren't supposed to change sprite info, and you supposed to change what is in vram, than I'm guessing you should try to write the mouse data starting at x9C00, then you just change bit4 of the LCDCONT register, and then make sure you only write to the vram at the non active part (doublebuffering?).

I haven't actually tried this though, this just seems like what is supposed to happen based on the provided documentation. (http://fms.komkon.org/GameBoy/Tech/Software.html from Cthullu32)

I'd guess that either only the second method works or both methods work, with the second method causing performance problems (how long does it take to write to vram?)
Still, I have to try this.
Logged
CatStack
Level 0
***


View Profile
« Reply #15 on: February 07, 2010, 12:51:19 PM »

Salade, as far as I can tell you were right with the first suggestion (changing the sprite's attribute's pattern number), it seems to work well. Thanks!
Logged

Cthulhu32
Level 6
*


Brawp


View Profile WWW
« Reply #16 on: February 07, 2010, 02:31:16 PM »

Salade, as far as I can tell you were right with the first suggestion (changing the sprite's attribute's pattern number), it seems to work well. Thanks!

Yeah I think for Tutorial 2 I'm going to break down how galaxy.c works. Because essentially the way the sprite system works is you have an OAM space (open up BGB, and look at your VRAM.) and each sprite object has a tile # associated with it. So when you want to animate a sprite, all you need to do is change the tile # of the OAM sprite to get animation.
Logged

ITS_Mike
Level 3
***


Programmer


View Profile WWW
« Reply #17 on: February 11, 2010, 01:37:56 PM »

With the following code, only values of 0-255 are printed.  Once "i" gets to 255, it resets to 0.  The line "if (i && J_LEFT)" seems to be causing the problem somehow.

The bug does not occur if...
  • that line is removed.
  • the "i &&" is removed.
  • the "i" is replaced with a #define constant.

The bug still occurs if...
  • the "i" is changed to any other variable.
  • "&&" is replaced with "&".

Of course, more tests could be performed to expand the previous lists, but those are the ones which I have had time to perform.

SDK: GBDK
Emulator: NO$GMB

Code:
#include <gb/gb.h>
#include <stdio.h>

void main()
{
while (1)
{
UWORD i = 0;

for (i = 0; i < 1024; i++)
{
printf("[%d]", i);
}

if (i && J_LEFT)
{

}
}
}

Any thoughts on why this is happening?
Logged

Acaceol
Level 0
*


View Profile
« Reply #18 on: February 11, 2010, 10:29:39 PM »

So far I've made a file with a scrolling background, looking forward to tutorial 2 to get sprites down d:

The only things I've had problems with so far are exporting data from the map editor and finding good reference material.

What's the "Gameboy Tech guide" that was mentioned in the first tutorial?
Edit: Found it.
« Last Edit: February 11, 2010, 10:34:08 PM by Acaceol » Logged
Cthulhu32
Level 6
*


Brawp


View Profile WWW
« Reply #19 on: February 16, 2010, 02:49:38 PM »

Tutorial 2
Picking Apart Galaxy.c


Introduction:
As many of you should have seen by now, GBDK comes with several examples that compile neatly into Gameboy roms. One such rom is the Galaxy.c file, which has moving backgrounds, sprites, and a new layer called the "Window" layer. This might seem like a lot at once, but trust me its really not that difficult! Hopefully with this explanation you'll be able to start rolling out your own programs in no time.

Lesson 2:
First, we want to include the gbdk defines for all Gameboy related functions.

Code:
#include <gb/gb.h>

First, galaxy.c declares some basic "standard" tiles.
Code:
const unsigned char std_data[] = {

  /* Basic tiles (0xFC to 0xFF) */
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

Next, we want to declare some sprite data for our rotating earth ball
Code:
const unsigned char earth_data[] = {

  /* Tile 0x00 */
  0x07,0x07,0x18,0x1F,0x32,0x2D,0x71,0x4E,0x70,0x4F,0xF8,0x87,0xF8,0x87,0xF8,0x87,
  0xFC,0x83,0xFE,0x81,0x7F,0x40,0x7F,0x40,0x3F,0x20,0x1F,0x18,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0xF0,0x30,0x78,0x88,0x3C,0xC4,0x5C,0xA4,0x9E,0x62,0x3E,0xC2,0x3E,0xC2,
  0x5E,0xA2,0x7E,0x82,0x0C,0xF4,0x0C,0xF4,0x98,0x68,0xB0,0x70,0xC0,0xC0,0x00,0x00,
  0x07,0x07,0x1F,0x18,0x2F,0x30,0x4F,0x70,0x6F,0x50,0x9F,0xE0,0x9F,0xE0,0xBF,0xC0,
  0xFF,0x80,0xB7,0xC8,0x63,0x5C,0x43,0x7C,0x3F,0x20,0x1F,0x18,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0xB0,0x70,0x18,0xE8,0x0C,0xF4,0x0C,0xF4,0x82,0x7E,0x82,0x7E,0x86,0x7A,
  0xC6,0x3A,0xE6,0x1A,0xF4,0x0C,0xFC,0x04,0xF8,0x08,0xF0,0x30,0xC0,0xC0,0x00,0x00,

  /* Tile 0x08 */
  0x07,0x07,0x1E,0x19,0x20,0x3F,0x40,0x7F,0x42,0x7D,0x81,0xFE,0x81,0xFE,0x83,0xFC,
  0xD7,0xA8,0xBB,0xC4,0x6E,0x51,0x7C,0x43,0x3F,0x20,0x1F,0x18,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0x70,0xB0,0xE8,0x18,0xF4,0x0C,0xF4,0x0C,0xFE,0x02,0xFE,0x02,0xFE,0x02,
  0xFE,0x02,0x7E,0x82,0x3C,0xC4,0x3C,0xC4,0xF8,0x08,0xF0,0x30,0xC0,0xC0,0x00,0x00,
  0x07,0x07,0x1B,0x1C,0x20,0x3F,0x40,0x7F,0x40,0x7F,0xE0,0x9F,0x90,0xEF,0x89,0xF6,
  0x8D,0xF2,0x9F,0xE0,0x5E,0x61,0x6F,0x50,0x3F,0x20,0x1F,0x18,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0xB0,0x70,0x28,0xD8,0x04,0xFC,0x2C,0xD4,0x1E,0xE2,0x1E,0xE2,0x3E,0xC2,
  0x7E,0x82,0xB6,0x4A,0xE4,0x1C,0xC4,0x3C,0xF8,0x08,0xF0,0x30,0xC0,0xC0,0x00,0x00,

  /* Tile 0x10 */
  0x07,0x07,0x18,0x1F,0x20,0x3F,0x40,0x7F,0x40,0x7F,0xEE,0x91,0xF1,0x8E,0xE0,0x9F,
  0xE0,0x9F,0xF1,0x8E,0x71,0x4E,0x72,0x4D,0x3F,0x20,0x1F,0x18,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0xF0,0x30,0x08,0xF8,0x04,0xFC,0x04,0xFC,0x02,0xFE,0x02,0xFE,0x92,0x6E,
  0xD6,0x2A,0xFE,0x02,0xEC,0x14,0xFC,0x04,0xF8,0x08,0xF0,0x30,0xC0,0xC0,0x00,0x00,
  0x07,0x07,0x1D,0x1A,0x36,0x29,0x5C,0x63,0x6C,0x53,0xCE,0xB1,0x9F,0xE0,0x9E,0xE1,
  0xAE,0xD1,0xBF,0xC0,0x47,0x78,0x47,0x78,0x2F,0x30,0x1F,0x18,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0x70,0xB0,0x08,0xF8,0x04,0xFC,0x04,0xFC,0xE2,0x1E,0x32,0xCE,0x0E,0xF2,
  0x0E,0xF2,0x1E,0xE2,0x1C,0xE4,0x2C,0xD4,0xF8,0x08,0xF0,0x30,0xC0,0xC0,0x00,0x00,

  /* Tile 0x18 */
  0x07,0x07,0x1E,0x19,0x33,0x2C,0x49,0x76,0x42,0x7D,0xC4,0xBB,0xC1,0xBE,0xC1,0xBE,
  0xE2,0x9D,0xF3,0x8C,0x78,0x47,0x78,0x47,0x3C,0x23,0x1C,0x1B,0x07,0x07,0x00,0x00,
  0xC0,0xC0,0x70,0xB0,0x68,0x98,0xC4,0x3C,0xC4,0x3C,0xEE,0x12,0xF2,0x0E,0xE2,0x1E,
  0xE2,0x1E,0xF2,0x0E,0x7C,0x84,0x7C,0x84,0xF8,0x08,0xF0,0x30,0xC0,0xC0,0x00,0x00
};

Next, we want to declare the tiles for the window layer, which goes over the sprites and background. This includes the window frame, and the little door that appears and dissapears when you press the right button.
Code:
const unsigned char frame_data[] = {

  /* Tile 0x00 */
  0xFF,0x00,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,
  0xFF,0x00,0x01,0xFE,0x03,0xFC,0x07,0xF8,0x0F,0xF0,0x1F,0xE0,0x3F,0xC0,0x7F,0x80,
  0xFF,0x00,0xFE,0x01,0xFC,0x03,0xF8,0x07,0xF0,0x0F,0xE0,0x1F,0xC0,0x3F,0x80,0x7F,
  0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
  0xFF,0x00,0xFF,0x01,0xFD,0x03,0xF9,0x07,0xF1,0x0F,0xE1,0x1F,0xC1,0x3F,0x81,0x7F,
  0x80,0x7F,0x81,0x7E,0x83,0x7C,0x87,0x78,0x8F,0x70,0x9F,0x60,0xBF,0x40,0xFF,0x00,
  0xFF,0x70,0xFF,0x98,0xEF,0xB8,0xCF,0xF8,0xFF,0x70,0xFF,0x00,0xFF,0x00,0xFF,0x01,
  0xFF,0x00,0xFE,0x01,0xFC,0x03,0xF8,0x07,0xF0,0x0F,0xE0,0x1F,0xC0,0x3F,0xFF,0xFF,

  /* Tile 0x08 */
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,
  0x00,0xFF,0x01,0xFE,0x03,0xFC,0x07,0xF8,0x0F,0xF0,0x1F,0xE0,0x3F,0xC0,0xFF,0xFF,
  0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,
  0xFF,0x0E,0xFF,0x13,0xFD,0x17,0xF9,0x1F,0xFE,0x0F,0xE0,0x1F,0xC0,0x3F,0x80,0xFF,
  0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,
  0xFF,0x01,0xFF,0x01,0xFD,0x03,0xF9,0x07,0xF1,0x0F,0xE1,0x1F,0xC1,0x3F,0x81,0x7F,
  0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,0x80,0x7F,
  0x01,0xFF,0x01,0xFF,0x03,0xFD,0x07,0xF9,0x0F,0xF1,0x1F,0xE1,0x3F,0xC1,0x7F,0x81,

  /* Tile 0x10 */
  0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,
  0x01,0xFF,0x01,0xFE,0x03,0xFC,0x77,0xF8,0xFF,0x98,0xEF,0xB8,0xCF,0xF8,0x7F,0xF0,
  0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x0E,0xFF,0x13,0xFD,0x17,0xF9,0x1F,0xFF,0x0E,
  0x80,0x7F,0x81,0x7E,0x83,0x7C,0x87,0x78,0x8F,0x70,0x9F,0x60,0xBF,0x40,0xFF,0x7F,
  0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF,0xFF,0xFF,

  /* Door1 */

  /* Tile 0x15 */
  0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,
  0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,

  /* Door2 */

  /* Tile 0x18 */
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,
  0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,
  0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,
  0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,

  /* Door3 */

  /* Tile 0x1C */
  0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,
  0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,
  0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,

  /* Door4 */

  /* Tile 0x20 */
  0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

Next, we want to declare the actual background data. This is the raw data that the user will see
Code:
const unsigned char bkg_data[] = {

  /* Tile 0x00 */
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xF7,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xDF,0xFF,0xEF,0xFF,0xFF,0xF7,0xFF,0xFB,0xFF,0xFD,0xFF,0xFE,0xFE,0xFF,

  /* Tile 0x08 */
  0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7D,0xFE,0x7C,0x39,
  0xFF,0xFF,0xF7,0xFF,0xEF,0xFF,0xFF,0xDF,0xFF,0xBF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF,0xFD,
  0xBB,0x01,0xC7,0x83,0xC7,0x83,0xC7,0x83,0xBB,0x01,0x7C,0x39,0x7D,0xFE,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
  0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB,0xAF,0x77,0x27,0x8F,0xDF,0x8F,0x27,0x8F,

  /* Tile 0x10 */
  0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFB,0xFF,0xF7,0xEF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xBF,0xFF,0xDF,0xEF,0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFE,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xAF,0x77,0xFF,0xFB,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,

  /* Tile 0x18 */
  0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x7D,0xFE,0x7C,0x39,
  0xFF,0xFF,0xF7,0xFF,0xEF,0xFF,0xFF,0xDF,0xFF,0xBF,0xFF,0x7F,0x7F,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFD,

  /* Tile 0x20 */
  0xFF,0xFF,0xDF,0xFF,0xEF,0xFF,0xFF,0xF7,0xFF,0xFB,0xFE,0xFD,0xFD,0xFE,0xFE,0xFF,
  0xAB,0x11,0xC7,0x83,0x83,0xC7,0xC7,0x83,0xAB,0x11,0x7C,0x39,0x7D,0xFE,0xFE,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFB,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0x7F,
  0xFB,0xFF,0xFF,0xFD,0xFE,0xFE,0xFE,0xFF,0xFE,0xFE,0xFF,0xFD,0xFB,0xFF,0xFF,0xFF,
  0xEF,0xFF,0xFF,0xDF,0x3F,0xBF,0x3F,0x7F,0x3F,0xBF,0xFF,0xDF,0xEF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFD,0xFE,0xFE,0xFD,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,

  /* Tile 0x28 */
  0xF7,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  0xFF,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};


Next, we want to declare all tile map data, this is data that tells each sprite which tile it will actually index to.
Code:
const unsigned char bkg_tiles[] = {
  0x00,0x01,0x02,0x03,0xFC,0xFC,0x04,0xFC,
  0xFC,0x05,0x06,0xFC,0x07,0x08,0x09,0x0A,
  0xFC,0xFC,0xFC,0x02,0x0B,0x0C,0x0D,0xFC,
  0x0E,0x0F,0x10,0xFC,0x11,0x12,0x13,0x14,
  0x15,0x16,0x17,0xFC,0x18,0x19,0x1A,0xFC,
  0x1B,0x1C,0x1D,0xFC,0xFC,0x1E,0x1F,0x20,
  0x21,0x22,0xFC,0x23,0x24,0x25,0xFC,0x26,
  0x27,0x13,0x28,0x29,0x2A,0x2B,0x2C,0x11
};

const unsigned char earth_tiles[] = {
  0x00,0x02,
  0x04,0x06,
  0x08,0x0A,
  0x0C,0x0E,
  0x10,0x12,
  0x14,0x16,
  0x18,0x1A
};

const unsigned char frame_tiles[] = {
  0x80,0x81,0xFD,0x82,0x83,0x81,0xFD,0x82,0x83,0x81,0xFD,0x82,0x83,0x81,0xFD,0x84,
  0x85,0x86,0x87,0x88,0x89,0x8A,0x87,0x88,0x89,0x8A,0x87,0x88,0x89,0x8A,0x8B,0x8C,
  0xFD,0x8D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8E,0x8F,
  0x82,0x8C,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x85,0x90,
  0x8E,0x8F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x8D,
  0x85,0x90,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x82,0x8C,
  0xFD,0x8D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8E,0x8F,
  0x82,0x8C,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x85,0x90,
  0x8E,0x91,0xFD,0x82,0x83,0x81,0xFD,0x82,0x83,0x81,0xFD,0x82,0x83,0x81,0x92,0x8D,
  0x93,0x8A,0x87,0x88,0x89,0x8A,0x87,0x88,0x89,0x8A,0x87,0x88,0x89,0x8A,0x87,0x94
};

const unsigned char door1_tiles[] = {
  0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,
  0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
  0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,
  0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,
  0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
  0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,

  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC
};

const unsigned char door2_tiles[] = {
  0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,
  0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
  0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,
  0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,
  0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
  0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,

  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
};

const unsigned char door3_tiles[] = {
  0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,
  0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,
  0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,0x9E,
  0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,0x9C,
  0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,
  0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,

  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC
};

const unsigned char door4_tiles[] = {
  0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,
  0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
  0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,
  0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,
  0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
  0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,

  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
  0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC
};

Finally, we declare pointers for the "film" variable, this way we can easily switch the backgrounds for the windows layer, and make the "smooth" animation.
Code:
const unsigned char *film[] = {
  &door1_tiles[0x0C*0],
  &door2_tiles[0x0C*0],
  &door3_tiles[0x0C*0],
  &door4_tiles[0x0C*0],
  &door1_tiles[0x0C*1],
  &door2_tiles[0x0C*1],
  &door3_tiles[0x0C*1],
  &door4_tiles[0x0C*1],
  &door1_tiles[0x0C*2],
  &door2_tiles[0x0C*2],
  &door3_tiles[0x0C*2],
  &door4_tiles[0x0C*2],
  &door1_tiles[0x0C*3],
  &door2_tiles[0x0C*3],
  &door3_tiles[0x0C*3],
  &door4_tiles[0x0C*3],
  &door1_tiles[0x0C*4],
  &door2_tiles[0x0C*4],
  &door3_tiles[0x0C*4],
  &door4_tiles[0x0C*4],
  &door1_tiles[0x0C*5],
  &door2_tiles[0x0C*5],
  &door3_tiles[0x0C*5],
  &door4_tiles[0x0C*5],
  &door1_tiles[0x0C*6]
};
Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic