Animation speed

Monkey Forums/Monkey Programming/Animation speed

erebel55(Posted 2014) [#1]
Can anyone share any code for slowing down their animations? I have a walking animation with only two frames, so obviously displaying this at 60 frames per second looks horrible.

Thank you


dawlane(Posted 2014) [#2]
What you need to do is to record the time and store it within the sprite object. Then you need to get the time again and see if it is greater than the time you stored + the time delay. If it is then store the current time and increase the frame. If the frame is the last the set it back to the start

Class Sprite
Field last_time:Int
Field frame_delay:Int
Field frame;Int
Field total:Int
Field x:Int
Field y:Int
Field img:Image

Method Animate:Void()
If Millisecs() > last_time + frame_delay
Self.last_time = Millisecs()
Self.frame += 1
If Self.frame > Self.total Then Self.frame = 0
EndIf
End Method

End Class

In practice you would have a general timer to keep track of the milliseconds and just read that instead of calling Millisecs function every time.


Nobuyuki(Posted 2014) [#3]
The above code of course won't work if elapsed time between updates is more than twice the frame delay. You can set frame by checking the time elapsed since the last update and updating a "virtual frame number" float -- then just cast it to Int when you need the frame number. Eg:

Class Anim
Field images:Image   'Something containing the strip of images.  Or, an array of images.

Field totalFrames:Int = 60  'Total number of frames in the animation.

Field frame:Float     'The current frame.  Decimals are its virtual "time offset".
Field frame_time:Int  'Speed of animation per frame, in ms
Field last_time:Int   'Last time index snapshot

Method UpdateFrame:Void()
	Local elapsed:Int = Millisecs() -frame_time
	frame = Cycle(frame + (elapsed / frame_time), 0, totalFrames + 1)
	last_time = Millisecs()
End Method

Method Render:Void(x:Float, y:Float)
	DrawImage(images, x, y, Int(frame))
End Method

'Summary: Cycles a value until it's within the range specified, from first(inclusive) to last(exclusive).
Function Cycle:Float(value:Float, first:Float, last:Float)
	Local amt:Float = last - first  'The amount to cycle values outside the range
	
	While value >= last
		value -= amt
	Wend
	
	While value < first
		value += amt
	Wend
	
	Return value
End Function	
End Class



Midimaster(Posted 2014) [#4]
I works always the same way: Frame number only changes, when a amount of time has ellapsed. Therefor every actor needs is own "time".

Here is a complete running sample:
Strict
Import mojo


Class Game Extends App

	Field ActorTime%, ActorFrame%, ActorSpeed%

	Method OnCreate%()
		SetUpdateRate 60
		Return 0
	End	

	Method OnUpdate%()
		' mouse changes animation speed 
		ActorSpeed=TouchX()/2+100
		
		
		If ActorTime<Millisecs()
			ActorTime=Millisecs() + ActorSpeed
			ActorFrame=(ActorFrame +1 ) Mod 2
		Endif
		Return 0
	End	

	Method OnRender%()
		Cls 0,0,0
		DrawText "Move the Mouse X to change the Speed: " + ActorSpeed,30,30
		'DrawImage Walker,0,0,Frame
		
		' or demo simulation:
		Select ActorFrame
			Case 0
				DrawLine 100,200,80,150
			Case 1
				DrawLine 100,200,120,150
		End Select
		Return 0
	End	
	
End

Function Main%()
	New Game
	Return 0
End