mcfly

Another collision detection discussion

Recommended Posts

Hi all,

I'm new to Pixi.js, so excuse me, if the answer to my question is obvious.

I'm building a 2d platformer where I have a PIXI.Container which contains a few sprites (let say player's arm, body, head etc.).

Based on the user input I'm moving the whole container (not each sprite individually). I also have container which contains all platforms of the level (they are all of type PIXI.Spirte).

I want to detect when the player's container intersects with any of the platforms and stop the container from moving forward (the usual stuff).

Currently I'm using the Bump.js library (https://github.com/kittykatattack/bump). But I'm encountering few problems.

First of all Bump.js doesn't work for 'container vs array with sprites' type of collision, so I've tried to detect an intersection between each player's sprite against the array with platforms. Basically I'm using the following:

player.move(); // move the player's container to any direction
BUMP.hit(playersArm, platformsArray, true, false, true);
BUMP.hit(playersBody, platformsArray, true, false, true);
BUMP.hit(playersHead, platformsArray, true, false, true);

This is testing for intersection between each player's sprite and stops it from moving, if there is a collision. All this is working fine and if there is an intersection the intersecting player's sprite position will be set to a value that is not intersecting with the platforms. However all the other sprites will continue moving, as they are not yet intersecting with the platforms. Hope I expressed myself clear.

Have you ever had such problem and how did you solve it? I can only think of building a custom collision detection logic which works with 'container vs array with sprites', so I don't have to care for each player's sprite individually, but work with the container. Do you know of any library that already handled such cases?

Or maybe I've been wrong from the start by taking such approach (having player's container with several sprites in it)?

Thank you in advance.

Share this post


Link to post
Share on other sites

In general:

Its not obvious , because you are basically making simple arcade phys engine, and PixiJS has only a few functions that you can rely on for it: "getBounds()", "containsPoint()", "contains()"  (that one is about Point but for shapes), and when you look inside element you have to dig out its geometry, its difficult to produce readable code because of that. 

We are only a renderer lib - we dont know what people want from their physics. We dont have enough expertise to provide physics for newbies, we are all about graphics.

Some people integrate existing libs like "p2.js" or "matter.js" with pixi and the result is awesome - when you do that means you know pixi on a good level. 

Sadly, we still dont have docs about it because people who did that before mostly kept it to themselves. I'm working on a article that explains that but i cant share it yet. 

All we have are threads in this subforum that are difficult to search but they contain simple physics, and I cant say that code is readable. I've spent many hours helping people to fix solutions that they wanted for their games.

 

Your case:
Lets see https://github.com/kittykatattack/bump/blob/master/src/bump.js#L1350

First that I see is it spawns many functions , and you call it several times in a frame - it can be a performance problem in case of 100 and more sprites.

I suggest to copy that lib locally and change it the way you need.

Share this post


Link to post
Share on other sites

@ivan.popelyshev, I understand that PIXI is used for rendering only. I don't expect it to have built-in physics methods. I was trying to understand if I'm doing something wrong, as I'm sure a lot of people has encountered the same problem. Thank you for your detailed explanation. I'll definitely wait for the article you've mentioned.

@bubamara, thank you too for your suggestion.

I'll try to work something out of both your suggestions.

Share this post


Link to post
Share on other sites
15 minutes ago, mcfly said:

I was trying to understand if I'm doing something wrong, as I'm sure a lot of people has encountered the same problem. 

I'll try to work something out of both your suggestions.

Yep, you've got it right.

I can also recommend to watch out for "width" in containers with children, its a tricky calculated value.

"getBounds().width" is fine, "sprite.width" is fine when sprite has no children. And at some point if you have many objects you'll see major garbage collecting when you profile app, and you'll have to remove extra object creations.

Also watch out that "getBounds()" and "containsPoint()" are the only things that returns global (screen) coords, everything else is local stuff, you have to be aware in which coord system they work.

Share this post


Link to post
Share on other sites

You also have perfect timing. I'm gonna add physics in the list of my specialisations in pixijs team, so I'm ready to help people more on this subject. ITs like "ok, I solved most of Filter-related problems that people have, whats next" :)

If you do something and it doesnt (or does) work please share, I'll help to find bugs.

Share this post


Link to post
Share on other sites

I use MatterJS with Pixi, and it's great. PlanckJS is a good choice too.

However... physics libraries are a potential rabbit hole. The demos you see on the library sites work flawless, but as soon as you realise you need to do something for which there isn't an example or there's no documentation, you can find yourself in a pitch-battle with the engine. The devil is in the details!

So, my advice is, go as far as you can with 2D arcade collision, and only move to physics library if absolutely have to do a detailed physics simulation (like a pinball machine.)

Share this post


Link to post
Share on other sites

Just for reference, here's my current MatterJS/Pixi render loop. The most import thing is that every of the matter body needs a reference to its matching Pixi sprite. Something like this:

body.sprite =yourPixiSprite;

And the Pixi sprites need their anchors set to 0.5

body.sprite.anchor.set(0.5);

Then you can run this in your game loop to sync the body and sprite positions:

  let bodies = MATTER.Composite.allBodies(engine.world);

  for (let i = 0; i < bodies.length; i++) {
    let body = bodies;
    //Non-compound bodies
    if (body.sprite) {
      body.sprite.x = body.position.x;
      body.sprite.y = body.position.y;
      body.sprite.rotation = body.angle;
    } else {
      //Compound bodies (In MatterJS compound bodies can only be one level deep, so no need for recursion)
      if (body.parts.length > 1) {
        for (let j = 0; j < body.parts.length; j++) {
          let childBody = body.parts[j];
          if (childBody.sprite) {
            childBody.sprite.x = childBody.position.x;
            childBody.sprite.y = childBody.position.y;
            childBody.sprite.rotation = childBody.parent.angle ;           

            //Or, I'm not sure if this last line might be more correct - I'm still testing:

           //childBody.sprite.rotation = childBody.parent.angle + childBody.angle;
          }
        }
      }
    }

Share this post


Link to post
Share on other sites

Thanks for that, I have something similar, not tidied it up yet so this is really useful

Once I got the Matter canvas to sit on top of the pixi stuff it got a lot easier to figure out.

I can now draw shapes in PIXI using PIXI.graphics and have them controlled by Matter.

In this quick test I have a PIXI sprite with a PIXI graphic drawn on it. All the red shapes in the image are PIXI graphics which become Matter bodies (the white lines are the Matter canvas overlay)

Lots of potential :)

 

Screenshot 2019-11-07 at 17.25.52.png

Share this post


Link to post
Share on other sites
On 11/7/2019 at 2:17 AM, macshemp said:

@d13 thanks for taking the time to reply.

Decided to go with MatterJS as it seemed more friendly. :)

I would say do your due diligence with MatterJS. I originally was going to use it but then abandoned it due to inconsistent behavior and you cannot (or rather I could not figure out how to) project trajectories with accuracy. I actually figured out how to mostly do it, but there was still a constant value multiplier off. That was unsettling to me.

For reference

https://github.com/liabru/matter-js/issues/768

https://github.com/liabru/matter-js/issues/767

 

Share this post


Link to post
Share on other sites

@mobileben - I did see your issues on the matter-js when i started looking, which is why I also looked at PlanckJS. Did you find box2d to be more consistent overall?

I guess the pixel coordinates in MatterJS were more appealing on first glance than having to convert everything to the box2d world space.

What port of box2d do you use as there seemed to be quite a few, was it PlanckJS? 

Thanks

Share this post


Link to post
Share on other sites

@macshemp, I'm using this version, as I'm using Typescript. Although it is possible it is now a dead project (see my issues). https://github.com/flyover/box2d.ts

My issues are minor and more about some incompleteness in the interface. It is possible once I finish up this prototype that I make my own fork and mod it some.

I have, however, found it to be stable and what I would deem as accurate (enough). Those tests I ran in my matterjs were tested against this version of box. I also compared "theoretical" trajectory with actual, and unlike matterjs, the box2d ones were "accurate". While I initially liked matter ... I now really like Box2D. It has some minor quirks, but it works well.

I also did what you did ... didn't want to bother with the conversion of pixel to metric and vice versa. However, it is easy to work with. I use game objects with a gfx and physics property, where gfx is the PIXI graphics object (well my wrapped version of it) and physics is a wrapper to Box2D.

I have a PhysicsManager which also has some methods for the conversion. Snippet look like this:

get ppm(): number {
    return this._ppm;
}

set ppm(val: number) {
    this._ppm = val;
    this._ppmInv = 1.0 / val;
}

get ppmInv(): number {
    return this._ppmInv;
}

scalarToPhysicsWorld(s: number): number {
    return s * this._ppmInv;
}

pointToPhysicsWorld(pos: Point): Point {
    return { x: pos.x * this._ppmInv, y: pos.y * this._ppmInv };
}

scalarFromPhysicsWorld(s: number): number {
    return s * this._ppm;
}

pointFromPhysicsWorld(pos: Point): Point {
    return { x: pos.x * this._ppm, y: pos.y * this._ppm };
}

 

And in my GameObject update code I do the following

if (this._physics && this._gfx) {
    // If we have both physics and gfx, update the gfx based on our physics
    const pos = this._physics.position;
    this._gfx.setPosition(pos);
    // Use rotation because this is in radians
    this._gfx.setRotation(-this._physics.rotation);
}

You may need to drop that negative rotation I'm doing.

Oh, yeah, on the PhysicsObject, the position code looks like

get position(): Point {
    const pos = this.body.GetPosition();
    return { x: PhysicsManager.shared.scalarFromPhysicsWorld(pos.x), y: PhysicsManager.shared.scalarFromPhysicsWorld(pos.y) };
}

So essentially I treat everything that doesn't have a special naming to it as "game space". So, box2D lives in "Physics" space. And actually, PIXI lives in Screen space. My game space is cartesian coords with center in the middle of the screen.

Forgive any nastiness with the code, I'm a C++ guy that's on the learning curve of Typescript.

Share this post


Link to post
Share on other sites

@mobileben Thanks for the detailed post, appreciate it.

A lot of really useful stuff here for me to digest. I'm still at the "R&D" stage so will definitely take some time to delve deeper into box2d.

 

Cheers

Share this post


Link to post
Share on other sites

Here's the demo for Pixi & P2 & PhysicsEditor: https://codesandbox.io/s/app-architecture-3-j0di5

Part of update determines whether we need to copy pixi filelds to physics or vice-versa. If pixi position was changed -> copy from pixi.


    if (this._memLocalId !== display.transform._localID) {
      this.previousPosition[0] = this.position[0] =
        -display.position.x * PIXEL_TO_METER;
      this.previousPosition[1] = this.position[1] =
        -display.position.y * PIXEL_TO_METER;
      this.previousAngle = this.angle = display.rotation;
      this.wakeUp();
    } else {
      display.position.set(
        -this.interpolatedPosition[0] * METER_TO_PIXEL,
        -this.interpolatedPosition[1] * METER_TO_PIXEL
      );
      display.rotation = this.interpolatedAngle;
    }
    this._memLocalId = display.transform._localID;

I used p2 compiled from sources, its different from NPM

Demo also has a Mesh&Shaders part. Its not batched i'll make batched version later.

From now on i will recommend this as a demo with physics and architecture

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

PhysicsJS: https://github.com/wellcaffeinated/PhysicsJS/

p2.js: https://github.com/schteppe/p2.js

verlet-js: https://github.com/subprotocol/verlet-js

JPE: https://github.com/colorhook/JPE

Newton: https://github.com/hunterloftis/newton

Matter.js: https://github.com/liabru/matter-js

 

that depends what or how you want to do. I used to make my own 3D physics engine for a complicated game before. or you can pick up one and modify to match your demand.

Share this post


Link to post
Share on other sites

There are numerous physics libraries out there. If you're sill undecided, I would recommend making some benchmark test to compare the functionality you need (which is what I did). I'd also look at how active that project is. Some of those listed above haven't been touched in years, so you'd def be on your own.

One advantage of box2d is it is well known and used a lot. So while the version I am using may perhaps be dead, it's easy to find out some explanation on how to do what I need to do ... though generally the answer will be C/C++ based, I found it translates over. Just be prepared to wade through the source code for confirmation as well as how that particular implementation of Box2D named stuff :D. The variant I am using is actually pretty close to the C names.

Oh, for the version I'm running, I didn't install via npm. I'm actually directly including it with my source files. It makes it easier for me to debug. 

Share this post


Link to post
Share on other sites
6 hours ago, macshemp said:

@ivan.popelyshev interested you chose P2, I saw this from  http://fatidol.com/phy-benchmark/ finscn who I recognised from the PIXI forums. In this test P2 runs around 20FPS slower than box2d

i honestly didnt care about performance yet, im new to that physics stuff. I needed something, I made it :) Which box2d lib do you recommend?

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

need a live benchmark, the bench is from 2015 😏 am sure a lot of thing change in those API.
Also versions,codes sources will help. :)
it easy to use a code and algo thats
 is favorable to a particular engine.

Edited by jonforum

Share this post


Link to post
Share on other sites
12 hours ago, tywang2006 said:

Newton: https://github.com/hunterloftis/newton

 

that depends what or how you want to do. I used to make my own 3D physics engine for a complicated game before. or you can pick up one and modify to match your demand.


ho!! if they are the same guys who developed the plugins Newton on AfterEffect or inspired! I'll bet on them, they've created a really good, effective and intuitive physic engine on AE.
https://www.motionboutique.com/newton2/

i made a fully tutorial on this physics engine plugins for french interested in dev in physique coding (eascript) inside AE.
Released for free on youtube include the 3d physic scripting.

https://youtu.be/MoykU_YUZ2Y

 

Edited by jonforum

Share this post


Link to post
Share on other sites
17 hours ago, macshemp said:

@ivan.popelyshev interested you chose P2, I saw this from  http://fatidol.com/phy-benchmark/ finscn who I recognised from the PIXI forums. In this test P2 runs around 20FPS slower than box2d

i like your link here because you share data, but the issue here is your link is not a bench!
it juste string html data !
ynNgoO2v_o.png

PIDmiz24_o.png

I get same result from all my web browsers , firefox,chrome,vivaldi,edge...
After look in deep the link compute nothing, and cant be a good reel reference.
need a reel bench here, this cant be a bench values to take.

Those values cant be take for reference, there only html strings values.

i dont know if box2d is >70% more speedUp, but please guys don't take this ref.

Edited by jonforum

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.