Jump to content

Breakout game incorrect ball rebound question


BdR
 Share

Recommended Posts

I have a question about a breakout type game.

All the square blocks are sprites in a Phaser.group and they're layed out in a grid pattern. The player breaks the blocks by boucing a ball against them. The problem is that the ball movement isn't always quite right. When the ball bounces off the side of a column or row of blocks, it sometimes deflects back in the opposite direction which is incorrect.

I know the cause of this, see the example image in the attachment.The ball collides with all the blocks (using arcade physics) and sometimes it collides with the bottom part of a block. In the example image it bounces against both brick 1 and 2, but because it collides with the bottom part of brick 1 it rebounds back downward.

tile_collision.png

I could set the body.checkCollision.down=false for block 1, and set it correctly for all the blocks according to their position to other blocks etc. However the problem then becomes that every time a block is removed it has to be rechecked for all the blocks (set body.checkCollision.up  correct again) according to the new block layout.

For example in the attachment image, at first brick 1 must not check the bottom collision, so body.checkCollision.down = false. But when brick 2 is removed, then it DOES have to check the bottom as well. I think a Phaser.tilemap isn't a good solution either, because the tiles (i.e. the blocks) need to be removed as the game is played, and a Phaser.tilemap isn't optimal for someting like that.

So what is a good way to implement this, without the rebound errors? :wacko:

Link to comment
Share on other sites

Ah yes, the breakout bounce... you would be surprised how many variants of this game get the bounce back all wrong. 

This is actually a fairly simple issue to resolve (I'm not going to be phaser specific here, but the logic should work regardless).

Keep track of how many hits the ball makes per frame, the max should be 3 (corner). If you hit 2 blocks all you need to do is figure out the offset of the two blocks. In your illustrations the offset (x,y) is probably something like (x:0, y:32). Since the offset is in the Y direction you will only reverse the bounce of your ball in the X direction. If it hit the bottom 2 blocks you would have an offset of (x:32, y: 0) so you would only apply the bounce back in the Y direction. If you managed to hit 3 blocks you will automatically bounce back in both X & Y directions.

Link to comment
Share on other sites

Thanks, your way makes sense when you make an Arkanoid game and you code all the physics yourself. Btw how do you calculate the new speed when the ball only hits one block?

Anyway, I want to use arcade physics, also because of some other collision detections for lasers, movably blocks, one way tiles etc.
My code is now like this:

	update: function() {
		this.game.physics.arcade.collide(this._player, this._grpblocks, this.player_block, null, this);
	}

	player_block: function(pl, bl) {
		// hit blocks
		bl.kill();

		// bounce up or down
		if ( (pl.body.touching.up) && (pl.body.velocity.y < 0) ) {
			pl.body.velocity.y *= -1;
		} else if ( (pl.body.touching.down) && (pl.body.velocity.y > 0) ) {
			pl.body.velocity.y *= -1;
		};
        
		// bounce left or right
		if ( (pl.body.touching.left) && (pl.body.velocity.x < 0) ) {
			pl.body.velocity.x *= -1;
		} else if ( (pl.body.touching.right) && (pl.body.velocity.x > 0) ) {
			pl.body.velocity.x *= -1;
		};
	}

I think the best way to do it is to set the checkCollision property of all the blocks in an efficient way, i.e. initially set them correctly and then only update adjacent blocks when one block is removed.

Link to comment
Share on other sites

With a Breakout style game the speed of the ball should never change (minus power ups etc. or the 'you hit the top boundary three times rule' ), just the trajectory that it is moving, and for the most part that doesn't change either. In most examples you'll notice the only time the angle changes is when you either hit a corner, or you hit the paddle. Making a basic Brick bashing game is easy, making a fun one is hard, and a lot of that has to do with how the paddle and corners act.

The problem I (think) I see with your implementation is that its always going to be the last hit that determines where the ball will go. So here is some modifications that I think should give you an idea of what you could do (again my code isn't phaser specific, but you can probably translate parts if you know how phaser would typically handle these cases). The biggest difference is that I only redirect the ball once per update. The Phaser physics still run and do all of their Hit Detection magic, but we wait for the final results of every collision before we take any actions.

update: function() {
	this.player._blocks_hit_count = 0;
	this.player._blocks_hit = []; // but put this outside of the loop so you only create it once. Probably when you create your initial player object.
	this.game.physics.arcade.collide(this._player, this._grpblocks, this.player_block, null, this);
	this.redirect_ball(this._player);
}
redirect_ball: function(pl) {

	if(!pl._blocks_hit) return // we didn't hit any blocks, so lets jump out of this function.

	if(!pl._blocks_hit >= 3) { // we hit an inside corner (I hope)
		pl.body.velocity.y *= -1;
		pl.body.velocity.x *= -1;
		return; // done, no need to continue
	}

	if(!pl._blocks_hit == 2){

		var difX = pl._blocks_hit[0].x;
		var difY = pl._blocks_hit[0].y;

		difX-=pl._blocks_hit[1].x;
		difY-=pl._blocks_hit[1].y;

		if(difX){ // if our difX is anything other than 0 we hit our blocks going up or down
			pl.body.velocity.y *= -1;
		}else{ // otherwise we hit our blocks on the left or right side
			pl.body.velocity.x *= -1;
		}

		return; // done no need to continue
	}

	// bounce up or down
	if ( (pl.body.touching.up) && (pl.body.velocity.y < 0) ) {
		pl.body.velocity.y *= -1;
	} else if ( (pl.body.touching.down) && (pl.body.velocity.y > 0) ) {
		pl.body.velocity.y *= -1;
	};
    
	// bounce left or right
	if ( (pl.body.touching.left) && (pl.body.velocity.x < 0) ) {
		pl.body.velocity.x *= -1;
	} else if ( (pl.body.touching.right) && (pl.body.velocity.x > 0) ) {
		pl.body.velocity.x *= -1;
	};
}

player_block: function(pl, bl) {
	// hit blocks

	pl._blocks_hit[pl._blocks_hit_count] = bl;
	pl._blocks_hit_count++;
	bl.kill();

}

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...