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>
Related
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>
I'm working on a small flappy-bird-like-game demo. Everthing seems fine, but I have a small problem/question.
I setup a collider function, and the callback works as expected, when the "two" objects collide, but there is a strange behavior:
the white-square (the bird) can fly through the obstacles, when coming from the side
but cannot passthrough when coming from below or on above
BUT the callback is execute always.
blue arrow marks where the square passes through
green arrows mark where the square doesn't passthrough
I'm not sure if this is, because I'm using rectangles (they sometimes) cause problems, or because of my nested physics setup. I even tried to replaced the white rectangel with a sprite, but this still produces the same result/error.
For my demo: I could probablly just destroy the object and restart the level on collision, but I still would like to understand why this is happening? And how I can prevent this, inconsistant behavior.
I'm probably missing something, but couldn't find it, and I don't want to rebuild the application again.
So my question is: why is this happening? And How can I prevent this?
Here is the code:
const width = 400;
const height = 200;
const spacing = width / 4;
const levelSpeed = width / 4;
const flySpeed = width / 4;
var GameScene = {
create (){
let player = this.add.rectangle(width / 4, height / 2, 20, 20, 0xffffff);
this.physics.add.existing(player);
this.input.keyboard.on('keydown-SPACE', (event) => {
if(player.body.velocity.y >= -flySpeed/2){
player.body.setVelocityY(-flySpeed);
}
});
player.body.onWorldBounds = true;
player.body.setCollideWorldBounds(true );
this.physics.world.on("worldbounds", function (body) {
console.info('GAME OVER');
player.y = height / 2;
player.body.setVelocity(0);
});
this.pipes = [];
for(let idx = 1; idx <= 10; idx++) {
let obstacle = this.createObstacle(spacing * idx, Phaser.Math.Between(-height/3, 0));
this.add.existing(obstacle);
this.pipes.push(obstacle);
this.physics.add.collider(obstacle.list[0], player)
this.physics.add.collider(obstacle.list[1], player, _ => console.info(2))
}
},
update(){
this.pipes.forEach((item) => {
if(item.x <= 0){
item.body.x = spacing * 10;
}
})
},
extend: {
createObstacle (x, y){
let topPipe = (new Phaser.GameObjects.Rectangle(this, 0, 0 , 20 , height / 2 ,0xff0000)).setOrigin(0);
let bottomPipe = (new Phaser.GameObjects.Rectangle(this, 0, height/2 + 75, 20 , height / 2 ,0xff0000)).setOrigin(0);
this.physics.add.existing(topPipe);
this.physics.add.existing(bottomPipe);
topPipe.body.setImmovable(true);
topPipe.body.allowGravity = false;
bottomPipe.body.setImmovable(true);
bottomPipe.body.allowGravity = false;
let obstacle = new Phaser.GameObjects.Container(this, x, y, [
topPipe,
bottomPipe
]);
this.physics.add.existing(obstacle);
obstacle.body.velocity.x = - levelSpeed;
obstacle.body.allowGravity = false;
return obstacle;
}
}
};
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width,
height,
scene: [GameScene],
physics: {
default: 'arcade',
arcade: {
gravity: { y: flySpeed },
debug: true
},
}
};
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
Currently I just can assume, that the physics objects don't seem to work correct, when physics objects are nested.
Maybe I'm wrong, but since I rewrote the code again without nested physics - objects and it seems to work, I think my assumption Is correct. I shouldn't have tried to over engineer my code.
If someone has more insides, please let me know/share. I still not 100% sure, if this is the real reason, for the strange behavior.
Here the rewriten code:
const width = 400;
const height = 200;
const spacing = width / 4;
const levelSpeed = width / 4;
const flySpeed = width / 4;
var GameScene = {
create (){
let player = this.add.rectangle(width / 4, height / 2, 20, 20, 0xffffff);
this.physics.add.existing(player);
this.input.keyboard.on('keydown-SPACE', (event) => {
if(player.body.velocity.y >= -flySpeed/2){
player.body.setVelocityY(-flySpeed);
}
});
player.body.onWorldBounds = true;
player.body.setCollideWorldBounds(true );
this.physics.world.on("worldbounds", function (body) {
console.info('GAME OVER');
player.x = width / 4;
player.y = height / 2;
player.body.setVelocity(0);
});
this.pipes = [];
for(let idx = 1; idx <= 10; idx++) {
let obstacle = this.createObstacle(spacing * idx, Phaser.Math.Between(-height/3, 0));
this.add.existing(obstacle[0]);
this.add.existing(obstacle[1]);
this.pipes.push(...obstacle);
this.physics.add.collider(obstacle[0], player)
this.physics.add.collider(obstacle[1], player, _ => console.info(2))
}
},
update(){
this.pipes.forEach((item) => {
if(item.x <= 0){
item.body.x = spacing * 10;
}
item.body.velocity.x = - levelSpeed;
})
},
extend: {
createObstacle (x, y){
let topPipe = (new Phaser.GameObjects.Rectangle(this, x, -20 , 20 , height / 2 ,0xff0000)).setOrigin(0);
let bottomPipe = (new Phaser.GameObjects.Rectangle(this, x, height/2 + 75, 20 , height / 2 ,0xff0000)).setOrigin(0);
this.physics.add.existing(topPipe);
this.physics.add.existing(bottomPipe);
topPipe.body.setImmovable(true);
topPipe.body.allowGravity = false;
topPipe.body.velocity.x = - levelSpeed;
bottomPipe.body.setImmovable(true);
bottomPipe.body.allowGravity = false;
bottomPipe.body.velocity.x = - levelSpeed;
return [topPipe, bottomPipe];
}
}
};
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width,
height,
scene: [GameScene],
physics: {
default: 'arcade',
arcade: {
gravity: { y: flySpeed },
debug: true
},
}
};
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I am currently making a small platformer game, where the player jumps up infinitely, much like the android game "Abduction". I have managed to create platforms in random locations on a timed interval and adding it to an array. However i can only get the player sprite to collide with 1 of the platform arrays, which is this.walls array that i have made so i have a set starting place for the player. Does anyone know what the issue might be.
Ugly code alert by the way, i am quite new at this.
I have checked update: function to see if i had forgot to add some stuff there. ive spellchecked the code and all sorts of things but i am at a completel loss.
var playState = {
preload: function () {
},
create: function () {
game.add.image (0, 0,'bg');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.renderer.renderSession.roundPixels = true;
this.cursor = game.input.keyboard.createCursorKeys();
game.input.keyboard.addKeyCapture(
[Phaser.Keyboard.UP, Phaser.Keyboard.DOWN, Phaser.Keyboard.LEFT, Phaser.Keyboard.RIGHT]);
this.wasd = {
up: game.input.keyboard.addKey(Phaser.Keyboard.W), left: game.input.keyboard.addKey(Phaser.Keyboard.A), right: game.input.keyboard.addKey(Phaser.Keyboard.D)
};
this.player = game.add.sprite(game.width/2, game.height/1.2, 'player');
this.player.anchor.setTo(0.5, 0.5);
game.physics.arcade.enable(this.player);
this.player.body.gravity.y = 800;
this.scoreLabel = game.add.text(30, 30, 'score: 0',
{ font: '18px Arial', fill: '#ffffff' });
game.global.score = 0;
game.time.events.loop(1000, this.updateScore);
game.time.events.loop(4000, this.addPlatform);
this.createWorld();
},
update: function () {
game.physics.arcade.collide(this.player, this.walls);
game.physics.arcade.collide(this.player, this.platforms);
if (!this.player.inWorld) {
this.playerDie();
}
this.movePlayer();
},
updateScore: function(){
this.score +=1;
game.global.score +=1;
//fix this at some point
},
createWorld: function() {
this.walls = [];
this.walls.push(game.add.sprite(170, 750, 'platform', 0));
this.walls.push(game.add.sprite(70, 650, 'platform', 0));
this.walls.push(game.add.sprite(320, 550, 'platform', 0));
this.walls.push(game.add.sprite(200, 450, 'platform', 0));
this.walls.push(game.add.sprite(10, 550, 'platform', 0));
this.walls.push(game.add.sprite(70, 350, 'platform', 0));
this.walls.push(game.add.sprite(310, 300, 'platform', 0));
this.walls.push(game.add.sprite(230, 200, 'platform', 0));
this.walls.push(game.add.sprite(100, 100, 'platform', 0));
this.walls.push(game.add.sprite(270, 0, 'platform', 0));
for (var x=0; x< this.walls.length; x++) {
game.physics.arcade.enable(this.walls[x]);
this.walls[x].enableBody = true;
this.walls[x].body.immovable = true;
this.walls[x].body.velocity.y = 20;
}
},
addPlatform: function() {
this.platforms = [];
this.platforms.push(game.add.sprite(game.rnd.integerInRange(0, 350),-20,'platform',0));
for (var x=0; x< this.platforms.length; x++) {
game.physics.arcade.enable(this.platforms[x]);
this.platforms[x].enableBody = true;
this.platforms[x].body.immovable = true;
this.platforms[x].body.velocity.y = 20;
}
},
movePlayer: function() {
if (this.cursor.left.isDown || this.wasd.left.isDown) {
this.player.body.velocity.x = -250;
}
else if (this.cursor.right.isDown || this.wasd.right.isDown) {
this.player.body.velocity.x = 250;
}
else {
this.player.body.velocity.x = 0;
}
if ((this.cursor.up.isDown || this.wasd.up.isDown)
&& this.player.body.touching.down){
this.player.body.velocity.y = -450;
}
},
playerDie: function() {
this.player.kill();
//this.deadSound.play();
//this.emitter.x = this.player.x;
//this.emitter.y = this.player.y;
//this.emitter.start(true, 800, null, 15);
game.time.events.add(1000, this.startMenu, this);
game.camera.shake(0.02, 300);
},
startMenu: function() {
game.state.start('menu');
},
};
this.walls is so i have a starting ground of set platforms and this.platforms is the randomly generated platforms.
I want to be able to actually jump on those platforms and not just
fall through, which i do at the moment
Your platform is an array of sprites, so you have to parse through each sprite inside your array.
Or, you can make a "Group" object, instead of plain array. You can make a Group of each plaform, then do collision with this Group and player.
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!
In my game, I need some buttons that will work on mobile devices (buttons that you can press and/or hold in the game). I saw this example (note that the version of Phaser being used here is old, however, it still works) and was able to temporarily have some working buttons. Here's the source code for that example.
However, one thing bothered me about this example's code for the creation of these virtual gamepad buttons: the buttons' code wasn't DRY (Don't Repeat Yourself). You can see how these buttons keep getting created in the same fashion here over and over again:
// create our virtual game controller buttons
buttonjump = game.add.button(660, 340, 'buttonjump', null, this, 0, 1, 0, 1); //game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame
buttonjump.anchor.setTo(0.5, 0.5);
buttonjump.fixedToCamera = true; //our buttons should stay on the same place
buttonjump.events.onInputOver.add(function(){jump=true;});
buttonjump.events.onInputOut.add(function(){jump=false;});
buttonjump.events.onInputDown.add(function(){jump=true;});
buttonjump.events.onInputUp.add(function(){jump=false;});
buttonfire = game.add.button(750, 340, 'buttonfire', null, this, 0, 1, 0, 1);
buttonfire.anchor.setTo(0.5, 0.5);
buttonfire.fixedToCamera = true;
buttonfire.events.onInputOver.add(function(){fire=true;});
buttonfire.events.onInputOut.add(function(){fire=false;});
buttonfire.events.onInputDown.add(function(){fire=true;});
buttonfire.events.onInputUp.add(function(){fire=false;});
buttonleft = game.add.button(40, 312, 'buttonhorizontal', null, this, 0, 1, 0, 1);
buttonleft.anchor.setTo(0.5, 0.5);
buttonleft.fixedToCamera = true;
buttonleft.events.onInputOver.add(function(){left=true;});
buttonleft.events.onInputOut.add(function(){left=false;});
buttonleft.events.onInputDown.add(function(){left=true;});
buttonleft.events.onInputUp.add(function(){left=false;});
buttonbottomleft = game.add.button(48, 352, 'buttondiagonal', null, this, 6, 4, 6, 4);
buttonbottomleft.anchor.setTo(0.5, 0.5);
buttonbottomleft.fixedToCamera = true;
buttonbottomleft.events.onInputOver.add(function(){left=true;duck=true;});
buttonbottomleft.events.onInputOut.add(function(){left=false;duck=false;});
buttonbottomleft.events.onInputDown.add(function(){left=true;duck=true;});
buttonbottomleft.events.onInputUp.add(function(){left=false;duck=false;});
buttonright = game.add.button(136, 312, 'buttonhorizontal', null, this, 0, 1, 0, 1);
buttonright.anchor.setTo(0.5, 0.5);
buttonright.fixedToCamera = true;
buttonright.events.onInputOver.add(function(){right=true;});
buttonright.events.onInputOut.add(function(){right=false;});
buttonright.events.onInputDown.add(function(){right=true;});
buttonright.events.onInputUp.add(function(){right=false;});
buttonbottomright = game.add.button(128, 352, 'buttondiagonal', null, this, 7, 5, 7, 5);
buttonbottomright.anchor.setTo(0.5, 0.5);
buttonbottomright.fixedToCamera = true;
buttonbottomright.events.onInputOver.add(function(){right=true;duck=true;});
buttonbottomright.events.onInputOut.add(function(){right=false;duck=false;});
buttonbottomright.events.onInputDown.add(function(){right=true;duck=true;});
buttonbottomright.events.onInputUp.add(function(){right=false;duck=false;});
buttondown = game.add.button(88, 360, 'buttonvertical', null, this, 0, 1, 0, 1);
buttondown.anchor.setTo(0.5, 0.5);
buttondown.fixedToCamera = true;
buttondown.events.onInputOver.add(function(){duck=true;});
buttondown.events.onInputOut.add(function(){duck=false;});
buttondown.events.onInputDown.add(function(){duck=true;});
buttondown.events.onInputUp.add(function(){duck=false;});
Because they were created in such a non-DRY and, what I feel to be, inefficient way, I decided that my buttons should have a gamepad button class that they all inherit from. Unfortunately, I've been running into lots of problems trying to make this button class work.
I have an example here that models what I'm trying to do in my game.
(Here's the source code for my example)
// Global constants
var GAME_WIDTH = 800;
var GAME_HEIGHT = 600;
var ORIGIN = 0;
var TEXT_X_POS = 50;
var TEXT_Y_POS = 100;
var TEXT_STYLE = { fontSize: "16px" };
var RIGHT_BUTTON_X_POS = 600;
var RIGHT_BUTTON_Y_POS = 400;
var LEFT_BUTTON_X_POS = 100;
var LEFT_BUTTON_Y_POS = 400;
var PHASER_DUDE_Y_POS = 300;
var PHASER_DUDE_GRAVITY = 300;
var PHASER_DUDE_RIGHT_VELOCITY = 100;
var PHASER_DUDE_LEFT_VELOCITY = -100;
var STOPPED = 0;
// Global variables
var background;
var rightButton;
var movingRight;
var rightButtonDown;
var leftButton;
var movingLeft;
var leftButtonDown;
var phaserDude;
var rightKey;
var leftKey;
// New instance of Phaser.Game
var game = new Phaser.Game(GAME_WIDTH, GAME_HEIGHT, Phaser.AUTO, "game", {preload: preload, create: create, update: update});
// Mobile button class
var MobileButton = function (button, movingInADirection, isTheButtonDown, pressedMethod) {
button.events.onInputOver.add(function () {
if (isTheButtonDown === true) {
movingInADirection = true;
}
});
button.events.onInputDown.add(function () {
isTheButtonDown = true;
movingInADirection = true;
});
button.events.onInputUp.add(function () {
movingInADirection = false;
});
};
function preload () {
game.load.image("background", "sprites/sky.png");
game.load.image("left arrow", "sprites/left_arrow.png");
game.load.image("right arrow", "sprites/right_arrow.png");
game.load.image("phaser dude", "sprites/phaser_dude.png");
}
function create () {
background = game.add.image(ORIGIN, ORIGIN, "background");
game.add.text(TEXT_X_POS, TEXT_Y_POS, "Use the arrow keys or the arrow buttons below to move", TEXT_STYLE);
rightButton = game.add.button(RIGHT_BUTTON_X_POS, RIGHT_BUTTON_Y_POS, "right arrow", moveRight);
leftButtonDown = game.add.button(LEFT_BUTTON_X_POS, LEFT_BUTTON_Y_POS, "left arrow", moveLeft);
phaserDude = game.add.sprite(game.world.centerX, PHASER_DUDE_Y_POS, "phaser dude");
game.physics.arcade.enable(phaserDude);
phaserDude.body.collideWorldBounds = true;
phaserDude.body.gravity.y = PHASER_DUDE_GRAVITY;
rightKey = game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
leftKey = game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
}
function update () {
stopMoving();
if (leftKey.isDown || movingLeft === true) {
moveLeft();
}
if (rightKey.isDown || movingRight === true) {
moveRight();
}
}
function moveRight () {
phaserDude.body.velocity.x = PHASER_DUDE_RIGHT_VELOCITY;
}
function moveLeft () {
phaserDude.body.velocity.x = PHASER_DUDE_LEFT_VELOCITY;
}
function stopMoving () {
phaserDude.body.velocity.x = STOPPED;
}
As you can see, the arrow keys work fine for moving the sprite, but the mobile buttons do not work well; they only move the sprite for a frame, and then it stops moving again. I'm not sure why the keys work, yet the mobile buttons don't. The problem seems to be that the code in the class is not being run the way that I am thinking it should run (i.e., it seems like all of the code concerning the onInputOver, onInputDown, and onInputUp events is not being correctly run and the class is only paying attention to the method to run when a button is pressed). Can anyone figure out what the problem is with my button class?
Your problem is that the onInputDown of Phaser.Button only fires once each time the button is pressed.
What you need to do is set an isDown property on the button something like this:
button.events.onInputDown.add(function () {
button.isDown = true;
});
button.events.onInputUp.add(function () {
button.isDown = false;
});
And the in your update method check for that property:
function update () {
stopMoving();
if (leftKey.isDown || leftButton.isDown) {
moveLeft();
}