Optimized Object Movement - RetroKoH/S1Fixed GitHub Wiki
(Credit: redhotsonic, flamewing, Naoto, DeltaW, RetroKoH, Hivebrain)
Source: SCHG Page
Commits: 00c3e73, 1db4101
There are at least four different functions that are responsible for speed-based object movement in Sonic 1. The first allows an object to move about by applying speed to the position variables. The second does the same thing, except it also applies gravity to the object by adding an additional amount to its Y speed. The third is a special function used by boss objects that applies speed to two completely different variables, which are then applied to the object's positioning, allowing for special movement. The 4th is a special function used by the Scrap Brain teleporters to move Sonic. S3K made small changes to these movement functions to provide a small optimization (which add up over time, considering they are called once per frame, for EVERY moving and/or falling object). Retro member flamewing has provided even further optimization to these functions, and from Hivebrain's advice, I was able to take it one step further by cutting out unused speeds for certain objects. Let's first look at SpeedToPos and see how S3K optimized things, then look at how things can be improved upon even further.
SpeedToPos
Open _incObj/SpeedToPos.asm, and make the following changes:
SpeedToPos:
- move.l obX(a0),d2 ; --REMOVE--
- move.l obY(a0),d3 ; --REMOVE--
move.w obVelX(a0),d0 ; load horizontal speed
ext.l d0
asl.l #8,d0 ; multiply speed by $100
! add.l d0,obX(a0) ; add to x-axis position (Add directly instead of to d2)
move.w obVelY(a0),d0 ; load vertical speed
ext.l d0
asl.l #8,d0 ; multiply by $100
! add.l d0,obY(a0) ; add to y-axis position (Add directly instead of to d3)
- move.l d2,obX(a0) ; --REMOVE--
- move.l d3,obY(a0) ; --REMOVE--
rts
As you can see, we don't need the extra steps taken to update the postion variables. We certainly don't need to load them to registers beforehand, because we are simply performing basic addition, and are always going to apply it to the positions at the end. But look at the ext
and asl
instructions. We can consolidate those into an lsl
instruction if we use movem
at the start to immediately load both speeds to registers. Here is what that looks like:
SpeedToPos:
movem.w obVelX(a0),d0/d2 ; load X speed (d0) and Y speed (d2)
lsl.l #8,d0 ; multiply by $100
add.l d0,obX(a0) ; add to x-axis position
lsl.l #8,d2 ; multiply by $100
add.l d2,obY(a0) ; add to x-axis position
Naoto provides an explanation for why this works as cleanly as it does:
Odd as it seems, movem.w actually sign extends to a longword, even on data registers. This way, we load the velocity values into their appropriate registers and sign-extend them to a long in a single instruction. Now, we can apply this to the others.
ObjectFall
Open _incObj/ObjectFall.asm, and change it to this:
ObjectFall:
movem.w obVelX(a0),d0/d2 ; load x/y speeds to d0/d2
Lsl.l #8,d0 ; multiply by $100
add.l d0,obX(a0) ; add to x-axis position
addi.w #$38,obVelY(a0) ; increase vertical speed (gravity)
Lsl.l #8,d0 ; multiply by $100
add.l d0,obY(a0) ; add to y-axis position
rts
BossMove
Open sonic.asm and find BossMove:
and change it to this:
BossMove:
movem.w obVelX(a0),d0/d2 ; load x/y speeds to d0/d2
lsl.l #8,d0 ; multiply by $100
add.l d0,objoff_30(a0) ; add to x-axis position
lsl.l #8,d0 ; multiply by $100
add.l d0,objoff_38(a0) ; add to y-axis position
rts
SBZ Teleporters
The speed function here is identical to SpeedToPos, except we are changing (a0) to (a1). This mini function is located in _incObj/72 Teleporter.asm at label loc_167DA. Change it to this:
loc_167DA:
movem.w obVelX(a1),d0/d2 ; load X speed (d0) and Y speed (d2)
lsl.l #8,d0 ; multiply by $100
add.l d0,obX(a1) ; add to x-axis position
lsl.l #8,d2 ; multiply by $100
add.l d2,obY(a1) ; add to x-axis position
rts
For all four functions, speed is applied directly to the positioning variable, instead of to an unnecessary data register buffer. We are also consolidating both move
instructions AND ext
into one instruction with movem
, greatly simplifying things.