How to have more than 4 monsters

I am working on a vertical shooter, and there’s only so many combinations of 4 enemies I can do before it starts to get old. I see similar games like Galaga have way more than 4 enemies at a time, and it also somehow bypasses the no more than 8 in a row rule. How can a game like Galaga exist on a console with such heavy restrictions? There’s also the fact that there can be tons of projectiles on screen without noticeable slowdown. Whereas in my game even 3 projectiles at a time causes massive dips. How did they do it?
 

smilehero65

Active member
I am working on a vertical shooter, and there’s only so many combinations of 4 enemies I can do before it starts to get old. I see similar games like Galaga have way more than 4 enemies at a time, and it also somehow bypasses the no more than 8 in a row rule. How can a game like Galaga exist on a console with such heavy restrictions? There’s also the fact that there can be tons of projectiles on screen without noticeable slowdown. Whereas in my game even 3 projectiles at a time causes massive dips. How did they do it?
More than 4 monsters could be achieved through NESMaker by making tiles (which can be placed in any amount) that generate these monsters.
These tiles can at the same time be static enemies in the game.

On the topic of Slowdown:
  • The number of projectiles on screen must be limited (e.g think of Super Mario can only shoot by having two fireballs on the screen)
  • NESMaker has a very big issue that eats a great part of the CPU: THE ANIMATION/DRAWING SPRITES SYSTEM.
    • EASY EXPLANATION: Since the engine must be easily customizable, it does a lot of checks per frame with all objects. However, this can be easily fixed if we replace the animation system and make our own, where we can draw only the objects we want. The big problem with this is that this is very advanced stuff, and would make your action steps animations useless.
 

smilehero65

Active member
Actually, Joe does this Custom Animation System in the advanced tutorial and really impacts the performance of the game.
Especially because the graphics are just ONE or TWO FRAMEs (that's why animation in those types of games was also limited)
 
More than 4 monsters could be achieved through NESMaker by making tiles (which can be placed in any amount) that generate these monsters.
These tiles can at the same time be static enemies in the game.

On the topic of Slowdown:
  • The number of projectiles on screen must be limited (e.g think of Super Mario can only shoot by having two fireballs on the screen)
  • NESMaker has a very big issue that eats a great part of the CPU: THE ANIMATION/DRAWING SPRITES SYSTEM.
    • EASY EXPLANATION: Since the engine must be easily customizable, it does a lot of checks per frame with all objects. However, this can be easily fixed if we replace the animation system and make our own, where we can draw only the objects we want. The big problem with this is that this is very advanced stuff, and would make your action steps animations useless.
Actually, Joe does this Custom Animation System in the advanced tutorial and really impacts the performance of the game.
Especially because the graphics are just ONE or TWO FRAMEs (that's why animation in those types of games was also limited)
I think I’m starting to get it. So a big problem is the animations, then? But even when I get rid of the animations, slowdowns are still apparent. And a game like, again, Galaga, uses way more projectiles at a time than I do, and it still doesn’t slow down. Does all movement count when you say “animation?”
 

smilehero65

Active member
I think I’m starting to get it. So a big problem is the animations, then? But even when I get rid of the animations, slowdowns are still apparent. And a game like, again, Galaga, uses way more projectiles at a time than I do, and it still doesn’t slow down. Does all movement count when you say “animation?”
For NESMaker, yes.
To fix it is not just making your objects be one frame...you must delete the default draw sprites routine. At first, the effect of this will be that your objects will still be present, but they will be invisible.

Then, in that empty script you will manually draw your player, you will manually draw your enemies, projectiles, everything.
Don't try to edit your animations in the program, it will ignore it.
You will have to do it manually.

This would be an example of the piece of code that draw a 16 x 16 monster.

Code:
DrawSprite tempA, tempB, #$81, #%00000000
DrawSprite temp1, tempB, #$82, #%00000000
DrawSprite temp1, temp2, #$92, #%00000000
DrawSprite tempA, temp2, #$91, #%00000000

For a shooter game this method would be very easy, as most of them are just one or two frames of animations.
 
For NESMaker, yes.
To fix it is not just making your objects be one frame...you must delete the default draw sprites routine. At first, the effect of this will be that your objects will still be present, but they will be invisible.

Then, in that empty script you will manually draw your player, you will manually draw your enemies, projectiles, everything.
Don't try to edit your animations in the program, it will ignore it.
You will have to do it manually.

This would be an example of the piece of code that draw a 16 x 16 monster.

Code:
DrawSprite tempA, tempB, #$81, #%00000000
DrawSprite temp1, tempB, #$82, #%00000000
DrawSprite temp1, temp2, #$92, #%00000000
DrawSprite tempA, temp2, #$91, #%00000000

For a shooter game this method would be very easy, as most of them are just one or two frames of animations.
And which advanced tutorial did Joe do this in? To my understanding each module has its own advanced tutorial. Was it the Shooter one?
 

smilehero65

Active member
FUN FACT:

1708569341312.png
This is an example of how Super Mario Bros handles enemies' graphics.
Each value (like $aa, $ab, $ac) is the coordinates of the graphic in the CHR table. The game is just assign it to the object.

(NESMaker's method is not necessarily like this one)
 

smilehero65

Active member
Alright, thanks. Guess I’ll start on this series and finally figure out how assembly actually works. Hopefully I can finally start making real progress (I haven’t really managed to do anything other than make an enemy move and get projectiles to fire up since yesterday lol)
lol Good luck! (y)
Just gonna say it is not easy, but becoming an expert on this can be achievable.
 
So after following the tutorial for a bit I all of a sudden ran into this. I was following the tutorial word for word. Not really sure what happened. There is a lot more if I scroll up, but it all boils down to "can't determine address." I did change the monster hurt and player hurt scripts to the Shooter ones in the script settings, but I don't see how that would cause this kind of error. Even after I changed them back, the error persists, so I don't think that would be the issue.Screenshot 2024-02-22 104457.png
 

smilehero65

Active member
So after following the tutorial for a bit I all of a sudden ran into this. I was following the tutorial word for word. Not really sure what happened. There is a lot more if I scroll up, but it all boils down to "can't determine address." I did change the monster hurt and player hurt scripts to the Shooter ones in the script settings, but I don't see how that would cause this kind of error. Even after I changed them back, the error persists, so I don't think that would be the issue.View attachment 7943
Wow...now this is big stuff...
I'm not really sure what's going on 😵

Maybe starting with the advanced part was not the best.
Specially when it is a modified project where you had all your custom scripts, and not one created from zero.
 
I went back and did more digging. Apparently when I swapped the hurt scripts back I swapped them to the wrong thing. For some reason, using any hurt scripts other than the Adventure module ones causes this error. Which kinda sucks, because I don't think the Adventure scripts use lives. I think I should clarify, I actually began this project on the Adventure module, because at the time I didn't plan on making it into a shooter. It hasn't been an issue until now. I was able to use other modules scripts for other things, like using a Platformer module to make my enemies move left and right, so I'm not sure why changing the hurt modules specifically is what caused the error.
 

smilehero65

Active member
I went back and did more digging. Apparently when I swapped the hurt scripts back I swapped them to the wrong thing. For some reason, using any hurt scripts other than the Adventure module ones causes this error. Which kinda sucks, because I don't think the Adventure scripts use lives. I think I should clarify, I actually began this project on the Adventure module, because at the time I didn't plan on making it into a shooter. It hasn't been an issue until now. I was able to use other modules scripts for other things, like using a Platformer module to make my enemies move left and right, so I'm not sure why changing the hurt modules specifically is what caused the error.
Ah! OK then.
Yeah, the adventure module don't use lives, it instead uses health.

However with a few tweaks (like adding a new user variable) you can get your lives system to be working.
 
Alright, thanks. Guess I’ll start on this series and finally figure out how assembly actually works. Hopefully I can finally start making real progress (I haven’t really managed to do anything other than make an enemy move and get projectiles to fire up since yesterday lol)
I almost completely got it to work, and yeah, it's definitely running faster. Only thing I'm missing is getting the projectiles to flash between colors. But there's a problem. Completely unrelated to NESMaker itself, but I stepped away from my computer for a while and it went to sleep. When I woke it up, the video page was blank. If I reload the page, exit the page and try to open it again from the NESMaker website, etc., it's still blank. even reset my computer. I kind of know what to do, but I ran into an error (branch out of reach), so I wish I could reference the video again to make sure I had the code right. Other than that, now I just need to figure out how to restrict the number of projectiles for smoother gameplay, and how to make spawners for the enemies (which should be easy enough, but I'd need to figure out the projectile limiting first to avoid spawning too many enemies).
 

Attachments

  • Screenshot 2024-02-22 172559.png
    Screenshot 2024-02-22 172559.png
    26.9 KB · Views: 2

smilehero65

Active member
I almost completely got it to work, and yeah, it's definitely running faster. Only thing I'm missing is getting the projectiles to flash between colors. But there's a problem. Completely unrelated to NESMaker itself, but I stepped away from my computer for a while and it went to sleep. When I woke it up, the video page was blank. If I reload the page, exit the page and try to open it again from the NESMaker website, etc., it's still blank. even reset my computer. I kind of know what to do, but I ran into an error (branch out of reach), so I wish I could reference the video again to make sure I had the code right. Other than that, now I just need to figure out how to restrict the number of projectiles for smoother gameplay, and how to make spawners for the enemies (which should be easy enough, but I'd need to figure out the projectile limiting first to avoid spawning too many enemies).
I think I can help.
Can you send me your code?
 
I think I can help.
Can you send me your code?
Code:
CMP #$03
    BEQ +isLaser
        JMP +isNotLaser
    +isLaser
    ;;; DRAW PROJECTILE
        DrawSprite tempA, tempB, #$01, #%00000000
            LDA tempA
            CLC
            ADC #$08
            STA temp1
        DrawSprite temp1, tempB, #$01, #%01000000
            LDA tempB
            CLC
            ADC #$08
            STA temp2
        DrawSprite tempA, temp2, #$01, #%10000000
        DrawSprite temp1, temp2, #$01, #%11000000
        JMP doneDrawingThisSprite
Here is the code just for the player projectile. I removed the flicker animation code so I could continue testing things before the tutorial bugged out so I forgot exactly what it would look like. I know it would go between +isLaser and ;;; DRAW PROJECTILE, and it uses a timer to detect the frame. I don't remember what the exact command for the timer is though. Something I'm doing different from Joe, though, is that while Joe had a different sprite for the projectile, I just want to use a different sub palette, sub palette 4, which if I remember right would be 11 in binary, though it could also be 01, not sure which. There's also the fact that his projectile was 1x1, while mine is 2x2 (he said making all objects 2x2 rather than only some being 2x2 would further improve performance), but I'm not sure if that makes any difference. I'm using basically this same code for the enemy projectiles, since they use the same sprite.
 
I think I can help.
Can you send me your code?
NEVERMIND I FIGURED IT OUT

I remembered what the code in the tutorial was, and after adding it back in I still go the "branch out of range error." I think I figured out why. In his example it only had to skip one line of code, so BEQ +isEvenFrame had no problems. However, in my case there are much more lines to skip through, so I instead had to do BEQ +isOddFrame JMP +isEvenFrame. And now it works. Now I just need to figure out limiting the projectiles. This is my projectile code as it stands:
Code:
;;; Create a Projectile.
;;; Assumes that the projectile you want to create is in GameObject Slot 01.

TXA
PHA
TYA
PHA
LDX player1_object
LDA Object_x_hi,x ; get player x coord
STA tempA
LDA Object_y_hi,x; get player y coord
STA tempB

LDA Object_screen,x
STA tempC

CreateObjectOnScreen tempA, tempB, #$03, #$00, tempC
;;; x, y, object, starting action.
;;; and now with that object, copy the player's
;;; direction and start it moving that way.

PLA
TAY
PLA
TAX

RTS
This is the input code, which I believe you're actually the one who gave it to me. I assume this is the script I need to edit, but I'm not really sure what to do. I imagine I need some way to count the number of this same object on the screen, right? But I'm unsure on specifically how to do that. I saw a code posted in another thread, but it didn't seem applicable to me, and when I tried to use it the game wouldn't launch. The code in question:
Code:
canShoot:
   ;; We count the projectile already on screen to see if can Shoot another one :
   CountObjects #%00000100, #$00   ;; count player weapon on screen
   LDA monsterCounter              ;; the variable used to count is monsterCounter
   CLC
   CMP #PROJECTILE_MAX             ;; compare to 2
   BCC +                    ;; if less than 2 on screen we can create a projectile
   RTS                             ;; else we quit
+
He says to put this code under the part of the script that says "canShoot," but my script doesn't have that. If I try to add it, it says "Already defined(8)," line 8, being where "canShoot" is inserted. If I insert the code without "canShoot," however, it just doesn't limit the projectiles. Just wastes lines. I need to find a way to get this code to work for my script.
 

smilehero65

Active member
NEVERMIND I FIGURED IT OUT

I remembered what the code in the tutorial was, and after adding it back in I still go the "branch out of range error." I think I figured out why. In his example it only had to skip one line of code, so BEQ +isEvenFrame had no problems. However, in my case there are much more lines to skip through, so I instead had to do BEQ +isOddFrame JMP +isEvenFrame. And now it works. Now I just need to figure out limiting the projectiles. This is my projectile code as it stands:
Code:
;;; Create a Projectile.
;;; Assumes that the projectile you want to create is in GameObject Slot 01.

TXA
PHA
TYA
PHA
LDX player1_object
LDA Object_x_hi,x ; get player x coord
STA tempA
LDA Object_y_hi,x; get player y coord
STA tempB

LDA Object_screen,x
STA tempC

CreateObjectOnScreen tempA, tempB, #$03, #$00, tempC
;;; x, y, object, starting action.
;;; and now with that object, copy the player's
;;; direction and start it moving that way.

PLA
TAY
PLA
TAX

RTS
This is the input code, which I believe you're actually the one who gave it to me. I assume this is the script I need to edit, but I'm not really sure what to do. I imagine I need some way to count the number of this same object on the screen, right? But I'm unsure on specifically how to do that. I saw a code posted in another thread, but it didn't seem applicable to me, and when I tried to use it the game wouldn't launch. The code in question:
Code:
canShoot:
   ;; We count the projectile already on screen to see if can Shoot another one :
   CountObjects #%00000100, #$00   ;; count player weapon on screen
   LDA monsterCounter              ;; the variable used to count is monsterCounter
   CLC
   CMP #PROJECTILE_MAX             ;; compare to 2
   BCC +                    ;; if less than 2 on screen we can create a projectile
   RTS                             ;; else we quit
+
He says to put this code under the part of the script that says "canShoot," but my script doesn't have that. If I try to add it, it says "Already defined(8)," line 8, being where "canShoot" is inserted. If I insert the code without "canShoot," however, it just doesn't limit the projectiles. Just wastes lines. I need to find a way to get this code to work for my script.
Good! Really glad you're getting a grasp of how ASM works!

(sorry if didn't answer, I was really busy)
 
NEVERMIND I FIGURED IT OUT

I remembered what the code in the tutorial was, and after adding it back in I still go the "branch out of range error." I think I figured out why. In his example it only had to skip one line of code, so BEQ +isEvenFrame had no problems. However, in my case there are much more lines to skip through, so I instead had to do BEQ +isOddFrame JMP +isEvenFrame. And now it works. Now I just need to figure out limiting the projectiles. This is my projectile code as it stands:
Code:
;;; Create a Projectile.
;;; Assumes that the projectile you want to create is in GameObject Slot 01.

TXA
PHA
TYA
PHA
LDX player1_object
LDA Object_x_hi,x ; get player x coord
STA tempA
LDA Object_y_hi,x; get player y coord
STA tempB

LDA Object_screen,x
STA tempC

CreateObjectOnScreen tempA, tempB, #$03, #$00, tempC
;;; x, y, object, starting action.
;;; and now with that object, copy the player's
;;; direction and start it moving that way.

PLA
TAY
PLA
TAX

RTS
This is the input code, which I believe you're actually the one who gave it to me. I assume this is the script I need to edit, but I'm not really sure what to do. I imagine I need some way to count the number of this same object on the screen, right? But I'm unsure on specifically how to do that. I saw a code posted in another thread, but it didn't seem applicable to me, and when I tried to use it the game wouldn't launch. The code in question:
Code:
canShoot:
   ;; We count the projectile already on screen to see if can Shoot another one :
   CountObjects #%00000100, #$00   ;; count player weapon on screen
   LDA monsterCounter              ;; the variable used to count is monsterCounter
   CLC
   CMP #PROJECTILE_MAX             ;; compare to 2
   BCC +                    ;; if less than 2 on screen we can create a projectile
   RTS                             ;; else we quit
+
He says to put this code under the part of the script that says "canShoot," but my script doesn't have that. If I try to add it, it says "Already defined(8)," line 8, being where "canShoot" is inserted. If I insert the code without "canShoot," however, it just doesn't limit the projectiles. Just wastes lines. I need to find a way to get this code to work for my script.
I LIMITED THE PROJECTILES

Just had to cut out LDA monsterCounter and CLC and now it's working great. But now I need to figure out how to make it count monster weapons, rather than player weapons. I assume it's related to the binary at the start of the code, but I don't really know what it means.

Now I just have to figure out how to make projectiles destroy each other on contact, as well as destroying themselves upon destroying enemies. Then I gotta fix a bug where destroyed enemies randomly turn into static player ships, and I'll finally have a functioning game!
 
Top Bottom