Actions

SCHG How-to

Difference between revisions of "Work with Objects"

From Sonic Retro

(Yeah yeah, I know :V)
(Lesson 3: Making Mappings: Correcting stuff)
Line 95: Line 95:
  
 
==Lesson 3: Making Mappings==
 
==Lesson 3: Making Mappings==
Ok, in this section we’re gonna cover the aspects of making object mappings, so what are mappings? Mappings are a way of presenting art tiles on an object in a certain way, now going back to “Section C: Displaying/Basic SSTs” in “Lesson 1” you’ll notice the line: <asm> move.l #Map_obj18,4(a0) ; moves the mappings into the mapping's SST</asm> This loads the mappings under the routine name “Map_obj18”.
+
Ok, in this section we’re gonna cover the aspects of making object mappings (Note: this is written for Sonic 1 primarily, however Sonic 2 and to an extend Sonic 3 (&K) mappings will be quite similar bar a few changes), so what are mappings? Mappings are a way of presenting art tiles on an object in a certain way, now going back to “Section C: Displaying/Basic SSTs” in “Lesson 1” you’ll notice the line: <asm> move.l #Map_obj18,4(a0) ; moves the mappings into the mapping's SST</asm> This loads the mappings under the routine name “Map_obj18”.
  
 
So, we need to make this routine and the mappings for it, now it doesn’t really matter where you put this but for now let’s put it directly under our object code (it just makes sense this way).
 
So, we need to make this routine and the mappings for it, now it doesn’t really matter where you put this but for now let’s put it directly under our object code (it just makes sense this way).
Line 115: Line 115:
  
 
<asm>ObjectMap_01: dc.b $01
 
<asm>ObjectMap_01: dc.b $01
dc.b $vv, $ww, $xx, $yy, $zz</asm>
+
dc.b $YY, $SS, $VV, $VV, $XX</asm>
  
So, you’ll notice that first of all the $00 that was previously there is now a $01, this is because a line has been added below it “dc.b $vv, $ww, $xx, $yy, $zz” that is one map block, if you had two of these below, then you would put $02 at the top there, that top value indicates the number of map blocks to use, we’re only gonna use one for now, so $01 it is.
+
So, you’ll notice that first of all the $00 that was previously there is now a $01, this is because a line has been added below it “dc.b $YY, $SS, $VV, $VV, $XX” that is one sprite, if you had two of these below, then you would put $02 at the top there, that top value indicates the number of sprites to use in these mappings, we’re only gonna use one for now, so $01 it is.
  
Now to the actual mapping at hand, you notice I’ve put vv ww xx yy and zz, this is just to explain what each byte does, so lets take a look at vv, vv sets how many pixels up or down to present the tiles from where the object is, for example:
+
Now to the actual mapping, you notice I’ve put '''YY SS VV VV''' and '''XX''', this is just to explain what each byte does, so lets take a look at '''YY''', '''YY''' sets how many pixels up or down to present the tiles from where the object is, it is signed so negative values from FF down to 80 will move the sprite up while positive values from 00 to 7F will move the sprite down, for example:
  
 
<asm>ObjectMap_01: dc.b $01
 
<asm>ObjectMap_01: dc.b $01
dc.b $08, $ww, $xx, $yy, $zz</asm>
+
dc.b $08, $SS, $VV, $VV, $XX</asm>
  
This will move the tile mappings down 8 pixels from where the object is, so if the object is on the Y axis of $0200, the tile mappings will present on the Y axis of $0208, simple.
+
This will move the tile mappings down 8 pixels from where the object is, so if the object is on the Y axis of $0200, the tile mappings will present on the Y axis of $0208.
  
Next let’s skip over to zz, this is the same as vv except it’s on the X axis (left or right) not the Y axis, so:
+
Next let’s skip over to '''XX''', this is the same as '''YY''' except it’s on the X axis (left or right) not the Y axis, so:
<asm> dc.b $vv, $ww, $xx, $yy, $08</asm>
+
<asm> dc.b $YY, $SS, $VV, $VV, $08</asm>
  
This will move the tile mappings right 8 pixels from where the object is, so if the object is on the X axis of $0340, the tile mappings will present on the X axis of $0348, simple.
+
This will move the tile mappings right 8 pixels from where the object is, so if the object is on the X axis of $0340, the tile mappings will present on the X axis of $0348.
  
Ok, now to ww, this is how the tiles should present them selves, in other words how the block is made, now lets say we have 16 tiles in VRam (from 00 to 0F), depending on what code is in ww, will change how those 16 tiles are stacked on each other:
+
Ok, now to '''SS''', this is the "shape" so to speak, it's how the tiles should present themselves (in other words how the block is made), now lets say we have 16 tiles in VRam (from 00 to 0F), depending on what code is in '''SS''' will change how those 16 tiles are stacked on each other:
  
 
So if we put $00 the tiles will map:  
 
So if we put $00 the tiles will map:  
Line 325: Line 325:
  
 
That should be self explanatory for you:
 
That should be self explanatory for you:
<asm> dc.b $vv, $ww, $xx, $yy, $zz</asm>
+
<asm> dc.b $YY, $SS, $VV, $VV, $XX</asm>
Next let's look at xx, this sets if it is flipped, mirrored, and or uses a certain palette line, now it works like this:
+
Next let's look at '''VV VV''', this is actually a word of data and is the V-Ram location to read the tiles for the sprite, it also has specific settings (if it is flipped, mirrored, and or uses a certain palette line, and if it's high or low plane), this is a "Map ID" and is used for map planes too, let's break '''VVVV''' up into sections of '''XYZZ''':
  
First, you need to set if it’s flipped or mirrored, if you put 08 in, the mappings with appear mirrored, if you put 10 in, the mappings will appear flipped, if you put 18 in, the mappings will appear both mirrored and flipped.
+
'''YZZ is broken into bits: ABBB BBBB BBBB'''
  
Now, you need to set what colour palette line to use, so the first line would be 00, the second line would be 20, third is 40, and forth 60.
+
B = the tile ID (or V-Ram location divided by 20 if you'd prefer)
 +
A = the mirror flag, if clear (bit 0), the "map tile"/"sprite" is normal, if set (bit 1), the "map tile"/"sprite" is mirrored.
  
So now you need to add these 2 codes together, for example, if I want the mappings to be flipped (10) and use the second colour palette line (20), add them together, you get 30, and then put it where xx is.
+
'''X is broken into bits: PCCF'''
  
Lets try another one, we want our mappings to be mirrored (08) and use the forth palette line (60), add them together, you get 68, and then put it where xx is, simple.
+
P = the plane flag, if clear (bit 0), the "map tile"/"sprite" is low plane, if set (bit 1), the "map tile"/"sprite" is high plane.
 +
CC = the palette line flag:
  
<asm> dc.b $vv, $ww, $xx, $yy, $zz</asm>
+
00 = line 0
 +
01 = line 1
 +
10 = line 2
 +
11 = line 3
  
And finally, yy, this is what tile to start mapping from, so lets say we set ww at 03 so the tiles will position them selves like this:
+
F = the flip flag, if clear (bit 0), the "map tile"/"sprite" is normal, if set (bit 1), the "map tile"/"sprite" is flipped.
{| border="1"
 
|00
 
|-
 
|01
 
|-
 
|02
 
|-
 
|03
 
|}
 
  
If we put $02 in yy instead of $00, it’ll position the tiles like this:
+
And there you have it, that’s how to map art on an object.
{| border="1"
 
|02
 
|-
 
|03
 
|-
 
|04
 
|-
 
|05
 
|}
 
  
As you may have noticed it mapped the tiles starting from tile number 02, instead of tile number 00, and there you have it, that’s how to map art on an object.
 
 
[[Category:SCHG How-tos|Work with Objects]]
 
[[Category:SCHG How-tos|Work with Objects]]

Revision as of 16:03, 25 November 2010

(Original guide by Malevolence and MarkeyJester)

I decided I wanted to start some tutorials on objects because there aren't too many hacks with new objects. I figure I can start off with the really basic things then move on to more intricate subjects such as bosses. For now here is the first tutorial on very basic object concepts:

Lesson 1: The Basic Object

Section A: Overview

So, you want to start creating objects using the sonic engine? (We'll be using S1's but most of the ideas cover S1 and S2) Let's see firstly how most objects start out. I'll be using Hivebrain's 2005 disassembly for these examples:

<asm>; ---------------------------------------------------------------------------

Object 18 - platforms (GHZ, SYZ, SLZ)
---------------------------------------------------------------------------

Obj18: moveq #0,d0 move.b $24(a0),d0 move.w Obj18_Index(pc,d0.w),d1 jmp Obj18_Index(pc,d1.w)</asm>

First you see a little description of the object (commented out of course), followed by the object's code itself. It starts off by making sure there is currently no value in d0. After that it puts the value of the routine counter into d0 (whatever's in $24(a0) is in d0 such as 0, 2, 4, ect...). From there it moves the index's value with the value of d0 into d1, followed by jumping to the correct routine based on d1.

Section B: Routines

Routines are used to organize where certain code is and to be able to branch to those sections easily. Most objects used $24(a0) as the main routine counter and $25 as a secondary, but any scratch ram (ram not used by the object) can be used as a routine counter. The value in the routine counter needs to be even in order to work.

<asm>;=========================================================================== Obj18_Index: dc.w Obj18_Main-Obj18_Index ; Jumped to if #0 is in $24(a0) dc.w Obj18_Solid-Obj18_Index ; Jumped to if #2 is in $24(a0) dc.w Obj18_Action2-Obj18_Index ; Jumped to if #4 is in $24(a0) dc.w Obj18_Delete-Obj18_Index ; Jumped to if #6 is in $24(a0) dc.w Obj18_Action-Obj18_Index ; Jumped to if #8 is in $24(a0)

===========================================================================</asm>


So, when this section is run (as soon as the object is loaded):

<asm>Obj18_Main: ; XREF: Obj18_Index addq.b #2,$24(a0)</asm>

When it gets to the next rts instead of going to Obj18_Main again, it will skip over that code and go to Obj18_Solid. Be warned if you put an odd value into the routine counter it won't work properly or if you put a number greater then the amount of routines, your game will crash.

Section C: Displaying/Basic SSTs

Alright, so you know the basis of routines, now where should we go? Well, some of the basic building blocks in objects are what are called SSTs. Every object in S1 and S2 is allotted $40 bytes of RAM to do whatever they want with, but some SSTs are already used for certain things (the game engine checks a few of the object's SSTs once each frame). Let's see an example:

<asm>Obj18_Main: addq.b #2,$24(a0) ; adds to the routine so this isn't run again move.w #$4000,2(a0) ; moves #$4000 to the art tile's SST (it's 2 in S1 and S2) move.l #Map_obj18,4(a0) ; moves the mappings into the mapping's SST move.b #$20,$19(a0) ; width of object in pixels cmpi.b #4,($FFFFFE10).w ; check if level is SYZ bne.s Obj18_NotSYZ move.l #Map_obj18a,4(a0) ; SYZ specific code (use different mappings) move.b #$20,$19(a0) ; this really isn't needed since $19(a0) already has #$20 in it from the code before</asm>

What this basically does is define the width of the object in pixels and loads the starting art tile and palette and mappings. Down more in the code you'll see:

<asm>Obj18_NotSLZ: move.b #4,1(a0) ; use screen coordinates (such as the ones you see in debug mode) move.b #4,$18(a0) ; set priority (if other objects have a priority of a number less then 4 then the other object will be seen over this one if they interact) move.w $C(a0),$2C(a0) ; store a copy of the y coordinate ($C(a0) is y coordingate in S1 and S2 and $2C(a0) is scratch ram) move.w $C(a0),$34(a0) ; store another copy of the y coordinate move.w 8(a0),$32(a0) ; store a copy of the x coordinate move.w #$80,$26(a0) ; move #$80 into $26(a0) (to be used later)</asm>

This is a continuation of the loading of the object (the priority and using screen coordinates) and it saves the x and y pos and a value which will be used later. All you need to do to display an object it to fill in 1(a0), 2(a0), 4(a0) and jump to DisplaySprite.


Lesson 2: More Intricate Things With Objects

Section A: Movement

Welcome to lesson 2 of my object tutorials, in this section we're going to talk about other things that can be done with objects. So say you have an object displaying now and would like it to move. What you'll have to do is set its X and/or Y speed which are the SSTs $10(a0) and $12(a0) consecutively and then simply call a SpeedtoPos (or ObjectMove in S2)

<asm> move.w #-$40,$10(a0) ; make the object have a speed which moves it to the left slowly move.w #$400,$12(a0) ; make the object have a speed which moves it down quickly jmp SpeedToPos ; update the object's position (move the object)</asm>

If SpeedToPos is not called the object will stay immobilized. Also as a note, if you have a positive speed in the Y speed SST, the object will move down and if you have a negative speed in the Y speed SST, the object will move up. This is just a simple explanation of movement and I will eventually cover things such as how to make objects move in circular motions, but for now it's not necessary.

Section B: Timers

Another pretty basic idea used quite frequently is timers. It's what the GHZ boss uses to turn around and go back and forth. To use a timer what you'll have to do is take an unused SST and make sure it's set aside. In this example code, let's use $38(a0). What you want to do is somewhere before the timer starts (say the main loading code) where the code won't be used again is fill this with a number:

<asm>ObjXX_Main: move.w #$100,$38(a0)</asm>

When you come to an area where you want to start counting down, you'll want to set up a code that gets repeated until the time is up, as in:

<asm>ObjXX_CountDown: sub.w #1,$38(a0) ; subtracts from the timer beq.s ObjXX_Next ; tests if timer has hit 0 rts</asm>

Now, in ObjXX_Next you can increase the routine, change the speed/reverse it and you can reset the timer there as well so that it keeps changing speed:

<asm>ObjXX_Next: neg.w $10(a0) move.w #$100,$38(a0) rts</asm>

Lesson 3: Making Mappings

Ok, in this section we’re gonna cover the aspects of making object mappings (Note: this is written for Sonic 1 primarily, however Sonic 2 and to an extend Sonic 3 (&K) mappings will be quite similar bar a few changes), so what are mappings? Mappings are a way of presenting art tiles on an object in a certain way, now going back to “Section C: Displaying/Basic SSTs” in “Lesson 1” you’ll notice the line: <asm> move.l #Map_obj18,4(a0) ; moves the mappings into the mapping's SST</asm> This loads the mappings under the routine name “Map_obj18”.

So, we need to make this routine and the mappings for it, now it doesn’t really matter where you put this but for now let’s put it directly under our object code (it just makes sense this way).

<asm>Map_obj18:</asm>

Next we need an index for this routine similar to the one explain in “Lesson 1”

<asm>Map_obj18: dc.w ObjectMap_01-Map_obj18 dc.w ObjectMap_02-Map_obj18 dc.w ObjectMap_03-Map_obj18 ObjectMap_01: dc.b $00

ObjectMap_02: dc.b $00

ObjectMap_03: dc.b $00</asm>

And now to make the mappings, you’ll notice three sections that look like “ObjectMap_01: dc.b $00” under this is where our set of mappings are going to go, now let me just set one out for you and explain what’s what:

<asm>ObjectMap_01: dc.b $01 dc.b $YY, $SS, $VV, $VV, $XX</asm>

So, you’ll notice that first of all the $00 that was previously there is now a $01, this is because a line has been added below it “dc.b $YY, $SS, $VV, $VV, $XX” that is one sprite, if you had two of these below, then you would put $02 at the top there, that top value indicates the number of sprites to use in these mappings, we’re only gonna use one for now, so $01 it is.

Now to the actual mapping, you notice I’ve put YY SS VV VV and XX, this is just to explain what each byte does, so lets take a look at YY, YY sets how many pixels up or down to present the tiles from where the object is, it is signed so negative values from FF down to 80 will move the sprite up while positive values from 00 to 7F will move the sprite down, for example:

<asm>ObjectMap_01: dc.b $01 dc.b $08, $SS, $VV, $VV, $XX</asm>

This will move the tile mappings down 8 pixels from where the object is, so if the object is on the Y axis of $0200, the tile mappings will present on the Y axis of $0208.

Next let’s skip over to XX, this is the same as YY except it’s on the X axis (left or right) not the Y axis, so: <asm> dc.b $YY, $SS, $VV, $VV, $08</asm>

This will move the tile mappings right 8 pixels from where the object is, so if the object is on the X axis of $0340, the tile mappings will present on the X axis of $0348.

Ok, now to SS, this is the "shape" so to speak, it's how the tiles should present themselves (in other words how the block is made), now lets say we have 16 tiles in VRam (from 00 to 0F), depending on what code is in SS will change how those 16 tiles are stacked on each other:

So if we put $00 the tiles will map:

00

If we put $01 the tiles will map:

00
01

If we put $02:

00
01
02

If we put $03:

00
01
02
03

If we put $04:

00 01


If we put $05:

00 02
01 03

If we put $06:

00 03
01 04
02 05

If we put $07:

00 04
01 05
02 06
03 07

If we put $08:

00 01 02

If we put $09:

00 02 04
01 03 05

If we put $0A:

00 03 06
01 04 07
02 05 08

If we put $0B:

00 04 08
01 05 09
02 06 0A
03 07 0B

If we put $0C:

00 01 02 03


If we put $0D:

00 02 04 06
01 03 05 07

If we put $0E:

00 03 06 09
01 04 07 0A
02 05 08 0B

If we put $0F:

00 04 08 0C
01 05 09 0D
02 06 0A 0E
03 07 0B 0F

That should be self explanatory for you: <asm> dc.b $YY, $SS, $VV, $VV, $XX</asm> Next let's look at VV VV, this is actually a word of data and is the V-Ram location to read the tiles for the sprite, it also has specific settings (if it is flipped, mirrored, and or uses a certain palette line, and if it's high or low plane), this is a "Map ID" and is used for map planes too, let's break VVVV up into sections of XYZZ:

YZZ is broken into bits: ABBB BBBB BBBB

B = the tile ID (or V-Ram location divided by 20 if you'd prefer) A = the mirror flag, if clear (bit 0), the "map tile"/"sprite" is normal, if set (bit 1), the "map tile"/"sprite" is mirrored.

X is broken into bits: PCCF

P = the plane flag, if clear (bit 0), the "map tile"/"sprite" is low plane, if set (bit 1), the "map tile"/"sprite" is high plane. CC = the palette line flag:

00 = line 0 01 = line 1 10 = line 2 11 = line 3

F = the flip flag, if clear (bit 0), the "map tile"/"sprite" is normal, if set (bit 1), the "map tile"/"sprite" is flipped.

And there you have it, that’s how to map art on an object.