slow motion / bullet time concepts

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

Previous topic - Next topic

RemiD

hi :)

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

i have found this article :
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 :
https://www.syntaxbomb.com/miscellaneous/bb-speed-of-the-turnsmovesanimations-automatically-adjusted-to-appear-constant-w/msg11988/#msg11988

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 factor
End funtion
 

Example:
Graphics 800,600
Global SloMo:Double=1
Global X:Int, Y:Double
Global Time:Int
Repeat
    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 0
Until AppTerminate()

Function MyMillisecs:Int()
    Return MilliSecs()/SloMo
End 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.0
if( keydown(57) = 1 )
  motioncoeff = 0.1
endif

turnentity( 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 )

;ground
Global 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 )
 
;thing
Global thing_root
Global thing_mesh
Global thing_on% : Const cground% = 1 : cair% = 2
Global thing_jump% ;true or false
Global 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 coeff
Global beforemilli%
Global aftermilli%
Global deltacoeff#
Global framerate%
 
;the delay milli value to slow down the mainloop update render
Global 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  :)