Phaser 3 collisions while dragging an object

Viewed 848

I'm trying to activate collision detection while dragging an object. The behaviour I'm looking for can be seen with the second example (circles) seen here with another library:

library example https://codepen.io/osublake/pen/bb6983d03e1c3582f9aac486ab9069f8

From my understanding, Phaser's collision engine will only work when object position is automatically updated through its velocity. Is it really the case ? If so, what would be a clean solution ?

My best solution right now is to change velocity in the update() method and use the pointer movement along with the delta time to calculate velocity. With constant deltas, the object movement would match the pointer movement. However, the result is a bit sketchy and has problems when the mouse stops to move (with button still down).

if (obj.membre.isDragging){
    let prevPos = {x: obj.membre.x, y: obj.membre.y};
    let pointer = scene.input.activePointer;
    let velocityX = 0;
    let velocityY = 0;

    if (pointer.position.x !== status.pointerX && pointer.position.y !== status.pointerY){
        status.pointerX = pointer.position.x;
        status.pointerY = pointer.position.y;
        velocityX = (pointer.position.x-pointer.prevPosition.x)/status.deltaS;
        velocityY = (pointer.position.y-pointer.prevPosition.y)/status.deltaS;
    }
    
    obj.membre.setVelocity(velocityX, velocityY);

}
2 Answers

Matter engine would make it work, but here is an acceptable solution with arcade engine. The trick is to add LOTS of drag (as in friction). It also seams to work fine in the drag callback.

    scene.input.on('drag', function (pointer, gameObject, dragX, dragY) {
        gameObject.body.setAllowGravity(false);
        gameobject.setDrag(1000,1000);
        
        //set velocity to match pointer movement - status.deltaS is frame delta in seconds
        velocityX = (pointer.position.x-pointer.prevPosition.x)/status.deltaS;
        velocityY = (pointer.position.y-pointer.prevPosition.y)/status.deltaS;
        gameObject.setVelocity(velocityX, velocityY);
        
    });

Here is the solution a finally retained. It uses a custom speration function, based on the example http://labs.phaser.io/edit.html?src=src%5Cphysics%5Carcade%5Ccustom%20separate.js

collider in create()

this.physics.add.collider(obj.dynamicGroup,obj.dynamicGroup,customSeparate);

adjust body properties for all objects (necessary? based on example)

    object.body.customSeparateX = true;
    object.body.customSeparateY = true;

regular drag

scene.input.on('drag', function (pointer, gameObject, dragX, dragY) {
    gameObject.x = dragX;
    gameObject.y = dragY;
}

and here is the custom seperation function. I didn't know how to make it cleaner.

function customSeparate(s1, s2) {
    var b1 = s1.body;
    var b2 = s2.body;

    //for dragged object, we have no velocity, so we take pointer direction
    let pointFacingX = "left";
    let pointFacingY = "top";
    if (scene.input.activePointer.position.x > scene.input.activePointer.prevPosition.x) pointFacingX = "right";
    if (scene.input.activePointer.position.y > scene.input.activePointer.prevPosition.y) pointFacingY = "bottom";

    //if we have velocity we use that - could add priority to fastest object
    if (b1.velocity.x > 0) pointFacingX = "right";
    if (b2.velocity.x > 0) pointFacingX = "right";
    if (b1.velocity.y > 0) pointFacingY = "bottom";
    if (b2.velocity.y > 0) pointFacingY = "bottom";

    let overlapX = 0;
    let overlapY = 0;
    if(b1.x > b2.x) {
        overlapX = b2.right - b1.left;
    }
    else {
        overlapX = b1.right - b2.left;
    }

    if(b1.y > b2.y) {
        overlapY = b2.bottom - b1.top;
    }
    else {
        overlapY = b1.bottom - b2.top;
    }

    //we move according to smallest overlap **no overlap is coded at 10000
    if (overlapX <= 0) overlapX = 10000;
    if (overlapY <= 0) overlapY = 10000;
    if(overlapX < overlapY){
        if (pointFacingX === "left"){
            if (b1.x > b2.x) {
                b2.x -= overlapX;
                b2.stop();
            }
            else {
                b1.x -= overlapX;
                b1.stop();
            }
        }
        else{
            if (b1.x < b2.x) {
                b2.x += overlapX;
                b2.stop();
            }
            else {
                b1.x += overlapX;
                b1.stop();
            }

        }
    }
    else{
        if (pointFacingY === "top"){
            if (b1.y > b2.y) {
                b2.y -= overlapY;
                b2.stop();
            }
            else {
                b1.y -= overlapY;
                b1.stop();
            }
        }
        else{
            if (b1.y < b2.y) {
                b2.y += overlapY;
                b2.stop();
            }
            else {
                b1.y += overlapY;
                b1.stop();
            }

        }

    }

}
Related