Website
Home
Database
News
Submissions queue
Community
Forum
Clubs
Discord
Members
Tools
ROM Patcher
ROM Hasher
Pages
Support us
Learn Romhacking
About
Contact Us
Help & Legal Pages
Guest
Login
Forum
Entries
News
Settings
Community
Tutorials & Guides
[Tutorial] How to create a Simple Scrolling HUD in Sonic 2
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
<blockquote data-quote="Mildanner" data-source="post: 6615" data-attributes="member: 7577"><p><em><strong>Original guide by</strong> <strong><span style="color: rgb(44, 130, 201)">Mildanner</span></strong></em></p><p></p><p>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.</p><p></p><p>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).</p><p></p><p>Go to your s2.asm from Sonic 2 disassembly file, find the BuildHUD: label. Replace the entire routine until <strong>; End of function BuildHUD</strong> with this</p><p>[CODE]BuildHUD:</p><p> ; --- HUD BLINKING LOGIC ---</p><p> moveq #0,d1 ; Clear d1 (Default mapping frame: no flashing)</p><p> tst.w (Ring_count).w ; Check if total rings equal 0</p><p> bne.s .checkMinuteOnly ; If rings > 0, branch to check minutes only</p><p></p><p> ; If rings equal 0, process ring counter flashing</p><p> btst #3,(Level_frame_counter+1).w ; Test frame counter bit for blink frequency</p><p> bne.s .checkMinuteWithRing ; If bit is set, hide ring text (skip frame increment)</p><p> addq.w #1,d1 ; Set mapping frame to flash rings index</p><p></p><p>.checkMinuteWithRing:</p><p> cmpi.b #9,(Timer_minute).w ; Has the game timer reached 9 minutes?</p><p> bne.s .calculateScroll ; If not, branch directly to scrolling calculation</p><p> addq.w #2,d1 ; Set mapping frame to double flash (Time + Rings)</p><p> bra.s .calculateScroll</p><p></p><p>.checkMinuteOnly:</p><p> btst #3,(Level_frame_counter+1).w ; Test frame counter bit for time flashing</p><p> bne.s .calculateScroll ; If bit is set, skip flashing adjustment</p><p> cmpi.b #9,(Timer_minute).w ; Has the game timer reached 9 minutes?</p><p> bne.s .calculateScroll ; If not, branch directly to scrolling calculation</p><p> addq.w #2,d1 ; Set mapping frame to flash time only</p><p></p><p>; ===========================================================================</p><p>.calculateScroll:</p><p> ; --- DYNAMIC SLOW SCROLLING LOGIC (3 PIXELS PER FRAME) ---</p><p> move.w (Level_frame_counter).w,d3 ; Read global level frame counter (starts at 0)</p><p> mulu.w #3,d3 ; Multiply frame count by 3 for a steady scroll rate</p><p></p><p> ; --- TOTAL SLIDING TRAVEL DISTANCE ---</p><p> cmpi.w #112,d3 ; Has the scroll distance hit or exceeded 112 pixels?</p><p> blt.s .applyOffset ; If less than 112, continue tracking movement</p><p> cmpi.w #114,d3 ; Is this the very first frame it reached the end?</p><p> bgt .lockValue </p><p> </p><p>.lockValue:</p><p> moveq #112,d3 ; Clamp the scroll register permanently at 112</p><p></p><p>.applyOffset:</p><p> subi.w #112,d3 ; Convert the climbing frame scale into negative entry displacement</p><p></p><p> ; --- X/Y COORDINATE CONFIGURATION ---</p><p> addi.w #spriteScreenPositionX(16),d3 ; Apply base X-macro position (compensated for extended scroll)</p><p> move.w #spriteScreenPositionYCentered(24),d2 ; Apply centered Y-axis row position</p><p></p><p> ; --- SPRITE RENDER ENGINE ---</p><p> lea (HUD_MapUnc_40A9A).l,a1</p><p> movea.w #make_art_tile(ArtTile_ArtNem_HUD,0,1),a3</p><p> </p><p> add.w d1,d1 ; Multiply frame layout index by 2 (Word sizing)</p><p> adda.w (a1,d1.w),a1 ; Fetch chosen mapping vector depending on flash state</p><p> move.w (a1)+,d1 ; Read the direct sprite piece array count</p><p> subq.w #1,d1 ; Subtract 1 to accommodate the core internal DBF loop</p><p> bmi.s .exit ; If sprite list is empty, abort safely</p><p> jsrto JmpTo_DrawSprite_Loop ; Execute standard Sonic 2 VDP sprite compilation loop</p><p></p><p>.exit:</p><p> rts</p><p>; End of function BuildHUD[/CODE]</p><p>Done! Now your hack has a fellow HUD scrolling.</p><h3>(Optional) Once position is reached to play sound effect</h3><p>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</p><p>[CODE] bgt .lockValue [/CODE]</p><p>and below it. Insert this</p><p>[CODE] move.w #SndID_TallyEnd,d0 ; Load the sound ID</p><p> jsr (PlaySound).l ; Play the sound effect exactly once[/CODE]</p><p><strong>Note:</strong> 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.</p><p></p><p>Good luck with your hack having a sound effect once the HUD scrolling is finished, I hope you enjoy this tutorial.</p></blockquote><p></p>
[QUOTE="Mildanner, post: 6615, member: 7577"] [I][B]Original guide by[/B] [B][COLOR=rgb(44, 130, 201)]Mildanner[/COLOR][/B][/I] 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 [B]; End of function BuildHUD[/B] 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[/CODE] Done! Now your hack has a fellow HUD scrolling. [HEADING=2](Optional) Once position is reached to play sound effect[/HEADING] 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 [/CODE] and below it. Insert this [CODE] move.w #SndID_TallyEnd,d0 ; Load the sound ID jsr (PlaySound).l ; Play the sound effect exactly once[/CODE] [B]Note:[/B] 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. [/QUOTE]
Insert quotes…
Verification
Post reply
Community
Tutorials & Guides
[Tutorial] How to create a Simple Scrolling HUD in Sonic 2
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.
Accept
Learn more…
Back
Top