My game is a top-down shooter, but how do I make player shoot?

Goaterby

Member
There was a good topic on it here:

http://nesmakers.com/viewtopic.php?f=3&t=290

Having tried to do something similar, it became apparent that, unless I am mistaken and someone would care to list the directory, there is no simple projectile script in the 4.0.0 release anymore. So you have to make your own simple projectile script using the code provided in the above link like so:

Notice that I commented out the changes the user made, so that it doesn't rely upon their ammo variable they added. If you want to use an ammo system, you can simply use the scripts from the other topic, but this one will get you going out of the box without any other changes.

Code:
CreateSimpleProjectileWithMotion:
    LDY player1_object
    CPY #$FF ;; if the player object is set to ff, he's dead.
    ;BNE playerCanCreateProjectile
    ;RTS
 ;playerCanCreateProjectile:
	;LDA GLOBAL_Player1_Ammo
	;BNE continueCreateProjectile
	;RTS
;continueCreateProjectile:
    ;; get offset
    ;; in a later version, we will use user defined offsets.
    ;; for now, we'll place projectile creation at center of object
    LDA Object_movement,y
    AND #%00000111
    TAX
    LDA weaponOffsetTableX,x
    ;;; now we have the offset
     CLC
     ADC Object_x_hi,y
    STA temp1
    LDA weaponOffsetTableY,x
    CLC
    ADC Object_y_hi,y
    STA temp2
    CreateObject temp1, temp2, #$01, #$00  ;;testVar
    LDA Object_movement,y
    AND #%00000111
    STA temp
    TAY
    LDA DirectionMovementTable,y
    ORA temp
    
    STA Object_movement,x
    
    ;; add object size offset.
    LDA Object_x_hi,x
    SEC
    SBC #$08 ;; half of the width of the intended projectile
    STA Object_x_hi,x
    LDA Object_y_hi,x
    SEC
    SBC #$08 ;; half of the height of the intended projectile
    STA Object_y_hi,x
    
    ;PlaySound #$00, #$00
    ;JMP decreasePlayerAmmo
    RTS

It should work normally if you make a projectile object, set it as a player weapon, give it a sprite, and set a button press (or hold, release whatever) to run this script during the main gameplay with a NULL target. Let us know how it goes!
 

dale_coop

Moderator
Staff member
The original code (from the beta):
Code:
CreateSimpleProjectileWithMotion:
    
    LDY player1_object
    CPY #$FF ;; if the player object is set to ff, he's dead.
    BNE playerCanCreateProjectile
    RTS
 playerCanCreateProjectile:
    ;; get offset
    ;; in a later version, we will use user defined offsets.
    ;; for now, we'll place projectile creation at center of object
    LDA Object_movement,y
    AND #%00000111
    TAX
    LDA weaponOffsetTableX,x
    ;;; now we have the offset
     CLC
     ADC Object_x_hi,y
    STA temp1
    LDA weaponOffsetTableY,x
    CLC
    ADC Object_y_hi,y
    STA temp2
    CreateObject temp1, temp2, #$01, #$00
    LDA Object_movement,y
    AND #%00000111
    STA temp
    TAY
    LDA DirectionMovementTable,y
    ORA temp
    
    STA Object_movement,x
    
    ;; add object size offset.
    LDA Object_x_hi,x
    SEC
    SBC #$08 ;; half of the width of the intended projectile
    STA Object_x_hi,x
    LDA Object_y_hi,x
    SEC
    SBC #$08 ;; half of the height of the intended projectile
    STA Object_y_hi,x
    
;;    PlaySound #$00, #$00
    RTS
 

dale_coop

Moderator
Staff member
Set your "Melee" game object (make it like a bullet for example, set the bounding box, the speed and acceleration) and that it.
Then, if you assign this script to Press B, you will be able to shoot.
 

darkhog

New member
Thanks, but as I've mentioned I want it to only start working once player will pick up a gun in one of the rooms.
 

dale_coop

Moderator
Staff member
I know you want.
But fist, you need to go by steps... first, make the script work (when you press A, it shoots)
Then you can modify the script, to add some variable to be tested: if a certain variable is a certain value, then I can create the projectile, else I do nothing.
Finally you can make a script that set the value of that certain variable. And assign that script to the "Power up 1" for exemple (in script settings). Power Up 1 corresponds to the "Charge Pickup" in the game objects.
Et voilà :)

file.php


Note: if you saw my WIP "PressStart game", you will see I did it. And I shared the code... from the beta
 

darkhog

New member
Thanks. Since I won't need a full blown ammo system, do you know how to set/read relic flags? So I can make gun powerup trigger a relic 1 and then make shooting code checking for whether a relic flag is set or not.
Qisl0Xx.png
 

dale_coop

Moderator
Staff member
A lot of property you can see in the tool (NESMaker tool) is not yet implemented in the engine (ASM code).
I think relic and songs, boss, ... are not implemented yet.

I would suggest to use an HUD user variable. For exemple, rename UserVar_3 to "myWeapon", initialized to 0 (would mean no weapon).
So you could modify the ShootProjectile script like this:
Code:
CreateSimpleProjectileWithMotion:
    LDY player1_object
    CPY #$FF ;; if the player object is set to ff, he's dead.
    BNE playerCanCreateProjectile
    RTS
 playerCanCreateProjectile:
	LDA myWeapon  ;;load the variable weapon
	BNE continueCreateProjectile  ;;if NOT equal to zero, when can continue creating the projectile
	RTS  ;; else we stop
continueCreateProjectile:
    ;; get offset
    ;; in a later version, we will use user defined offsets.
    ;; for now, we'll place projectile creation at center of object
    LDA Object_movement,y
    AND #%00000111
    TAX
    LDA weaponOffsetTableX,x
    ;;; now we have the offset
     CLC
     ADC Object_x_hi,y
    STA temp1
    LDA weaponOffsetTableY,x
    CLC
    ADC Object_y_hi,y
    STA temp2
    CreateObject temp1, temp2, #$01, #$00  ;;testVar
    LDA Object_movement,y
    AND #%00000111
    STA temp
    TAY
    LDA DirectionMovementTable,y
    ORA temp
    
    STA Object_movement,x
    
    ;; add object size offset.
    LDA Object_x_hi,x
    SEC
    SBC #$08 ;; half of the width of the intended projectile
    STA Object_x_hi,x
    LDA Object_y_hi,x
    SEC
    SBC #$08 ;; half of the height of the intended projectile
    STA Object_y_hi,x
	    
    ;;PlaySound #$00, #$00
 
 	;;; we also need to set up the routine to update the HUD
	;; for this to work right, health must be a "blank-then-draw" type element.
	;;STA hudElementTilesToLoad
	;;	LDA #$00
	;;	STA hudElementTilesMax
	;;	LDA DrawHudBytes
	;;	ORA #HUD_ myWeapon
	;;	STA DrawHudBytes   
    RTS

And make a "PowerUpActivateWeapon" script:
Code:
;;; activateWeapon code for player.
;;; works with variable myWeapon
;;; works with HUD variable HUD_myWeapon
	TXA
	STA tempx
	;;;you may want to test against a MAX value.
	;;; this could be a static number in which case you could just check against that number
	;;; or it could be a variable you set up which may change as you go through the game.
	LDA #$01
	STA myWeapon
	
	;;; we also need to set up the routine to update the HUD
	;; for this to work right, health must be a "blank-then-draw" type element.
	;;STA hudElementTilesToLoad
	;;	LDA #$00
	;;	STA hudElementTilesMax
	;;	LDA DrawHudBytes
	;;	ORA #HUD_ myWeapon
	;;	STA DrawHudBytes
	
	LDX tempx
 

darkhog

New member
dale_coop said:
A lot of property you can see in the tool (NESMaker tool) is not yet implemented in the engine (ASM code).
I think relic and songs, boss, ... are not implemented yet.

Quoting your post so you get a notification. Do you know if there is a way to limit amount of shots player have at a single time (kinda like Mario can only shoot two fireballs) since I've come across the issue with the original script that makes it so you can fire too much and slow the game, then corrupt it (enemies/NPCs start using weird tiles and palettes and so on). Then I'll make it so you can only shoot after obtaining the gun in a way you have suggested.
 

dale_coop

Moderator
Staff member
Yes you right.
Already talk with Joe about that. I could use a variable to limit the number of projectiles .... or could use a timer Brtween to projectiles.

Didn’t try yet those solutions.
But it’s in my check list ;)
 

Melatonin

New member
Followed the steps above and am having a heck of a bug.

Once I import the CreateSimpleProjectile script into the project, it fires a projectile anytime any user input is detected on the controller, including D Pad inputs. This is puzzling as I haven't hooked the code up to anything in the input editor. If I hook up the CreateSimple script to a button, that button will fire the projectile as intended, but again so will the D-Pads.

Any ideas why this script linked above would be acting this way?
 

dale_coop

Moderator
Staff member
Because you need the fixed movement scripts (the ones that come with NESMaker have issues)
From here: http://nesmakers.com/viewtopic.php?f=19&t=390
 

darkhog

New member
Timer-based solution would be highly volatile and based on how fast bullets are moving and how far. I can see game becoming corrupted with slow enough bullets since you'd be able to make a somewhat high amount of bullets.
 

Melatonin

New member
dale_coop said:
Because you need the fixed movement scripts (the ones that come with NESMaker have issues)
From here: http://nesmakers.com/viewtopic.php?f=19&t=390

You're a legend, thank you!

For my own education, what in the old script was causing that to happen? There's not much in those scripts so my little asm knowledge isn't cutting it :)
 

darkhog

New member
Lack of RTS opcode (return from subroutine). It just kept executing whatever was after the actual code in the rom until it encountered actual rts or game data that may have had illegal opcodes and made game crash.
 

darkhog

New member
Okay, mostly done with the bullet limiting code, with one little problem: When bullets go into the enemy (they're set up as player weapon), the counter doesn't refill properly, the solid reaction of the bullet code seems to not be executed. Any idea how to fix that part? Otherwise it works fine.
 

dale_coop

Moderator
Staff member
In the HandleObjectCollision.asm, find the subroutine "skipHurtingMonster" and you write your code just after the ";; what should we do with the projectile?".
 

darkhog

New member
Thanks, got it now. Had other minor issue with the weapon pool not resetting on screen change, but I've been able to fix it myself.

There's still a slowdown issues when there are too many objects, but it's okay for now.
 

dale_coop

Moderator
Staff member
Great! Glad you found!
Could you share your code / scripts for other nesmakers who would to same? It would be very nice <3
 

darkhog

New member
Frankly, most of it is a hack. In some parts it looks nice, but most of it is really ugly. Here's the shooting script though, I'm sure that people will figure out the rest (all it really takes is to increment the counter in places where the bullet gets destroyed, in this script called weaponpool and reset it on screen change):

Code:
shootdathing:

    LDY player1_object
    CPY #$FF ;; if the player object is set to ff, he's dead.
    BNE playerCanCreateProjectile
    RTS
 playerCanCreateProjectile:
    lda guyweapon
    cmp #0
    bne continueshooting
    rts
    continueshooting:
    lda weaponpool
    cmp #0
    bne continueshootingmore
    rts
    continueshootingmore:
    ; removing bullet from the weaponpool
    ldx weaponpool
    dex
    stx weaponpool
    ;; get offset
    ;; in a later version, we will use user defined offsets.
    ;; for now, we'll place projectile creation at center of object

    LDA Object_movement,y
    AND #%00000111
    TAX
    LDA weaponOffsetTableX,x
    ;;; now we have the offset
     CLC
     ADC Object_x_hi,y
    STA temp1
    LDA weaponOffsetTableY,x
    CLC
    ADC Object_y_hi,y
    STA temp2
    CreateObject temp1, temp2, #$01, #$00
    LDA Object_movement,y
    AND #%00000111
    STA temp
    TAY
    LDA DirectionMovementTable,y
    ORA temp

    STA Object_movement,x

    ;; add object size offset.
    LDA Object_x_hi,x
    SEC
    SBC #$08 ;; half of the width of the intended projectile
    STA Object_x_hi,x
    LDA Object_y_hi,x
    SEC
    SBC #$08 ;; half of the height of the intended projectile
    STA Object_y_hi,x

;;    PlaySound #$00, #$00
    RTS

In my case weaponpool is set to 4 as while it still causes some slow down, it doesn't cause corruption at least, even with enemies shooting. Obviously feel free to experiment with it, but I wouldn't suggest setting it to or past 6 as it may cause corruption.

This code requires two custom variables - guyweapon and weaponpool. I suggest creating new file in GameEngineData/Routines/Variables and then including it in the same way UserVariables.asm is included in ZP_and_vars.asm, then making an initialization ASM in GameEngineData/Routines/InitializationScripts and including it in InitLoads.asm, right under the line where hudVarInits.asm is included (you can use UserVariables.asm and hudVarInits.asm as templates how to declare/init a variable if you don't know how)
 
Top Bottom