2

enter image description here

I'm making a game that involves Tetris, but I'm having trouble with getting the blocks to land. For some reason, the blocks are stopping just short of the long, clear sprite that I'm using as the ground.

The Code I'm using is as follows:

In the Create method:

this.active = false;
this.activeBlock = null;

In the Update method:

if (this.active == false){
    this.cube = Math.floor((Math.random()* 7));
    this.testblock = this.physics.add.sprite(608, 32, this.blocks[this.cube]);
    this.testblock.body.immovable = true;
    this.testblock.body.allowGravity = false;
    this.physics.add.collider(this.testblock, this.walls);
    this.physics.add.collider(this.p1, this.testblock);
    this.activeBlock = this.testblock;
    this.active = true;
}

this.activeBlock.y = this.testblock.y + 0.1;

if(Phaser.Input.Keyboard.JustDown(this.keyA) && this.activeBlock.x != 352) {
    this.activeBlock.x = this.activeBlock.x - 64;
}

if(Phaser.Input.Keyboard.JustDown(this.keyD) && this.activeBlock.x != 928) {
    this.activeBlock.x = this.activeBlock.x + 64;
}

if (this.checkCollision(this.activeBlock, this.ground)){
    this.activeBlock = null;
    this.active = false;
}

And this is the checkCollision method I regularly use:

checkCollision(a, b) {
// simple AABB checking
if ((a.x < b.x + b.width && 
    a.x + a.width > b.x && 
    a.y < b.y + b.height &&
    a.height + a.y > b.y) ) {
        return true;
} 
else {
    return false;
}
}

I'm not sure what I did wrong. Can someone tell?

If it helps, I'm using Phaser 3 in VSCode employing arcade physics.

Update:

if (this.active == false){
    this.cube = Math.floor((Math.random()* 7));
    this.testblock = this.physics.add.sprite(608, 32, this.blocks[this.cube]);
    this.testblock.body.immovable = true;
    //this.testblock.body.allowGravity = false;
    this.testblock.body.setGravity(0.1);
    this.physics.add.collider(this.walls, this.testblock, this.callbackOnCollision, null, this);
    this.physics.add.collider(this.p1, this.testblock);
    this.activeBlock = this.testblock;
    this.active = true;
}

//this.activeBlock.y = this.activeBlock.y + 0.1;

callbackOnCollision(floor, block){
    this.physics.world.disable( block)
    this.activeBlock = null;
    this.active = false;
}

This is the code I added after reading the suggestion.

It did get the blocks closer to the ground, but it still didn't reach the bottom. Also, the new line to control the block's gravity didn't work, as the blocks are now just affected by normal gravity.

Did I mess up in adding the code?

EmptyStone
  • 235
  • 1
  • 7

1 Answers1

2

The problem is, the checkCollision function, since it only checks for hits by considering: x,y,width and height, it doesn't take other properties like for example origin. (See in the example below, on the right)

I would recommend just using the builtin collider function, of the physics engine, seen also in following example

btw.: moving the objects yourself, by setting x or y, like this this.activeBlock.y = this.testblock.y + 0.1;, will cause the collision system of the physics engine not to function correctly, if the gravity is to slow/fast just set a different value globaly in the config, or if you only need different gravity for some objects, set it directly, with setGravityY (link to documenation).

Short Demo:

document.body.style = 'margin:0;';

var config = {
    type: Phaser.AUTO,
    width: 536,
    height: 183,
    physics: {
        default: 'arcade',
        arcade: {            
            gravity:{ y: 100 },
            debug: true
        }
    },
    scene: {
        create,
        update
    },
    banner: false
}; 

let blockCustomCollision;
let floor;

let label;
let blockCollision2;

function create () {
    label = this.add.text(10,10, 'Left physics  collision /" 
        + " Right custom collision (+ slow gravity)')
        .setScale(1)
        .setOrigin(0)
        .setStyle({fontStyle: 'bold', fontFamily: 'Arial'});

    let graphics  = this.make.graphics();
    graphics.fillStyle(0xffffff);
    graphics.fillRect(0, 0, 10, 10);
    graphics.generateTexture('img', 10, 10);
    
    let blockCollision = this.physics.add.image(50, 10, 'img');
    
    blockCustomCollision = this.physics.add.image(200, 10, 'img')
        .setOrigin(1)
        .setGravityY(-50); 

    this.add.text(90, 95, '<- Stop mid Air ')
            .setScale(1)
            .setOrigin(0, .5)
            .setStyle({fontStyle: 'bold', fontFamily: 'Arial'});
            
    blockCollision2 = this.physics.add.image(80, 10, 'img')
        .setGravityY(100);
    
    floor = this.add.rectangle(0, config.height-10, config.width, 20, 0xcdcdcd)
        .setOrigin(0, 0);
    
    this.physics.add.existing(floor, true);
    
    this.physics.add.collider(floor, blockCollision, onCollision, null, this);
    this.physics.add.collider(floor, blockCollision2, onCollision, null, this);
   
}

function onCollision(floor, block){
  label.setText(' Executes on Collision');
  this.physics.world.disable( block)
}

function update(){

    if (checkCollision(blockCustomCollision, floor)){
      this.physics.world.disable( blockCustomCollision)
    }
    
    if(blockCollision2.body.velocity.y > 1 && blockCollision2.body.y >= 90){
        blockCollision2.body.setAllowGravity(false);
        blockCollision2.body.setVelocity(0);
    }
}

function checkCollision(a, b) {
// simple AABB checking
    if ((a.x < b.x + b.width && 
        a.x + a.width > b.x && 
        a.y < b.y + b.height &&
        a.height + a.y > b.y) ) {
            return true;
    } 
    else {
        return false;
    }
}

new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>

Update: if you want to trigger function on collision, you can use the callback function fo the colliderfunction (parameter 3). The example above was updated, also

this.physics.add.collider(floor, blockCollision, callbackOnCollision);

Update 2:

Demo Code was update to show stopping in midair, with a defined y height in the update function.

winner_joiner
  • 12,173
  • 4
  • 36
  • 61
  • I think I understand your suggestion, but I'm not sure if I can get rid of the use of the checkCollision method, as I'm using it not to stop the blocks, but to trigger the spawning of the next block. Also, earlier in the create method I made this.walls, which is a group that contains the clear, thin sprites that I'm using for the ground and the side walls. In my code, I have added a collider for this.walls and this.testblock. Am I already using your suggestion? – EmptyStone Nov 13 '22 at 07:44
  • About the gravity, if that's what the problem is, I kinda have the gravity reserved for another part of the game. I'm making a Tetris crossed with a platformer, with a character running around the play area while dodging blocks. I currently have the gravity only effecting the platformer while the blocks fall via this.activeBlock.y = this.activeBlock.y + 0.1; Could this set up be the source of the problem? – EmptyStone Nov 13 '22 at 07:50
  • @EmptyStone I update my code/answer showcasing how you can, trigger on collision, i hope this helps. And yes move the block by hand can cause strange behavior when used in combination with physics. I hope this help abit – winner_joiner Nov 13 '22 at 07:55
  • I get that having the block move with its own code is possibly the source of the issue, but I don't want the same gravity to affect the platformer and the blocks. If the blocks fall at the same rate as the platformer, I can't see balancing the gameplay as possible. – EmptyStone Nov 13 '22 at 08:40
  • @EmptyStone, as shown in the demo code, you can set a different gravity to the dropping objects than the player, by using `setGravity` or `setGravityY` on the blocks. – winner_joiner Nov 13 '22 at 10:45
  • Hey, I updated the question to show some code examples of what I've tried. You've seen it, right? – EmptyStone Nov 13 '22 at 23:34
  • @EmptyStone I didn't see the code until now, well first the `setGravity` function hast to be called with greater values, try `100` or more, depeding on the needed speed _(with 0.1 you won't notice the difference)_ . Why it doesn't reach the ground, I can't say, with the posted code. Maybe the image, has a transparent border, or something else. Is the physics debug border visible, when the block stops moving? – winner_joiner Nov 14 '22 at 06:38
  • Yes, the debug view is on. I haven't turned it off once. Its the same as in the picture with the first post. – EmptyStone Nov 14 '22 at 07:41
  • @EmptyStone if the debug border is still on, on the stopped Blocks, the block didn't collide with `this.walls`, because the command `this.physics.world.disable( block );` , in the `callbackOnCollision` function would deactivate it. It must be that somewhere else in your code you must be stopping the block. – winner_joiner Nov 14 '22 at 07:55
  • I think I located the problem in the setGravity method. I changed the number around and some numbers made it stop short of the ground while others got it closer. – EmptyStone Nov 14 '22 at 08:08
  • I did recently have an idea to forgo the collision detection and instead have the block stop when it's y coordinate reached a certain number. Would this work, or am I thinking to simple? – EmptyStone Nov 14 '22 at 08:10
  • @EmptyStone this can work, you just must on reaching the point, stop movement and prevent gravity. Just like `block.body.setAllowGravity(false);` and `block.body.setVelocity(0);`. I hope this solves your problem. – winner_joiner Nov 14 '22 at 08:21
  • Hey there. I believe I got a working falling and landing with that last idea. Thanks for the help. – EmptyStone Nov 14 '22 at 11:03
  • Just want to ask a quickie while you're still looking. Is there a line I can write that stops or pauses the game? I need something like that to show winners. – EmptyStone Nov 14 '22 at 11:04
  • @EmptyStone you can `pause` and `resume` the scene, with the equally named functions. check out this example for details https://phaser.io/examples/v3/view/scenes/pause-and-resume – winner_joiner Nov 14 '22 at 11:51