Advice on the Art of Genesis level Building

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Thu Mar 18, 2010 9:29 am

In my stuff I have a "zone" based setup. All of the stages are built of 16x16 tile zones, each zone is compressed with non bloatly RLE (1 data element for up to 4 same tiles, 2 data elements for 5 to 65536 consecutive tiles). Each tile is 16x16 pixel block, and there's always 4 active zones, where objects are checked etc. For faster seeking in level data there's a seek table too when needed, and there's some "instructions" between zones to trigger events or tile data updates etc.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

eteream
Very interested
Posts: 81
Joined: Tue Dec 22, 2009 2:13 pm

Post by eteream » Thu Mar 18, 2010 3:30 pm

TmEE, what type of game is? (platformer, beat'm up,...)
How many scrolls have? (1,2,... 1 direction, both directions,...)

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Thu Mar 18, 2010 5:01 pm

eteream wrote:TmEE, what type of game is? (platformer, beat'm up,...)
How many scrolls have? (1,2,... 1 direction, both directions,...)
Its a platforming run 'n' gun mostly, inspired by Contra, Metal Slug and Turrican.
1 Foreground scroll layer(grounds etc.) and a backgorund layer, which I've not yet decided how to handle, scrolling happens in all directions.

Each sector requires 512 bytes of space when decompressed, there's always 4 decompressed sectors so 2Kbytes is needed at all times.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

eteream
Very interested
Posts: 81
Joined: Tue Dec 22, 2009 2:13 pm

Post by eteream » Fri Mar 19, 2010 1:35 am

Yes, I was wrong: definitely you can work with compresed map-data in active game. For one direction scroll game simply keep decompressing when you need it. For multiple direction scroll make 'zones' as TmEE said.
Only one account, when screen scrolls it takes more CPU than when not.
MottZilla wrote: In commercial games I've heard of compression techniques like a Tree system where you have your level made up of big blocks which are defined somewhere. Sometimes these big blocks are made up of smaller blocks that are defined elsewhere. Then with all of that you might use RLE or some other compression to get size down even more. I suppose if you only had a few of these "big" blocks or little blocks you could save data room by only using as many bits as you needed. I'm sure there are alot of ways to compress level data.
You can create a map for the map (and go on... if you like), something like TmEE said. He has a blocks composed by tiles, and a map composed by blocks. But you can create more levels in this structure, and you get that tree. With the tree, finding something (for colision detection, drawing only near things,...) is easy and factible in a 3D world, while in memory you only have unique 3D objects.
But I think MD can't handle a deep tree to draw various objects in one frame.
Gigasoft wrote: For tile updates, you could transfer a manageable number of tiles every frame until you're done. Uncompressing can be done in the background when the game is idle. In an upcoming game I'm making, I switch to a background task that performs loading of world data whenever I'm waiting for the next frame, enabling seamless scrolling in a very large world. I used the same technique in a NES game (which was never finished) with splendid results. In both games, I have 4x4 screenfuls loaded at once.
Completly true. But... you are speaking about: idle, background task... are you working in a PC game, a modern game? well, well, well... reply if you can do it.;)

There is any chance to see that NES game?
Gigasoft wrote: The world data itself is command based, where there are commands to draw floors, walls and other objects, and the objects can be placed freely without regard for screeen boundaries.
I don't fully understant it. Are you talking about scripting (or some kind of it)? You do not have a tile map?
Megadrive can handle some binary command based scripting, but the whole world...?

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Fri Mar 19, 2010 7:00 am

Nope, not PC, Mega Drive. I used the same technique on the NES. I switch to loading task at the end of frame processing, and the VBL handler returns me back to where I was before. Many Capcom NES and SNES games have support for (non-preemptive) multitasking too in the code, although they don't usually use it much. For example, in Mega Man 5, the debug key handler is a separate task.

I don't have a tile map in the ROM, it's dynamically created when moving around. Command based worlds were used in many popular Nintendo titles such as the Super Mario Bros series, Super Metroid, Zelda 2, Zelda 3 (in dungeons, caves and houses), but in those, loading only happened at screen transitions.

In my NES game, each screen was a separate data block, so objects had to fit within their screen. I found this to be too limiting, so in my upcoming Mega Drive game I have a technique where the world is divided into a tree of arbitrarily sized regions, and when loading a screeen, I find the objects that overlap the screen (using region commands to skip over large numbers of irrelevant objects) and draw the portion that is within the screen. It's okay for this process to take a couple of frames since it only happens for every screenful scrolled, and is running in the background loading screens that haven't scrolled into view yet. An early version of the system has been implemented and works, but I'm redesigning it to have better support for heights. There will be a terrain map containing byte indexes into a table with heights and ground types, a display map for planes A and B, and a map with heights for the blocks on A and B. They are all generated from the same data, except when plane A is separate from B. In total, these screens use 5000h bytes of RAM, still leaving plenty more for other things. Something that worked in the NES game but won't work here is breakable blocks, due to the detachment of terrain and display maps (the same block may not be loaded simultaneously in both maps).

I'll see if I can dig up that NES game, it's on my other computer.

MottZilla
Interested
Posts: 40
Joined: Mon Feb 08, 2010 9:54 pm

Post by MottZilla » Fri Mar 19, 2010 8:25 pm

Gigasoft wrote:For example, in Mega Man 5, the debug key handler is a separate task.
What's this? Is there some code or patch to enable debug features in Mega Man 5? I've never heard of this and would like to know. =)

dtech
Interested
Posts: 33
Joined: Tue Jan 19, 2010 2:56 pm
Location: Latvia, EU
Contact:

Post by dtech » Fri Mar 19, 2010 9:31 pm

Eteream:
What I'd say there is that there ARE a lot of games that do constantly or casually update tile data in VRAM. Contra simply could not be the only game (even if I haven't ever checked any other) because it shares engine with other games - for example Rocket Knight Adventures... Generaly same engine with changes and additions regarding specific effects and object behaviours.

All sonics except for first one, do update tiles frequently, in speific places in levels, that can only be passed one-way or through only one path, and have minimal tile usage on screen.

The best example of very smooth and fast, almost-constant "live" tile raster data updating is one in Sonic 3d blast. Almost-constant it is because it gets updated in small steps while also updating offscreen map whenever character moves. also all ground animation (water, snow, fans, bubbles, whatever) is done via DMA updating.

Such dma stuff is done also on many other games, while in different fashion, still share some common logic. As far as I remember, quite complex tile updating is used in "Mickey Mania" and other games sharing same engine ("Puggsy" for example).

Decompression is also very common thing for any game that has large levels, otherwise stuff gets needlessly bloated. For example, a large level (maybe mainly filled with air..?) of, lets say, 30 by 30 screens wil take up about 2Mbytes of cart space.

Macroblocks and RLE do make sense.

All macroblocks used in level may also be decompressed to 68k ram, for fast dma transfer to VRAM whenever needed.

ROMs are not realy that cheap today, if we talk about ones that are relatively glue-less compatible with genesis. Parallel NOR roms still cost considerable amounts of money, and cheap and 3.3V or 5V compatible ones are about 1..4Mbyte in reasonable prices. 16Mbyte is the upper limit and usualy require more specific power needs (say 3.0V) along with more specific bus voltage adapting. Large NAND arrays (the ones used in USB Sticks, CFs, SDs or any other nonvolatile memory) does not count here. It's completely different technology that requires faulty sector remapping and cannot be used without appropriate SRAM/DRAM on cart and 'magic' chip that will refresh the DRAM (no, segas built-in optional refresh on cart will not work with enything newer than 1990 DIP 4-bit wide DRAMs) and load the required blocks from the NAND array, while performing faulty sector mapping.

Everything can be built, especially in small quantities, yet if we'd want to produce large runs of carts, every cent matters. That meaning - less logic / voltage adaptation / psu stuff in cart, smaller rom chip(s) --> cheaper, faster production with more reliable products as the result :)

I think the optimum is still 4Mbytes of maximum cheap NOR rom, that is 16bit wide and in simple non-bga smd chip package. Advanced carts could have a small additional chip (that I can produce) with custom internals that helps to interface to larger NOR roms and perform address decoding and programmable page mapping, adapt simple peripheral (like i²c EEPROM that costs nothing - for savegames) to parallel access bus, and maybe add some reliable stereo dac with large intelligent FIFO.

Adding, for example, a super cheap nowdays gigabyte SD card inside cart can be done, but requires aforementioned 2..4Mbyte DRAM for page/segment loading, much smarter custom chip (that will cost more due to significantly larger internal resources required) that will have much more pins (because entire genesis address and data buss will have to be put THROUGH it), that might cause the need to choose BGA packages, that will require much finer at least 4-layer PCB production...

...and the price skyrockets.

I think genesis even phylosophicaly 'requires' skillful/artful/compact/tailored coding techniques to be used. Just like pixel-level tailoring of image data... Otherwise it's not realy that oldschool beauty anymore :)

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Fri Mar 19, 2010 9:59 pm

In Mega Man 5, the GG code ATLKGL (C33C:60) enables debug keys on controller 2. Some of these are processed in the main game task (Task 0). These are Left (pauses the game) and Right (palette editor). Task 1 handles palette and background animations. Task 2 just starts up the other tasks. Task 3 is supposed to handle some more debug keys, but it's never actually started. To enable it, write A9 E4 85 94 A9 3B 85 93 A9 03 20 F3 FE 4C 0B FF to offset 3FFCD in the ROM, and write BD to offset 3DE7E. This enables A for restart and Down for upside down play. With EA EA EA at 3DE30, there's no introduction and the A button instead skips to the next level.

eteream
Very interested
Posts: 81
Joined: Tue Dec 22, 2009 2:13 pm

Post by eteream » Sun Mar 21, 2010 11:33 pm

For "task" I understand some kind of procedure with his own stack, 'memory map' and register set, and with some kind of task schedule.

May be "interrupt procedure" is enough. One for debug proposes (zero division,...), one for VINT, one for RESET, and one for IDLE or non-VINT code.
Gigasoft wrote: I don't have a tile map in the ROM, it's dynamically created when moving around. Command based worlds were used in many popular Nintendo titles such as the Super Mario Bros series, Super Metroid, Zelda 2, Zelda 3 (in dungeons, caves and houses), but in those, loading only happened at screen transitions.
Yes, they have commands associated to a block, for example when you enter into a pipe a number command determines which is the new map. But essentially they are map tile based (yes, with commands!). (Zelda-> Cellda! :D)
dtech wrote: All macroblocks used in level may also be decompressed to 68k ram, for fast dma transfer to VRAM whenever needed.
It's not clear if you're saying that RAM is more faster than the ROM, but in any case, I listened similar things many times, but without providing any data.
It really is the ram faster than the rom? how much? why?

dtech, I don't want to be rude, but we are speaking about working with more tiles that the ones are stored on VRAM, and dynamically change them between RAM and VRAM (or something like that).

Character animation with DMA is so easy (this afternoon I did it to simulate water movement) is just one C line. But working with a background with more tiles that the ones you have in VRAM is a challenge.

Code: Select all

DMA(source+(step++%4), destiation, size);

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Mon Mar 22, 2010 12:08 am

Yes, by a command I just mean something which specifies a large object to be made out of 16x16 blocks, just like in those Nintendo titles.

If you load the level data into RAM as tiles first, transferring them will take just a short time because you don't have to interpret the level data as you draw. In my game, the data is stored as 16x16 tiles in RAM, and is only converted to 8x8 tiles one row at a time when updating borders, but the conversion to 8x8 tiles happens in advance so that the row can be transferred fast in the VBL handler. Drawing has to happen during VBL so it won't be disturbed by the HBL routine.

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Tue Mar 23, 2010 10:42 am

eteream wrote:It's not clear if you're saying that RAM is more faster than the ROM, but in any case, I listened similar things many times, but without providing any data.
It really is the ram faster than the rom? how much? why?
You can decompress GFX straight to VRAM, but VRAM is slow to transfer to, so that's why you decompress to RAM so you can neatly DMA the stuff to VRAM. RAM itself is sliiiightly slower than ROM thanks to some refresh cycles that happen every happen every once in a while (RAM is PSRAM not plain SRAM), you can enable ROM area refreshes too in one register (forgot it) which makes ROM as "slow" as RAM is.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Alex Khan
Very interested
Posts: 77
Joined: Thu Jan 07, 2010 9:51 am

Post by Alex Khan » Sat Mar 27, 2010 5:28 am

dtech wrote:(A short reply due to lack of time at the moment)

HINT and VINT - horisontal and vertical interrupt, realy work well on genny, in contrast to pc cga/ega/vga hell :)

Sonic3 and many other games use hint for water.

Regarding reprogramming - challenge is everything! :D
To have large, interesting levels, you also need to reprogram the maps quite frequently and fast, usually involving decompression of some sort. This is a challenge, especially if a game is a fast scroller. I remember playfield was programmable to 64x64 tiles and thus, when running around, that flayfield need to be updated off-screen for all the new stuff there is. Also handle the disapperaing and appearing enemies and their actions. This all is a hard part.

Reprogramming, however, is a relatively easy one - when some token is reached with the hero alone in the center on mostly only background visible and ground of some sort, engine updates specific blocks of tile data (that is used on the next part of the level), the ones, which are on the screen, stay intact. Games usualy have a slight hickup at that point (a freeze for a frame or two) and then does not allow you to go back (because graphics will be trashed up by new tiles). sonic2/3/knuckles do this stuff a lot and quite smoothly.

I think i could dig up my old tool sources that had quite a powerful optimiser amongst them, and maybe rework them for windows and any user interface (they were for DOS and x-mode graphics hahaha *scary*).

Another extreme programming challenge is to make effective enemy/object engine - again, sonic2/3/K does this amazingly well. Challenge is to make it all flexible and fluent - that every object that enters the proximity space, becomes active and has it's own processing/interaction routine (form rom, shared for all enemies of the same type), yet have dynamically assigned context scratchpads (separate for every 'live' object), that hold objects behaviour/position/action/phase, and that all such objects are processed using a dynamically maintained list where such routine can terminate itself and remove from list (when, for example, enemy is killed and explosion animation is done and over) or suspend (or keep alve) if that object is important (boss doesn't disapper or stop operating when leaving frame).

Such engine allows almost interaction things to be handled in the same way (like it's done in sonic) - be it a wall opening from a button press or operating a pulleys or some mechanisms, bosses that can release more enemies, animated checkpoints, etc...

I find this thing, along with map update engine, to be the hardest points, but also most beneficial ones, when those are up and running :) Because creating detailed and ellaborate levels becomes a joy! As well as creating enemies, that can generate more enemies (even by just shooting) and interactive objects.

Contra hard corps is an another example of extremely well programmed engine that does hell lot of tricks and everything combined in a solid piece of consistent code. Same about vectorman and well... many many other games :)
Dtech thank you your post was very educational. I had no idea that Sonic and the Contra engines were so technical and had so much depth to each game's 'Engine' architecture.

However I am also starting to feel a little worried now. Because everytime I think I have understood some aspect of Sega Console programming some new information is thrown my way and then I start to doubt my grasp of Sega programming. :(

However Dtech have you considered writing a book on Sega Game programming? With your knowledge and the lack of books on Sega Game programming it would do very well in sales. I am very serious it would!

Where can I read more about implementing Vint and Hint it seems a very useful for any programmer's toolkit. Is there a tutorial or documentation you can refer me too?
Gigasoft wrote:For tile updates, you could transfer a manageable number of tiles every frame until you're done. Uncompressing can be done in the background when the game is idle. In an upcoming game I'm making, I switch to a background task that performs loading of world data whenever I'm waiting for the next frame, enabling seamless scrolling in a very large world. I used the same technique in a NES game (which was never finished) with splendid results. In both games, I have 4x4 screenfuls loaded at once.

Usually, level data is not based on individual tiles, but larger blocks composed of tiles (usually 2 by 2 or 4 by 4 tiles). This is also so in my game, where the result after loading is an arrangement of blocks made of 2 by 2 tiles. The world data itself is command based, where there are commands to draw floors, walls and other objects, and the objects can be placed freely without regard for screeen boundaries.
Why won't you share some of your routines with the community? Please show me some of your code. :)

TmEE co.(TM) wrote:Its a platforming run 'n' gun mostly, inspired by Contra, Metal Slug and Turrican.
1 Foreground scroll layer(grounds etc.) and a backgorund layer, which I've not yet decided how to handle, scrolling happens in all directions.

Each sector requires 512 bytes of space when decompressed, there's always 4 decompressed sectors so 2Kbytes is needed at all times.
Tiido please make some tutorials please! Something for beginners like me.
eteream wrote: Character animation with DMA is so easy (this afternoon I did it to simulate water movement) is just one C line. But working with a background with more tiles that the ones you have in VRAM is a challenge.
Please share water movement effect routine. You guys talk about such Amazing stuff but when are you going to share some code. Eteream please take time to make some tutorials. It is so frustrating seeing people talk about these great routines but no one is showing me how it's done.

For God's Sake Gentlemen ... please less talk and more code! :)

Especially if Code is in the Basic Language ... hehehhehe
I need a Black Belt in Game Programming!

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Sat Mar 27, 2010 7:36 am

The code is mostly in ASM or C here, and I was once writing a guide but it never got anywhere, and I'm a bit too buzy now...
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Sat Mar 27, 2010 5:33 pm

Alex Khan wrote: Why won't you share some of your routines with the community? Please show me some of your code. :)
Well, here are some short excerpts. I can't share too many secrets :P

The VSync function.

Code: Select all

vsync:
 move.l d0-d7/a0-a6,-(a7)
 move.w #$2700,sr
 move.w a7,stack1
 move.w stack2,a7
 move.l (a7)+,d5-d7/a4-a6
 tst.w LoadRetryPC
 beq load_noretry
 move.l (a7)+,d0-d4/a0-a3 
 move.w LoadRetrySP,a7
 move.w LoadRetryPC,-(a7)
 clr.w -(a7)
 rts
load_noretry:
 move.l (a7)+,d0-d4/a0-a3
 rte
Here, LoadRetryPC is used to restart operations such as allocating a character or inserting it into the character list, when they have been interrupted. That's the two places where it's used for now.

The end of my VBL handler:

Code: Select all

 move.w #$2300,sr
 move.w stack1,d0
 beq noresumevs
 clr.w stack1
 move.l d5-d7/a4-a6,-(a7)
 move.w a7,stack2
 move.w d0,a7
 bra vsynccont
noresumevs:
 move.l (a7)+,d0-d4/a0-a3
 rte
Reading a rectangle and cropping it:

Code: Select all

rr0:
 moveq #-1,d0
 rts
ReadRect:
 moveq #0,d0
 moveq #0,d1
 moveq #0,d4
 moveq #0,d5
 move.b (a0)+,d0
 move.b (a0)+,d1
 move.b (a0)+,d4
 move.b (a0)+,d5
BeginDrawRect:
 sub.w CurLoadHt,d4
 moveq #16,d6
 sub.w d2,d0
 cmp.w d6,d0
 bge rr0
 add.w d0,d1
 ble rr0
 sub.w d3,d4
 cmp.w d6,d4
 bge rr0
 add.w d4,d5
 ble rr0
 cmp.w d6,d1
 blt rr1
 moveq #16,d1
rr1:
 cmp.w d6,d5
 bcs rr2
 moveq #16,d5
rr2:
 tst.w d0
 bmi rr3
 sub.w d0,d1
 add.w d0,a1
 clr.w d0
rr3:
 neg.w d0
 tst.w d4
 bmi rr4
 sub.w d4,d5
 lsl.w #6,d4
 add.w d4,a1
 clr.w d4
rr4:
 neg.w d4
 moveq #64,d6
 sub.w d1,d6
 rts
Drawing an indentation in the ground:

Code: Select all

HoleTable dc.b 14,14,2,0
DispC_hole:
 moveq #0,d7
 move.b (a0)+,d7
 bsr ReadRect
 move.b (a0)+,d3
 tst.w d0
 bmi rch2
 lsl.w #2,d7
 move.w #HoleTable,a2
 add.l d7,a2
 move.b (a2)+,d7
 subq.w #1,d1
 move.l a1,a3
 add.w #$2000,a3
 move.b CurLoadHt+1,d2
 tst.w d4
 bne rch1
 subq.w #1,d5
rchlp2:
 move.w d1,d0
 cmp.b d3,d4
 beq rch0
 subq.w #1,d2
rchlp:
 move.b d7,(a1)+
 move.b d2,(a3)+
 dbra d0,rchlp
 add.w d6,a1
 add.w d6,a3
 addq.b #1,d4
rch1:
 move.b (a2),d7
 dbra d5,rchlp2
 rts
rch0:
 move.b 1(a2),d7
 addq.w #1,d1
 addq.w #1,d5
 move.l d0/d1/d5/a1,-(a7)
 bsr FillMapRect
 move.l (a7)+,d0/d1/d5/a1
 move.b CurLoadHt+1,d7
 sub.b -1(a0),d7
 add.w #$2000,a1
 bra FillMapRect
TerrC_hole:
 addq.l #1,a0
 bsr ReadRect
 move.b CurLoadTerrHt,d7
 sub.b (a0)+,d7
 bra FillMapRect

eteream
Very interested
Posts: 81
Joined: Tue Dec 22, 2009 2:13 pm

Post by eteream » Sat Mar 27, 2010 9:06 pm

Alex Khan wrote:
eteream wrote:...
Please share water movement effect routine. You guys talk about such Amazing stuff but when are you going to share some code. Eteream please take time to make some tutorials. It is so frustrating seeing people talk about these great routines but no one is showing me how it's done.
Well, as I said, it's nothing special. Just a TEST did that day.

On my stage (module) init VINT callback:

Code: Select all

GFX_Enable( 0 );
...
// Load level
DO_DMA( DMA_RAM_TO_VRAM, (void*)g_tilesLvl1, TILE_LVL1*TITLE_SIZE, sizeof(g_tilesLvl1) );
DO_DMA( DMA_RAM_TO_CRAM, (void*)g_paletteLvl1, 0, sizeof(g_paletteLvl1) );
...
GFX_Enable( 1 );
And this moves a generic tile map to vram:

Code: Select all

u16 y, x;
	for( y = 0; y < SCREEN_TITLES_HEIGHT; y++ )
	{
		CopyToVRAM_1Addr( ADDR_PLANE_B + (PLANE_TITLES_WIDTH * 2 * y) );

		for( x = 0; x < SCREEN_TITLES_WIDTH; x++ )
		{
			// 2????
			CopyToVRAM_2Data( g_mapLvl1[LVL1_TITLESHEIGHT+2-SCREEN_TITLES_HEIGHT+y][x] );
		}
	}
On my per frame VINT module call back:
Modify four tiles on tile table, witch are mapped all around plane B (the scene is about a bridge):

Code: Select all

static u16 i=0;
i++;
DO_DMA( DMA_RAM_TO_VRAM, (void*)g_tilesWater+((i>>(4+0))%3), TILE_LVL1*TITLE_SIZE, sizeof(g_tilesWater[0]) );
DO_DMA( DMA_RAM_TO_VRAM, (void*)g_tilesWater+((i>>(4+3))%3), TILE_LVL1*TITLE_SIZE+TITLE_SIZE, sizeof(g_tilesWater[0]) );
DO_DMA( DMA_RAM_TO_VRAM, (void*)g_tilesWater+((i>>(4+2))%3), TILE_LVL1*TITLE_SIZE+TITLE_SIZE*2, sizeof(g_tilesWater[0]) );
DO_DMA( DMA_RAM_TO_VRAM, (void*)g_tilesWater+((i>>(4+1))%3), TILE_LVL1*TITLE_SIZE+TITLE_SIZE*3, sizeof(g_tilesWater[0]) );
BUT if you are really interested you can find info in the deep internet, things like that:
http://www.consolasparasiempre.net/kid/angellandE.htm
http://www.consolasparasiempre.net/kid/ ... veiled.pdf
which explains how a commercial game works.

Post Reply