GBA library v0.1 for the TI-83+
This tutorial is for those who already know the basics of programming in assembly for the TI-8x series and wish to write typical game-boy games. The tools in this library will give you more freedom with making your games. I will use the examples for the ion shell throughout these tutorials, but nothing prevents you from porting them on another shell since GBA.8xp does not use any specific function to ion or any rom call. If you have questions or suggestions, do not hesitate to contact me.
I) Introduction 1) Linking the library to your program 2) About variables
II) Using tile maps
1) Principle
2) Displaying a tile
3) Multidirectional scrolling
4) Changing the screen size
III) Managing sprites
1) Displaying a sprite
2) Organizing sprites in your program
3) Including sprites
4) Loading a sprite table
5) Deleting a sprite
IV) Conclusion 1) Some additional variables and routines 2) Summary of the functions
I) Introduction
1) Linking the library to your program
As you will have probably guessed, GBA is an external file: the routines do not copy into your source code, they are collected and compiled to be directly called in your program. The problem is that the variables of the TI-83 + often change addresses; when you eliminate a real or a list for example, the other data is automatically moved. To call a routine of a program, it is necessary to know the address of this routine in the memory! A solution would have been to set up the program address GBA.8xp with a file back-up, as do most of the shells, but that would have put problems of incompatibility with the different shells as well as problems of porting on the other calculators. So I chose to write the routines in an include file that will look for the program GBA.8xp through the VAT, and updates all the addresses of the routines according to the one of the program. This routine is called Find_gba , is located in the file Findgba.inc, and defines also a list of variables used by GBA. You include the file at the end of your code source. In practice, here is what it is:
.nolist #include "ion.inc" .list .org ProgStart-2 ; normal header .db $bb,$6d ret jr nc,Start .db "Not First",0 Start: call Find_gba ; update all the addresses of the routines ;; your program ;; ... ;; ... #include "Findgba.inc" .end
What does it pass if the program GBA.8xp is untraceable ( if you forgot to send it to your calc)? In this case, the carry flag will be worth 1. One can therefore to change the previous program to:
.nolist #include "ion.inc" .list .org ProgStart-2 ; normal header .db $bb,$6d ret jr nc,Start .db "Not First",0 Start: call Find_gba ; update all the addresses of the routines jr nc,GBA_ok ; if it finds the file (carry flag=0), ld hl,Texte_erreur ; it passes following the program bcall(_puts) bcall(_getkey) ret Texte_erreur: .db "Error 404: not found",0 ; :) GBA_ok: ;; your program ;; ... ;; ... #include "Findgba.inc" .end
There! You now know how to link up your program with GBA.8xp.
2) About variables
All the variables used by the GBA program are located in the memory text (saferam3). Nothing needs to be stored in the program GBA.8xp because it would then be necessary to match the data in your program to another that constantly changes addresses . The first 32 8-bit bytes (saferam3 to saferam3+31) are any parameters. The following 54 (saferam3+32 to saferam3+85) are a table of jumps; when you call a routine, the program goes on this table and is redirected towards the routine's corresponding address, do not modify the values of these 54 bytes!
Comment : Since the variables are stored in the memory text, watch out when you want to write something to the screen (with the routines _puts, _disphl etc.), otherwise these variables will be obliterated and the program will crash. The simplest one is to include at the beginning of your program the order res appTextSave, (IY+appflags), that allows the memory text (saferam3) to not be affected by the routines of displaying of text. You will write the inverse order res appTextSave, (IY+appflags), at the end of your program.
II) Tile Maps
1) Principle
Most 2D games use tile maps: the picture that will be displayed to the screen is divided in small squares of a certain size which have attributed numbers. These tiles are in a matrix that contain the numbers of these small squares. Here is a pulled example from the game Zelda II: The Adventure Of Link (rather old of course, but cool!) :
One can see 6 different tiles (16x16 in size): - one for the grass - one for the road - one for the forest - one for the mountains - one for the water - one for the temple
Now we want to do the same thing on TI-83+..
We then begin by drawing the tiles 8x8...
... Then we export them into binary and then paste it into an include file that is used in the program. The tiles are then put into numerical order starting with zero:
Tiles: .db %10000000 ; tile 0 (grass) .db %10000100 .db %00010000 .db %01000001 .db %00000000 .db %00100000 .db %00000010 .db %00000000 .db %00000000 ; tile 1 (road) .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00000000 .db %00010000 ; tile 2 (forest) .db %00110000 .db %00101000 .db %01100000 .db %01010100 .db %11000000 .db %11111110 .db %00010000 .db %00000000 ; tile 3 (mountain) .db %00000000 .db %00001000 .db %00010100 .db %00100110 .db %01010010 .db %11011001 .db %10001000 .db %11111010 ; tile 4 (water) .db %11011111 .db %10101101 .db %11111010 .db %11101111 .db %11010111 .db %11111111 .db %11111101 .db %11111111 ; tile 5 (temple) .db %01011110 .db %00101100 .db %00101100 .db %00101100 .db %00101100 .db %01111110 .db %10011111
These numbers will be encoded on a 8-bit byte, you can make 256 different tiles
for a same card which will be sufficient for most projects. But nothing
prevents you from use several lists of tiles in your game, for example to create
a table that indicates, for every card, a specific list of tiles.
Below is an example of a map with the previous map tiles:
Carte: .db 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0 .db 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,1,1,1 .db 3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 3,3,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 .db 3,3,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0 .db 3,3,0,0,0,0,0,0,2,2,2,2,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0 .db 3,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0 .db 3,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,1,1,0,0,0,2 .db 0,0,0,0,0,0,0,0,4,4,4,4,1,1,1,4,4,4,4,0,0,0,0,0,1,1,0,0,0,2,2 .db 0,0,0,0,0,0,0,0,4,4,4,4,1,5,1,1,1,1,1,1,1,1,1,1,1,0,0,0,2,2,2 .db 3,3,0,0,0,0,0,0,4,4,4,4,1,1,1,4,4,4,4,0,0,0,0,0,0,0,0,0,2,2,2 .db 3,3,3,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,2,2,2,2 .db 3,3,3,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,2,2,2,2,2 .db 3,3,3,3,0,0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,3 .db 3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,0,0,0,0,0,0,2,3,3,3,3,3 .db 3,3,3,3,3,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,0,0,0,3,3,3,3,3,3,3
2) Displaying a map
First, it is necessary to indicate GBA addresses its tiles and the one of the map data; for that it suffices to store these addresses respectively in the variables tiles_addr and map_addr:
; ... ld hl,Carte ; label of the map ld (map_addr),hl ld hl,Tiles ; label of the tiles ld (tiles_addr),hl ; ...
It is also necessary to store the number of rows and of columns of the map, in the variables map_height and map_width.
; ... ld bc,16 ld (map_height),bc ld bc,31 ld (map_width),bc ; ...
Now that GBA knows all the map data, you need to initialize the map with the routine gba_initmap to copy the map in the APDRAM (saferam1). You can write a routine that copies the content of the APDRAM in the GRAPH_MEM (with the instruction ldir), but I recommend for now that you use the routine gba_restoremap (which has some explanation in paragraph 4).
You get this:
(Exemple1.Asm)
You will notice it's the top left of the map that is displayed. To change that, there are two 16-bit variables, scroll_x and scroll_y , that define the x and y coordinates of the map displayed. Initially, these two variables are worth 0. Change these values before calling the routine gba_initmap to understand how that works. Of course if you put scroll_x=3541, for example, there will be a display bug, but the calc will not crash.
3) Multidirectional scrolling
After displaying your map, you can call the routines gba_scroll_right, gba_scroll_left, gba_scroll_down and gba_scroll_up to scroll up, down, left, right respectivly.
( Exemple2.asm)
Magic, no? If the scroll is impossible, then you have reached the map limit (the carry flag will also be worth 1), but you won't have anything to worry about if you follow my recommendations at the conclusion.
4) Changing the screen size
In certain games, sometimes people want to have some space in the screen to be able to draw a life bar, give score, etc. To modify the routines of GBA would be to complicated and could cause some problems. The simplest one is to copy the GRAPH_MEM portions of picture that interests us, and this is where the gba_restoremap routine intervenes: this one depends on the parameters screen_width and screen_height, which give the width and the height in 8-bit bytes of the portion of the picture that will be copied to the APDRAM in the GRAPH_MEM. These values are initially to 12 and to 8 (for a picture of 96x64 pixels). Here is what we get when we put screen_width=4 and screen_height=4:
The window by default is displayed in top left of the screen. It is possible to change that: with the parameter zero_point give it addresses of the top left pixel of the screen.The conversion equasion for a literal (x,y) system is GRAPH_MEM+12*y+x/8, which is equal to zero_point = 12*y+x/8. This value is initially to 0 (the window is posted from GRAPH_MEM). For example, to display the screen to the coordinates (16,3), you would put zero_point = 3*12+16/8 = 38. We get:
The routine gba_restoremap is not therefore necessary in this case; I recommend for you to write your own adapted routine for your game because it will be much quicker.
III) Managing sprites
Now that you know how to handle tile maps we can start adding sprites. This section will tell you how to use sprites with your maps.
1) Draw a sprite to the screen
Reminder on mask usage: What is a mask? The routine's "simple" way of displaying of sprites use the operator OR to copy the picture in a place of the graph_mem. Thus if a picture bit is worth 1, it will give a black pixel. But if it is worth 0, it will be a white pixel. The posted sprite is therefore transparent. To regulate this problem, one will create another picture, called masks, that has for goal to remove the pixels before picture displaying. This mask is copied with the operator AND: if a mask bit is worth 1, one will obtain a black pixel to be a white pixel. If it is worth 0, one will always obtain a white. One picture is better than a long speech:
Desired Pixel | Picture Bit |
Mask Bit |
black | 0 | 0 |
white | 1 | little imports |
transparent | 0 | 1 |
For example, here is a sprite (16*28 pixels) pulled from Great Mario World (the gray pixels represent the transparent pixels) :
From that we see this:
This is the mask:
Post a sprite with GBA: With GBA, the mask and the picture are mixed: one creates a label where one puts the first 8-bit byte of the mask, then the first 8-bit byte of the picture, the second 8-bit byte of the mask, then the second 8-bit byte of the picture, etc. In a bitmap you get this:
We then convert it to assembly binary (using the excellent program "Bitmap to asm", available on ticalc.org) :
Mario_sprite: .db %11111110,%00000001,%00001111,%11110000 .db %11111000,%00000110,%00000111,%00001000 .db %11110000,%00001000,%00000111,%00001000 .db %11100000,%00010001,%00000011,%11111100 .db %11000000,%00100111,%00000001,%11111110 .db %10000000,%01001111,%00000001,%11111110 .db %10000000,%01001100,%00000011,%00001100 .db %10000000,%01011000,%00000011,%10100000 .db %00000000,%11011000,%00000011,%10100100 .db %00000000,%11011100,%00000011,%00000100 .db %10000000,%01001001,%00000011,%00000100 .db %10000000,%01100011,%00000001,%11111110 .db %11000000,%00110000,%00000011,%11111100 .db %11100000,%00011100,%00000111,%00001000 .db %11110000,%00001111,%00001111,%11110000 .db %11100000,%00010010,%00000111,%10001000 .db %11000000,%00100001,%00000011,%00000100 .db %11000000,%00100001,%00000011,%00000100 .db %11000000,%00110000,%00000111,%10001000 .db %11000000,%00111001,%00001111,%11110000 .db %11000000,%00101111,%00000111,%00001000 .db %11000000,%00100000,%00000111,%00001000 .db %11100000,%00010000,%00001111,%01010000 .db %11100000,%00010000,%00001111,%01010000 .db %11110000,%00001111,%00011111,%11100000 .db %11110000,%00001000,%00001111,%01010000 .db %11110000,%00001000,%00000111,%00101000 .db %11110000,%00001111,%00000111,%11111000
The routine that allows copying a sprite in the GRAPH_MEM is gba_drawsprite. You store in hl addresses the sprite, in d his width in 8-bit bytes, in e his height in pixels, in b and c its coordinates (x,y) to the screen (the point (0,0) is situated in top to the left) :
; ... ld hl,Mario_sprite ld de,$021c ; d=2, e=28 ld bc,$1024 ; b=16, c=36 call gba_drawsprite ; ...
(Exemple3.asm)
Gba_drawsprite also to cuts the pictures if they go out of the screen, in order to avoid corrupting the memory. You will not have to be concerned with the coordinates of a sprite before you display it which will simplify your programs. Here is a small example that illustrates this principle:
(Exemple4.asm)
2) Organizing the sprites in your program
When it is necessary to manage, say, ten enemies at the same time in a game, it is easier to group together all the data of the present enemies to the screen in a picture, where every line (lists) represents a sprite, and every column a characteristic of this sprite. For example one wants to write a table where every enemy is characterized by its coordinates (2 8-bit bytes), the address of his picture (2 8-bit bytes), its life points (1 8-bit bytes), and the routine address that uses for him (2 8-bit bytes) :
Ennemi_table: Ennemi_1: .db 0,0,0,0,0,0,0 ; y, x, img, PV, AI address Ennemi_2: .db 0,0,0,0,0,0,0 ; y, x, img, PV, AI address Ennemi_3: .db 0,0,0,0,0,0,0 ; ... Ennemi_4: .db 0,0,0,0,0,0,0 Ennemi_5: ; 5 sprites max .db 0,0,0,0,0,0,0
You can then write a routine that posts the enemies to the screen like so:
Afficher_ennemis: ld hl,Ennemi_table ld b,5 GE_boucle: push bc ld c,(hl) ; y inc hl ld b,(hl) ; x inc hl ld e,(hl) ; img inc hl ld d,(hl) inc hl push hl ex de,hl ld e,(hl) ; sprite dim inc hl ld d,(hl) ; sprite dim inc hl call gba_drawsprite pop hl inc hl inc hl pop bc djnz GE_boucle ret
And here is how the pictures of the sprites are put at the end of the program:
Ennemi_Img: .db dimy,dimx .db %...,%... ; image .db %...,%...
Where dimy and dimx are the height and the width of the picture of the sprite.
Returning to programming with GBA: the address of your table will be stored in the 16 bit variable sprite_table. The number of information (8-bit bytes) necessary to describe a sprite will be stocked in the variable 16 bits l_sprite. At last the number of maximum sprites will be stored in the variable l_sprite. Finally the number of maximum sprites will be stoored in the variable sprite_max. The length of your table will be therefore of l_sprite*sprite_max. We will then get:
ld hl,Ennemi_table ld (sprite_table),hl ld bc,7 ld (l_sprite),bc ld a,5 ld (sprite_max),a
You nevertheless must respect certain constraints: the 3 first 8-bit bytes of every list of the table must not be modified, you will learn to use them in the following paragraph. The 2 following 8-bit bytes of every list are coordinated them there and x of the sprite to the screen. You can use the following 8-bit bytes as you want it.
3) Including sprites in your maps
In the video games, you will want to place your enemies in a map: while you progress in a level, enemies appear (are loaded in the table of the present sprites to the screen); if you kill them then leave the level and come back to the same place, they return. The question is: under which form and to which place will one have the necessary data so that these sprites are loaded at the right moment?
First of all, every sprite is characterized by his type: for example in Great Mario there are the tortoises, the flying tortoises, the meat-eater plants, cannonballs... Two sprites of identical type have the same behavior (IA), the same picture, the same number of points of initial life... It is a matter in fact of the same sprite! It is not rare to see on a screen 2 or 3 times it same enemy, it is a matter all simply of sprites of same type. To every type corresponds a number (attributed arbitrarily), and this is this number that will be used to include personages in the cards.
For that the sprites are loaded while one advances in a level, I have first thought that it was necessary to create a table for every map containing the types of sprites and their coordinated ones in this one, but this is a method that one can use in one way especially for the games that use only the horizontal scrolls (as Great Mario ti82 of Sam Heald). It is not very practical for the games with multidirectional scrolling. I finally chose for the inclusion of the sprites directly in the card matrices. It is necessary of course to indicate to which GBA numbers correspond to tiles and which numbers correspond to sprites! This is the reason why I defined the variable n_sprite. All the numbers understand between 0 and n_sprite-1 are tiles and will be posted normally, while all the numbers understand between n_sprite and 255 are types of sprites (encoded on 8bits).
But another problem present itself: if an enemy is loaded in the table of the sprites, it must not be it that a single time! If there remains at the screen, and that you go back then forward, it is outside question to post it another time while the other did not disappear! It is necessary therefore to distinguish between the sprites that must be loaded the moment the map is displayed (the enemies "living"), and those that must not be(the already present enemies to the screen and those that are "dead")...
I chose this solution: the sprites all must have a type that is an even number. The odd numbers are reserved to the sprites that not more will have to be loaded in the table of sprites. For example, if a tortoise ninja is characterized by the type 6, a tortoise ninja "dead" is characterized by the type 6+1=7.
4) Loading a sprite into a table
See how GBA concretely manages the load of the sprites in the table.
While you carry out a map projection, the number of the tiles that will be posted to the screen edges are examined; let us call N the number of a tile, and ADR his address in the memory (addresses kind (map_addr)+...). If N < n-sprite, it is a matter of habit (see previous paragraph). If N >= N-sprite, it is a matter of a sprite, and the following steps are executed:
If N is odd, this sprite is been unaware of. The program returns to the habitual execution. If N is even, the program modifies the map
ld hl,ADR inc (hl)
It increments the number of the sprite so as not to post it several times. Then it will look for a free location in the table of the sprites, with the routine gba_findsprite. If there is no room in the table, the sprite is been unaware of and the program continues normally. You remember of the 3 8-bit bytes that did not have to be changed in every list? (see paragraph 2) In the two first ones will be stocked addresses it ADR, called identity of the sprite, and in the third one will be stocked the number N-n_sprite, that corresponds to his type (this is an even number, rappelons-le!). At last, the program stocks in the two following 8-bit bytes them coordinated there and x of the sprite.
Important: The routine gba_findsprite is based on a simple principle: the identity of a sprite never is null, for it is a matter of an address that not at all inside your program (therefore different of $0000). To know if a list is free or not, it suffices to read the 2 first 8-bit bytes: themselves they are null, the place is free, otherwise there already is a sprite. Little imports the value of the following 8-bit bytes. To eliminate a list sprite, it suffices therefore to put zero to the identity.
The variable new_sprite, In this variable, you will store the address of a routine that will be executed immediately following. The moment this routine is called, the register of not at all on the 6th 8-bit byte of the list, has is equal to the type of the sprite. That is very useful to initialize the various data concerning this sprite. If you do not want to use this routine, you will leave this parameter to his initial value, zero.
In the following program, one writes a routine that initializes the points of lives of an enemy according to his type:
ld hl,Nouveau_sprite ld (new_sprite),hl ;... Nouveau_sprite: ld hl,Table_ptsdevie srl a ; has a multiple of 2 ld b,0 ld c,a add hl,bc ld a,(hl) ld (de),a ret Table_sprite: .db 0,0,0,0,0,0 ; identity (2 8-bit bytes), type, y and x coords, life points .db 0,0,0,0,0,0 .db 0,0,0,0,0,0 Table_ptsdevie: .db 6,6,12,50,82,125
Of course, when you carry out a projection, the coordination of the sprites are automatically changed.
At last, here is a small synthetic program that groups together what we saw:
(Exemple5.asm)
One notices several bugs in this example:
- Our first programs it runs a single time: if one restarts it, the sprites do not post themselves any more! This is completely normal, for the map was modified the first time and all the sprites became sprites "dead" (with an odd type). It suffices to resolve the bug to call, just before gba_initmap, the routine gba_initsprite, which "revives" all the sprites of the map and reinitializes the table of the sprites.
- Among the 6 present enemies in the card (represented by the numbers 240), only 5 enemies appear. Eh yes! The table can contain only 5 sprites to the maximum, and therefore the following sprites will be been unaware of. To resolve this bug, it is necessary be to increase the table capacity, be to obliterate the enemies of the table when they disappear (the subject of our next paragraph). Here is a corrected version of the example 5:
(Exemple6.asm)
5) Deleting a sprite
Sometimes you need to delete a sprite off of the the table when it goes off screen, it will also increase the speed of the program. To do sos is very simple:
; hl not at all on the first 8-bit byte of the identity of a sprite ld (hl),0 inc hl ld (hl),0 ; eliminate the list sprite
If you delete a sprite because it goes out of the screen, as a rule it should be loaded a new time in the table if one returns, nevertheless this is not the case... You have every reason; it is necessary in this case to restore the initial value of the 8-bit byte that was modified to the load of the sprite:
; hl not at all on the first 8-bit byte of the identity of a sprite push hl ld e,(hl) inc hl ld d,(hl) inc hl ex de,hl ; hl=identity dec (hl) ; restore the initial value of the 8-bit byte that was modified pop hl ld (hl),0 inc hl ld (hl),0 ; eliminate the list sprite
IV) Conclusions
1) Some routines and additional variables
gba_collision: This routine is very useful, especially in the platform games; you store in (b,c) them more coordinated, more positive or more negative, of a point to the screen (or in outside), and this routine sends back you the number of the tile that contains this point and in hl addresses it of this tile.
gba_hl_plus_dexbc: A very used routine internally by GBA. The result gives hl + of*bc -> hl, with of positive or negative, and strictly positive bc.
gba_drawinverted: This routine works exactly as gba_drawsprite, with some differences. The picture is inverted as on a film photo: the white and black pixels are reversed. This picture shows the different possibilities:
Picture bit | Mask bit | gba_drawsprite | gba_drawinverted |
0 | 0 | black | black |
1 | 0 | white | black |
1 | 1 | white | white |
0 | 1 | transparent | transparent |
gba_findsprite: This routine will look for in the table of the sprites a free location for there to stock the data of a new sprite. If there is place, hl will point on the first 8-bit byte of the list (that serves for the identity). Otherwise the zero flag will be worth not zero.
tile_zero : Maybe you already were confronted by the following problem: after drawing a magnificent background, you note that you cannot include sprite in your card without leaving a big white hole, there where an element of setting was replaced by the sprite... No panic, here what I propose to you: you will indicate to which GBA tile must be posted instead of a white hole left by the presence of a sprite. tile_zero is in fact the number (8 BITS) tile that is considered as "wallpaper", it is initially to zero (from which his name).
n_tiles2: Sometimes in certain games as Lemmings or Worms, one needs to do important modifications in the map, as to break pads, dig... The problem is that it is necessary nonetheless to preserve in memory the original card, under penalty of to be able to play only a single time before downloading the game again. Then, to less than to copy the whole card to a sure place of the ram (which can reveal itself problematic with cards of 5000 8-bit bytes), it will be necessary to find a means to modify directly the card in a reversible way.
I chose this solution: suppose that the game uses almost 90 different tiles, and about twenty enemies. If one wants to obliterate a map tile, it will suffice for example to add 100 to the number of the tile and do in to go out that all the tiles of which the number is superior to 100 is posted in white. To do "to reappear" the tiles, it will suffice to subtract 100 to all those of which the number and superior to 100. This is there that arrives the parameter 8BITS n_tile2: all the tiles of which the number is inferior to n_tiles2 are treated normally, those having a number understand between n_tiles2 and n_sprite-1 will be posted as the tile tile_zero.
But the usefulness of this variable does not stop there! You can use tiles having a superior number to n_tiles2 as of markers: for example, one easily can do to execute a routine when your personage arrives on the one of these tiles (while calling the simple routine gba_collision), which is very practical to manage the card changes, the unexpected events...
2) Summary of the GBA functions
Variables:
Variable name
|
Size
|
Description
|
Paragraph
|
Initial value
|
screen_width
|
8bits
|
window width in 8-bit byte
|
II) 4)
|
12
|
screen_height
|
8bits
|
window height in 8-bit byte
|
II) 4)
|
10
|
zero_point
|
16bits
|
address point in top to the left of the window, less
GRAPH_MEM
|
II) 4)
|
0
|
new_sprite
|
16bits
|
address executed routine when a sprite is loaded in
the table of the sprites (of not at all on the 6th 8-bit byte of a list
of the table, has is equal to the type of the sprite that has just been
created)
|
III) 4)
|
$0000
|
tile_zero
|
8bits
|
number of the tile to post "by default", to the place
where a sprite is created, or for the tiles of which the number is
superior to n_tiles2
|
IV) 1)
|
0
|
n_tiles2
|
8bits
|
all the tiles of which the number is superior or equal
to n_tiles2 will be posted as having an equal number to tile_zero
|
IV) 1)
|
0
|
n_sprite
|
8bits
|
defines the difference, in the card matrix, between a
tile (strictly inferior number to n_sprite) and a sprite (superior or
equal number to n_sprite)
|
III) 3)
|
0
|
sprite_table
|
16bits
|
address table of the sprites
|
III) 2)
|
$0000
|
sprite_max
|
8bits
|
number of sprites that can manage the table at the
same time
|
III) 2)
|
0
|
l_sprite
|
16bits
|
number of information (in 8-bit byte) that
characterize a sprite in the table
|
III) 2)
|
0
|
tiles_addr
|
16bits
|
address list of the tiles
|
II) 2)
|
0
|
map_addr
|
16bits
|
address matrix of the map
|
II) 2
|
$0000
|
map_width
|
16bits
|
number of columns of this matrix
|
II) 2)
|
$0000
|
map_height
|
16bits
|
number of lines of this matrix
|
II) 2)
|
0
|
scroll_y
|
16bits
|
number of entire tiles surpassed by the window to the
left
|
II) 2)
|
0
|
scroll_x
|
16bits
|
number of entire tiles surpassed by the window in top
|
II) 2)
|
0
|
Routines:
Routine name | Description | Paragraph | Entry | Returns |
gba_initmap | put the map in the APDRAM | II) 2) | - | - |
gba_hl_plus_dexbc | hl+de*bc -> hl | IV) 1) | not bc no positive one, of positive or negative one | - |
gba_restoremap | copy the map in the APDRAM in the GRAPH_MEM | II) 2) | - | - |
gba_scroll_right | scroll map right | II) 3) | - | - |
gba_scroll_left | scroll map left | II) 3) | - | - |
gba_scroll_up | scroll map up | II) 3) | - | - |
gba_scroll_down | scroll map down | II) 3) | - | - |
gba_collision | send back the number and the address of the tile that contains the situated point to (b,c) | IV) 1) | (b,c) coordinated of a point, can be negative or outside of the screen | has is equal to the number of the tile, hl contains the address of this tile |
gba_findsprite | look for a empty location in the table of the sprites | IV) 4) | - |
-if there is place: hl not at all on the 1st 8-bit byte of a list life - otherwise the zero flag is worth not zero |
gba_initsprite | restore the due modifications to the load of sprites in the table | IV) 4) | - | - |
gba_drawsprite | draw sprite with mask | III) 1) | (b,c) coordinated of the sprite, (of) width in 8-bit byte and height in pixels of the sprite, hl addresses it picture | - |
gba_drawinverted | draw a sprite negative | IV) 1) | ditto | - |