Posted: 16th Feb 2021 2:56
I've been talking about this problem for a few days on discord, and blinkOk recommended me to make a thread about it

I have some problems with box2d physics

Moving the window or click on the title bar causes non-sleeping sprites to behave strangely
like here for example, where the sprite gains negative velocity and starts to jump.
https://streamable.com/czy5xi

+ Code Snippet
SetWindowTitle("Physics Test")
SetVirtualResolution(320, 180)
SetWindowSize(1280, 720, 0)
SetClearColor(151, 170, 204)
UseNewDefaultFonts(1)
SetPhysicsScale(0.2)
SetPhysicsGravity(0, 276)
SetSyncRate(0, 1)
spr = CreateSprite(0)
SetSpriteSize(spr, 25, 25)
SetSpritePositionByOffset(spr, GetVirtualWidth()/2, GetVirtualHeight()/2)
SetSpritePhysicsOn(spr, 2)
SetPhysicsSleeping(0)
do
    Print(ScreenFPS())
    Print(GetFrameTime())
    Sync()
loop

and notice that the framerate goes down when you move the window, this could be the cause of the problem

Here is another example where the ball loses speed when the window is moved
https://streamable.com/2nlbjs

+ Code Snippet
SetPrintSize( 40 )
SetVirtualResolution ( 320, 480 )
CreateSprite ( LoadImage ( "background3.jpg" ) )
LoadImage ( 1, "small_ball.png" )
CreateSprite ( 1, 1 )
SetSpritePosition ( 1, 0, 0 )
SetSpritePhysicsOn ( 1, 2 )
do
    Print(GetSpritePhysicsVelocityY(1))
    Sync()
loop


happens only in sprites that are not sleeping

I found a temporary solution to this, changing the update() to as fixed value, but this causes problems especially if the hardware running the game is unable to maintain 60fps
+ Code Snippet
#CONSTANT FIXED_FRAME_TIME 0.016667
Update(FIXED_FRAME_TIME)
render()
swap()

as seen here the sprite doesn't jump, and the problem is solved, but this has its bad parts, if the game is running at 30fps

https://streamable.com/bj081v

+ Code Snippet
#CONSTANT FIXED_FRAME_TIME 0.016667 

SetWindowTitle("Physics Test")
SetVirtualResolution(320, 180)
SetWindowSize(640, 360, 0)
SetClearColor(151, 170, 204)
UseNewDefaultFonts(1)
SetPhysicsScale(0.2)
SetPhysicsGravity(0, 276)
SetSyncRate(0, 0)
spr = CreateSprite(0)
SetSpriteSize(spr, 25, 25)
SetSpritePositionByOffset(spr, GetVirtualWidth()/2, GetVirtualHeight()/2)
SetSpritePhysicsOn(spr, 2)
SetPhysicsSleeping(0)

SetSyncRate(60, 1)
SetPrintSize(25)

fixed = 1
do
    print(ScreenFPS())
    print("Spr VY: " + str(GetSpritePhysicsVelocityY(spr)))
    if fixed = 1
        Update(FIXED_FRAME_TIME)
    else
        Update(0)
    endif
    render()
    swap()
loop



the cause of this may be because the game loses framerate when the top bar is clicked or moved as MadBit said here https://forum.thegamecreators.com/thread/219478?page=3#msg2662817
Posted: 16th Feb 2021 4:07
Here's my take. Others might know better or be able to explain better:

I found a temporary solution to this, changing the update() to as fixed value, but this causes problems especially if the hardware running the game is unable to maintain 60fps

Or call "StepPhysics(FIXED_FRAME_TIME)", which causes sync to not step the physics based on that frame's rate. By stepping the physics at a constant rate, you guarantee that the physics will behave the same no matter what the render frame rate is.

From the StepPhysics help page:
"Stepping the physics simulation by a large time value (greater than say 0.1) may result in undefined behaviour and physics objects moving through each other."
While the title is clicked, the box moves below the bottom of the window and gets a negative velocity to move it back up. GetFrameTime is limited to 0.2 seconds so it doesn't fly up when you hold the mouse button longer.

More from StepPhysics:
"By using a fixed time step every frame your physics will perform exactly the same across all devices and all frame rates, but a reduction in fps will result in the physics appearing to go slower, as it will always step the same amount of time whether the frame was quick or slow to draw. "

So you can try something like this to maintain a constant physics rate across FPS that are faster:
+ Code Snippet
#CONSTANT FIXED_FRAME_TIME 0.016667
lastStepTime as float = 0
do
	inc lastStepTime, GetFrameTime()
	if lastStepTime >= FIXED_FRAME_TIME
		// Only step once even if a lot of time has passed.
		while lastStepTime >= FIXED_FRAME_TIME
			dec lastStepTime, FIXED_FRAME_TIME
		endwhile
		StepPhysics(FIXED_FRAME_TIME)
	else
		// Enough time hasn't passed to step physics. StepPhysics(0) prevents Sync() from stepping the physics itself.
		StepPhysics(0)
	endif
    Print(ScreenFPS())
    Print(GetFrameTime())
    Sync()
loop

This separates the physics and rendering so that the box falls at the same rate at 60 FPS and 1000 FPS. 30 FPS will be half speed due to the fixed rate time value. Set your physics to the slowest your game should run, even if the render rate is faster.
Also, the physics and render rates don't have to match.
Posted: 16th Feb 2021 14:21
that is in fact a better solution than i have

however i cannot set the stephysics to 0.0333 (30fps), joints have many problems when running at low framerate, they just don't work

the joints start to break and do things they shouldn't, for example this
https://streamable.com/tjeoqh


definitely having a fixed value for step physics is the best idea, because SetSpritePhysicsmpulse depends entirely on the framerate
but unfortunately if the game is running at 30fps with fixed frametime of 60 everything is in slow motion
and I can't set the frametime to 30 because joints don't work at 30
Posted: 16th Feb 2021 14:42
Maybe try stepping physics twice with 0.016667 instead of once with 0.0333? Larger steps can become more erratic because objects can move farther during the larger time period.
Posted: 16th Feb 2021 15:26
but doesn?t that speed up physics more if the framerate is more than 30?

changing SetPhysicsGravity and SetPhysicsScale can fix this, i think
Posted: 16th Feb 2021 15:32
I think I have an idea
it is very unlikely that the game will run below 60fps regardless of the machine (if they are modern)

but if it runs lower, it will be at 30fps, for example on a laptop when the battery is not charging (for example, from HP), all games will be played at 30fps
so I can detect if the game is at 60 or 30 and change the times it passes through the stepphysics, if it's 30fps, do it 1 time, if it's 60fps, do it 2 times
Posted: 16th Feb 2021 15:37
Then you lose the benefits of a constant physics step.

+ Code Snippet
#CONSTANT RENDER_FRAME_TIME 0.03333
#CONSTANT PHYSICS_STEP 0.016667
lastStepTime as float = 0
do
    inc lastStepTime, GetFrameTime()
    if lastStepTime >= RENDER_FRAME_TIME 
        // Only step once even if a lot of time has passed.
        while lastStepTime >= RENDER_FRAME_TIME 
            dec lastStepTime, RENDER_FRAME_TIME 
        endwhile
        StepPhysics(PHYSICS_STEP)  // NOTE: Call this twice to make the physics run twice as fast while remaining constant among all FPS.
    else
        // Enough time hasn't passed to step physics. StepPhysics(0) prevents Sync() from stepping the physics itself.
        StepPhysics(0)
    endif
    Print(ScreenFPS())
    Print(GetFrameTime())
    Sync()
loop
Posted: 16th Feb 2021 16:08
now the physics are at the correct speed regardless of the framerate

but, sprites that use SetSpritePhysicsImpulse or SetSpritePhysicsVelocity stutter a lot, but it only happens if above 30fps.
Posted: 16th Feb 2021 17:47
it seems that the problem comes from here, the ViewOffset, that follows the character in the middle of the screen
this only happens above 30fps

+ Code Snippet
ProxX = GetSpriteX(2)
ProxY = GetSpriteY(2)
smooth = 0.1
if ProxY > GetVirtualHeight() * 0.5 then ProxY = GetVirtualHeight() * 0.5
SetViewOffset((GetViewOffsetX() + ((ProxX - (GetVirtualWidth()/2)) - GetViewOffsetX()) * smooth), (GetViewOffsetY() + ((ProxY - (GetVirtualHeight()/2)) - GetViewOffsetY()) * smooth))


changing the smooth variable to something smaller removes the stutter but stops following the character correctly
Posted: 16th Feb 2021 21:04
I'd have to see more complete code (a small example project) to see what I can figure out.
Posted: 17th Feb 2021 1:34
I made here an example of what is happening
+ Code Snippet
SetWindowTitle("Physics")
SetVirtualResolution(320, 180)
SetWindowSize(1280, 720, 0)
SetClearColor(151, 170, 204)
SetScissor(0, 0, 0, 0)
UseNewDefaultFonts(1)

SetSyncRate(60, 1)

SetPhysicsGravity(0, 276)
SetPhysicsScale(0.2)

CreateSprite(2, 0)
SetSpriteSize(2, 15, 30)
SetSpritePhysicsOn(2, 2)
SetSpritePhysicsCanRotate(2, 0)
SetSpritePosition(2, 150, 50)

createsprite(5, 0)
SetSpriteColor(5, 75, 90, 150, 255)
SetSpritePosition(5, 0, GetVirtualHeight()-50) 
SetSpriteSize(5, 20000, 50)
SetSpritePhysicsOn(5, 1)

#CONSTANT RENDER_FRAME_TIME 0.03333
#CONSTANT PHYSICS_STEP 0.016667

lastStepTime as float = 0
smooth as float
smooth = 0.1
global ProxX as float
global ProxY as float
do
    
	//Move
	if GetRawKeyState(KEY_D)
		SetSpritePhysicsVelocity(2, 100, GetSpritePhysicsVelocityY(2)) 
	elseif GetRawKeyState(KEY_A)
		SetSpritePhysicsVelocity(2, -100, GetSpritePhysicsVelocityY(2))
	endif

	//Jump
	if GetRawKeyPressed(KEY_W)
		SetSpritePhysicsImpulse(2, 0, 0, 0, -2200)
	endif
	
	
	ProxX = GetSpriteXByOffset(2)
	ProxY = GetSpriteYByOffset(2)
	if ProxY > GetVirtualHeight() * 0.5 then ProxY = GetVirtualHeight() * 0.5
	SetViewOffset((GetViewOffsetX() + ((ProxX - (GetVirtualWidth()/2)) - GetViewOffsetX()) * smooth), (GetViewOffsetY() + ((ProxY - (GetVirtualHeight()/2)) - GetViewOffsetY()) * smooth))
	//SetViewOffset(GetSpriteX(2), GetSpriteY(2))

    inc lastStepTime, GetFrameTime()
    if lastStepTime >= RENDER_FRAME_TIME
        // Only step once even if a lot of time has passed.
        while lastStepTime >= RENDER_FRAME_TIME
            dec lastStepTime, RENDER_FRAME_TIME
        endwhile
		StepPhysics(PHYSICS_STEP)
        StepPhysics(PHYSICS_STEP)  
    else
        // Enough time hasn't passed to step physics. StepPhysics(0) prevents Sync() from stepping the physics itself.
        StepPhysics(0)
    endif
    Print(ScreenFPS())
    Sync()
loop

#constant    KEY_D            68
#constant    KEY_W            87
#constant    KEY_A            65
Posted: 17th Feb 2021 2:25
Try moving all physics-related stuff into the block where the physics is stepped, and only call StepPhysics(PHYSICS_STEP) once.

+ Code Snippet
<snip>
direction as integer
jump as integer
do
	//Move
	if GetRawKeyState(KEY_D)
		direction = 1 // right
	elseif GetRawKeyState(KEY_A)
		direction = 2 // left
	endif
	//Jump
	if GetRawKeyPressed(KEY_W)
		jump = 1
	endif
	inc lastStepTime, GetFrameTime()
	if lastStepTime >= RENDER_FRAME_TIME
		if direction = 1
			SetSpritePhysicsVelocity(2, 100, GetSpritePhysicsVelocityY(2)) 
		elseif direction = 2
			SetSpritePhysicsVelocity(2, -100, GetSpritePhysicsVelocityY(2))
		endif
		direction = 0
		if jump = 1
			SetSpritePhysicsImpulse(2, 0, 0, 0, -2200)
		endif
		jump = 0

		// Only step once even if a lot of time has passed.
		while lastStepTime >= RENDER_FRAME_TIME
			dec lastStepTime, RENDER_FRAME_TIME
		endwhile
		ProxX = GetSpriteX(2)
		ProxY = GetSpriteY(2)
		SetViewOffset(ProxX - GetVirtualWidth() / 2,  ProxY - GetVirtualHeight() / 2)
		StepPhysics(PHYSICS_STEP)
	else
		// Enough time hasn't passed to step physics. StepPhysics(0) prevents Sync() from stepping the physics itself.
		StepPhysics(0)
	endif
	Print(ScreenFPS())
	Sync()
loop
<snip>
Posted: 17th Feb 2021 3:26
it's great now!! Thanks a lot for the help!
I am not seeing any problems so far.

if someone in the future has the same problem I will leave the code here with the complete solution
+ Code Snippet
SetWindowTitle("Physics")
SetVirtualResolution(320, 180)
SetWindowSize(1280, 720, 0)
SetClearColor(151, 170, 204)
SetScissor(0, 0, 0, 0)
UseNewDefaultFonts(1)

SetSyncRate(60, 1)

SetPhysicsGravity(0, 276)
SetPhysicsScale(0.2)

CreateSprite(2, 0)
SetSpriteSize(2, 15, 30)
SetSpritePhysicsOn(2, 2)
SetSpritePhysicsCanRotate(2, 0)
SetSpritePosition(2, 150, 50)

createsprite(5, 0)
SetSpriteColor(5, 75, 90, 150, 255)
SetSpritePosition(5, 0, GetVirtualHeight()-50) 
SetSpriteSize(5, 20000, 50)
SetSpritePhysicsOn(5, 1)

SetSyncRate(60, 1)

#CONSTANT RENDER_FRAME_TIME 0.03333
#CONSTANT PHYSICS_STEP 0.016667

lastStepTime as float = 0
smooth as float
smooth = 0.1
global ProxX as float
global ProxY as float
do
	
	// Move
	if GetRawKeyState(KEY_D)
		SetSpritePhysicsVelocity(2, 100, GetSpritePhysicsVelocityY(2)) 
	elseif GetRawKeyState(KEY_A)
		SetSpritePhysicsVelocity(2, -100, GetSpritePhysicsVelocityY(2))
	endif

	//Jump
	if GetRawKeyPressed(KEY_W)
		SetSpritePhysicsImpulse(2, 0, 0, 0, -2200)
	endif

    inc lastStepTime, GetFrameTime()
    if lastStepTime >= RENDER_FRAME_TIME
        while lastStepTime >= RENDER_FRAME_TIME
            dec lastStepTime, RENDER_FRAME_TIME
        endwhile

		ProxX = GetSpriteXByOffset(2)
		ProxY = GetSpriteYByOffset(2)
		if ProxY > GetVirtualHeight() * 0.5 then ProxY = GetVirtualHeight() * 0.5
		SetViewOffset((GetViewOffsetX() + ((ProxX - (GetVirtualWidth()/2)) - GetViewOffsetX()) * smooth), (GetViewOffsetY() + ((ProxY - (GetVirtualHeight()/2)) - GetViewOffsetY()) * smooth))

		StepPhysics(PHYSICS_STEP)
        StepPhysics(PHYSICS_STEP)  
    else
        // Enough time hasn't passed to step physics. StepPhysics(0) prevents Sync() from stepping the physics itself.
        StepPhysics(0)
    endif
    Print(ScreenFPS())
    Sync()
loop

#constant    KEY_D            68
#constant    KEY_W            87
#constant    KEY_A            65
Posted: 17th Feb 2021 6:23
Glad it's working for you now.
Posted: 4th Mar 2021 14:58
is it possible to change RENDER_FRAME_TIME and PHYSICS_STEP to higher values ??for the physics to be smoother?
I have tested with some values ??but with no good results

the way it is, the physics are always locked at 30fps, which is good because it solved the previous problem.
But sprites with physics are not as smooth as sprites that have no physics

and I found that joints don't have the same behavior that they do at 60fps
joints at 30fps don't work very well
Posted: 6th Mar 2021 20:35
I haven't messed with the sprite physics much more than I have for this thread. I think you can try out whatever values you want to determine what works best for you.
Posted: 22nd Mar 2021 19:19
I will leave this in this Thread, in case someone in the future has this problem

I found that this can also solve the problem of physics that behaves strangely when the window moves

if GetFrameTime() > 0.1 then StepPhysics(0)

but it will not make physics independent of the framerate, for that I recommend the adambiser solution