A Selection Menu on the Start Screen [4.1.X Basic module]

dale_coop

Moderator
Staff member
I will share here how I made a small selection menu, on the Start Screen.
For this demo, I will just make a "NORMAL" or "HARD" selection mode. Use a sprite to display the selection. This menu will allow you to start the game with 3 lives (normal mode) or 1 life only (hard mode).

SelectionMenu.gif


When you'll understand how it works, you can add your own thing (add more health, start on different screens, ... etc).


How to do...

0/ Prepare your Start Screen, drawing some choices to select.

2019-05-16-00-36-18.png

Here, I wrote two items for my selection menu: "NORMAL" and "HARD".

1/ In "Project Settings > User Variables", we will add new ones used for the selection script:
"curSelection" with an initial value of "0" (this variable will be the value of the selection:"0" for the first item selected, "1" if the second item is selected, ...)

2/ In "Project Settings > User Constants", we will add new ones used for the selection script:
"STARTSCREEN_CURSOR_TILE" with a value of "127" (in fact, the tile index --from your gameObjectTiles-- you want to use as the selector).
"SELECTION_POS_X"with a value of "98" (for the horizontal position of the first item, in pixels)
"SELECTION_POS_Y" with a value of "150" (for the vertical position of the first item, in pixels)
"SELECTION_STEP_X" with a value of "0" (the horizontal distance between items, in pixels)
"SELECTION_STEP_Y" with a value of "16" (the vertical distance between items, in pixels)
"SELECTION_MAX_VALUE" with a value of "1" (the max value for the "curSelection" variable. Starting from "0" if only one item/choice... if "1" it means you want to have 2 items on your screen. "2" means you want to have 3 items, ...).

As you can guess here, you would have to adapt some of those constants values to your start screen layout (positions and maybe distance between items) or maybe the number of items you want.


3/ Now, modify the "PreDraw" script (assigned to the "Handle Sprite Pre-Draw" element in the "Project Settings > Script Settings"), around line 51 (after all the sprite 0 drawing), add those lines:

Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
checkStartScreenSelector:
	LDA update_screen_details
	BNE endCheckingStartScreenSelector 
	;; is special screen:
	LDA newScreen
	CMP #$01
	BEQ endCheckingStartScreenSelector
	;; is START SCREEN:

	;; positions selection: 
	LDA #SELECTION_POS_Y  	;; coord Y position when selection mode is 0
	STA temp1
	LDA #SELECTION_POS_X
	STA temp2  				;; coord X position of all selections

	LDX #$00
startScreenSelectorLoop:
	CPX curSelection
	BCS +
	LDA temp1
	CLC
	ADC #SELECTION_STEP_Y
	STA temp1
	LDA temp2
	CLC
	ADC #SELECTION_STEP_X
	STA temp2
	INX
	JMP startScreenSelectorLoop
+
	DrawSprite temp2, temp1, #STARTSCREEN_CURSOR_TILE, #%00000000, #$00	
	UpdateSpritePointer
	;JMP endCheckingStartScreenSelector
	
endCheckingStartScreenSelector:
This script will draw the selector sprite on the start screen.


4/ Make a new script "SelectionStartScreen.asm" in your "GameEngineData\Routines\Basic\ModuleScripts\InputScripts" folder, with this code:

Code:
checkSelection:
	TXA
	STA tempx
	LDA gamepad
	AND #%00110100
	BNE continueCheckingSelection
	JMP endCheckingSelection

continueCheckingSelection:
	LDA gamepad
	AND #%00010000
	BNE selectionUp
	LDA gamepad
	AND #%00100000
	BNE selectionDown
	LDA gamepad
	AND #%00000100
	BNE selectionSelect
	JMP endCheckingSelection

selectionUp:
	LDA curSelection
	BNE + 
	LDA #SELECTION_MAX_VALUE	;; <-- the max value of curSelection
	STA curSelection
	JMP ++
	+
	DEC curSelection
	++
	JMP endCheckingSelection
	
selectionDown:
	LDA curSelection
	CMP #SELECTION_MAX_VALUE	;; <-- the max value of curSelection
	BNE + 
	LDA #$00
	STA curSelection
	JMP ++
	+
	INC curSelection
	++
	JMP endCheckingSelection
	
selectionSelect:
	JMP selectionDown

endCheckingSelection:
	LDX tempx
	RTS
This script will change the value of the "curSelection" variable, when you press a button (but need to assign it, to inputs, first).


5/ Add the "SelectionStartMenu.asm" script in your project, under "Scripts >Input Scripts". And assign the script to a press button, for the Start Screen:

2019-05-16-00-22-56-NES-MAKER-4-1-5-Version-0x159-Basic-Platformer-MST.png

I'd suggest "PRESS" on the SELECT button.


6/ Lastly, modify the "StartGame.asm" script (located in your "GameEngineData\Routines\Basic\ModuleScripts\InputScripts" folder), at the beginning (1st line), adding this code:

Code:
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; SELECTION  MODE : 
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;; curSelection is 0 (normal) or curSelection is 1 (hard):
	LDA curSelection
	CMP #$01
	BNE +
	;; Start in HARD mode:
	LDA #$01
	STA myLives
	JMP ++
	+
	;; ELSE:
	;; Start in NORMAL mode :
	;LDA #$03		;; commented out, here, in order to use the value specified in the NESMaker tool itself
	;STA myLives	;; commented out, here, in order to use the value specified in the NESMaker tool itself
	++
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Here if curSelection value is "1" (it means the second item was selected) then I modify the lives value to "1" before the game starts. Else it will remains to "3" (I commented out those lines to keep the values set by default by the NESmaker tool).
Don't forget to assign the GameStart script to your press start button, if not already did.

VoilĂ , this should work as shown in the gif.



Notes: if you want to add more choices... just modify the constant "SELECTION_MAX_VALUE" and modify the "StartGame.asm" to do more actions depending of the value of the curSelection variable.
 

dale_coop

Moderator
Staff member
Yes I think it could be doable...
Modifying the "StartGame.asm" script (this script is "what I do when I start my game" after having press on the START button... so as I modified it already, it checks the value of the "curSelection" variable to do different things), so in HARD mode you could also maybe force a JUMP to a specific screen (instead of letting the game start to the overworld defined "starting screen").
 

dale_coop

Moderator
Staff member
For example, in the "StartGame.asm" script, just before the "JMP ++" line, add this portion of code to WARP to a specific screen instead of the normal starting screen:

Code:
    ;; WARP to the HARD_START_LEVEL screen (in overworld) 
    LDA #$00
    STA newGameState
    STA change_state

    GoToScreen #HARD_START_LEVEL, #$01, #$02

    JSR DeactivateAllObjects  
    LDA #$01
    STA loadObjectFlag    
    ;; from here the rest of the code:
    
    JMP ++

Add a new user constant named "HARD_START_LEVEL" with the screen index you want to start for your hard mode.
(Note: don't forget to set the Warp in X,Y coords in your screen.)
 

crazygrouptrio

Active member
dale_coop said:
For example, in the "StartGame.asm" script, just before the "JMP ++" line, add this portion of code to WARP to a specific screen instead of the normal starting screen:

Code:
    ;; WARP to the HARD_START_LEVEL screen (in overworld) 
    LDA #$00
    STA newGameState
    STA change_state

    GoToScreen #HARD_START_LEVEL, #$01, #$02

    JSR DeactivateAllObjects  
    LDA #$01
    STA loadObjectFlag    
    ;; from here the rest of the code:
    
    JMP ++

Add a new user constant named "HARD_START_LEVEL" with the screen index you want to start for your hard mode.
(Note: don't forget to set the Warp in X,Y coords in your screen.)

I got a chance to try this and it didn't work... Selecting hard mode doesn't warp to the other screen, and it makes a second player object. :?
 

dale_coop

Moderator
Staff member
A second player...? cool ;)
Could you share your StartGame script. I will try to fix that.

And, btw, which module are you using?
 

crazygrouptrio

Active member
Sure, haven't done anything with the start script except add in your code. Using the Simple Platformer Module.
Code:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; SELECTION  MODE : 
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; curSelection is 0 (normal) or curSelection is 1 (hard):
    LDA curSelection
    CMP #$01
    BNE +
    ;; Start in HARD mode:
    ;LDA #$01
    ;STA myLives
        ;; WARP to the HARD_START_LEVEL screen (in overworld) 
    LDA #$00
    STA newGameState
    STA change_state

    GoToScreen #HARD_START_LEVEL, #$01, #$02

    JSR DeactivateAllObjects  
    LDA #$01
    STA loadObjectFlag    
    ;; from here the rest of the code:
    
    JMP ++
    +
    ;; ELSE:
    ;; Start in NORMAL mode :
    ;LDA #$03       ;; commented out, here, in order to use the value specified in the NESMaker tool itself
    ;STA myLives    ;; commented out, here, in order to use the value specified in the NESMaker tool itself
    ++
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LDA #STATE_START_GAME
  STA change_state
  
  ;StopSound
  ;PlaySound #$00, $00

  LDA #%10000000
  STA gameHandler ;; turn sprites on
  RTS
 

dale_coop

Moderator
Staff member
Ok, I see... try this one:

Code:
  LDA #STATE_START_GAME
  STA change_state

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; SELECTION  MODE : 
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; curSelection is 0 (normal) or curSelection is 1 (hard):
    LDA curSelection
    CMP #$01
    BNE +
    ;; Start in HARD mode:
    ;LDA #$01
    ;STA myLives
        ;; WARP to the HARD_START_LEVEL screen (in overworld) 
    LDA #$00
    STA newGameState
    STA change_state

    GoToScreen #HARD_START_LEVEL, #$01, #$02

    JSR DeactivateAllObjects  
    LDA #$01
    STA loadObjectFlag    
    ;; from here the rest of the code:
    
    JMP ++
    +
    ;; ELSE:
    ;; Start in NORMAL mode :
    ;LDA #$03       ;; commented out, here, in order to use the value specified in the NESMaker tool itself
    ;STA myLives    ;; commented out, here, in order to use the value specified in the NESMaker tool itself
    ++
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
  ;StopSound
  ;PlaySound #$00, $00

  LDA #%10000000
  STA gameHandler ;; turn sprites on
  RTS
 

Jonny

Well-known member
Any chance on a 4.5 verison of this code?
I'm getting somewhere with converting Dales code above. This is where I'm at so far...

- Steps 0 to 2 are the same (although, I didn't bother with STARTSCREEN_CURSOR_TILE as a user constant, thats upto you.)

3/ I add the code to doSpritePreDraw.asm but made these small changes...

Code:
;;; BEFORE ;;;

checkStartScreenSelector:
    LDA update_screen_details
    BNE endCheckingStartScreenSelector
    ;; is special screen:
    LDA newScreen
    CMP #$01
    BEQ endCheckingStartScreenSelector
    
;;; AFTER ;;;

checkStartScreenSelector:
;;    LDA update_screen_details                     ;;; NOT SURE ABOUT THIS YET   ;;;
;;    BNE endCheckingStartScreenSelector    ;;; DONT KNOW WHAT IT DOES ;;;
    ;; is special screen:
    LDA gameState                                        ;;; CHECK GAME STATE 4.5.6       ;;;
    CMP #GS_StartScreen
    BEQ endCheckingStartScreenSelector

I also commented out " UpdateSpritePointer " because I haven't been able to figure out what it does or the equivenent routine in 4.5.6

4/ Same.

5/ Same.

6/ Same apart from my input script was called startGameWithContinuePoints.asm

This is as far as I've got. The cursor tile toggles with the select button and the game starts. Not fully tested.
 

dale_coop

Moderator
Staff member
Yeah, you don't need the "UpdateSpritePointer" in the 4.5.X version, because it's already integrated in the DrawSprite macro.
 

Jonny

Well-known member
Yeah, you don't need the "UpdateSpritePointer" in the 4.5.X version, because it's already integrated in the DrawSprite macro.
Thanks for clarifying, I thought maybe that was the case but wasn't sure.
I've edited your script a bit further. I put in an extra JMP as I wanted to do some more graphics stuff with the menu. I'll post the finished result in my game topic when it's done. Working on passcodes next. Real game saving is too far past my skill set to even attempt.
 

vanderblade

Active member
Thanks for clarifying, I thought maybe that was the case but wasn't sure.
I've edited your script a bit further. I put in an extra JMP as I wanted to do some more graphics stuff with the menu. I'll post the finished result in my game topic when it's done. Working on passcodes next. Real game saving is too far past my skill set to even attempt.
Did you ever get this fully implemented and working, Jonny? If so, can you share?
 
Top Bottom