[SOLVED] adnzzzzZ windfield collision classes confusion

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.
User avatar
kuzika
Prole
Posts: 16
Joined: Tue Apr 21, 2020 3:58 pm

[SOLVED] adnzzzzZ windfield collision classes confusion

Post by kuzika »

pushstuff.png
pushstuff.png (85.33 KiB) Viewed 2970 times
Hi guys, I'm having some trouble understanding collision classes with a box2d physics library called windfield by adnzzzzZ.
github link:https://github.com/adnzzzzZ/windfield#create-a-world

The documentation says.
Capture collision events
Collision events can be captured inside the update function by calling the enter, exit or stay functions of a collider. In the example below, whenever the box collider enters contact with another collider of the Solid collision class it will get pushed to the right:

function love.update(dt)
...
if box:enter('Solid') then
box:applyLinearImpulse(1000, 0)
box:applyAngularImpulse(5000)
end
end

So basically what I want to do is switch animations to a pushing animation when the player is in contact with ObjectA pushable objects by switching the players state to "pushing" if the player collider is staying on contact with the box or pot of ObjectA class. I cant really seem to get the collision to check and when it does its only like for a mirco split second when I use the collider:enter("ObjectA") and it then skips to the walking state imedietly. Its a logical error so they syntax seems fine but the way i'm doing it must be wrong or something.

Firstly I set up a physics world called myWorld in main.lua line 4.

Code: Select all

wf = require("libs/windfield-master/windfield")
myWorld = wf.newWorld()
Second I declared some collision classes in object.lua line 2, the player is set up to ignore ObjectB type classes such as chairs but ObjectA type classes cannot overlap ObjectB such as a box can not be pushed over a chair. ObjectA class is what we want to check when we make contact and mostly if we are staying on this contact, this means the player.state should switch to "pushing".

Code: Select all

myWorld:addCollisionClass("ObjectA")
myWorld:addCollisionClass("ObjectB")
myWorld:addCollisionClass("Player", {ignores = {"ObjectB"}})
I defined the player collider in objects.lua line 36, its part of a large layer table because we are using "sti" simple tiled implementation to draw all instances on a special layer in between other layers that go over and under the player and instances.

Code: Select all

layer.player = {}
  layer.player.collider =  myWorld:newCircleCollider(
  player.x + player.width/2,
  player.y + player.height/2,
  player.width/3
  )
  layer.player.vx = 0
  layer.player.vy = 0
  layer.player.ox = player.width/2
  layer.player.oy = player.height/1.5
  layer.player.direction = "south"
  layer.player.state = "standing"
  layer.player.speed = 16*4
  layer.player.collider:setFixedRotation(true)
  layer.player.collider:setCollisionClass("Player") --player object ignores static objects
  layer.player.collider:setObject(layer.player)
Then in a layer.update(dt, self) function in object.lua line 115, I update the player state which should change to "pushing" when I am staying in contact with "ObjectA". at least thats how I interpreted the documentation. It glitches with enter but sort of works anyway this is where I am not to clear and probably where the logical error is.

Code: Select all

  --control player state
  if self.player.collider:stay("ObjectA") then
      self.player.state = "pushing"
  else
    if self.player.vx == 0 and self.player.vy == 0 then
      self.player.state = "standing"
    else
      self.player.state = "walking"
    end
  end
I have attached a full .love file with everything as it is up and running with windfield. There is a sprite sheet in the sprites folder called pushing_cycle.png, it is the animation that is supposed to switch to when the player is in contact with ObjectA. I am using LOVE 11.3 as of this post.
pushstuff.love
.love
(166.72 KiB) Downloaded 109 times
Last edited by kuzika on Wed May 06, 2020 2:16 pm, edited 1 time in total.
"kuzika" literally means "to burry"
User avatar
4vZEROv
Party member
Posts: 123
Joined: Wed Jan 02, 2019 8:44 pm

Re: adnzzzzZ windfield collision classes confusion

Post by 4vZEROv »

When I tried the windfield library I believe I also had some problems with the stay function, maybe it's a bug ?

I also made a box2d wrapper if you want to try it out (https://github.com/4v0v/physics).
User avatar
kuzika
Prole
Posts: 16
Joined: Tue Apr 21, 2020 3:58 pm

Re: adnzzzzZ windfield collision classes confusion

Post by kuzika »

4vZEROv wrote: Wed May 06, 2020 3:46 am When I tried the windfield library I believe I also had some problems with the stay function, maybe it's a bug ?

I also made a box2d wrapper if you want to try it out (https://github.com/4v0v/physics).
Great, I’ll implement your library and get back to you if there any problems. Thanks a lot.
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EDIT:
@4vZEROv
Everything is working fine except the actual collision checking, I'm not sure how to implement this code with your library. objects.lua line 119. It seems there is no stay equivalent, I'm thinking I should use postSolve or something but maybe you could clear this up for me.

Code: Select all

  if self.player.collider:stay("ObjectA") then
      self.player.state = "pushing"
  else
    if self.player.vx == 0 and self.player.vy == 0 then
      self.player.state = "standing"
    else
      self.player.state = "walking"
    end
  end
The documentation says something like this from the 4v0v/Physics wiki
set...()
collider:setEnter(function(shape1, shape2, contact, inverted) end)
collider:setExit(function(shape1, shape2, contact, inverted) end)
collider:setPresolve(function(shape1, shape2, contact, inverted) end)
collider:setPostsolve(function(shape1, shape2, contact, inverted, ...) end)
shape1(Shape): the Shape of the current Collider.
shape2(Shape): the Shape of the other Collider.
contact(Contact): Contact
inverted(boolean): if true then the first love.physics shape returned by Contact:getNormal() and Contact:getPositions() correspond to shape2 and the second to shape1.
...: normal_impulse1, tangent_impulse1, normal_impulse2, tangent_impulse2 (see the Notes part).
shape1 and shape2 are NOT love.physics shapes, they are Shapes.

return : self
Attached is the .love file with your library implemented. I commented out the if statement in objects.lua line 119.
pushstuff2.love
(176.74 KiB) Downloaded 114 times
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
SOLUTION:
pushstuff3.png
pushstuff3.png (85.72 KiB) Viewed 2869 times
As I thought it was postSolve to get it to work like a stay would. So I changed the code from object.lua line 119 to this after checking out Demo2 from the 4v0v/Physics library.

Code: Select all

  --control player state
  self.player.collider:setPostsolve(function(s1,s2)
      if s2:getClass() == "ObjectA" then
          self.player.state = "pushing"
      end
  end)
  if self.player.vx == 0 and self.player.vy == 0 then
    self.player.state = "standing"
  else
    self.player.state = "walking"
  end
Here is the fixed .love incase anyone comes across a similar problem with trying to check collision with a box2d physics wrapper for love 11.3.
pushstuff3.love
(176.74 KiB) Downloaded 108 times
Once again THANK YOU
Last edited by kuzika on Wed May 06, 2020 2:15 pm, edited 1 time in total.
"kuzika" literally means "to burry"
User avatar
4vZEROv
Party member
Posts: 123
Joined: Wed Jan 02, 2019 8:44 pm

Re: adnzzzzZ windfield collision classes confusion

Post by 4vZEROv »

Code: Select all

    
--outside layer.update
local player_is_pushing = false
layer.player.collider:setEnter(function(s1, s2, c, i)
    if s2:getClass() == "ObjectA" then
      player_is_pushing = true
    end
end)

layer.player.collider:setExit(function(s1, s2, c, i)
  if s2:getClass() == "ObjectA" then
    player_is_pushing = false
  end
end)

-- inside  layer.update
if self.player.vx == 0 and self.player.vy == 0 then
  self.player.state = "standing"
elseif player_is_pushing then 
  self.player.state = "pushing"
else
  self.player.state = "walking"
end
 
Something like that.
I made a wiki here : https://github.com/4v0v/physics/wiki if you didn't see it

Good to read : https://www.iforce2d.net/b2dtut/collision-anatomy

The presolve / Postsolve event are called every frames where 2 colliders are in contact.
Presolve before the physic is applied, postsolve after.
Last edited by 4vZEROv on Wed May 06, 2020 2:24 pm, edited 1 time in total.
User avatar
kuzika
Prole
Posts: 16
Joined: Tue Apr 21, 2020 3:58 pm

Re: [SOLVED] adnzzzzZ windfield collision classes confusion

Post by kuzika »

Hmmm, I think I prefer it with Postsolve since as you said it is called when 2 colliders are in contact and after the physics is applied.

Code: Select all

  --control player state
  self.player.collider:setPostsolve(function(s1,s2)
      if s2:getClass() == "ObjectA" then
          self.player.state = "pushing"
      end
  end)
  if self.player.vx == 0 and self.player.vy == 0 then
    self.player.state = "standing"
  else
    self.player.state = "walking"
  end
Still its good to know how it all works. Thanks to your awesome physics wrapper I can do some really complex collision checks. Thumbs up bro (or sis...).
"kuzika" literally means "to burry"
User avatar
4vZEROv
Party member
Posts: 123
Joined: Wed Jan 02, 2019 8:44 pm

Re: [SOLVED] adnzzzzZ windfield collision classes confusion

Post by 4vZEROv »

:setEnter/Exit/Postsolve/presolve must be called only when then collider is initialized.

Postsolve/Presolve are called once every frame, it's not a good idea to use it like a switch for your states.

Every callback function that you've setted is called inside 'myWorld:update(dt)'
So your code

Code: Select all

  if self.player.vx == 0 and self.player.vy == 0 then
    self.player.state = "standing"
  else
    self.player.state = "walking"
  end
override the comportement you've previoulsy setted.
User avatar
kuzika
Prole
Posts: 16
Joined: Tue Apr 21, 2020 3:58 pm

Re: [SOLVED] adnzzzzZ windfield collision classes confusion

Post by kuzika »

pushstuff5.png
pushstuff5.png (54.98 KiB) Viewed 2809 times
Thanks this is what worked for me.

player.lua 103

Code: Select all

  --outside update
  function player_state()
      p.player.collider:setEnter(function(s1,s2,c,i)
          if s2:getClass() == "ObjectA" and
          (p.player.vx > 0 or p.player.vy > 0)
          then
              p.player.state = "pushing"
          end
      end)
      p.player.collider:setExit(function(s1,s2,c,i)
          if s2:getClass() == "ObjectA" and
          (p.player.vx > 0 or p.player.vy > 0)
          then
              p.player.state = "walking"
          elseif p.player.vx == 0 and p.player.vy == 0 then
              p.player.state = "standing"
          end
      end)
      return p.player.state
  end
player.lua 75

Code: Select all

--inside player draw function
  local pose = sprites.stand_cycle 
    if player_state() == "pushing" then
      pose = sprites.player_pushing
    elseif player_state() == "walking" then
      pose = sprites.player_walking
    elseif player_state() == "standing" then
      pose = sprites.player_standing
    end
updated .love
pushstuff4.love
(179.05 KiB) Downloaded 107 times
"kuzika" literally means "to burry"
User avatar
4vZEROv
Party member
Posts: 123
Joined: Wed Jan 02, 2019 8:44 pm

Re: [SOLVED] adnzzzzZ windfield collision classes confusion

Post by 4vZEROv »

Code: Select all

  local pushing = false
  p.pushing = function()
    p.player.collider:setEnter(function(s1,s2,c,i)
        if s2:getClass() == "ObjectA" then
            pushing = true
        end
    end)
    p.player.collider:setExit(function(s1,s2,c,i)
        if s2:getClass() == "ObjectA" then
            pushing = false
        end
    end)
    return pushing
  end
Don't do that T_T

If you want to do the equivalent as :enter() :exit() :stay() you need to play with what is in the "world._collisions" table.
Also now that I see my code it look pretty bad. Maybe i'll try to implement those methods in the near future.
User avatar
kuzika
Prole
Posts: 16
Joined: Tue Apr 21, 2020 3:58 pm

Re: [SOLVED] adnzzzzZ windfield collision classes confusion

Post by kuzika »

Is this better? I used myWorld instead of the player collider to check setEnter and setExit. I think this is what you meant right?

Code: Select all

function player_state()
      myWorld:setEnter(function(s1,s2,c,i)
          if s2:getClass() == "ObjectA" and
          (p.player.vx > 0 or p.player.vy > 0)
          then
              p.player.state = "pushing"
          end
      end)
      myWorld:setExit(function(s1,s2,c,i)
          if s2:getClass() == "ObjectA" and
          (p.player.vx > 0 or p.player.vy > 0)
          then
              p.player.state = "walking"
          elseif p.player.vx == 0 and p.player.vy == 0 then
              p.player.state = "standing"
          end
      end)
      return p.player.state
  end
Also now that I see my code it look pretty bad. Maybe i'll try to implement those methods in the near future.
Hey man, don't say that. I've been trying out a bunch of box2d physics wrappers like breezefield and windfield mainly and even just pure love.physics on its own but your lib is probably the easiest to understand and best of all the collision actually works perfect, as far as I'm concerned this might be the best physics wrapper I've come across so far. I know it might have some bugs only you understand but no need to try to force in other methods like push() stay() exit() since already those methods where buggy in those other libraries in the first place.

And once again thanks for helping me, I was on the verge of giving up entirely until I discovered this library. So stay encouraged o.k.
"kuzika" literally means "to burry"
User avatar
4vZEROv
Party member
Posts: 123
Joined: Wed Jan 02, 2019 8:44 pm

Re: [SOLVED] adnzzzzZ windfield collision classes confusion

Post by 4vZEROv »

Ahah my code being bad is a fact, doesn't mean it does the job wrong.

The problem you raised, if I understand correctly is that atm i forces you to write game logic at 2 separate places:
-inside love.update()
-inside physic_world:enter/exit

I've made this decision because it's the box2d way (https://love2d.org/wiki/World:setCallbacks) but I understant the need of a enter() function to put inside love.update().

The enter() function should make you able to to check if a collider collide with a specific class, a specific collider or specific shape. In my code I already register every collision (in the world._collisions table) but only with ids so i need to change so that I can check the shapes/class/colliders.

As for you code it's still not good, I know you want to keep game logic at only one place but you currently cant .

Code: Select all

function love.load()
    world = Physics()

    world:setEnter(function() 
        --code
    end)

    world:setExit(function() 
        --code
    end)
end

function love.update(dt)
    world:update(dt)
end
Is what you code should look like, you don't want to change the callback functions every time you call your 'player_state()' function.
Post Reply

Who is online

Users browsing this forum: No registered users and 61 guests