Moving Sprite loop with slow motion when changing direction.

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
sdm
Posts: 306
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Moving Sprite loop with slow motion when changing direction.

Post by sdm » Mon Jul 10, 2017 3:52 am

The object moves in a loop from point A to point B and returns. I would like to slow down the movement of the object so that it smoothly slows down the movement at each approach to these points. I tried to do two times slow motion, which will start 8pixels before those points. Ideally, if the slowdown in the direction change was more fluid (like normal speed->slow 2x->slow 4x->reverse movement->slow4x->slow2x->normal speed.
Attachments
demo.nes
(40.02 KiB) Downloaded 88 times
pict.jpg
monsterslo.zip
code
(52.33 KiB) Downloaded 93 times

na_th_an
Posts: 554
Joined: Mon May 27, 2013 9:40 am

Re: Moving Sprite loop with slow motion when changing direct

Post by na_th_an » Mon Jul 10, 2017 4:30 am

I'd use fixed point math with velocity and acceleration (linear movement equations). I'd calculate the distance to the limit where I have to begin applying deceleration. Then, if suitable, I'd make a LUT with the results.

User avatar
rainwarrior
Posts: 7824
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Moving Sprite loop with slow motion when changing direct

Post by rainwarrior » Mon Jul 10, 2017 6:47 am

As an alternative to using 16-bit velocity, you could take a random number (0-255) each frame, and compare it against some sort speed throttle value to decide whether or not to move this frame, i.e. "if rand() >= 128" will move at 50% speed, "if rand() >= 64" at 75% speed, etc.

This thread might be of interest, talks about similar ideas: viewtopic.php?f=2&t=12831

na_th_an
Posts: 554
Joined: Mon May 27, 2013 9:40 am

Re: Moving Sprite loop with slow motion when changing direct

Post by na_th_an » Mon Jul 10, 2017 6:53 am

You don't need 16 bits if the distance for the slowdown is always the same (if I've understood correctly). You can use fp during the calculations, then output a lut with integer pixel increments per frame.

sdm
Posts: 306
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Moving Sprite loop with slow motion when changing direct

Post by sdm » Mon Jul 10, 2017 12:53 pm

I managed to do it the way I wanted it, ie releasing 8pix before points A and B. But the code does not look too good, especially as far as optimizations are concerned, I will be grateful for the improvement of the code.

Code: Select all

ENM_loop:

	LDA ENM_Slow			;EOR changes the value of one bit per frame
	EOR #%00000001
	STA ENM_Slow

	lda ENM_S
	and #%00000100
	bne ENM_loop_Left		;Czy bit kierunku jest ustawiony? Skocz, jeśli tak.

	lda ENM_MovePos
	cmp ENM_INC
	beq ENM_loop_chngDir		;When the max INC is reached, change the direction

	LDA ENM_X
	CMP ENM_SlowDEC
	BCC ENM_Loop_INCslo

	LDA ENM_MovePos
	CMP ENM_SlowINC
	BCC ENM_Loop_INCnoSlo		;When it will be 8pix before MAX INC. Do not make a branch

ENM_Loop_INCslo:

	LDA ENM_Slow			;Now it is 8pix or less since max INC - now slow down the movement
	CMP #1
	BNE ENM_Loop_SkipINCFrame

ENM_Loop_INCnoSlo:

	INC ENM_MovePos

ENM_Loop_SkipINCFrame:

	RTS
 
ENM_loop_Left:

	lda ENM_MovePos
	cmp ENM_DEC
	beq ENM_loop_chngDir		;When the max DEC is reached, change the direction

	LDA ENM_X
	CMP ENM_SlowINC
	BCS ENM_Loop_DECslo

	LDA ENM_MovePos
	CMP ENM_SlowDEC
	BCS ENM_Loop_DECnoSlo		;When it will be 8pix before MAX DEC. Do not make a branch

ENM_Loop_DECslo:

	LDA ENM_Slow			;Now it is 8pix or less since max DEC - now slow down the movement
	CMP #1
	BNE ENM_Loop_SkipDECFrame

ENM_Loop_DECnoSlo:

	DEC ENM_MovePos

ENM_Loop_SkipDECFrame:
 
	RTS

ENM_loop_chngDir:			;CHANGE DIRECTION

	JSR SND1
	lda ENM_S
	EOR #%01000100
	sta ENM_S

ENM_loop_end:

	RTS
I mainly mean that the ENM_INC and ENM_DEC variables can be changed to any value, and the slowdown itself will be executed (without further changes in the ENM_Loop)


EDIT:
I made a slow down consisting of two parts (1x-> 2x-> 4x reverse direction 4x, 2x, 1x)


The code does not look beautiful, but it works. Unfortunately it is quite curly and has a large size ...

Code: Select all

ENM_Slowmo:

	LDA ENM_Slow
	EOR #%00000001
	STA ENM_Slow

	LDA ENM_Slow
	CMP #1
	BNE ENM_Slowmo_Skip

	LDA ENM_Slow2
	EOR #%00000001
	STA ENM_Slow2

ENM_Slowmo_Skip:

	RTS

;------------------------------------

ENM_loop:

	JSR ENM_Slowmo

   lda ENM_S
   and #%00000100
   bne ENM_loop_Left      ;Czy bit kierunku jest ustawiony? Skocz, jeśli tak.

   lda ENM_MovePos
   cmp ENM_INC
   beq ENM_loop_chngDir      ;When the max INC is reached, change the direction

   LDA ENM_X
   CMP ENM_SlowDEC
   BCC ENM_Loop_INCslo

   LDA ENM_MovePos
   CMP ENM_SlowINC
   BCC ENM_Loop_INCnoSlo      ;When it will be 8pix before MAX INC. Do not make a branch

ENM_Loop_INCslo:

   LDA ENM_Slow         ;Now it is 8pix or less since max INC - now slow down the movement
   CMP #1
   BNE ENM_Loop_SkipINCFrame

ENM_Loop_INCnoSlo:

	LDA ENM_MovePos
	CMP ENM_Slow2DEC
	BCC ENM_Loop_INCSlo2

	LDA ENM_MovePos
	CMP ENM_Slow2INC
	BCC ENM_Loop_INCnoSlo2

ENM_Loop_INCSlo2:

	LDA ENM_Slow2
	CMP #1
	BNE ENM_Loop_SkipINCFrame

ENM_Loop_INCnoSlo2:

   INC ENM_MovePos

ENM_Loop_SkipINCFrame:

   RTS
 
ENM_loop_Left:

   lda ENM_MovePos
   cmp ENM_DEC
   beq ENM_loop_chngDir      ;When the max DEC is reached, change the direction

   LDA ENM_X
   CMP ENM_SlowINC
   BCS ENM_Loop_DECslo

   LDA ENM_MovePos
   CMP ENM_SlowDEC
   BCS ENM_Loop_DECnoSlo      ;When it will be 8pix before MAX DEC. Do not make a branch

ENM_Loop_DECslo:

   LDA ENM_Slow         ;Now it is 8pix or less since max DEC - now slow down the movement
   CMP #1
   BNE ENM_Loop_SkipDECFrame

ENM_Loop_DECnoSlo:

	LDA ENM_MovePos
	CMP ENM_Slow2INC
	BCS ENM_Loop_DECSlo2

	LDA ENM_MovePos
	CMP ENM_Slow2DEC
	BCS ENM_Loop_DECnoSlo2

ENM_Loop_DECSlo2:

	LDA ENM_Slow2
	CMP #1
	BNE ENM_Loop_SkipDECFrame

ENM_Loop_DECnoSlo2:

   DEC ENM_MovePos

ENM_Loop_SkipDECFrame:
 
   RTS

ENM_loop_chngDir:         ;CHANGE DIRECTION

   JSR SND1
   lda ENM_S
   EOR #%01000100
   sta ENM_S

ENM_loop_end:

   RTS
Attachments
demo4.nes
(40.02 KiB) Downloaded 82 times
monsterslo4.zip
(51.85 KiB) Downloaded 84 times
demo2.nes
(40.02 KiB) Downloaded 85 times

Oziphantom
Posts: 861
Joined: Tue Feb 07, 2017 2:03 am

Re: Moving Sprite loop with slow motion when changing direct

Post by Oziphantom » Wed Jul 12, 2017 10:58 pm

While not really the right thing to do.. you can do something like this

Code: Select all

 bit Direction
        bmi Backwards
;Forward
        lda ENM_MovePosHi
        sec
        sbc ENM_EndPos
        lsr a
        lsr a
        cmp #3
        bcc safeF
        lda #2
safeF   
        tax
        lda ENM_MovePosLo
        clc
        adc SpeedTableFLo,x
        sta ENM_MovePosLo
        lda ENM_MovePosHi
        adc SpeedTableFHi,x
        cmp ENM_EndPos
        bcc safeF2
        lda #80
        sta Direction
        lda #0
        sta ENM_MovePosLo
        lda ENM_EndPos
safeF2
        sta ENM_MovePosHi
        rts
        
Backwards
        lda ENM_StartPos
        sec
        sbc ENM_MovePosHi
        lsr a
        lsr a
        cmp #3
        bcc safeB
        lda #2
safeB   
        tax
        lda ENM_MovePosLo
        sec
        sbc SpeedTableFLo ,x
        sta ENM_MovePosLo
        lda ENM_MovePosHi
        sbc SpeedTableFHi,x
        cmp ENM_StartPos
        bcc safeB2
        lda #0
        sta Direction
        sta ENM_MovePosLo
        lda ENM_StartPos
safeB2
        sta ENM_MovePosHi
        rts
        
SpeedTableFLo .db $40,$80,$00
SpeedTableFHi .db $00,$00,$10
Note this is off the top of my head and might have bugs ;)

The idea is you do
EndPos - Pos
Which gives you the number of pixels until the end. Now you want to have 0-3 1 speed, 4-7 another 8+ another, so what I do is a shift right 2 times so
1000 -> 0010 8 = 2
0111 -> 0001 7 = 1
0100 -> 0001 4 = 1
0011 -> 0000 3 = 0
0001 -> 0000 1 = 0
so if the number after shift it higher than 2 I set the index to 2.
Then I use 16 bits maths to add the pixels. This is basically 8.8 fixedpoint, you set sprites based upon the Hi value.
$100 = 1
$080 = 0.5
$040 = 0.25

as in
040 +
040
----
080

080 +
040
----
0C0

0C0 +
040
----
100

so basically you use it to get the 1x,0.5,0.25 speeds but you might want to scale them up so the enemy moves at 2px a frame for example, then 1, then .5 or whatever.

It then checks to see if it has gone over or hit the target, then it snaps to the target and flips the direction. Note I use $80, $00 so I can use BIT instruction to do the test, as BIT will pull bit 7 into the N flag, an LDA will also do the same

Backwards is the same thing, just now you do Pos-Start and then subtract the speeds to go the other way.

User avatar
OmegaMax
Posts: 83
Joined: Wed Sep 21, 2016 8:55 am
Location: Calgary.Alberta,Canada

Re: Moving Sprite loop with slow motion when changing direct

Post by OmegaMax » Fri Jul 14, 2017 9:56 am

How about using tables for you enemy object movement logic,I'm using the stack but you can use temp variables to save the values(NmeXVelocity,NmeYVelocity,NmeMovementPatternTimer) also the tables are integer values(you can add fixed point values like Oziphantom showed you) if you can't understand or have trouble implementing my example private message me and we can modify code that suits your game needs.Best of luck which ever way you decide."Off topic" sdm you have unconventional ways of solving problems and you manage to solve them each time,it's neat to see. :)


Code: Select all

;------------------------------------------------------- 
Do_BuildNmeLogicPointer:
  ldy #NmeObjLogicOffset
  lda (_NMEArray),Y
  sta _NmeLogicPointer+0 
  iny
  lda (_NMEArray),Y 
  sta _NmeLogicPointer+1 
  rts
;-------------------------------------------------------
Do_NMEMovementTimers: 
  sec
  sbc #1
  sta (_NMEArray),y 
  rts
;-------------------------------------------------------
Do_BuildNMEMovementPattern:
  ldy #NmeMovementPatternTimerOffset
  lda (_NMEArray),Y
  bne Do_NMEMovementTimers
  jsr Do_BuildNmeLogicPointer
  ldy #MovementPatternTableOffset
  lda (_NMEArray),Y 
  tay
  lda (_NmeLogicPointer),Y 
  iny
  pha                                                        ;Push NmeXVelocity to stack
  lda (_NmeLogicPointer),Y 
  pha                                                        ;Push NmeYVelocity to stack
  iny
  lda (_NmeLogicPointer),Y 
  bpl +                                    
  and #%01111111                                      
  ldy #$FF 
+:  
  iny
  pha                                                         ;Push NmeMovementPatternTimer to stack
  tya
  ldy #NMEMovementPatternTableOffset             
  sta (_NMEArray),Y                   
  pla                                                          ;Pull NmeMovementPatternTimer from stack
  ldy #NmeMovementPatternTimerOffset          
  sta (_NMEArray),Y                                            ;Save NmeMovementPatternTimer in EnemyArray
  pla                                                          ;Pull NmeYVelocity from stack 
  ldy #NmeYVelocityOffset
  sta (_NMEArray),Y                                            ;Save NmeYVelocity in EnemyArray
  pla                                                          ;Pull NmeXVelocity from stack
  ldy #NmeXVelocityOffset
  sta (_NMEArray),Y                                            ;Save NmeXVelocity in EnemyArray
  rts

;================================================== 
;Data Format 
;Byte 0 = NmeXVelocity
;Byte 1 = NmeYVelocity
;Byte 2 = NmeMovementPatternTimer
;==================================================
Enemy1PatternLogicTable: 
.db $FE,$02,$05  
.db $FE,$02,$05   
.db $FE,$FE,$05  
.db $FE,$FE,$85  
;-------------------------------------------------------
NME2PatternLogicTable: 
.db $FE,$00,$0A  
.db $FE,$03,$0A  
.db $FE,$05,$0A  
.db $FE,$09,$0A  
.db $FE,$05,$0A  
.db $FE,$03,$0A  
.db $FE,$00,$0A  
.db $FE,$FD,$0A  
.db $FE,$FB,$0A  
.db $FE,$F7,$0A  
.db $FE,$FB,$0A  
.db $FE,$FD,$8A 

Post Reply