Coding friction without love.physics

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Pardaleco
Prole
Posts: 10
Joined: Mon Dec 31, 2018 7:12 pm

Coding friction without love.physics

Post by Pardaleco »

Hello everyone!

In my code for friction, there's is a small issue that I'm not sure how to fix efficiently.
It does what it is supposed to do, it creates a force with a given magnitude and opposite direction to the motion.

The problem is that when my player starts decelerating and the velocity is very close to zero, it never really stays at zero w it becomes negative and then positive again alternating between the two every new tick, resulting in very small movements in the player when he should be stopped.

This happens because of the way I coded the

Code: Select all

local friction = vector2.mult(player.velocity, -1)
. How can I make the layer stop completely?

This is my code for the player:

Code: Select all

-- everything player related

player = {
position = vector2.new(100, 800-(304+65)),
velocity = vector2.new(0, 0),
width = 30,
height = 65,
maxspeed= vector2.new(400, 800),
frictioncoefficient = 400,
--maxspeedair = vector2.new(50,800),
mass = 1,
onGround = false
}

function UpdatePlayer(dt)
  
  print(player.velocity.x)
  local acceleration = vector2.new(0, 0)
  local gravity = vector2.new(0, 1000)

  acceleration = vector2.applyForce(gravity, player.mass, acceleration) -- applying gravity to the player

  
  local friction = vector2.mult(player.velocity, -1) -- The problem comes from here
  friction = vector2.normalize(friction)
  friction = vector2.mult(friction, player.frictioncoefficient)
  acceleration = vector2.applyForce(friction, player.mass, acceleration) -- applying friction to the player
  
  
  local movedirection = vector2.new(0, -1)
  
--Movement imput start

  if love.keyboard.isDown("right") then

    local move = vector2.new(1600, 0)
    acceleration = vector2.applyForce(move, player.mass, acceleration)
    movedirection.x = 1
    
  end

  if love.keyboard.isDown("left") then
    local move = vector2.new(-1600, 0)
    acceleration = vector2.applyForce(move, player.mass, acceleration)
    movedirection.x= -1
  end
  
  if (player.onGround) then 
    if love.keyboard.isDown("up") then
      
      local jump = vector2.new(0, -40000)
      acceleration = vector2.applyForce(jump, player.mass, acceleration)
      movedirection.y = 1
      player.onGround = false
     
    end
  end


-- MOvement input end



  local futurevelocity = vector2.add(player.velocity,vector2.mult(acceleration, dt))
  futurevelocity = vector2.limit(futurevelocity, player.maxspeed.x)
  local futureposition = vector2.add(player.position,vector2.mult(futurevelocity, dt))
  acceleration = CheckCollision(world, futureposition, movedirection, acceleration)



  player.velocity = vector2.add(player.velocity, vector2.mult(acceleration, dt))
  
  if player.onGround == true then
    player.velocity = vector2.limit(player.velocity, player.maxspeed.x)
  else
    --player.velocity = vector2.limit(player.velocity, vector2.magnitude(player.maxspeed))
    if player.velocity.x > 400 then
      player.velocity.x = 400
    elseif player.velocity.x < -400 then
      player.velocity.x = -400
    end
  end
  
  player.position = vector2.add(player.position, vector2.mult(player.velocity, dt)) -- Player movement


-- Player collision with edges of the window start

  if (player.position.x > love.graphics.getWidth() - player.width) then 
    
    player.position.x = love.graphics.getWidth() - player.width
    player.velocity.x = (player.velocity.x * -1) / 2

  elseif (player.position.x < 0) then
    player.position.x = 0
    player.velocity.x = (player.velocity.x * -1) / 2

  end

  if (player.position.y > love.graphics.getHeight() - player.height) then
    player.position.y = love.graphics.getHeight() - player.height
    player.velocity.y = 0
    player.onGround = true
  end
  
  -- Player collision with edges of the window end

end

function DrawPlayer()
  love.graphics.rectangle("fill", player.position.x, player.position.y, player.width, player.height)
end



-- Player collisions start


function CheckCollision(world, futureposition, movedirection, acceleration)
  for i = 1, table.getn(world), 1 do
    local collisiondir = GetBoxCollisionDirection(futureposition.x, futureposition.y, player.width, player.height, world[i].position.x, world[i].position.y, world[i].size.x, world[i].size.y)
    --print(collisiondir.x .. " " .. collisiondir.y)
    if (collisiondir.x ~= 0 or collisiondir.y ~= 0) then
      if collisiondir.y == movedirection.y then --down collision
        player.velocity.y = 0
        acceleration.y = 0
        player.onGround=true
      elseif collisiondir.y == 1 then --up collision
        player.velocity.y = 0
        acceleration.y = 0
      elseif movedirection.x ~= collisiondir.x then --side collision
        player.velocity.x = 0
        acceleration.x = 0
      end
    end
  end
  return acceleration
end 

function Death()
  if Collided_with_enemy then
    love.graphics.print("GAME OVER", 700, 400)
    
  end
end
All the vector2 functions I'm using come from this code that allows me do operate with vectors

Code: Select all

-- All vector operations I'll use


vector2 = {}

function vector2.new(px,py)
  return {x = px, y = py}
end

function vector2.add(vec, inc)
  local result = vector2.new(0,0)
  result.x = vec.x + inc.x
  result.y = vec.y + inc.y
  return result
end 

function vector2.sub(vec, dec)
  local result = vector2.new(0,0)
  result.x = vec.x - dec.x
  result.y = vec.y - dec.y
  return result
end

function vector2.mult(vec, n)
  local result = vector2.new(0,0)
  result.x = vec.x * n
  result.y = vec.y * n
  return result
  end

function vector2.div(vec, n)
  local result = vector2.new(0,0)
  result.x = vec.x / n
  result.y = vec.y / n
  return result
end

function vector2.magnitude(vec)
  local magnitude
  magnitude = math.sqrt(vec.x^2 + vec.y^2)
  return magnitude
end

function vector2.normalize(vec)
  local mag = vector2.magnitude(vec)
  if mag ~= 0 then
    return vector2.div(vec,mag)
  else
    return vec
  end
  end


function vector2.limit(vec, max)
  local result = vec
  if vector2.magnitude(vec) > max then
    result = vector2.normalize(vec)
    result = vector2.mult(result, max)
  end
  return result
end

function vector2.applyForce(force, mass, accelaration)
  local f = vector2.div(force, mass)
  return vector2.add(accelaration, f)
end
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Coding friction without love.physics

Post by ivan »

Hello Pardaleco,
You are dealing with a common issue here.
One thing I would like to point out is that what you are simulating here is more like "damping" rather than friction.
Note that there are well established formulas for damping, for example: https://2dengine.com/?p=platformers#Damping
There are solutions for the "velocity coming very close to zero" issue too.
One approach that Box2D uses is that when the velocity drops under a certain threshold the body is considered to be "sleeping".
So basically you can check and clamp the vector if "vector2.magnitude(velocity) < minVelocity then velocity.mult(0)
Your code doesn't look too bad so I'm sure you will figure it out.
Good luck!
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 148 guests