Help with two draggable objects colliding

Hello great people,

I’ve spent 2 nights struggling with the above problem. As per the below, I have 4 draggable objects (UFOs) on the canvas that move on their own in an orthogonal direction when dragged in the relevant direction. I have been able to get the UFOs to stop when they hit the brown block and collect the stars on their way to the blocks. I’m struggling to get the UFOs to stop when they get to another UFO. I’ve used both the collider and overlap events, but the UFO objects cross each other instead of stopping just before they collide.

The below is a section of the code I have written to solve this problem, which doesn’t work as desired.

        function loadLevel(self, levelIndex){
        resetGame(ark);
        
        let levels = getLevelObjects();
        let level = levels[levelIndex];

        ark.blocks = placeObjects(self, level.blocks, 'block', false);
        ark.players = placeObjects(self, level.players, 'ufo', true);
        ark.cows = placeObjects(self, level.cows, 'starGold', false);

        self.physics.add.collider(ark.players, ark.blocks, detectBlockCollision, null, self);
        // self.physics.add.collider(ark.players, ark.players, detectPlayerCollision, null, self);
        self.physics.add.overlap(ark.players, ark.cows, detectCowCollision, null, self);
        self.physics.add.collider(ark.players, ark.players, function(player1, player2){
            // player1.setBounce(false);
            // player2.setBounce(false);

            console.log('overlap player 1: ' + player1.x + ' , ' + player1.y);
            console.log('overlap dragged player 2: ' + player2.x + ' , ' + player2.y);

            player2.setVelocityX(0);
            player2.setVelocityY(0);
        }, null, self);

        self.input.setDraggable(ark.players);

        levelText.setText ('Level: ' + currentLevel);
    }

Any assistance with the technique to do this would be greatly appreciated.

Hi,
You can try to use the process callback to stop the ufo’s movement and return false to not provide a collision.

Thanks for your comment. Do you have any further information or example on now I can use the process callback please as I’m quite new to Phaser 3?

self.physics.add.collider(ark.players, ark.blocks, detectBlockCollision, null, self);

The process callback is the second callback (null in your case)
You can use it the same way you use detectBlockCollision with an exception, you must return true or false at the end.
If you return true the detectBlockCollision is called, and not called if you return false.

I’ve tried something like this and I think it’s very difficult to make it work. Input dragging and physics collisions just aren’t a good fit.

I would advise you either modify velocity instead of position while dragging (that can look weird) or do your own simple overlap tests while dragging (without physics).

Thanks both for your replies. I’ve modified the collider action to include a processCallback function, but the problem still persists. See below:

function loadLevel(self, levelIndex){
        resetGame(ark);
        
        let levels = getLevelObjects();
        let level = levels[levelIndex];

        ark.blocks = placeObjects(self, level.blocks, 'block', false);
        ark.players = placeObjects(self, level.players, 'ufo', true);
        ark.cows = placeObjects(self, level.cows, 'starGold', false);

        self.physics.add.collider(ark.players, ark.blocks, detectBlockCollision, null, self);
        // self.physics.add.collider(ark.players, ark.players, detectPlayerCollision, null, self);
        self.physics.add.overlap(ark.players, ark.cows, detectCowCollision, null, self);
        self.physics.add.overlap(ark.players, ark.players, function(player1, player2){
            // player1.setBounce(false);
            // player2.setBounce(false);

            console.log('overlap player 1: ' + player1.x + ' , ' + player1.y);
            console.log('overlap dragged player 2: ' + player2.x + ' , ' + player2.y);

            player2.setVelocityX(0);
            player2.setVelocityY(0);
        }, function(player1, player2){
            console.log('processCallback player 1: ' + player1.x + ' , ' + player1.y);
            console.log('processCallback dragged player 2: ' + player2.x + ' , ' + player2.y);

            player2.setVelocityX(0);
            player2.setVelocityY(0);

            return false;
        }, self);

        self.input.setDraggable(ark.players);

        levelText.setText ('Level: ' + currentLevel);
    }

@samme - do you by any chance have an example of what the overlap tests could look like?

Here’s a simple working example, don’t know if this is what you want exactly.

Thanks a bunch for your code snippet. Based on your code sample, it works when the moving player is colliding with another player when moving from right to left. The moving player stops okay just before colliding with the static player in the right to left direction. However, when moving from left to right, it pushes the player out of the screen as shown in the below screenshot.

The behaviour is also unpredictable when colliding with players from top to bottom or bottom to top. If you could enhance your code to cater for all directions, that would make my day as that is the sort of behaviour I’m trying to replicate in code.

The below is what I have got now so far:

function loadLevel(self, levelIndex){
        resetGame(ark);
        
        let levels = getLevelObjects();
        let level = levels[levelIndex];

        ark.blocks = placeObjects(self, level.blocks, 'block', false);
        ark.players = placeObjects(self, level.players, 'ufo', true);
        ark.cows = placeObjects(self, level.cows, 'starGold', false);

        self.physics.add.collider(ark.players, ark.blocks, detectBlockCollision, null, self);
        // self.physics.add.collider(ark.players, ark.players, detectPlayerCollision, null, self);
        self.physics.add.overlap(ark.players, ark.cows, detectCowCollision, null, self);
        self.physics.add.overlap(ark.players, ark.players, function(player1, player2){
            console.log('overlap player 1: ' + player1.x + ' , ' + player1.y);
            console.log('overlap dragged player 2: ' + player2.x + ' , ' + player2.y);

            player2.setVelocityX(0);
            player2.setVelocityY(0);

        }, function(player1, player2){
            console.log('processCallback player 1: ' + player1.x + ' , ' + player1.y);
            console.log('processCallback dragged player 2: ' + player2.x + ' , ' + player2.y);

            console.log(player2.body.velocity.x)
            player2.body.reset(player1.x + player1.width, player2.y);

            return false;
        }, self);

        self.input.setDraggable(ark.players);

        levelText.setText ('Level: ' + currentLevel);
    }

Thanks in anticipation.

Works when direction is from right-to-left

Doesn’t quite line up when direction is from left-to-right or top-to-bottom or bottom-to-top

Yes, in the code snippet i just handle one case, with this line:

b.body.reset(a.x + a.width, b.y);

If you examine this line, the b square reset its position to the right of the a square, and keep the same y value.
So you just need to handle the others cases, but you must firstly detect what is the direction of the b square.

if (b.body.velocity.x < 0) {
  // b come from the right
  b.body.reset(a.x + a.width, b.y);
}
if (b.body.velocity.x > 0) {
  // b come from the left
  b.body.reset(?, ?);
}
// same for b.body.velocity.y

You have the beginning of the logic, i let you find the positions :wink:

1 Like

Thanks again @BlunT76! I managed to ‘craft’ the other cases as per the below:

function loadLevel(self, levelIndex){
        resetGame(ark);
        
        let levels = getLevelObjects();
        let level = levels[levelIndex];

        ark.blocks = placeObjects(self, level.blocks, 'block', false);
        ark.players = placeObjects(self, level.players, 'ufo', true);
        ark.cows = placeObjects(self, level.cows, 'starGold', false);

        self.physics.add.collider(ark.players, ark.blocks, detectBlockCollision, null, self);
        // self.physics.add.collider(ark.players, ark.players, detectPlayerCollision, null, self);
        self.physics.add.overlap(ark.players, ark.cows, detectCowCollision, null, self);
        self.physics.add.overlap(ark.players, ark.players, function(player1, player2){
            console.log('overlap player 1: ' + player1.x + ' , ' + player1.y);
            console.log('overlap dragged player 2: ' + player2.x + ' , ' + player2.y);

            player2.setVelocityX(0);
            player2.setVelocityY(0);

        }, function(a, b){
            console.log('processCallback player 1: ' + a.x + ' , ' + a.y);
            console.log('processCallback dragged player 2: ' + b.x + ' , ' + b.y);

            if(b.body.velocity.x < 0){
                // b coming from right
                b.body.reset(a.x + a.width, b.y);
            }
            
            if(b.body.velocity.x > 0){
                // b coming from left
                b.body.reset(a.x - a.width, b.y);
            }

            if(b.body.velocity.y < 0){
                // b coming from top
                b.body.reset(b.x, a.y + a.height);
            }
            
            if(b.body.velocity.y > 0){
                // b coming from bottom
                b.body.reset(b.x, a.y - a.height);
            }

            return false;
        }, self);

        self.input.setDraggable(ark.players);

        levelText.setText ('Level: ' + currentLevel);
    }

Was this the sort of logic you were expecting?

Much appreciated again for your assistance!

2 Likes

Thanks Samme for your example. You guys have made me learn new tricks with Phaser 3 - much appreciated.

1 Like

Hi guys, in trying to understand the key differences between this.x and this.body.x, I did wonder if anyone could shed more light on why both properties do not have the same value?

Also, in the drag event (screenshot below), will anyone know why if I interchange this.setPosition(dragX, dragY) with this.body.position.set(dragX, dragY) I don’t get the same outcome? This would help me better understand the difference between this (ArcadeSprite object) and this.body (ArcadeSprite body object)

Thanks in anticipation.

I didn’t explain well in the pen.

Input happens before physics.

So in the drag handler you need to (finally) position the game object.

The physics step happens afterwards and positions the body anew from the game object. Positioning the body before then makes no difference, it’s lost.