[bb] Speed of the turns/moves/animations automatically adjusted to appear constant whatever the FPS by RemiD [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:43

Previous topic - Next topic

BlitzBot

Title : Speed of the turns/moves/animations automatically adjusted to appear constant whatever the FPS
Author : RemiD
Posted : 1+ years ago

Description : This allows your program to run at the same speed whatever the FPS, whatever is drawn on screen, whatever the computer hardware

Code :
Code (blitzbasic) Select
;Speed of the turns/moves/animations automatically adjusted to appear constant whatever the FPS
;
;This code shows a way to have an automatic adjustment of the speed of the turns/moves/animations
;so that the program appears to run at the same speed, whatever the FPS, whatever is drawn on screen, whatever the hardware of the computer/graphics card.
;The variable SC# must be applied to all turns/moves/animations. See the example.
;I have tested this code on several computers with different hardwares and os and it seems to work as expected.
;There may be inaccuracies if there is less than 10fps but overall it works well.

Graphics3D(800,600,32,2)    
   
HidePointer()  

SeedRnd(MilliSecs())
   
Origine = CreateCube()
ScaleMesh(Origine,0.1/2,100,0.1/2)
EntityColor(Origine,125,000,000)
EntityAlpha(Origine,0.5)
EntityFX(Origine,1)
PositionEntity(Origine,0,0,0)

Target = CreateCube()
ScaleMesh(Target,0.1/2,100,0.1/2)
EntityColor(Target,250,000,000)
EntityAlpha(Target,0.5)
EntityFX(Target,1)
PositionEntity(Target,0,0,128)

GroundMesh = CreatePlane()    
PositionEntity(GroundMesh,0,0,0)    
EntityColor(GroundMesh,050,050,050)        
     
Camera = CreateCamera()  
CameraRange(Camera,0.1,1000)
CameraClsColor(Camera,063,125,250)  
PositionEntity(Camera,0,0,0)  
 
CharacterMesh = CreateCube()
ScaleMesh(CharacterMesh,0.5/2,1.7/2,0.25/2)
PositionMesh(CharacterMesh,0,1.7/2,0)
HideEntity(CharacterMesh)

Global PlayerFeet = CreatePivot()
Global PlayerEyes = CreatePivot()
MoveEntity(PlayerEyes,0,1.6,0.1+0.1)
EntityParent(PlayerEyes,PlayerFeet,True)
Global PlayerMesh = CopyMesh(CharacterMesh)
EntityColor(PlayerMesh,000,000,250)
EntityParent(PlayerMesh,PlayerFeet,True)

PositionEntity(Camera,EntityX(PlayerEyes,True),EntityY(PlayerEyes,True),EntityZ(PlayerEyes,True))
RotateEntity(Camera,EntityPitch(PlayerEyes,True),EntityYaw(PlayerEyes,True),EntityRoll(PlayerEyes,True))
MoveEntity(Camera,0,0,-1.5)
EntityParent(Camera,PlayerEyes,True)
TurnEntity(PlayerEyes,22.5,0,0)

Global BotsCount% = 0
Dim BotFeet(10000)
Dim BotMesh(10000)

For i% = 1 To 1000 ;change this value to 1 or 10 or 100 or 1000 or more to see how the speed of the turns/moves are automatically adjusted so that it appears to run at the same speed whatever the FPS, whatever is drawn on screen.
 BotsCount = BotsCount + 1
 BId% = BotsCount
 BotFeet(BId) = CreatePivot()
 BotMesh(BId) = CopyMesh(CharacterMesh)
 EntityColor(BotMesh(BId),Rand(025,250),Rand(025,250),Rand(025,250))
 EntityParent(BotMesh(BId),BotFeet(BId),True)
 PositionEntity(BotFeet(BId),Rnd(-30,30),0,Rnd(10,90))
 RotateEntity(BotFeet(BId),0,Rnd(-180,180),0)
Next

SLight = CreateLight(1)
LightColor(SLight,255,255,255)  
PositionEntity(SLight,-1000,1000,-1000)
RotateEntity(SLight,45,-45,0)
 
AmbientLight(050,050,050)

MillisecOld% = MilliSecs()
MillisecCur% = MilliSecs()
SecsCount% = 0
FramesCount% = 0
FramesTotalCount% = 0
FramesPerSecond% = 0
Global SC# = 1.0  
   
While(KeyDown(1)<>1)    
 
 MainLoopStart% = MilliSecs()      
         
 UpdateBots()

 UpdatePlayer()

 If( EntityZ(PlayerFeet) >= EntityZ(Target) )
  ClsColor(000,000,000)
  Cls()
  Locate(0,0)
  Print("Average FramesPerSecond (FPS) = "+FramesTotalCount/SecsCount)
  Print("Seconds passed during the travel = "+SecsCount)
  FlushKeys()
  WaitKey()
  Goto LineExitGame
 EndIf

 SetBuffer(BackBuffer())

 RenderWorld()    

 MillisecCur = MilliSecs()
 If(MillisecCur < MillisecOld + 1000)
  FramesCount = FramesCount + 1
 ElseIf(MillisecCur >= MillisecOld + 1000)
  FramesPerSecond = FramesCount
  FramesTotalCount = FramesTotalCount + FramesCount
  FramesCount = 0  
  SecsCount = SecsCount + 1
  MillisecOld = MillisecCur        
 EndIf
         
 Text(0,0,"Triangles = "+TrisRendered())  
 Text(0,20,"MainLoopTime = "+MainLoopTime)  
 Text(0,40,"FramesCount = "+FramesCount)
 Text(0,60,"FramesPerSecond (FPS) = "+FramesPerSecond)
 Text(0,80,"FramesTotalCount = "+FramesTotalCount)    
 Text(0,100,"SC = "+SC)
 Text(0,120,"SecsCount = "+SecsCount)    
 Text(0,140,"See how the speed of the turns/moves are automatically adjusted so that ")
 Text(0,160,"it appears to run at the same speed, whatever the FPS, whatever is drawn on screen.")

 Flip(True)
 
 MainLoopTime% = MilliSecs() - MainLoopStart
 If(MainLoopTime < 1)
  MainLoopTime = 1
 EndIf  
   
 SC = Float(30) / 1000 * MainLoopTime

Wend
.LineExitGame

EndGraphics()

End()
 
Function UpdatePlayer()
 MoveEntity(PlayerFeet,0,0,0.2*SC)
End Function
 
Function UpdateBots()
 For BId% = 1 To BotsCount
  TurnEntity(BotFeet(BId),0,2.0*SC,0)
  MoveEntity(BotFeet(BId),0,0,0.2*SC)
 Next
End Function


Comments :


Imperium(Posted 4 months ago)

 Amazing! thanks!


RemiD

updated code example, simplified, clarified, with a scene made of meshes and images (to really see the impact on the FPS, but which does not impact the speed of the turns/moves/animations)
26/01/2018

;Speed of the turns/moves/animations automatically adjusted to appear constant whatever the FPS
;
;This code shows a way to have an automatic adjustment of the speed of the turns/moves/animations
;so that the program appears to run at the same speed, whatever the FPS, whatever is drawn on screen, whatever the hardware of the computer/graphics card.
;The variable SpeedCoeff# must be applied to all turns/moves/animations. See the example.
;I have tested this code on several computers with different hardwares and os and it seems to work as expected.
;There may be inaccuracies if there is less than 10fps but overall it works well.

Global ProgramState%
Const CStart% = 1
Const CUpdate% = 2
Const CEnd% = 3

ProgramState = CStart

Graphics3D(800,600,32,2)     
   
HidePointer() 

SeedRnd(MilliSecs())

Global Origine = CreateCube()
ScaleMesh(Origine,0.1/2,0.1/2,0.1/2)
EntityColor(Origine,125,000,125)
EntityAlpha(Origine,0.5)
EntityFX(Origine,1)
PositionEntity(Origine,0,0,0,True)

Global Target = CreateCube()
ScaleMesh(Target,0.1/2,100.0,0.1/2)
EntityColor(Target,250,000,250)
EntityAlpha(Target,0.5)
EntityFX(Target,1)
PositionEntity(Target,0,0,128.0,True)

GroundMesh = CreatePlane()     
EntityColor(GroundMesh,125,125,125)
PositionEntity(GroundMesh,0,0,0)           
     
Global Camera = CreateCamera()   
CameraRange(Camera,0.1,1000)
CameraViewport(Camera,0,0,GraphicsWidth(),GraphicsHeight())     
CameraClsColor(Camera,000,000,000)

XCharacterMesh = CreateCube()
ScaleMesh(XCharacterMesh,0.5/2,1.75/2,0.25/2)
PositionMesh(XCharacterMesh,0,1.75/2,0)
HideEntity(XCharacterMesh)

Global PlayerFeet = CreatePivot()
Global PlayerEyes = CreatePivot()
MoveEntity(PlayerEyes,0,1.65,0)
EntityParent(PlayerEyes,PlayerFeet,True)
Global PlayerMesh = CopyEntity(XCharacterMesh)
EntityColor(PlayerMesh,000,000,250)
EntityParent(PlayerMesh,PlayerFeet,True)

Global BotsCount% = 0
Dim BotFeet(10000)
Dim BotMesh(10000)

For n% = 1 To 2000 ;change this value to 1 or 10 or 100 or 1000 or more
BotsCount = BotsCount + 1
I% = BotsCount
BotFeet(I) = CreatePivot()
BotMesh(I) = CopyEntity(XCharacterMesh)
EntityColor(BotMesh(I),Rand(025,250),Rand(025,250),Rand(025,250))
EntityParent(BotMesh(I),BotFeet(I),True)
PositionEntity(BotFeet(I),Rnd(-30,30),0,Rnd(10,90),True)
RotateEntity(BotFeet(I),0,Rnd(-180,180),0,True)
Next

DLight = CreateLight(1)
LightColor(DLight,255,255,255) 
PositionEntity(DLight,0,1000,-1000,True)
RotateEntity(DLight,45,0,0,True)

AmbientLight(064,064,064)

TurnEntity(PlayerEyes,22.5,0,0)

;to count the millitime it takes for player to from the start point to the target point
Global TravelMilliStart% = MilliSecs()
Global TravelMilliTime%

;to count the millitime a mainloop takes
Global MainLoopMilliStart%
Global MainLoopMilliTime%

;to lock the FPS at 30fps maximum
Global MainLoopTimer = CreateTimer(30)

;to count the number of frames per second
Global FPS%

;the value to apply to all turns/moves/animations so that the speed of the turns/moves/animations appear constant whatever the FPS, whetever is drawn on the screen
Global SpeedCoeff# = 1.0   
   
ProgramState = CUpdate

Main()

EndGraphics()

End()

Function Main()

Repeat   

  MainLoopMilliStart = MilliSecs()     
         
  UpdateBots()

  UpdatePlayer()

  If( EntityZ(PlayerFeet,True) >= EntityZ(Target,True) )
   ClsColor(000,000,000) : Cls()
   Locate(0,0)
   Print("Total time passed during the travel = "+Int(Float(TravelMilliTime)/1000)+"seconds")
   FlushKeys()
   WaitKey()
   ProgramState = CEnd
EndIf

TravelMilliTime = MilliSecs() - TravelMilliStart

;position/rotate the camera before the rendering of the scene
PositionEntity(Camera,EntityX(PlayerEyes,True),EntityY(PlayerEyes,True),EntityZ(PlayerEyes,True))
RotateEntity(Camera,EntityPitch(PlayerEyes,True),EntityYaw(PlayerEyes,True),EntityRoll(PlayerEyes,True))
MoveEntity(Camera,0,0,-1.5)

CameraViewport(Camera,0,0,GraphicsWidth(),GraphicsHeight())     
CameraClsColor(Camera,000,000,000)
SetBuffer(BackBuffer())

RenderWorld()     

For n% = 1 To 10 Step 1 ;change this value to 1 or 10 or 100 or more
  PWidth% = Rand(25,100) : PHeight% = Rand(16*1,16*10)
  PX% = Rand(0+1,GraphicsWidth()-PWidth-1) : PY% = Rand(0+1,GraphicsHeight()-PHeight-1)
  Color(Rand(025,255),Rand(025,255),Rand(025,255)) : Rect(PX,PY,PWidth,PHeight,True)
Next
   
Color(255,255,255)      
Text(0,0,"Triangles = "+TrisRendered())   
Text(0,16,"MainLoopMilliTime = "+MainLoopMilliTime)   
Text(0,32,"FPS = "+FPS)   
Text(0,48,"SpeedCoeff = "+SpeedCoeff)
Text(0,64,"Current time of the travel = "+Int(Float(TravelMilliTime)/1000)+"seconds")   
Text(0,80,"See how the speed of the turns/moves/animations are automatically adjusted so that ")
Text(0,96,"it appears to run at the same speed, whatever the FPS, whatever is drawn on screen.")

;Flip(true)
WaitTimer(MainLoopTimer)
VWait():Flip(False)

MainLoopMilliTime = MilliSecs() - MainLoopMilliStart
If(MainLoopMilliTime < 1)
  MainLoopMilliTime = 1
EndIf  
   
SpeedCoeff = Float(30) / 1000 * MainLoopMilliTime

FPS% = 1000.0/MainLoopMilliTime

Until( KeyDown(1)=1 Or ProgramState = CEnd )

End Function

Function UpdatePlayer()

MoveEntity(PlayerFeet,0,0,0.2*SpeedCoeff)

End Function

Function UpdateBots()

For I% = 1 To BotsCount

  TurnEntity(BotFeet(I),0,2.0*SpeedCoeff,0)
  MoveEntity(BotFeet(I),0,0,0.2*SpeedCoeff)

Next

End Function