Phaser 3, No collisions between bullets and tilemap - javascript

According to the Phaser 3 examples I've created a tilemap from JSON file and added firing bullets with a left mouse clicking in a cursor's direction. Also a platform was added. My problem is that there are no collisions detected between a bullet and a tilemap's objects. But collisions work fine between the bullet and a platform.
Here is my demo code:
var config = {
type: Phaser.CANVAS,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
},
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
var bullets;
var platforms;
function preload ()
{
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/impact-tilemap.json');
this.load.image('kenney', 'assets/tilemaps/tiles/kenney.png');
this.load.image('ground', 'src/games/firstgame/assets/platform.png');
this.load.image('bullet', 'src/games/firstgame/assets/star.png');
}
function create ()
{
var map = this.make.tilemap({ key: 'map' });
var tileset = map.addTilesetImage('kenney');
var layer = map.createStaticLayer(0, tileset, 0, 0);
layer.setCollisionByExclusion([-1]);
this.physics.world.bounds.width = layer.width;
this.physics.world.bounds.height = layer.height;
platforms = this.physics.add.staticGroup();
platforms.create(400, 268, 'ground');
// Fires bullet on left click of mouse
this.input.on('pointerdown', function() {
fire(this);
}, this);
var Bullet = new Phaser.Class({
Extends: Phaser.GameObjects.Image,
initialize: function Bullet(scene)
{
Phaser.GameObjects.Image.call(this, scene, 0, 0, 'bullet');
this.speed = Phaser.Math.GetSpeed(300, 1);
this.velocity = new Phaser.Geom.Point(0, 0);
},
fire: function (x, y, direction)
{
this.setPosition(x, y);
this.setActive(true);
this.setVisible(true);
this.velocity.setTo(0, -this.speed);
Phaser.Math.Rotate(this.velocity, direction);
},
update: function (time, delta)
{
// Update position based on velocity
this.x += this.velocity.x * delta;
this.y += this.velocity.y * delta;
}
});
bullets = this.physics.add.group({
classType: Bullet,
maxSize: 30,
runChildUpdate: true
});
this.physics.add.collider(bullets, platforms, callbackFunc, null, this);
this.physics.add.collider(bullets, layer, callbackFunc, null, this);
}
function callbackFunc(bullet, target)
{
if ( bullet.active === true ) {
console.log("Hit!");
bullet.setActive(false);
bullet.setVisible(false);
}
}
function fire(that)
{
var bullet = bullets.get();
if (bullet) {
bullet.body.allowGravity = false;
var angle = Math.atan2(that.input.activePointer.y - 400, that.input.activePointer.x - 300);
bullet.fire(300, 400, angle + (3.14/2));
}
}
You can copy-paste it to any example at https://labs.phaser.io and start clicking to fire at any direction.
I've tried to add a standard player from examples too and collisions work fine with the tilemap's objects. So the problem is with bullets only.
Please help to solve this. Thanks!

Related

Phaser 3 Arcade Gravity Isn't working properly no matter what value i set it to

I'm working on a new project in phaser and for some reason the gravity in the game is all messed up, when i attempt to jump i jump like a centimeter. if i change the values nothing changes its always glitched. how can i make it so that i jump and fall normally?
I've had some previous projects and the gravity works just fine, for this project i am using the latest stable release of phaser 3. I honestly cant see what the error is and i've been at it for a while.
there was a lot of code that wasn't relevent to the error so i removed it to make it easier for someone to review this.
game.js
const socket = io();
var config = {
type: Phaser.AUTO,
width: 1000,
height: 550,
parent: 'master',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: true
}
},
scene: {
preload: resources,
create: mechanics,
update: controls
}
};
const game = new Phaser.Game(config);
function resources() {
this.load.image("arena", "../resources/images/arena1.png");
this.load.image("floor", "../resources/images/floor.png");
this.load.atlas("warrior", "../resources/images/characters/warrior.png","../resources/images/characters/warrior.json");
}
var warrior;
function mechanics() {
grasslands = this.add.image(500, 225, "arena").setScale(0.7);
warrior = this.physics.add.sprite(100, 490, "warrior").setScale(2).setSize(15, 15);
floor = this.physics.add.staticGroup();
floor.create(500, 545, "floor").setVisible(false);
this.physics.add.collider(warrior, floor);
warrior.body.collideWorldBounds = true;
warrior.body.onWorldBounds = true;
}
function controls() {
key = this.input.keyboard.addKeys("W,A,S,D");
if(key.A.isDown) {
warrior.setVelocityX(-100);
warrior.flipX = true;
}else if (key.D.isDown) {
warrior.setVelocityX(100);
warrior.flipX = false;
}else if (key.W.isDown && warrior.body.touching.down) {
warrior.setVelocityY(-330);
}else{
warrior.setVelocity(0);
}
}
The problem occurs because of this line warrior.setVelocity(0);. This line, stops the gravity of working, as intended (and hinders jumping), since on scene updates, the velocity is set to 0. Remove that line and add warrior.setVelocityX(0) at the start of the controls function and everything should work fine (if you want/have to keep the if-else block). Or check out my working demo at the end of this answer.
function controls() {
key = this.input.keyboard.addKeys("W,A,S,D");
warrior.setVelocityX(0);
if(key.A.isDown) {
warrior.setVelocityX(-100);
warrior.flipX = true;
}else if (key.D.isDown) {
warrior.setVelocityX(100);
warrior.flipX = false;
}else if (key.W.isDown && warrior.body.touching.down) {
warrior.setVelocityY(-330);
}
}
I would only stop the left/right movement, when the player stops pressing the keys ( with setVelocityX(0)), and let gravity take care of stopping the jump/upwards movement.
Here a basic demo:
var config = {
type: Phaser.AUTO,
width: 400,
height: 160,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 200 },
}
},
scene: {
create,
update
}
};
var cursors;
var player;
var playerStateText;
const SPEED = 250;
var isJumping = true;
function create () {
cursors = this.input.keyboard.createCursorKeys();
this.add.text(10, 10, 'Use arrow Keys to move!')
let ground = this.add.rectangle(-40, 120, 480, 50, 0xBAF0FF).setOrigin(0);
player = this.add.rectangle(20, 20, 30, 30, 0xcccccc).setOrigin(0);
ground = this.physics.add.existing(ground);
ground.body.setImmovable(true);
ground.body.allowGravity = false;
player = this.physics.add.existing(player);
this.physics.add.collider(player, ground, _ => isJumping = false);
}
function update (){
if (cursors.left.isDown){
player.body.setVelocityX(-SPEED);
} else if (cursors.right.isDown) {
player.body.setVelocityX(SPEED);
}
else {
player.body.setVelocityX(0);
}
if (!isJumping && cursors.up.isDown){
player.body.setVelocityY(-SPEED * .75);
isJumping = true;
}
}
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

How to get target who are touching on a specific sprite

I am trying to make a mini-game by phaser.js. In my idea. A sprite object can collided to a static sprite and continually perform desired effect if they are stick together. However, when I handle them with this.physics.add.collider, the callback function just run once.
Search for API document. I find the touching event can be judged by object.body.touching. But seen it can only return the facing. So I wonder how to get the object who are touching on the specific direction of a sprite? Or the function is need to handle by handy?
Thanks for your help.
If you need more "detailed"/"better" physics functions in phaser, you could use the matterjs physics engine.
(It is as easy as the arcade engine, atleast to setup)
With matterjs there are more options, like the "collisions events", using matter you could use the event collisionactive.
(link to the documentation)
collisionactive executes as long as the two colliding objects touch.
Like this you know the exact object(s) touching. (And if you need the direction you could find it with the x and y postions of the objects, or the velocity of the impact)
Here a demo from the offical website, showing collisionstart Event https://phaser.io/examples/v3/view/physics/matterjs/collision-event
Here a small with matter demo:
// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";
var config = {
type: Phaser.AUTO,
width: 536,
height: 153,
backgroundColor: '#1b1464',
physics: {
default: 'matter',
matter: {
debug:true,
gravity:{y:0, x:0}
}
},
scene: {
create: create
}
};
var game = new Phaser.Game(config);
var counter = 0;
var gOverlay;
function create ()
{
var blockA = this.matter.add.image(50, 80, 'block1');
var blockB = this.matter.add.image(300, 80, 'block1').setStatic(true);
var text = this.add.text(10,10, 'Not touching')
blockA.setVelocityX(3);
gOverlay = this.add.graphics();
this.matter.world.on('collisionstart', function (event, bodyA, bodyB) {
text.setText(text.text + '\nHIT')
drawDirectionArrow(bodyA, bodyB)
});
this.matter.world.on('collisionactive', function (event, bodyA, bodyB) {
text.setText(`Touching: ${counter++}`)
if(counter > 60 ) {
counter = 0;
blockA.setVelocityX(-2);
}
});
this.matter.world.on('collisionend', (function (event, bodyA, bodyB) {
text.setText(text.text + '\nNot touching');
gOverlay.clear();
this.time.delayedCall(2000, _ => blockA.setVelocityX(5));
}).bind(this));
}
function drawDirectionArrow(a, b){
gOverlay.clear();
gOverlay.fillStyle( 0xFF00FF);
gOverlay.fillTriangle(a.position.x, a.position.y, b.position.x, b.position.y - 10, b.position.x, b.position.y + 10);
}
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js">
</script>
Update:
If you need/want to use arcade physics, here is a similar demo, with a small workaround using a second physics-object to check for overlap.
Arcade - Physics workaround - Demo:
// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";
var config = {
type: Phaser.AUTO,
width: 536,
height: 153,
backgroundColor: '#1b1464',
physics: {
default: 'arcade',
arcade: {
debug:true,
}
},
scene: {
create: create
}
};
var game = new Phaser.Game(config);
var counter = 0;
var gOverlay;
function create () {
var blockA = this.physics.add.image(50, 80, 'block1').setOrigin(.5);
var blockB = this.physics.add.image(300, 80, 'block1').setOrigin(.5);
// Helper
var blockBx = this.add.rectangle(300, 80, 34, 34);
this.physics.add.existing(blockBx);
blockB.setImmovable();
var text = this.add.text(10,10, 'Not touching')
blockA.setVelocityX(50);
gOverlay = this.add.graphics();
this.physics.add.collider(blockA, blockB, function ( bodyA, bodyB) {
drawDirectionArrow(bodyA, bodyB);
})
this.physics.add.overlap(blockA, blockBx, function ( bodyA, bodyB) {
text.setText(`Touching: ${counter++}`);
if(counter > 60 ) {
counter = 0;
gOverlay.clear();
blockA.setVelocityX(-50);
text.setText('Not touching');
this.time.delayedCall(2000, _ => blockA.setVelocityX(50));
}
}, null, this);
}
function drawDirectionArrow(a, b){
gOverlay.clear();
gOverlay.fillStyle( 0xFF00FF);
gOverlay.fillTriangle(a.x, a.y, b.x, b.y - 10, b.x, b.y + 10);
}
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js">
</script>

How to prevent objects to jump off platforms?

I have a game set up like this:
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', {preload: preload, create: create, update: update});
var platforms;
var aGroup;
function preload() {
game.load.image('platform', 'img/platform.png');
game.load.image('a', 'img/a.png');
}
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
platforms = game.add.group();
platforms.enableBody = true;
var platform = platforms.create(100, 100, 'platform');
aGroup = game.add.group();
aGroup.enableBody = true;
platforms.forEach(function(item) {
item.body.immovable = true;
aGroup.create(item.x, item.y - 32, 'a');
}, this);
aGroup.forEach(function(a) {
a.body.velocity.x = 100;
}
}
function update() {
game.physics.arcade.collide(aGroup, platforms);
aGroup.forEach(function(a) {
if(a.body.blocked.right) {
a.body.velocity.x = -100;
}
else if(a.body.blocked.left) {
a.body.velocity.x = 100;
}, this);
}
}
Currently I can check if a is colliding with the world boundaries and if it does it changes direction. Right now when a reaches the end of the platform it just falls down. I want a to change direction when it reaches the end of the platform.
How can I do it?

Phaser - Implementing states / changing active script

Sorry if this is the wrong place to put this, I haven't had much luck anywhere else unfortunately.
In Phaser I have made a tilemap and a player sprite, this all works perfectly using P2 physics. I have a door way in my tilemap which when I enter I want a different script to run, changing the current tilemap to a different one and moving the player's position accordingly.
I already have a basic if statement that checks if the player's position is within the range of the door and console logs, that works fine.
Code:
var game = new Phaser.Game(560, 560, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render });
function preload() {
game.load.tilemap('tilemap', 'assets/tilemaps/test.json', null, Phaser.Tilemap.TILED_JSON);
game.load.image('tiles', 'assets/tilemaps/tileset.png');
game.load.image('player', 'assets/images/player.png');
}
var player;
var cursors;
var map;
var layer;
function create() {
map = game.add.tilemap('tilemap');
map.addTilesetImage('basic', 'tiles');
layer = map.createLayer('Background');
layer2 = map.createLayer('Walls');
layer.resizeWorld();
game.physics.startSystem(Phaser.Physics.P2JS);
game.physics.p2.setBoundsToWorld(true, true, true, true, false);
map.setCollision(1, true, "Walls");
game.physics.p2.convertTilemap(map, "Walls");
player = game.add.sprite(game.world.centerX, game.world.centerY, 'player');
game.physics.p2.enable(player);
player.body.fixedRotation = true;
player.body.clearShapes();
player.body.addRectangle(20, 0, 0, 0);
cursors = game.input.keyboard.createCursorKeys();
game.camera.follow(player);
//player.body.debug = true;
}
function update() {
player.body.setZeroVelocity();
if (cursors.up.isDown)
{
player.body.moveUp(300)
}
else if (cursors.down.isDown)
{
player.body.moveDown(300);
}
if (cursors.left.isDown)
{
player.body.velocity.x = -300;
}
else if (cursors.right.isDown)
{
player.body.moveRight(300);
}
if (player.x > 248 && player.x < 311 && player.y < 25)
{
console.log("Door opened");
}
}
function render() {
game.debug.cameraInfo(game.camera, 32, 32);
game.debug.spriteCoords(player, 32, 500);
}

Cancel collision after initial detection, using phaser in js

When 2 sprites collide I'd like to count that as 1 life lost, and then cancel the collision so the sprites pass over one another. I don't want multiple lives to be lost as the same 2 sprites pass over each other.
Any ideas how I can cancel the contact after I've subsracted 1 life?
http://jsfiddle.net/bobbyrne01/44zmvm8z/
javascript ..
var player,
emitter,
lives = 5;
var game = new Phaser.Game(
800,
600,
Phaser.CANVAS,
'Game', {
preload: preload,
create: create,
update: update,
render: render
});
function preload() {
game.load.image('missile', 'http://images.apple.com/v/iphone-5s/a/images/buystrip_retail_icon.png');
game.load.image('player', 'http://38.media.tumblr.com/avatar_0714f87e9e76_128.png');
}
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.gravity.y = 300;
game.stage.backgroundColor = '#000';
game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL; // Maintain aspect ratio
player = game.add.sprite(game.world.width / 2, game.world.height / 2, 'player');
player.scale.setTo(0.5, 0.5);
game.physics.arcade.enable(player);
player.body.allowGravity = false;
emitter = game.add.emitter(0, 100, 100);
emitter.makeParticles('missile');
emitter.gravity = 200;
emitter.width = 500;
emitter.x = game.world.width / 2;
emitter.y = -300;
emitter.minRotation = 0;
emitter.maxRotation = 0;
emitter.setScale(0.1, 0.5, 0.1, 0.5, 6000, Phaser.Easing.Quintic.Out);
emitter.start(false, 2000, 500);
}
function update() {
game.physics.arcade.collide(player, emitter, chec, change, this);
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) {
player.x -= 4;
} else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) {
player.x += 4;
}
}
function chec() {}
function change() {
lives--;
return false;
}
function render() {
game.debug.text('Lives: ' + lives, 2, 28, "#00ff00");
}
Is it optional to destroy the particle just after the collision? If yes, do it this way, just edit the change() function like this:
function change(a, b) {
b.destroy();
lives--;
return false;
}
The second parameter happens to be the particle itself, the first one is the emitter.

Categories