Page 1 of 2

How to calculate physical stats for a platformer game

Posted: Wed Nov 20, 2019 3:20 pm
by ilovelove2019
Hello everyone, I am in need of your help. I am trying to make a platform game with windfield. And I have difficulty with the physical index. I don't know how to calculate physics properly, or just relatively for my game, like the popular platformer games today. I do not know the gravity of the world, the force appliedForce (?,?). Sorry, my English is too poor and I don't know how to express it. My specific case is that the player is 24 pixels high and 16 pixels wide. Can everyone align me with some perfect stats? More specifically, it is world: setGravity (0,?). When I want the player to move right, left and jump, what is the force of applyForce (?,?). It would be great if you showed me how to calculate on a case-by-case basis so that I can later align (such as a character jumping 2 times his height or even 3?). The problem I need to solve is the index I leave the '?' suitable for a game platformer with a character 24pixel high and 16 pixels wide. Sorry my question was stupid and disturbed your valuable time. Hope you help me solve this problem. Thank you very much. Thank you.

Re: How to calculate physical stats for a platformer game

Posted: Wed Nov 20, 2019 3:55 pm
by ivan
I wrote a calculator that can find the missing constants for you:
https://2dengine.com/?p=platformers#Calculator
Note that you need to input at least 2 of the following 4 constants: jump height, gravity, initial velocity and time to apex.
The jump height you already know to be 24*2 (ideally you want to convert that to meters).
On planet earth gravity is ~9.8 m/s^2 so you can input that too if you want to be realistic.
The other 2 variables will be solved for you.
Once you know the initial velocity then you can find the force as follows: force = (velocity/time)*mass
Also, don't use damping or the formulas won't work.

Re: How to calculate physical stats for a platformer game

Posted: Wed Nov 20, 2019 4:35 pm
by pgimeno
I don't think the character is 24 m high though, and since gravity is in m/s² the length units need conversion. The actual value to enter also depends on the metre length (the value you set with love.physics.setMeter), which in turn depends on the actual height of the character. So:
  • Determine how high your character would be in m, if it was real. 1.70m is a good average height, if your character looks like a normal person. But given its width vs height ratio, I'd say it's shorter.
  • Use Windfield functions? to set the setMeter value (I don't know if it supports this) to 24 / height. This value is in pixels/metre. If it doesn't allow you, I expect that you can use love.physics.setMeter directly.
  • Use that value to calculate every conversion of metres to pixels and vice versa. Always use the same units when using Ivan's calculator (either m, m/s, m/s², s or px, px/s, px/s², s).
  • Use Ivan's calculator.
  • If necessary, convert the result back so that length units are in px and enter it. I'm assuming that Windfield expects gravity values in px/s² just as love.physics.newWorld does, and forces in kg*px/s². Check the Windfield docs to be sure.
  • Also assign a mass to your character and set its density accordingly!
I haven't used Windfield so I don't know if it will work well.

Edit: Note though that platformers are rarely physically realistic (there are a few exceptions like Flashback and Prince of Persia). If you're after something like that, then sure, try to refine the physics to adapt them to the real world. If not, just play with the values until they look right to your game.

Re: How to calculate physical stats for a platformer game

Posted: Wed Nov 20, 2019 10:47 pm
by ilovelove2019
Yes, I am trying. My game doesn't need physics to be complete, I just need it like some popular platformer games today. I think I will leave the default of one meter equal to 30 pixels. I want the character to jump 3 times in height. So I have to fill in the computer of ivan the jump height is (24/30 * 3 = 2.4)? Is it right? And the gravity box I still have is 9.8? I don't need physics so right, I just need to index the character left and right proportionally and jump 3 times its height. If you look at the index in my file, I don't know why it is so big and it looks weird. Because I just tried refining the index, please understand because I haven't completed the jump method. Besides, I also want to disable acceleration, I want to play basic game, but I don't know how. It would be great if it could be adjusted so that the acceleration x is small and can limit the player's maximum speed x.

Re: How to calculate physical stats for a platformer game

Posted: Thu Nov 21, 2019 3:02 am
by pgimeno
So, your character is 80 cm tall, and your conversion factor is 30 px/m.

Now, 9.8 m/s² = (9.8m/1s²)*(30px/1m) = 294 px/s². That's the value to enter in love.graphics.newWorld (or in world:setGravity).

About jumps: ivan's calculator returns an initial velocity of ~6.8586 m/s, i.e. ~205.758 px/s. Now you have a little problem: there's no function to add that vertical velocity directly. Your options are applyForce, applyLinearImpulse and setLinearVelocity.

applyForce divides the acceleration to apply, by the mass of the body, so you have to compensate for the mass in order to apply an acceleration. But you don't want to apply an acceleration, you want to apply a velocity. The acceleration determines how much velocity will be added after 'dt' seconds have passed, therefore in order to apply a specific velocity, you need to know in advance the dt that will be applied in the next world:update(dt) to compensate for that. In your example, you're applying the jump in love.keypressed, therefore you don't even have dt. I don't recommend this approach.

applyLinearImpulse divides the value by the mass of the body to obtain the velocity to apply, so you can compensate by multiplying it by the mass. This is a possibility.

setLinearVelocity can't be used directly, because you need to set both horizontal and vertical components. But you can retrieve the current velocity, add the values, and set the new one, so this option is not off the table. It has the additional advantage that you can easily set, rather than add to, the current vertical velocity.

My recommendation is to use applyLinearImpulse(0, getMass*-205.758).

Tried that in your world. I don't know much about Windfield, but apparently it gives you the actual world and bodies. Edited main.lua follows. I've moved setMeter before newWorld which is where it should be, even if it doesn't make a difference in this case. I've added a rectangle with the desired height for reference. The actual height seems to be a wee bit short, not sure if that's a miscalculation, rounding errors, or internal precision of Box2D.

Code: Select all

function love.load()
    Object = require'classic'
    anim8 = require 'anim8'
    love.graphics.setDefaultFilter('nearest', 'nearest')
    Camera = require "Camera"
    camera = Camera()
    --camera:setFollowStyle('PLATFORMER')
    camera:setFollowStyle('SCREEN_BY_SCREEN')
    camera.scale = 1
    ---- physics library
    wf = require 'windfield-master/windfield'
    love.physics.setMeter(30)
    world = wf.newWorld(0, 0, true)
    world:setGravity(0, 294)
    ---add player
    require 'player'
    player = Player(400, 300)
    -- add some platforms
    require 'block'
    block = Block(0, 500.5, 1000, 30)
end

function love.keypressed(key)
    if key == 'w' then
--        player.collider:applyForce(0, -10000)
        --local x, y =player.collider:getLinearVelocity()
        --player.collider:setLinearVelocity(0, y-205.758)
        player.collider:applyLinearImpulse(0, player.collider:getMass()*-205.758)
    end
end

function love.update(dt)
    camera:update(dt)
    camera:follow(player.x + player.width / 2, player.y + player.height / 2)
    player:update()
    --- update physics
    world:update(dt)
end

function love.draw()
  camera:attach()
    player:draw()
    block:draw()
    world:draw()
  camera:detach()
  camera:draw()
  love.graphics.rectangle("line", 300.5, 500.5-24*3, 17, 24*3-1)
  love.graphics.rectangle("line", 300.5, 500.5-24*2, 17, 24)
end

Re: How to calculate physical stats for a platformer game

Posted: Thu Nov 21, 2019 4:04 am
by ilovelove2019
Reasonable. Your answer is very detailed, I took out my calculator, paper and pen and thought about it, each of your explanations, it was like a lecture, very rewarding. I agree with the use of 'applyLearearImpulse'. And now I have to handle the x speed, when the player holds the key, the speed increases and reaches very fast after a short time. I want to disable acceleration, so the velocity x is immutable. Or still apply it but is there any way to limit the maximum speed or not? I briefly thought about self.collider: setX (self.collider: getX () + self.vx) with self.vx is a constant value, but seems to be ineffective, whether this will probably cause the player be teleported and the next collision will cause many errors? In short, I need to find a way to limit the speed or disable the acceleration of x, hope you can solve it for me. Thank you so much for all.

Re: How to calculate physical stats for a platformer game

Posted: Thu Nov 21, 2019 6:05 am
by ivan
applyForce divides the acceleration to apply, by the mass of the body, so you have to compensate for the mass in order to apply an acceleration.
The problem with applyForce is illustrated by the formula:
force = acceleration*mass
acceleration = change in velocity/time
where "time" is the amount of time your feet are pushing against the floor.
We don't use applyForce for jumping because Box2D is frame-based.
If you use applyForce it will work as thrust which is not what you want for jumping.
applyLinearImpulse divides the value by the mass of the body to obtain the velocity to apply, so you can compensate by multiplying it by the mass. This is a possibility.
You got it. Impulses are basically instant changes in velocity:
impulse = change in velocity*mass
Where the "change in velocity" is usually the same as the "initial jump velocity"
setLinearVelocity can't be used directly
It could as long as you preserve the X-component.
The actual height seems to be a wee bit short, not sure if that's a miscalculation, rounding errors, or internal precision of Box2D.
One of the problems is "world:update(dt)". You will never catch the apex of a jump on screen unless you use a constant time step.
Also, as mentioned in the link I posted "if the initial jump velocity is not a multiple of gravity the maximum height is reached between frames"

Re: How to calculate physical stats for a platformer game

Posted: Thu Nov 21, 2019 11:28 am
by pgimeno
ivan wrote: Thu Nov 21, 2019 6:05 am
applyForce divides the acceleration to apply, by the mass of the body, so you have to compensate for the mass in order to apply an acceleration.
The problem with applyForce is illustrated by the formula:
force = acceleration*mass
Sorry about the poor wording. I'm aware of the formulas behind, I was just trying to put it in simple terms, but I'm afraid I made it more confusing. I meant that the acceleration applied to the body is the value passed to applyForce divided by the mass, therefore you need to compensate it by multiplying it by the mass, and you still get acceleration, which is not so useful as you and I explained.

Re: How to calculate physical stats for a platformer game

Posted: Thu Nov 21, 2019 11:52 am
by pgimeno
ilovelove2019 wrote: Thu Nov 21, 2019 4:04 am In short, I need to find a way to limit the speed or disable the acceleration of x, hope you can solve it for me. Thank you so much for all.
Just ceasing to apply force or impulse is not a good idea, because then the character is subject to friction and the velocity can decrease. There are several other ways.

One trick to achieve this is by applying a simplified model of drag: a force proportional to the velocity and opposed to it: applyForce(-getLinearVelocity*k) (in practice, do it component by component). This results in a terminal velocity, but I don't know the formula to obtain it, therefore you can play with the constant k to find an acceptable value.

Another way is to use getVelocity(), clamp it, and then use setVelocity(). This will probably look less realistic.

Re: How to calculate physical stats for a platformer game

Posted: Thu Nov 21, 2019 10:11 pm
by ilovelove2019
Yes, it is also a very effective solution. Now I realize that, for simple platformer games, you should not use windfield because it is quite complicated and unnecessary. In your experience, which physical library should I use?