Zalo DS Blog

Sunday, December 04, 2016

Game Boy Development - Tips and Tricks (III)

This is the 3rd post on the series Game Boy Development - Tips and Tricks

7. SDCC Issues


No matter how you look at it, the SDCC that comes with the GBDK has some serious issues. Here I am going to talk a little bit about some of them that I have been able to isolate an reproduce 100% and the workarounds I was forced to use.

1. Minus unary operator (-) doesn't work with numbers bigger than 130

The minus operator used for negating a number either gives you a random value or crashes. You can easily test this with the next code: 

void Test0()  {
INT16 n   = 1000;
INT16 tmp = -n;
//Printing -n crashes
printf("%d neg: %d", n, tmp);
}

For some reason it only fails with numbers bigger than 130, so you can safely use if with 8 bits values (because the biggest 8 bit signed is 127). You shouldn't use it with unsigned values for obvious reasons.
The workaround is simple but annoying, use the next macro that negates a two's complement number

#define NEG(A) (0xFFFF - A + 1)
void Test0()  {
INT16 n   = 1000;
INT16 tmp = -n;
//Workaround
printf("%d neg: %d\n", n, NEG(n));
}

2. Extra cast is required for adding  an 8-bit value to an unsigned 16-bit value

I have to admit I wasn't sure at first it this was a bug or not. Mixing signed and unsigned values is always complicated but when you start using unsigned values is going to happen sooner or later. I just wrote a similar code on Visual Studio using shorts and ints and it seem to be a bug according to that.

Calling the next function with v0=100 and v1=-50 outputs 306 instead of 50

void Test1(UINT16 v0, INT8 v1) {
printf("%d ", v0 + v1);
}

At least for this one there is an explanation. The compiler is converting v1  to unsigned (256 - 50 = 206) and adding that value wich gives that result.

If Instead of writing the test as a function with two parameters we declare the vars as local:

void Test1() {
UINT16 v0 = 100;
INT8 v1 = -50;
printf("%d ", v0 + v1);
}

then it outputs 50. This is probably resolved by the compiler but because of the lack of consistency there is definitely something wrong going on here 

The workaround is simple (but once again annoying), you just have to force a cast like this:

void Test1(UINT16 v0, INT8 v1) {
printf("%d", v0 + (INT16)v1);
}

3. Right Shift operator (>>) doesn't work with 16-bit values

Similar to the unary minus, the >> operator either crashes or gives you a random value. The next code crashes:

void Test2() {
UINT16 v16 = 50;
UINT16 n = 2;
printf("%d ", v16 >> n);
}

Also 50 >> n or v16 >> 2 will crash but if you write 50 >> 2 that works, I think the compiler is resolving that on compilation time. The workaroud I found here is a big surprising since it uses the operator itself. You just need to use the next function:

INT16 DespRight(INT16 a, INT8 b) {
return a >> b;
}

void Test2() {
UINT16 v16 = 50;
UINT16 n = 2;
printf("%d \n", DespRight(v16, n));
}

that seems to stop some kind of optimization that at the end is breaking up everything... strange
The Left Shift operator (<<) seems to work without problems

4. Comparing 8 bit value from struct with another 8 bit value fails


This one was causing a very odd behaviour on my engine making some sprites not properly being spawned. Calling Test3 here with a value of 5 will output 1 (TRUE)

struct StructTest {
UINT8 v8;
};

void Test3(UINT8 v8_0) {
struct StructTest test = {0};

printf("%d ", (UINT16)(test.v8 == v8_0));
}

This won't happen if you use 16-bit values instead. I found a couple of workarounds here, you can either change the order of the comparison:

void Test3_fix(UINT8 v8_0) {
struct StructTest test = {0};
printf("%d ", (UINT16)(v8_0 == test.v8));
}

or cast the values to 16-bit

void Test3_fix(UINT8 v8_0) {
struct StructTest test = {0};
printf("%d\n", ((UINT16)v8_0 == (UINT16)test.v8));
}

Something interesting is that if you write the code followed by the workarounds like this:

void Test3(UINT8 v8_0) {
struct StructTest test = {0};

printf("%d ", (UINT16)(test.v8 == v8_0));
printf("%d ", (UINT16)(v8_0 == test.v8)); 
printf("%d\n", ((UINT16)v8_0 == (UINT16)test.v8));
}

then it outputs the right value (¿?¿?) in the 3 cases

That's all for now. I have created a public repository wit the tests here, feel free to contribute and if you find any mistake on anything I said please let me know. I have tried to compile all this using gbdk-n which works with the latest version of sdcc but since it doesn't support printf I haven't been able to test it. Also gbdk-n doesn't have proper support for banks yet and that is a big problem. 


Sunday, September 11, 2016

Getting the Wii core back

One of the things that has been bothering me over the past 4 years is not being able to compile for the Wii. I had support for it a few years back, but then I introduced several improvements and never found the time to work on them for the Wii.

Recently with the 3ds port a bit more stable I decided to get it back. There are other platforms I want to support in the future but before that it is important to get all my cores up to date. Taking advantage of all the things I did for the 3ds and all the improvements that had been added to Dolphin during all these years I had finally updated it!

And of course I had compiled a version of

Rokoban





and Whack Mania




If anyone is still playing Wii homebrew games out there, please let me know your thoughts!

Sunday, July 31, 2016

Game Boy Development - Tips and Tricks (II)

5. The game loop

Most of the examples I've seen contain a main loop similar to this

void main() {
<game initializations>
while(1) {
wait_vbl_done();
...
<process input>
<your frame update>
}
}

this is a good starting point. Waiting for the vblank interruption prevents your game from running faster than it  should. If you start with this and keep coding you'll eventually notice a frame rate slowdown. A high slowdown actually, and that is because your frame update at some point takes more time than what is available between 2 vblanks, but you are still waiting an extra vblank.

1. Skipping vblank wait when we don't need it

One way to improve the previous code will be:

void vbl_update() {
vbl_count ++;
}

void main() {

//Subscribe vbl_update to vblank interruption
disable_interrupts();
add_VBL(vbl_update);
set_interrupts(VBL_IFLAG);
enable_interrupts();


while(1) {
if(vbl_count == 0)
wait_vbl_done();
vbl_count = 0;
...


}
}

in this new code we have declared an interruption that will store in a var the number of vblanks that have happened during the current frame. If there are more than one we no longer need to wait to the vblank and we can continue processing. Bear in mind this can duplicate your framerate up to x2 specially in situations where your processing takes more than one vblank just for a few instructions

2. Frame skipping

This is a good improvement, but it can be improved even more by using frame skipping. As its name says it consists of skipping the painting of some frames to save processing time and this way keeping the game logic running without suffering an slow down. So let's say your game is running at 60Hz meaning your fixed update time is 0.016 secs aprox, in normal conditions you will update your logic 0.016 secs, paint, update 0.016 secs, paint... and so on. Then at some point you realize that updating your logic takes more than 0.16 secs and in order to prevent an slow down  you start dropping frames like: update 0.016 secs, update 0.016 secs, paint, update 0.016 secs, update 0.016 secs...

In the Game Boy the painting happens automatically and it takes 0 processing time from your main loop. The only thing you need to do is prepare the OAM table and update the scroll coordinates and it will just happen. So just doing two consecutive updates during one frame iteration will not help up us at all

Once thing we can do though is processing several updates together. Instead of updating 0.016 secs and then update 0.016 secs we can do one single update of 0.032 secs which basically means multiplying all your updating calculations by 2 (which is a very simple operation as we saw), like this:

...
while(1) {
if(vbl_count == 0)
wait_vbl_done();
delta_time = vbl_count ? 1 : 0;
vbl_count = 0;
...
}
...

so now we have a var called delta_time that is 1 or 0 depending on having to do frame skipping or not. If for example in some of your updates you were doing
 sprite.x += 1;
you just need to change it to:
 sprite.x += 1 << delta_time;
x <<  0 is the same as multiplying by 1 and x << 1 is the same as multiplying by 2

On this implementation we are just skipping one frame, doing 2 will be complicated because that cannot be done with a shift operator. Skipping 3 will be posible but If you need to do that you should probably take a look at your calculations and try to optimize a little bit (I mean your update is taking 4 times what it should...)

3. Keeping the scroll movement smooth

Even though your game is not running at 60Hz you can still do your scroll being updated at 60Hz if you update  the scroll position registers during the vblank interruption. In order to do this you should store your scroll position in a variable during your update process and then refresh the scroll position registers during vblank. But instead of doing

SCX_REG = scroll_x;

update them like this:

if(old_scroll_x < scroll_x)
old_scroll_x ++;
else if(old_scroll_x > scroll_x)
old_scroll_x --;
SCX_REG = old_scroll_x;

where scroll_x is the current x position of the scroll and old_scroll_x is the position in the previous frame. If your scroll was moving faster than one pixel per frame sometimes you can improve this with an small spring interpolation

if(old_scroll_x < scroll_x)
old_scroll_x += (scroll_x - old_scroll_x + 1) >> 1;
else if(old_scroll_x > scroll_x)
old_scroll_x -= (old_scroll_x - scroll_x + 1) >> 1;
SCX_REG = old_scroll_x;

And you should do the same for the y axis. You can check the full implementation here

6. Funny things in the world of 8 bits

Here is a list of some of the things that made me waste some time because I am not very used to work with these kind of limitations

- printf implementation only works with 16bits values. Funny when this is the only method you have to get some debug info and you realize you are printing all that info incorrectly. If you want to print the values of 8bits vars ensure you do a casting:
printf("signed:%d - unsigend %u", (INT16)signed_8_x, (UINT16)unsigned_8_x)

- lcc optimizes array indexing using ints, which in 8bits limits array access to 128 as stated in the documentation. It also says that for statically allocated arrays this doesn't apply. At some point of the implementation of the SpriteManager I started seeing some weird behaviour and it took me a while to discover that actually when accessing sprite[10] the 10 was calculated as sizeof(struct sprite) * 10 instead of sizeof(struct sprite) * (UINT16)10 giving me te wrong address of sprite 10 and causing some weird behaviour

- As seen above it is actually a very bad idea to randomly acess an element of an array of structs because it contains a multiplication. Instead it is a good idea to create an array of pointers to the elements of the array on startup and use this array instead

- I've read in lots of places that structs have a lot of problems and you shouldn't use them... as far as I have seen there are no problems using them (except for the array accessing issue which actually makes sense for optimization purposes)

- Also, I've read in lots of places that you cannot use pointers to functions. I have successfully used pointers to functions of 0 and 1 parameters. And the GDBK uses this for interruption handler!

- There are a lot of tutorials telling you how to do things... you'll be surprised to see some of them contain errors and you should use them as reference but never as the absolute truth. Once again check this post from AntonioND

- As a final conclussion... is the GBDK a mess like lots of people are saying on lots of forums and blogs? I have been using it for a month and I can tell you that is a lie. I am not gonna say working with it is easy but that's not the GBDK's fault alone. First there is the SDCC which is the compiler the GBDK is using and probably the one people should be blaming. There is a new version of the GDBK using the latest version of SDCC here, I didnt' have the time to test it. But most of the things people seem to complain about are more related to a lack of C knowledge (and again, this is not a good enviroment for learning it) and the limitations of having to work with and 8-bit machine. The creators of the GBDk are perfectly aware of this as you can see here

Thursday, July 28, 2016

Game Boy Development - Tips and Tricks (I)


As promised here is the first post with some advices based on my experience programming for the Game Boy during the Bit Bit Jam 3.

1. Choosing your SDK

The Gameboy has some different SDks you can choose to work with. The two main ones are the GBDK and the RGBDS. Choosing between any of them depends on what you want to accomplish and what skills you have. Check the next table with pros and cons of each one


GBDK RGBDS
C and asm asm (better than asm in GBDK*)
Slower if you use C Asm is always faster but requires experience
Faster to write programs in C Assembly is very low level, requires more time
Reliable for a jam If you are not an skilled programmer you might not finish your jam entry
Horrible SDK for learning C because of the 8bits limitations, no debugger.... Perfect for learning asm. You can even use a debugger with the BGB emulator 


With all these in mind, I chose GBDK because I have a lot of experience with C and C++ and I was feelling more confident to finish the game with it.

*so I've heard, because I didn't have the chance to try it

2. Getting your environment ready

I will suggest spending some time doing this, it can save you from lot of problems that will happen that last hour before sending the game. Code completion, launching the emu after compiling and the ability to add or delete files from your project easily are the things you should focus to get before starting your project.

A couple of weeks before the jam I started playing with GBDK and getting my development environment ready. Same as I did for the 3ds, Ds and the Wii I started configuring visual studio and some makefiles (see this post for more info). Most of the tutorials I followed along the internet were using some dos .bat files but I was looking for something more general. I created a makefile that:

- Compiles any source found under the folder src, so you don't have to specify the list of files to compile

- Parse the extension of the file to select the bank (anything.c will be on bank0, anything.b1.c will be on bank1, anything.b2.c on bank 2 and so on...)

- Automatically changes the unsigned char of the resources exported by GameBoy Map Builder and GameBoy Tile designed to const unsigned char

And some other features that you can check here. The important thing is having a confortable environment so you only have to worry about coding the videogame

If you are under Windows you will need a way to run makefiles. Since I have been using devkitpro for a long time I already had msys installed. One funny thing that I noticed is that the version of make that comes with devkitpro doesn't display any compilation errors so I guess the stderr is not properly configured. If you have the same problem you just need to download the last version of make for windows here

3. Banks

I would recommend reading the full documentation of the GBDK prior to any development. And specially trying to understand banks, what they are and how they work. AntonioND explains it pretty well on this post. The idea is very simple. If you take a look at the size of variables of the GBDK you'll see that the size of a pointer is 2 bytes. The maximum address you can point to with 2 bytes is 65535 (2^16). In these addresses the gameboy needs to get access to everything, not only the rom. Basically it needs 32kb for internal registers: sound, video, power, etc (you can find the complete list here if you are curious) and then there are other 32 kb for rom access(the cartdridge data). These 32kb are splitted into two: a fixed part that is always accesible (called bank0) and a swapable part (by default set to bank1). You can change the starting address of bank1 and make it point to addresses beyond 65535. Each group of 16386 (16kb) is known as a bank

So the idea is splitting your code along any of these banks and before excuting any part of it swapping the start address so the code can be reached. Take some time to understand this because it is extremely important. And also pay attention to the next things:

- You can only swap banks from code that is stored in bank0. Actually you can swap banks from any bank if you dare but your program will crash and it has an easy explanation. In any computer no matter how big or small it is there is a register (usually known as EIP) that contains the address of the next instruction to be executed. If no jump occurs then this register will automatically advance to the next register and execute the next instruction and basically that's how programs run. So, what will happen if you are in bank2 for example and swap to banks3? The EIP will execute the command to change the bank (in bank2) then it will advance to the next register and will try to execute the next command. The problem is that this comand that was supposed to belong to bank2 now belongs to bank3 and it can be literally anything. An easy solution to this is calling a function on bank0 (always accesible) that swaps banks, do the job on that new bank and then before returning swap banks back to bank2

- Lcc errors. You will eventually find a message like this from the compiler "warning : possibly wrote twice at addr 407a (21>21)". This will happen everytime you write code larger than 16kb and part of it ends in addresses that belong to the next bank. When this happens you should start moving your code to another bank

- Try to fill all banks with some info. If you have decided your game is gonna take 4 banks then the size of the game will be 64kb (16kb per bank) event if you don't fill them. Because of this it is a good idea to put some info in each bank from the beginning, otherwise you won't see the message I was telling you before when a bank gets full and your program will randomly crash at some point

- A stack can be very helpful to deal with bank swapping. Implementing a stack is very simple, you can check my implementation here. Once you have a stack implemented you can use it to move between banks like I do here. Everytime I want to change to a new bank I call PUSH_BANK and when I finish I just call POP_BANK so it automatically leaves me on the previous bank. Using this technique I was able to call gbt_update that automatically changes the bank to bank1 on my vblank interruption and then return to the bank I was previously working on calling REFRESH_BANK, fixing the issue AntonioND is stating on this post

4. Basic Maths

The Gameboy isn't very powerful and it can't even deal with multiplications or divisions, so you should avoid them at all cost (you can use them, but the performance will suffer). Most of these multiplications and divisions can be replaced by simpler operations, like:

- instead of multiplying by any power of 2 use the shift left operator (<<). Specially for multiplying by 2 use x << 1

- instead of dividing by any power of 2 use the shirft right operator (>>). Specially for dividing by 2 use x >> 1

- instead of the module operator (%) with any power of 2 you can do a mask. For example for getting the module 8 of a number do x & 0x7 (7 is 111 in binary so using & here turns everything except the last 3 digits into 0 which is what we want)

- the gbdk manual encourages you to use unsigned values. Take into account that these values are always bigger than 0. So doing something like 3 - 4 will result in an overflow giving you 255 (or 65535 if you are using 16bits) and checking if this is < 0 will unexpectecly return false. The best way I found to deal with this is masking against 0x8000 (1000 0000 0000 0000 in binary) and checking that the result is 0 (that 1 in the highest bit will only happen after an overflow)

Tuesday, July 26, 2016

BitBitJam 3 - Pretty Princess' Castle Escape

The bit bit jam is a retro jam based on old systems up to 16 bits. The jam lasts one week and you can use any technology you have developed before that week. The game must work in real hardware.

Before the jam starts a theme is randomly selected and this year it was "Red Hot Princess Carnage". A total of 20 games were presented. You can take a look at all of them here, and also you can check the winners on each different category: best theme, best platform usage and funniest game

This year I ended up joininig forces with sergeeo. He was in charge of the music and graphics and I was working on all the coding stuff. Together we created Pretty Princess' Castle Escape for the old nintendo Game Boy. Althought we finished the game on time we continued working on it after the jam and finally we have released a new version we consider final. Check it out here!




We'd like to thank all  the guys playing it and specially the ones who have uploaded some videos:



Also special thanks to David Colmenero for organizing the jam and for convince me to participate

During this week I'll be posting a few entries with my experience developing using the GBDK providing some info that I hope will be usefull for someone. Stay tuned!

Tuesday, January 05, 2016

Rokoban for Nintendo 3DS


Rokoban is not a new game. I already released it on Nds and later on the Wii (and it won the 4th place on the Wii Homebrew Competition organized by tehskeen in 2008). After that I was going to release a new version for IOS and Android about 4 years ago. Although very close to finishing it, I had to abandon it because back on those days I needed to start working on Whack Mania.

Together with me working in this new version was Juanmi, making all the graphics. He actually finished all his work but I never got the time to put it all together. After the release of Whack Mania the engine had changed so much that making it work again was a bit complicated.

That was until this past summer when I actually realeased Whack Mania for 3ds. I was thinking which other project I could work on after it when  william341 in the gbatemp forums suggested me to work on Rokoban. There are other projects I was thinking of but then I did a quick test and in a couple of days (holidays, yeah!) it was running again. Althought making it work is just the first step I decided to focus on it, the good thing was I already had all the graphics and menus :)

A few months have passed and finally I am going to release it hoping you will enjoy it and it will become a good contribution for the 3ds scene which as of today keeps growing and growing. Also I am going to finish what I started 4 years ago with poor Juanmi and he is gonna see his job finally released

 

Download it from the links below. The game is available in 3ds, cia and 3dsx format. There is also the Windows version if you wanna give a try on your PC. I also have an Android and IOS build but I don't really know what to do with them...

Download: Rokoban 3DS

Download: Rokoban Windows

As usual, please leave me your feedback in the comments. Thanks in advance!

 

Thursday, August 13, 2015

Familiar Game Camp

The Familiar Game Camp was celebrated the past  August 1st-2nd at Málaga, in the south of Spain (sadly we didn't find the time for visiting the beach :_(... )


It was a weekend for meeting nice people and sharing our experiences, and also meeting the new generations. There were workshops for chiptunes, pixel art and Gameboy development and talks about the Familiar Game Jam, Publishing on Steam, Game Art, AltGames and Not Games and what to do with your free time.

This time I didn't want to talk about some technical stuff so my talk was a bit more related to what I do with my free time, based on my experience along all these years of videogames development.
Here are the slides of the presentation I offered
- Programar por Trabajo vs Ocio (spanish)
- Coding for Work vs Fun (english)



You can find some posts covering the event here:
- Official website (with links to all workshops and talks)
- Sergeeo's post (he is the one organizing so you should take a look)
- Crónicas de #FamiliarGameCamp
- Twitter #familiargamecamp (I have stolen all the photos from there, yeah)

Some of us were missing the Game Conga, but maybe next year it will happen...  :D

I hope to see you again soon!

Whack Mania on Nintendo 3DS

Remember Whack Mania? You should if you know me, but just in case here is a video to refresh your memory

I have finished porting my little engine to the nintendo 3ds meaning the game is now working too. As you can see


I needed to to a few changes before releasing it:
- Since the game was thought to use a touch screen I had to adapt the controls a little bit (I could have used the touchscreen but I wanted to have the 3d effect instead
- I have reviewed all the levels and kept only those that I considered fun enought (from 40 levels, there are only 14 here... you can take a look at my postmortem to see why :P)
- I had made myself sure that the game doesn't have any memory issues and it is stable (and it is now). Also I needed to check it was working using the Homebrew Launcher, cia or 3ds formats
- Some other minor changes I don't remember right now. But the good thing is that the code is exactly the same that I used for the IOS or Android version


Here is the link if you wanna give it a try. The game looks awesome on the 3ds :)

Download: Whack Mania 3DS