[4.5.X] Sine Wave Monster Movement (Using Lookup Table)

Jonny

Well-known member
I'm calling this sine wave movement but you could make modifications to manipulate the Y and/or X axis of your object however you want.
Disclaimer: This is NOT the best or most efficient way to do this. I'm not a programmer. It's just what I could come up with using the knowledge I currently have. If there are better ways please let me know. Also, this is more of a 'story so far' tutorial as I was hoping for a little help with a couple of things which I will mention at the end.

SINETHING.gif

The Actual Tutorial...

1. The monster action is a modification of the standard 'move left' script. First create a User Variable called starPos and start it at 255.​
2. Make a new monster AI action with the following code and assign it in your script settings to an available AI Behavior slot...​
Code:
;;; Y TABLE LOOP ;;;;;;;;;;;;;;;;;;;;;
    
    INC starPos
    LDY starPos
    CPY #24              ;;; STEPS ;;;
    BCC UpdateObjectPos
    LDY #0
    STY starPos
    
;;; UPDATE POSITION ;;;;;;;;;;;;;;;;;;
    
UpdateObjectPos:
    LDA Yobject,y
    STA Object_y_hi,x
    
;;; NORMAL MOVE LEFT STUFF ;;;;;;;;;;;
    
    TXA                                 
    STA tempA                           
    LDA #%00000110         
    TAY                                   
    LDA DirectionTableOrdered,y     
    STA tempB                         
    LDA FacingTableOrdered,y       
    STA tempC                         
    StartMoving tempA, tempB, #$00     
    ChangeFacingDirection tempA, tempC

3. Now we need a table. You have a few options for writing the values (where the object Y pos will be) either draw the sine wave by hand and work out the how many steps you want and and their positions, use excel or spreadsheet software to work out the places somehow, use this website I found or just be awesome at math. In this example we need the absolute values of where you want to object (i.e not based on where you actually placed the monster on the screen) more on that at the end.​
4. Open up your ExtraTables.asm script or make one and assign it to Game \ Extra Tables in Project Settings \ Script Settings. Add your table values like this...​
Code:
Yobject:
    .db 95,101,108,113,117,119,120,119,117,113,108,101,95,89,83,77,73,71,70,71,73,77,83,89

This is the full wave, the peak and trough in other words. It's the same example as the .gif If you have more steps in your table make sure you change the steps number in the loop ( CPY #24 )​
5. Lastly, setting up the monster. Give the object only 1 frame of animtion. The Y pos updates quickly because I'm not repeating the action but repeating when the animation ends. Repeating the action takes too long. This is one of the parts I need to figure out how to do better. The more animation frames you have the longer between steps. Basically, at the moment you can't animate the object AND move it in the sine wave. Improvements welcomed.​
So... settings should be... lowish speed (say 15 ish), EndAction - Loop, EndAnimation - Repeat, Animation Speed - 1, Ignore Gravity.​
That's it! Not very technical but it works.

A few things I'm working though now (any help appreciated)

Updating Object_y_hi somewhere else. The way things are set up at the moment, having the Y changes as part of the monster action means that I can't realistically have an animation which sucks. The changes become too slow. Try this out for yourself and you'll see what I mean. Atm I'm not sure how to go about that.

At the moment the position changes of the object are absolute values on the screen and not based on where the object is placed to start with on the Y axis. I want to change the Y value as increments starting with the position the object is in when loaded. I tried doing this but I must have been doing somehting wrong as it didn't work :(

I want to spawn the monster at the right cam edge, not sure if that's the correct term. Being a scrolling game I don't want to spawn at the screen edge on a timer as that wont make the object look like its constantly spawning from the right edge. How the gorilla guys spawn at the start of Ducktales is what I'm trying to do. I can do the timer but I don't know what to do to get the edge position as the screen is scrolling.

Thank you for any help in advance or improvements to the above. Enjoy.
 

Jonny

Well-known member
The numbers in the Yobject lookup table are absolute values for the monsters Y position. You could just add whatever you need to which will bring them down.

I'm working on code so the monster starts in the position it's placed in NM screens but having a bit of trouble because some values are less than the original Y position and some are more. I can't just add (ADC) values from the table because the movement is up and down. Almost got it by using conditionals for the amount of starPos steps but for some reason it always goes up more than down. I'll post better code once I've figured it out but for now you'll just need to change the Yobject table to get what you want.
 

9Panzer

Well-known member
Excellent work @Jonny ! I'm playing with what can be done with this!
I noticed if you have more then one object using the code it tends to get a choppy - could that be because they are referencing the same table?
 

Jonny

Well-known member
Excellent work @Jonny ! I'm playing with what can be done with this!
I noticed if you have more then one object using the code it tends to get a choppy - could that be because they are referencing the same table?
Maybe. Are you able to show what happens because I intend to come back to this and improve things eventually.
 
Last edited:

9Panzer

Well-known member
Oh I apologize @Jonny I didn't see you message sooner. Here is what I am talking about:

Single Monster using your code:

Multiple Monster using your code:

As you can see the single monster does a very smooth and clean Sine Wave. When there is another monster on the screen it appears that they maybe they are referencing the same table so they skip points, maybe?

Regardless this is incredible work! Thank you for sharing it!
 

Subotai

Active member
@Jonny : Do you have some improvement about it? I'm trying to do something similar as you said earlier : working on code so the monster starts in the position it's placed in NM screens but having a bit of trouble because some values are less than the original Y position and some are more.

I'm trying to use it with a player weapon instead, a magic spell.
The object appear on screen and make wave when attack button is pressed, but it is always start on the first value of the Table Yobject instead of the player location.

So I have tried to make some changes, At the creation of the object, my script store in a user variable(heroPos) the Y position of the player.
In the Extra table :
Yobject:
.db heroPos+8,heroPos+12, etc

But it doesn't work.
I'm not sure, but I think that user variable is not checked on the table.
Even if the player is at the top of the screen, or at the bottom, the object appear always at the same place.
 

Subotai

Active member
I found a solution to make it an attack for the player :
SinWaveAttack.gif

1. I've added a new UserVariable heroPos with a value of 0
2. In my shootprojectile_ammo.asm, I've replaced the tempB variable with heroPos
Code:
 LDX player1_object
        LDA Object_x_hi,x
            CLC
        ADC #$04
        STA tempA
        LDA Object_y_hi,x
            CLC
        ADC #$04
        STA heroPos
        LDA Object_direction,x
        AND #%00000111
        STA tempC
        CreateObject tempA, heroPos, #$0F, #$00
            ;;; x, y, object, starting action.
            ;;; and now with that object, copy the player's
            ;;; direction and start it moving that way.

3. In ExtraTable.asm, here's the position. It must start at 0 or nearby to have an effect that the player is shooting.
Code:
Yobject:
    .db 0,0,0,2,4,6,9,12,15,18,20,22,24,24,24,22,20,18,15,12,9,6,4,2

4. For the SinWave.asm that my magic object is using as a AI_behavior:
I've commented all the move left section, because direction is define on my attack script.
Instead of loading directly the table and store it into vertical value of the object :
LDA Yobject,y
STA Object_y_hi,x


Script load the heroPos and add to this position the value in the table:, and store:

Code:
;;; Y TABLE LOOP ;;;;;;;;;;;;;;;;;;;;;

    INC starPos
    LDY starPos
    CPY #24              ;;; STEPS ;;;
    BCC UpdateObjectPos
    LDY #0
    STY starPos
   
;;; UPDATE POSITION ;;;;;;;;;;;;;;;;;;
   
UpdateObjectPos:
     LDA heroPos
     ADC Yobject,y
     STA Object_y_hi,x
   
;;; NORMAL MOVE LEFT STUFF ;;;;;;;;;;;
   
    ; TXA                                
    ; STA tempA                          
    ; LDA #%00000110        
    ; TAY                                  
    ; LDA DirectionTableOrdered,y    
    ; STA tempB                        
    ; LDA FacingTableOrdered,y      
    ; STA tempC                        
    ; StartMoving tempA, tempB, #$00    
    ; ChangeFacingDirection tempA, tempC

It doesn't work with the normal variable of NesMaker tempB for the vertical value, that's why I've added a new one. (heroPos)
 
Eu encontrei uma solução para torná-lo um ataque para o jogador:
View attachment 5500

1. Adicionei um novo HeroPos UserVariable com um valor de 0
2. No meu shootprojectile_ammo.asm, substituí a variável tempB por heroPos
[CÓDIGO] LDX player1_object
Objeto LDA_x_hi,x
CLC
ADC #$04
STA tempA
Objeto LDA_y_hi,x
CLC
ADC #$04
STA heroPos
LDA Object_direction,x
E #%00000111
STA temp C
CreateObject tempA, heroPos, #$0F, #$00
;;; x, y, objeto, ação inicial.
;;; e agora com esse objeto, copie o player
;;; direção e comece a se mover dessa maneira.[/CODE]

3. Em ExtraTable.asm, aqui está a posição. Deve começar em 0 ou próximo para ter um efeito de que o jogador está atirando.
Code:
Yobjeto:
    .db 0,0,0,2,4,6,9,12,15,18,20,22,24,24,24,22,20,18,15,12,9,6,4,2[ /CÓDIGO]

4. Para o SinWave.asm que meu objeto mágico está usando como AI_behavior:
Eu comentei toda a seção de mover para a esquerda, porque a direção é definida no meu script de ataque.
Em vez de carregar diretamente a tabela e armazená-la no valor vertical do objeto:
LDA Yobjeto,y
Objeto STA_y_hi,x


Script carrega o heroPos e adiciona a esta posição o valor na tabela:, e armazena:

[CÓDIGO];;; Y TABLE LOOP ;;;;;;;;;;;;;;;;;;;;;

    INC starPos
    LDY starPos
    CPY #24 ;;; DEGRAUS ;;;
    BCC UpdateObjectPos
    LDY #0
    STY starPos
  
;;; ATUALIZAR POSIÇÃO ;;;;;;;;;;;;;;;;;;
  
UpdateObjectPos:
     LDA heroPos
     ADC Yobjeto,y
     Objeto STA_y_hi,x
  
;;; MOVER NORMAL COISA PARA A ESQUERDA ;;;;;;;;;;;
  
    ; TXA                               
    ; STA tempA                         
    ; LDA #%00000110       
    ; TAY                                 
    ; LDA DirectionTableOrdered,y   
    ; STA temp B                       
    ; LDA FacingTableOrdered,y     
    ; STA temp C                       
    ; StartMoving tempA, tempB, #$00   
    ; ChangeFacingDirection tempA, tempC

Não funciona com a variável normal do NesMaker tempB para o valor vertical, por isso adicionei uma nova. (heroPos)
Amazing
 
Top Bottom