[Tutorial] How to create a Simple Scrolling HUD in Sonic 2

Mildanner

Newcomer
Original guide by Mildanner

In Sonic 2, the HUD has a complex code to begin with. If you want to take a look how it looks like, it also loads the sprites and specific. In Sonic 2, the only difference the HUD is popping once the Title Cards leave, which is the one reason why it doesn't look perfect.

In this guide, you will learn how to move a object builder like HUD and how to make the HUD moving every time it loads a level (Only works with 1P).

Go to your s2.asm from Sonic 2 disassembly file, find the BuildHUD: label. Replace the entire routine until ; End of function BuildHUD with this
Code:
BuildHUD:
    ; --- HUD BLINKING LOGIC ---
    moveq   #0,d1                     ; Clear d1 (Default mapping frame: no flashing)
    tst.w   (Ring_count).w            ; Check if total rings equal 0
    bne.s   .checkMinuteOnly          ; If rings > 0, branch to check minutes only

    ; If rings equal 0, process ring counter flashing
    btst    #3,(Level_frame_counter+1).w ; Test frame counter bit for blink frequency
    bne.s   .checkMinuteWithRing      ; If bit is set, hide ring text (skip frame increment)
    addq.w  #1,d1                     ; Set mapping frame to flash rings index

.checkMinuteWithRing:
    cmpi.b  #9,(Timer_minute).w       ; Has the game timer reached 9 minutes?
    bne.s   .calculateScroll          ; If not, branch directly to scrolling calculation
    addq.w  #2,d1                     ; Set mapping frame to double flash (Time + Rings)
    bra.s   .calculateScroll

.checkMinuteOnly:
    btst    #3,(Level_frame_counter+1).w ; Test frame counter bit for time flashing
    bne.s   .calculateScroll          ; If bit is set, skip flashing adjustment
    cmpi.b  #9,(Timer_minute).w       ; Has the game timer reached 9 minutes?
    bne.s   .calculateScroll          ; If not, branch directly to scrolling calculation
    addq.w  #2,d1                     ; Set mapping frame to flash time only

; ===========================================================================
.calculateScroll:
    ; --- DYNAMIC SLOW SCROLLING LOGIC (3 PIXELS PER FRAME) ---
    move.w  (Level_frame_counter).w,d3    ; Read global level frame counter (starts at 0)
    mulu.w  #3,d3                         ; Multiply frame count by 3 for a steady scroll rate

    ; --- TOTAL SLIDING TRAVEL DISTANCE ---
    cmpi.w  #112,d3                       ; Has the scroll distance hit or exceeded 112 pixels?
    blt.s   .applyOffset                  ; If less than 112, continue tracking movement
    cmpi.w  #114,d3                       ; Is this the very first frame it reached the end?
    bgt     .lockValue               
 
.lockValue:
    moveq   #112,d3                       ; Clamp the scroll register permanently at 112

.applyOffset:
    subi.w  #112,d3                       ; Convert the climbing frame scale into negative entry displacement

    ; --- X/Y COORDINATE CONFIGURATION ---
    addi.w  #spriteScreenPositionX(16),d3 ; Apply base X-macro position (compensated for extended scroll)
    move.w  #spriteScreenPositionYCentered(24),d2 ; Apply centered Y-axis row position

    ; --- SPRITE RENDER ENGINE ---
    lea     (HUD_MapUnc_40A9A).l,a1
    movea.w #make_art_tile(ArtTile_ArtNem_HUD,0,1),a3
 
    add.w   d1,d1                         ; Multiply frame layout index by 2 (Word sizing)
    adda.w  (a1,d1.w),a1                  ; Fetch chosen mapping vector depending on flash state
    move.w  (a1)+,d1                      ; Read the direct sprite piece array count
    subq.w  #1,d1                         ; Subtract 1 to accommodate the core internal DBF loop
    bmi.s   .exit                         ; If sprite list is empty, abort safely
    jsrto   JmpTo_DrawSprite_Loop         ; Execute standard Sonic 2 VDP sprite compilation loop

.exit:
    rts
; End of function BuildHUD
Done! Now your hack has a fellow HUD scrolling.

(Optional) Once position is reached to play sound effect​

If your hack looks clear with a fellow HUD scrolling and it has no sound, you can simply go to the line which that one code is this
Code:
    bgt   .lockValue
and below it. Insert this
Code:
    move.w  #SndID_TallyEnd,d0        ; Load the sound ID
    jsr     (PlaySound).l             ; Play the sound effect exactly once
Note: Sonic 2 has a very different code than Sonic 1, we ported this code to work with Sonic 2. Which gave the same results as the original does.

Good luck with your hack having a sound effect once the HUD scrolling is finished, I hope you enjoy this tutorial.
 
Last edited:
Back
Top