## slow motion / bullet time concepts

Started by RemiD, April 06, 2023, 11:05:57

#### RemiD

hi

i am currently trying to implement a slow motion effect only in specific cases, in my game.

https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/coding-slow-motion-r5864/

which suggests that i have to use a global variable 'gamespeed' (0.1-0.9 for slowed down speed and 1.0 for normal speed) and multiply each variable of turn / movement by this value.

however if i do that, it seems to decrease the amplitude of the turns / movements...

what i mean is that the character will jump less high and turn with less angle and move less distance than without this tweak.

or is it a problem in my logic ?

#### RemiD

after some research, i need to learn about delta time.

i have already coded a similar thing, here :

but i have to learn a little more...

#### RemiD

#2
i have made more clear (imo) a bb code example of delta time based movement :
`Graphics( 640,480,32,2 )Global beforemilli%Global aftermilli%Global deltacoeff#Global MainTimer = CreateTimer(60) ;change the max framerate (FPS) (between 6 to 60) and see how the rectangle will still move at the same speed, whatever the framerate (FPS)Repeat ;get the milli time before the mainloop beforemilli = MilliSecs()  ;update tranforms x = x + deltacoeff * 100 : If( x > 640 ) :  x = 0 : EndIf ;use the deltacoeff to calculate the movement / new position  y= 480/2 - 16/2 ;render SetBuffer( BackBuffer() ) ClsColor(000,000,000) : Cls()     Color( 120, 120, 120 ) : Rect( x, y, 16, 16, 1 ) ;debug infos     Text( 0, 0, deltacoeff ) ;display the result on the screen ;Flip(true) WaitTimer(MainTimer) VWait():Flip(False) ;get the milli time after the mainloop aftermilli = MilliSecs() ;calculate the deltacoeff ( = elapsed milli time / 1000 ) deltacoeff#= Float( aftermilli - beforemilli) / 1000        Until( KeyDown(1)=1 )End()`

initially by Rob :
https://archive.blitzcoder.org/forums/code-graphics/140.html

it seems to work well, however from what i understand, Rob made a mistake, the delta value is a coeff corresponding to the elapsed milli time value / 1000, not a milli time value,

#### DaiHard

Probably telling you the bleeding obvious which you already know, but delta time is normally used to give games frame-rate independence: you work out how long it was (i.e. from system time) since the last frame was rendered, and multiply the movements by that time length - so, say, if something is moving at 1 m/s, and you render one frame per second, then it needs to move 1 metre - but at 100  fps, it should only move 1 cm each frame. Of course, you can also "fake" the time to get slow motion/accelerated time effects - if you only move it 1 millimeter each frame (at 100 fps) it will effectively slow time down 10 fold!

You might want to break your multiplier up into two components, one of which honestly compensates for the elapsed time (i.e. 1/fps), and one of which accounts for your slowing of the motion).

Hope that's useful - if not, ignore it, and I'll go back under my stone!

#### Midimaster

A simple idea:

What would happen, if your delta-time model works and you would replace all calls of the function Millisecs() with your function MyMillisecs()?

`Function MyMillisecs:Int()    Return Millisecs()/SloMo  ' the slow motion factorEnd funtion`

Example:
`Graphics 800,600Global SloMo:Double=1Global X:Int, Y:DoubleGlobal Time:IntRepeat    Cls         ' for testing use the key <S> to switch on Slow motion:    If KeyHit(KEY_S)        If SloMo=1            SloMo = 4            Print "Slow Motion ON"        Else            SloMo = 1            Print "Slow Motion OFF"        EndIf                 Time = MyMilliSecs()    EndIf     If time < MyMilliSecs()        Time = MyMilliSecs()+1        Y = Sin(X)*100 +300        X = (X + 1) Mod 800    EndIf         DrawRect X,Y,10,10        Flip 0Until AppTerminate()Function MyMillisecs:Int()    Return MilliSecs()/SloMoEnd Function `
...back from Egypt

#### Derron

There are multiple "times" to consider:
- system time (this is where you use the "delta" - to compensate for "hickups" etc, means you know how much fractions of a real time second have passed since last "update" - all together will add to "1 second" after "fixed amount of updates/second" happened)

- (game) world time: the time in your game, can run faster or slower ...

- global (game) physics time: It can be tied to the world time ... or not

- local (game) physics time: absolute value or a "modifier" for "global physics time" it descibes if an entity's physics happen faster/less often than others in the world

I would even think a "local world time" might be ... to consider.

I also assume that you somewhere should store the "time reference". So if you watch an entity which is "faster", then physics "per delta time step" are advancing "normal" for this entity, and all the default "Global physics time" is updated in relation to it. Means "fast element has speedMod 2.0" will lead to the fast element updated with "normal speed", and all the other elements with "normal speed / 2.0".
If "world time" is affected (means "fast element" is just moving faster than others - and if it watches a clock in the game it ticks "slower" ---- compared to "fast element slowed down the whole world") then world time needs to tick also by "normal world time speed / 2.0").

Assume if you look for "bullet time" you might find better descriptions and surely code examples - I just typed down my thoughts here.

bye
Ron

#### RemiD

#6
QuoteYou might want to break your multiplier up into two components, one of which honestly compensates for the elapsed time (i.e. 1/fps), and one of which accounts for your slowing of the motion).
that what is explained in the gamedev.net example, and what i tried, but for some reason the slowmotion coeff decreases the amplitudes of the movements, turns...

something like that :
`motioncoeff = 1.0if( keydown(57) = 1 )  motioncoeff = 0.1endifturnentity( player_root, 0, player_turnspeed*deltacoeff*motioncoeff , 0 ) moventity( player_root, 0, (player_jumpspeed+player_gravityspeed)*deltacoeff*motioncoeff, player_movespeed*deltacoeff*motioncoeff )`
there is a slow motion effect but this also decreases the amplitudes of the turns / movements...

anyway, not urgent, i will come back at this later...

#### MrmediamanX

There was this example from a few years back, It should come with a demo.
It's a thing that doe's when it don't..

#### RemiD

@MrmediamanX>> thanks for the link to this bb code example.

after a quick look at the code, i am not sure that this will help with the amplitude issue that i am talking about, but i am going to do some tests.

#### DaiHard

Sounds like you are doing your movements a certain number of times (cycles) rather than for a certain total time: if you decrease the amount of movement each cycle, but do the same number of cycles, then the movement will be smaller. If you do the cycles for the same (simulated) time, but each cycle is "shorter", then you will need to do more cycles, but the total movement will be correct.

In  other words, say you move 1 metre in 1 second. At 10 FPS, you need to move 10 cm with each frame, for 10 frames.
If you want to slow things down 10 fold, then you need to move only 1 cm with each frame, but you will need to do it for 100 frames.

#### RemiD

@DaiHard >> yes that's what i am talking about.

i will experiment with this later. not urgent.

#### RemiD

#11
during the night i have had an idea :

let's say that the game renders at 60fps.

we could potentially decrease the framerate to 10fps or 15fps for a slow motion effect (if it is temporary) by simply using a delay before updating the next transforms / animations and rendering the next frame.

with the command delay(millivalue)...

not ideal but this should work.

in my game, the movements / turns / animations are fast, and i want the player to, in some cases, temporarily, have the time to prepare the next 'trick' (with a combination of keys).

so it may be a good solution for this game.

#### Midimaster

Normaly the framerate would not effect speed in modern coded games.

Only if you wrote a game in bad (old-style) manner, this would have an effect.

Game-movements should be connected with time. So if you reduce the framerate, the characters would jump jerky, but same way.

Did you have a look on my idea to manipulate the Millisecs()-timer?
...back from Egypt

#### RemiD

#13
Quotelet's say that the game renders at 60fps.

we could potentially decrease the framerate to 10fps or 15fps for a slow motion effect (if it is temporary) by simply using a delay before updating the next transforms / animations and rendering the next frame.

with the command delay(millivalue)...

it seems to work !

`;slow motion effect using delay by RemiD ( 20230413 );while on ground, press space to jump;while on air, hold altleft to slow down time Graphics3D( 640,480,32,2 ) Global Camera = CreateCamera()CameraRange( Camera, 0.1, 100 )CameraClsColor( Camera, 000, 000, 000 )PositionEntity( Camera, +25, 1.75, +10 ) : TurnEntity( Camera, 0,+90, 0 );PositionEntity( Camera, +0, 1.75, -5 );groundGlobal ground_mesh ground_mesh = CreateCube() : ScaleMesh( ground_mesh, 300.0/2, 0.1/2, 300.0/2) : PositionMesh( ground_mesh, 0, -0.1/2, 0 ) EntityColor( ground_mesh, 120, 120, 120 ) ;thingGlobal thing_rootGlobal thing_meshGlobal thing_on% : Const cground% = 1 : cair% = 2Global thing_jump% ;true or falseGlobal thing_movespeed#Global thing_jumpspeed#Global thing_flipspeed#Global thing_gravityspeed# thing_root = CreatePivot()thing_mesh = CreateCubicMan()EntityColor( thing_mesh, 240, 240, 240 )MoveEntity( thing_mesh, 0, +0.875, 0 )EntityParent( thing_mesh, thing_root, True ) ;delta coeffGlobal beforemilli%Global aftermilli%Global deltacoeff#Global framerate% ;the delay milli value to slow down the mainloop update renderGlobal delaymilli% = 0 ;max framerate Global maintimer = CreateTimer(60) Repeat  ;by default it is normal motion ;hold left alt key for slow motion delaymilli = 0 If( KeyDown(56)=1 )  delaymilli = 100 EndIf  ;wait x millis Delay(delaymilli)  ;get the milli time before the mainloop beforemilli = MilliSecs()  ;update tranforms ;check if thing is onground or onair If( EntityY(thing_root,True) <= 0.2 )  ;is on ground  thing_on = cground  PositionEntity( thing_root, EntityX(thing_root,True), 0, EntityZ(thing_root,True) )  ;RotateEntity( thing_mesh, 0, 0, 0, False )  thing_jumpspeed = 0  thing_gravityspeed = 0  thing_flipspeed = 0 Else  ;is on air  thing_on = cair EndIf  ;if on ground If( thing_on = cground )  ;hit space key to make the thing move and jump and flip  If( KeyHit(57)=1 )   ;reset thing position / orientation   PositionEntity( thing_root, 0, 0, 0 )   RotateEntity( thing_mesh, 0, 0, 0, False )   ;jump   thing_movespeed = 5.4   thing_jumpspeed = 0   thing_flipspeed = -82*2   thing_jump = True   MoveEntity( thing_root, 0, 0.22, 0 )  EndIf ;if onair Else If( thing_on = cair )  ;jumpspeed up  thing_jumpspeed = thing_jumpspeed + 0.5*2 : If( thing_jumpspeed => 5.4 ) : thing_jumpspeed = 5.4*2 : EndIf  ;gravityspeed down  thing_gravityspeed = thing_gravityspeed - ( 0.1635 *0.5  )  ;turn  TurnEntity( thing_mesh, thing_flipspeed*deltacoeff, 0, 0 )  ;move  MoveEntity( thing_root, 0, (thing_jumpspeed+thing_gravityspeed)*deltacoeff, thing_movespeed*deltacoeff ) EndIf  WireFrame(False) If( KeyDown(2)=1 )  WireFrame(True) EndIf  ;render SetBuffer( BackBuffer() )  RenderWorld()  ;debug infos     Text( 0, 0, deltacoeff ) Text( 0, 20, framerate )  ;display the result on the screen ;Flip(true) WaitTimer(maintimer) VWait():Flip(False)  ;get the milli time after the mainloop aftermilli = MilliSecs() ;calculate the deltacoeff ( = elapsed milli time / 1000 ) deltacoeff#= Float( aftermilli - beforemilli) / 1000 : If( deltacoeff < 0.0166 ) : deltacoeff = 0.0166 : EndIf  ;calculate the framerate FPS ( = 1.0 / deltacoeff ) framerate% = 1.0 / deltacoeff : If( framerate > 60 ) : framerate = 60 : EndIf       Until( KeyDown(1)=1 ) End() Function CreateCubicMan()  mesh = CreateMesh()  ;head tpart = CreateCube() : ScaleMesh( tpart, 0.25/2, 0.3/2, 0.3/2 ) : PositionMesh( tpart, 0, 0.625+0.3, 0 ) AddMesh( tpart, mesh ) : FreeEntity( tpart ) ;chest tpart = CreateCube() : ScaleMesh( tpart, 0.5/2, 0.55/2, 0.25/2 ) : PositionMesh( tpart, 0, 0+0.275, 0 ) AddMesh( tpart, mesh ) : FreeEntity( tpart ) ;hips tpart = CreateCube() : ScaleMesh( tpart, 0.56/2, 0.2/2, 0.31/2 ) : PositionMesh( tpart, 0, 0, 0 ) AddMesh( tpart, mesh ) : FreeEntity( tpart ) ;arms tpart = CreateCube() : ScaleMesh( tpart, 1.75/2, 0.2/2, 0.2/2 ) : PositionMesh( tpart, 0, 1.5-0.875, 0 ) AddMesh( tpart, mesh ) : FreeEntity( tpart ) ;legs  tpart = CreateCube() : ScaleMesh( tpart, 0.2/2, 0.8/2, 0.2/2 ) : PositionMesh( tpart, -0.15, 0-0.4, 0 ) AddMesh( tpart, mesh ) : FreeEntity( tpart ) tpart = CreateCube() : ScaleMesh( tpart, 0.2/2, 0.8/2, 0.2/2 ) : PositionMesh( tpart, +0.15, 0-0.4, 0 ) AddMesh( tpart, mesh ) : FreeEntity( tpart ) Return mesh End Function`
in this case the amplitudes of the turns, movements, are not altered.

#### RemiD

QuoteDid you have a look on my idea to manipulate the Millisecs()-timer?
i have missed your post, i will take a look, thanks