Tweening

Blitz3D Forums/Blitz3D Programming/Tweening

Moraldi(Posted 2006) [#1]
Please take a look to the following piece of code

Const FPS = 60

Global FramePeriod%		; main game loop timing
Global FrameTime%
Global FrameElapsed%
Global FrameTicks%
Global FrameTween#

Global ProgramEnd% = False

Graphics3D 640, 480, 16, 0
SetBuffer BackBuffer()

camera = CreateCamera() : MoveEntity camera, 0, 0, -10
light = CreateLight()
cube = CreateCube()

Frame_Init()

Global dpitch#
Global dyaw#
Global droll#

Global velpitch# = 0
Global velyaw# = 180
Global velroll# = 0

start_time% = -1

While Not ProgramEnd


	If KeyHit(1) Then ProgramEnd = True
	Frame_Capture()
	For FrameLimit = 1 To FrameTicks
		FrameTime = FrameTime + FramePeriod
		If FrameLimit = FrameTicks Then
			CaptureWorld
		EndIf
		dpitch = velpitch * 1/FPS
		dyaw = velyaw * 1/FPS
		droll = velroll * 1/FPS
		TurnEntity cube, dpitch, dyaw, droll
		UpdateWorld
	Next
	RenderWorld FrameTween
	If start_time < 0 Then start_time = MilliSecs()
	If MilliSecs() - start_time <= 1000
		y = EntityYaw(cube)
	Else
		velyaw = 0
	EndIf
	Text 0, 0, "Yaw = " + y
	Flip
	
Wend

Function Frame_Init()

	FramePeriod = 1000 / FPS
	FrameTime = MilliSecs () - FramePeriod
	
End Function

Function Frame_Capture()

	Repeat
		FrameElapsed = MilliSecs () - FrameTime
	Until FrameElapsed
	FrameTicks = FrameElapsed / FramePeriod
	FrameTween = Float (FrameElapsed Mod FramePeriod) / Float (FramePeriod)
	
End Function


I want to have my entities to move in terms of velocities. The question is:
What is the velocity of Y-Axis, velyaw, in order to get the Cube rotated exactly 180 degrees within 1 second?
If you run the program you will see that I don't get the desired result setting the velyaw to 180 degrees/sec. OK I know that I am wrong but I don't know where!

Thanks


b32(Posted 2006) [#2]
I tried running the code a few times and I noticed it doesn't allways end up at the same angle. I don't understand how captureworld and renderworld tween work, so I have trouble understanding what your code does exactly, but I think it doesn't complete the 1000 ms timeperiod exactly enough.
There is deltatiming, but I think you know that. You could rotate something 180 deg/sec like this:
RotateEntity mesh, 0, Millisecs() * 180 / 1000, 0


Moraldi(Posted 2006) [#3]
Thanks for your time to spend and your advise.
The tweening code is not mine. It comes from Blitz castle demo and I have to say that I don't understand its all aspects.
For example I don't understand why the program execution exits from the Repeat-Until loop in Frame_Capture() function since FrameElapsed is constantly grow.
I suppose the deltatiming is the time that corresponds to 1 Frame Per Second (FPS). That's why I multiply the velocity (velpitch, velyaw, velroll) with the 1/FPS factor (remember this simple formula: distance = velocity * time).
I want to avoid the use RotateEntity command because I have already build a whole set of functions based in the TurnEntity command.


John Blackledge(Posted 2006) [#4]
The point of tweening is that it smooths out _animated_ characters no matter what the framerate at any gven moment.

To smoothly rotate a cube a certain amount in a given period you would either have to:
a) create an animation of a cube using a bone pivot, or
b) if using your own then read the pitch,roll,yaw every frame and calculate ahead how much you need to turn the cube for the next ideal time slice.

My own tutorial on tweening is at
http://www.blitzbasic.co.nz/codearcs/codearcs.php?code=1497


b32(Posted 2006) [#5]
If you want to use deltatiming with turnentity, try something like this:
now = millisecs()
elapsed = (now - old)
old = now

Then use TurnEntity mesh, 0, elapsed * 180 / 1000, 0
The variable 'old' should be global if you are using this in a function.


Moraldi(Posted 2006) [#6]
I just returned from my day work. Thank you both. I will follow your guidelines and see...


Sir Gak(Posted 2006) [#7]
Because of floating point rounding errors, I like b32's suggestion which corrects for such:
RotateEntity mesh, 0, Millisecs() * 180 / 1000, 0 


I might adjust it a little, though. If you want one 180 degree rotation per second, then you will of course use millisecs(). But, the current amount of ms since you last checked is what you really want, not the ms command itself.

So, I would suggest:
start = millisecs()
;
ms_diff = millisecs() - start
if ms_diff > 1000 then start = millisecs():ms_diff=ms_diff-1000
RotateEntity mesh, 0, ms_diff * 180 / 1000, 0



Moraldi(Posted 2006) [#8]
Do you mean
RotateEntity mesh, 0, ms_diff * 180 / 1000, 0

or
TurnEntity mesh, 0, ms_diff * 180 / 1000, 0



Moraldi(Posted 2006) [#9]
It works!, it works!. Thanks to you!
I used the b32's last formula and I made a final touch as Sir Gak noted.
I have a function named TransformMeshes (in the main program loop) where I calculate for all my meshes the delta_rotation using a constant angle_velocity
delta_rotation = angle_velocity * delta_time
TurnEntity myentity, 0, delta_rotation, 0

But what is the delta_time?. Actually is the time between 2 successive calls of TransformMeshes and simply I can't change it. delta_time is not constant!.
So If I want to get the total rotation that corresponds to the end of 1000 msecs I have to change the angle_velocity only for the LAST delta_time just before the end of 1000 msecs