Merge branch 'gamepadsupport' of https://github.com/karlmacklin/phaser into karlmacklin-gamepadsupport

Conflicts:
	README.md
This commit is contained in:
photonstorm 2013-12-31 00:43:54 +00:00
parent ba74bea4b4
commit 29d7cc36a0
19 changed files with 3541 additions and 0 deletions

View file

@ -76,6 +76,9 @@
<script src="$path/src/input/MSPointer.js"></script>
<script src="$path/src/input/Pointer.js"></script>
<script src="$path/src/input/Touch.js"></script>
<script src="$path/src/input/Gamepad.js"></script>
<script src="$path/src/input/SinglePad.js"></script>
<script src="$path/src/input/GamepadButton.js"></script>
<script src="$path/src/input/InputHandler.js"></script>
<script src="$path/src/gameobjects/Events.js"></script>

View file

@ -388,6 +388,30 @@
"file": "game+scale.js",
"title": "game scale"
},
{
"file": "gamepad+analog+button.js",
"title": "gamepad analog button"
},
{
"file": "gamepad+debug.js",
"title": "gamepad debug"
},
{
"file": "gamepad+hotkeys.js",
"title": "gamepad hotkeys"
},
{
"file": "gamepad+multiple+pads.js",
"title": "gamepad multiple pads"
},
{
"file": "gamepad+tanks.js",
"title": "gamepad tanks"
},
{
"file": "gamepad.js",
"title": "gamepad"
},
{
"file": "key.js",
"title": "key"
@ -439,6 +463,10 @@
{
"file": "snap+on+drag.js",
"title": "snap on drag"
},
{
"file": "touch+joystick.js",
"title": "touch joystick"
}
],
"loader": [

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@
<base href="../"></base>
<script src="_site/js/jquery-2.0.3.min.js" type="text/javascript"></script>
<script src="_site/js/purl.js" type="text/javascript"></script>
<script src="_site/js/gamecontroller.js" type="text/javascript"></script>
<!--
If you're wondering why we embed each script separately, and not just the single-file phaser lib
it's because it makes debugging *significantly* easier for us. Feel free to replace all the below
@ -80,6 +81,9 @@
<script src="../src/input/MSPointer.js"></script>
<script src="../src/input/Pointer.js"></script>
<script src="../src/input/Touch.js"></script>
<script src="../src/input/Gamepad.js"></script>
<script src="../src/input/SinglePad.js"></script>
<script src="../src/input/GamepadButton.js"></script>
<script src="../src/input/InputHandler.js"></script>
<script src="../src/gameobjects/Events.js"></script>

View file

@ -6,6 +6,7 @@
<base href="../"></base>
<script src="_site/js/jquery-2.0.3.min.js" type="text/javascript"></script>
<script src="_site/js/purl.js" type="text/javascript"></script>
<script src="_site/js/gamecontroller.js" type="text/javascript"></script>
<!--
If you're wondering why we embed each script separately, and not just the single-file phaser lib
it's because it makes debugging *significantly* easier for us. Feel free to replace all the below

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,93 @@
// Try this demo on Chrome with an XBOX 360 controller.
// Use left and right triggers.
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update:update });
function preload() {
game.load.spritesheet('controller-indicator', 'assets/misc/controller-indicator.png', 16,16);
}
var leftTriggerButton;
var leftTriggerGfx;
var rightTriggerGfx;
var indicator;
function create() {
game.stage.backgroundColor = '#736357';
game.input.gamepad.start();
setupScene();
/*
Here we see two ways to get similar result. Left trigger is via 'hotkey button' style and using Phaser Signals.
Right trigger is via callbacks. NOTE the difference in the callback functions - right trigger must make a check
for which button we're listening to.
*/
leftTriggerButton = game.input.gamepad.pad1.addButton(Phaser.Gamepad.XBOX360_LEFT_TRIGGER);
leftTriggerButton.onDown.add(onLeftTrigger);
leftTriggerButton.onUp.add(onLeftTrigger);
leftTriggerButton.onFloat.add(onLeftTrigger);
game.input.gamepad.pad1.addCallbacks(this, {
onFloat:onRightTrigger,
onUp: onRightTrigger,
onDown: onRightTrigger
});
}
function onLeftTrigger(button, value) {
leftTriggerGfx.clear();
leftTriggerGfx.beginFill(0xFF700B, 1);
leftTriggerGfx.lineStyle(2, 0xFFFFFF, 1);
leftTriggerGfx.drawRect(0, -value*500, 50, value*500 + 5);
leftTriggerGfx.endFill();
}
function onRightTrigger(buttonCode,value) {
if(buttonCode !== Phaser.Gamepad.XBOX360_RIGHT_TRIGGER) {
return;
}
rightTriggerGfx.clear();
rightTriggerGfx.beginFill(0xFF700B, 1);
rightTriggerGfx.lineStyle(2, 0xFFFFFF, 1);
rightTriggerGfx.drawRect(0, -value*500, 50, value*500 + 5);
rightTriggerGfx.endFill();
}
function update() {
// Pad "connected or not" indicator
if(game.input.gamepad.supported && game.input.gamepad.active && game.input.gamepad.pad1.connected) {
indicator.animations.frame = 0;
} else {
indicator.animations.frame = 1;
}
}
function setupScene() {
indicator = game.add.sprite(10,10, 'controller-indicator');
indicator.scale.x = indicator.scale.y = 2;
indicator.animations.frame = 1;
leftTriggerGfx = game.add.graphics(300,550);
leftTriggerGfx.beginFill(0xFF700B, 1);
leftTriggerGfx.lineStyle(2, 0xFFFFFF, 1);
leftTriggerGfx.drawRect(0, 0, 50, 5);
leftTriggerGfx.endFill();
rightTriggerGfx = game.add.graphics(450,550);
rightTriggerGfx.beginFill(0xFF700B, 1);
rightTriggerGfx.lineStyle(2, 0xFFFFFF, 1);
rightTriggerGfx.drawRect(0, 0, 50, 5);
rightTriggerGfx.endFill();
}

View file

@ -0,0 +1,189 @@
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
function preload() {
game.load.spritesheet('start-input-button', 'assets/buttons/gamepad-input-start.png', 168,70);
game.load.image('reset-buttons','assets/buttons/gamepad-reset-buttons.png');
}
var startInputButton;
var resetButton;
var supportedText;
var activeText;
var gamepadCountText;
var pad1;
var pad1Text;
var pad2;
var pad2Text;
var pad3;
var pad3Text;
var pad4;
var pad4Text;
var activityPad1Text;
var activityPad2Text;
var activityPad3Text;
var activityPad4Text;
var activityGlobalText;
var pad1StateText;
var pad2StateText;
var pad3StateText;
var pad4StateText;
function create() {
game.stage.backgroundColor = '#222222';
startInputButton = game.add.button(625, 5, 'start-input-button', onStartInput, this, 0, 0, 0);
resetButton = game.add.button(425, 5, 'reset-buttons', onResetButtons, this);
pad1 = game.input.gamepad.pad1;
pad2 = game.input.gamepad.pad2;
pad3 = game.input.gamepad.pad3;
pad4 = game.input.gamepad.pad4;
setupText();
}
function onStartInput() {
if(game.input.gamepad.active) {
game.input.gamepad.stop();
startInputButton.setFrames(0,0,0);
} else {
game.input.gamepad.start();
startInputButton.setFrames(1,1,1);
}
}
function onResetButtons() {
game.input.gamepad.reset();
}
function update() {
supportedText.setText('Gamepad supported in this browser: '+game.input.gamepad.supported);
activeText.setText('Gamepad input active: '+game.input.gamepad.active);
gamepadCountText.setText('Gamepads connected: '+game.input.gamepad.padsConnected);
updatePadStatusText(pad1._rawPad, pad1Text, 1);
updatePadStatusText(pad2._rawPad, pad2Text, 2);
updatePadStatusText(pad3._rawPad, pad3Text, 3);
updatePadStatusText(pad4._rawPad, pad4Text, 4);
updatePadsButtonsAxes(pad1._rawPad, pad1StateText, 1);
updatePadsButtonsAxes(pad2._rawPad, pad2StateText, 2);
updatePadsButtonsAxes(pad3._rawPad, pad3StateText, 3);
updatePadsButtonsAxes(pad4._rawPad, pad4StateText, 4);
}
function updatePadStatusText(rawPad, padText, num) {
if(rawPad) {
padText.setText('Pad '+num+': [ index: '+rawPad['index']+' | id: '+rawPad['id']
+' | timestamp: '+rawPad['timestamp']+']'
+' | buttons: '+rawPad.buttons.length
+' | axes: '+rawPad.axes.length
);
} else {
padText.setText('Pad '+num+': Not connected');
}
}
function updatePadsButtonsAxes(rawPad, padStateText, num) {
if(rawPad) {
var txt = 'Pad '+num+' buttons/axes: \n';
for (var i = 0; i < rawPad.buttons.length; i += 1) {
txt += 'Button '+i+': '+rawPad.buttons[i]+'\n';
}
for (var i = 0; i < rawPad.axes.length; i += 1) {
txt += 'Axis '+i+': '+rawPad.axes[i]+'\n';
}
padStateText.setText(txt);
}
}
function setupText() {
var style = { font: "12px Arial", fill: "#ffffff", align: "left" };
var tinyStyle = { font: "10px Arial", fill: "#ffffff", align: "left" };
supportedText = game.add.text(10, 10, 'Gamepad supported in this browser: '+game.input.gamepad.supported, style);
activeText = game.add.text(10, 30, 'Gamepad input active: '+game.input.gamepad.active, style);
gamepadCountText = game.add.text(10, 50, 'Gamepads connected: '+game.input.gamepad.padsConnected, style);
pad1StateText = game.add.text(10, 300, 'Pad 1 buttons/axes: ', tinyStyle);
pad2StateText = game.add.text(200, 300, 'Pad 2 buttons/axes: ', tinyStyle);
pad3StateText = game.add.text(390, 300, 'Pad 3 buttons/axes: ', tinyStyle);
pad4StateText = game.add.text(580, 300, 'Pad 4 buttons/axes: ', tinyStyle);
// Setting up infotext and callbacks for all separate four gamepads
pad1 = game.input.gamepad.pad1;
pad1Text = game.add.text(10, 80, 'Pad 1: ', style);
pad2 = game.input.gamepad.pad2;
pad2Text = game.add.text(10, 100, 'Pad 2: ', style);
pad3 = game.input.gamepad.pad3;
pad3Text = game.add.text(10, 120, 'Pad 3: ', style);
pad4 = game.input.gamepad.pad4;
pad4Text = game.add.text(10, 140, 'Pad 4: ', style);
activityPad1Text = game.add.text(10, 180, 'Last activity pad 1: ', style);
addPadCallbacks(pad1, activityPad1Text, 1);
activityPad2Text = game.add.text(10, 200, 'Last activity pad 2: ', style);
addPadCallbacks(pad2, activityPad2Text, 2);
activityPad3Text = game.add.text(10, 220, 'Last activity pad 3: ', style);
addPadCallbacks(pad3, activityPad3Text, 3);
activityPad4Text = game.add.text(10, 240, 'Last activity pad 4: ', style);
addPadCallbacks(pad4, activityPad4Text, 4);
activityGlobalText = game.add.text(10, 270, 'Last activity all pads: ', style);
// Here we're setting callbacks that will trigger from ALL gamepads connected
game.input.gamepad.addCallbacks(this, {
onConnect: function(padIndex){
activityGlobalText.setText('Last activity all pads: Connected with pad index '+padIndex);
},
onDisconnect: function(padIndex){
activityGlobalText.setText('Last activity all pads: Disconnected with pad index '+padIndex);
},
onDown: function(buttonCode, value, padIndex){
activityGlobalText.setText('Last activity all pads: Pad index '+padIndex+' buttonCode: '+buttonCode+' | value: '+value);
},
onUp: function(buttonCode, value, padIndex){
activityGlobalText.setText('Last activity all pads: Pad index '+padIndex+' buttonCode: '+buttonCode+' | value: '+value);
},
onAxis: function(axisState, padIndex) {
activityGlobalText.setText('Last activity all pads: Pad index '+padIndex+': axis '+axisState.axis+': '+axisState.value);
},
onFloat: function(buttonCode, value, padIndex) {
activityGlobalText.setText('Last activity all pads: Pad index '+padIndex+' buttonCode: '+buttonCode+' | value (float): '+value);
}
});
}
function addPadCallbacks(pad, text, index) {
pad.addCallbacks(this, {
onConnect: function(){
text.setText('Last activity pad '+index+': Connected');
},
onDisconnect: function(){
text.setText('Last activity pad '+index+': Disconnected');
},
onDown: function(buttonCode, value){
text.setText('Last activity pad '+index+': buttonCode: '+buttonCode+' | value: '+value);
},
onUp: function(buttonCode, value){
text.setText('Last activity pad '+index+': buttonCode: '+buttonCode+' | value: '+value);
},
onAxis: function(axisState) {
text.setText('Last activity pad '+index+': axis '+axisState.axis+': '+axisState.value);
},
onFloat: function(buttonCode, value) {
text.setText('Last activity pad '+index+': buttonCode: '+buttonCode+' | value (float): '+value);
}
});
}

View file

@ -0,0 +1,61 @@
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update:update });
function preload() {
game.load.image('phaser', 'assets/sprites/phaser-dude.png');
game.load.image('logo', 'assets/sprites/phaser_tiny.png');
game.load.image('pineapple', 'assets/sprites/pineapple.png');
game.load.spritesheet('controller-indicator', 'assets/misc/controller-indicator.png', 16,16);
}
var button1;
var button2;
var button3;
var indicator;
function update() {
// Pad "connected or not" indicator
if(game.input.gamepad.supported && game.input.gamepad.active && game.input.gamepad.pad1.connected) {
indicator.animations.frame = 0;
} else {
indicator.animations.frame = 1;
}
}
function create() {
game.stage.backgroundColor = '#736357';
game.input.gamepad.start();
indicator = game.add.sprite(10,10, 'controller-indicator');
indicator.scale.x = indicator.scale.y = 2;
indicator.animations.frame = 1;
// Here we create 3 "hotkey buttons" for Gamepad #1, buttons 0-2 and bind them all to their own functions
button1 = game.input.gamepad.pad1.addButton(Phaser.Gamepad.BUTTON_0);
button1.onDown.add(addPhaserDude, this);
button2 = game.input.gamepad.pad1.addButton(Phaser.Gamepad.BUTTON_1);
button2.onDown.add(addPhaserLogo, this);
button3 = game.input.gamepad.pad1.addButton(Phaser.Gamepad.BUTTON_2);
button3.onDown.add(addPineapple, this);
}
function addPhaserDude () {
game.add.sprite(game.world.randomX, game.world.randomY, 'phaser');
}
function addPhaserLogo () {
game.add.sprite(game.world.randomX, game.world.randomY, 'logo');
}
function addPineapple () {
game.add.sprite(game.world.randomX, game.world.randomY, 'pineapple');
}

View file

@ -0,0 +1,120 @@
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update:update });
function preload() {
game.load.image('phaser', 'assets/sprites/phaser-dude.png');
game.load.image('melon', 'assets/sprites/melon.png');
game.load.spritesheet('controller-indicator', 'assets/misc/controller-indicator.png', 16,16);
}
var pad1;
var pad2;
var indicator1;
var indicator2;
var player1;
var player2;
var melon;
function create() {
game.stage.backgroundColor = '#736357';
game.input.gamepad.start();
indicator1 = game.add.sprite(10,10, 'controller-indicator');
indicator1.scale.x = indicator1.scale.y = 2;
indicator1.animations.frame = 1;
indicator2 = game.add.sprite(10,50, 'controller-indicator');
indicator2.scale.x = indicator2.scale.y = 2;
indicator2.animations.frame = 1;
player1 = game.add.sprite(300, 300, 'phaser');
player1.anchor.setTo(0.5,0.5);
player2 = game.add.sprite(450, 300, 'phaser');
player2.anchor.setTo(0.5,0.5);
// This little melon dude is controlled by all gamepads!
melon = game.add.sprite(375, 350, 'melon');
melon.anchor.setTo(0.5,0.5);
pad1 = game.input.gamepad.pad1;
pad2 = game.input.gamepad.pad2;
}
function update() {
// Pad "connected or not" indicator
if(game.input.gamepad.supported && game.input.gamepad.active && game.input.gamepad.pad1.connected) {
indicator1.animations.frame = 0;
} else {
indicator1.animations.frame = 1;
}
if(game.input.gamepad.supported && game.input.gamepad.active && game.input.gamepad.pad2.connected) {
indicator2.animations.frame = 0;
} else {
indicator2.animations.frame = 1;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1)
{
player1.x--;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_RIGHT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) > 0.1)
{
player1.x++;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) < -0.1)
{
player1.y--;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_DOWN) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1)
{
player1.y++;
}
if (pad2.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || pad2.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1)
{
player2.x--;
}
if (pad2.isDown(Phaser.Gamepad.XBOX360_DPAD_RIGHT) || pad2.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) > 0.1)
{
player2.x++;
}
if (pad2.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || pad2.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) < -0.1)
{
player2.y--;
}
if (pad2.isDown(Phaser.Gamepad.XBOX360_DPAD_DOWN) || pad2.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1)
{
player2.y++;
}
// isDown on game.input.gamepad checks ALL gamepad buttons
if (game.input.gamepad.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT))
{
melon.x--;
}
if (game.input.gamepad.isDown(Phaser.Gamepad.XBOX360_DPAD_RIGHT))
{
melon.x++;
}
if (game.input.gamepad.isDown(Phaser.Gamepad.XBOX360_DPAD_UP))
{
melon.y--;
}
if (game.input.gamepad.isDown(Phaser.Gamepad.XBOX360_DPAD_DOWN))
{
melon.y++;
}
}

View file

@ -0,0 +1,335 @@
// Try this demo on Chrome with an XBOX 360 controller.
// Steer with left analog, accelerate/brake with analog triggers,
// fire with A and steer turret with left and right 'bumper' (shoulder) buttons.
EnemyTank = function (index, game, player, bullets) {
var x = game.world.randomX;
var y = game.world.randomY;
this.game = game;
this.health = 3;
this.player = player;
this.bullets = bullets;
this.fireRate = 1000;
this.nextFire = 0;
this.alive = true;
this.shadow = game.add.sprite(x, y, 'enemy', 'shadow');
this.tank = game.add.sprite(x, y, 'enemy', 'tank1');
this.turret = game.add.sprite(x, y, 'enemy', 'turret');
this.shadow.anchor.setTo(0.5, 0.5);
this.tank.anchor.setTo(0.5, 0.5);
this.turret.anchor.setTo(0.3, 0.5);
this.tank.name = index.toString();
this.tank.body.immovable = true;
this.tank.body.collideWorldBounds = true;
this.tank.body.bounce.setTo(1, 1);
this.tank.angle = game.rnd.angle();
game.physics.velocityFromRotation(this.tank.rotation, 100, this.tank.body.velocity);
};
EnemyTank.prototype.damage = function() {
this.health -= 1;
if (this.health <= 0)
{
this.alive = false;
this.shadow.kill();
this.tank.kill();
this.turret.kill();
return true;
}
return false;
};
EnemyTank.prototype.update = function() {
this.shadow.x = this.tank.x;
this.shadow.y = this.tank.y;
this.shadow.rotation = this.tank.rotation;
this.turret.x = this.tank.x;
this.turret.y = this.tank.y;
this.turret.rotation = this.game.physics.angleBetween(this.tank, this.player);
if (this.game.physics.distanceBetween(this.tank, this.player) < 300)
{
if (this.game.time.now > this.nextFire && this.bullets.countDead() > 0)
{
this.nextFire = this.game.time.now + this.fireRate;
var bullet = this.bullets.getFirstDead();
bullet.reset(this.turret.x, this.turret.y);
bullet.rotation = this.game.physics.moveToObject(bullet, this.player, 500);
}
}
};
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
function preload () {
game.load.atlas('tank', 'assets/games/tanks/tanks.png', 'assets/games/tanks/tanks.json');
game.load.atlas('enemy', 'assets/games/tanks/enemy-tanks.png', 'assets/games/tanks/tanks.json');
game.load.image('logo', 'assets/games/tanks/logo-gamepad.png');
game.load.image('bullet', 'assets/games/tanks/bullet.png');
game.load.image('earth', 'assets/games/tanks/scorched_earth.png');
game.load.spritesheet('kaboom', 'assets/games/tanks/explosion.png', 64, 64, 23);
game.load.spritesheet('controller-indicator', 'assets/misc/controller-indicator.png', 16,16);
}
var land;
var shadow;
var tank;
var turret;
var enemies;
var enemyBullets;
var explosions;
var logo;
var currentSpeed = 0;
var cursors;
var bullets;
var fireRate = 200;
var nextFire = 0;
var indicator;
var pad1;
var turretOffset = 0;
function create () {
// Resize our game world to be a 2000 x 2000 square
game.world.setBounds(-1000, -1000, 2000, 2000);
// Our tiled scrolling background
land = game.add.tileSprite(0, 0, 800, 600, 'earth');
land.fixedToCamera = true;
// The base of our tank
tank = game.add.sprite(0, 0, 'tank', 'tank1');
tank.anchor.setTo(0.5, 0.5);
tank.animations.add('move', ['tank1', 'tank2', 'tank3', 'tank4', 'tank5', 'tank6'], 20, true);
// tank.play('move');
// This will force it to decelerate and limit its speed
tank.body.drag.setTo(200, 200);
tank.body.maxVelocity.setTo(400, 400);
tank.body.collideWorldBounds = true;
// Finally the turret that we place on-top of the tank body
turret = game.add.sprite(0, 0, 'tank', 'turret');
turret.anchor.setTo(0.3, 0.5);
// The enemies bullet group
enemyBullets = game.add.group();
enemyBullets.createMultiple(100, 'bullet');
enemyBullets.setAll('anchor.x', 0.5);
enemyBullets.setAll('anchor.y', 0.5);
enemyBullets.setAll('outOfBoundsKill', true);
// Create some baddies to waste :)
enemies = [];
for (var i = 0; i < 20; i++)
{
enemies.push(new EnemyTank(i, game, tank, enemyBullets));
}
// A shadow below our tank
shadow = game.add.sprite(0, 0, 'tank', 'shadow');
shadow.anchor.setTo(0.5, 0.5);
// Our bullet group
bullets = game.add.group();
bullets.createMultiple(30, 'bullet');
bullets.setAll('anchor.x', 0.5);
bullets.setAll('anchor.y', 0.5);
bullets.setAll('outOfBoundsKill', true);
// Explosion pool
explosions = game.add.group();
for (var i = 0; i < 10; i++)
{
var explosionAnimation = explosions.create(0, 0, 'kaboom', [0], false);
explosionAnimation.anchor.setTo(0.5, 0.5);
explosionAnimation.animations.add('kaboom');
}
tank.bringToTop();
turret.bringToTop();
logo = game.add.sprite(0, 200, 'logo');
logo.fixedToCamera = true;
game.camera.follow(tank);
game.camera.deadzone = new Phaser.Rectangle(150, 150, 500, 300);
game.camera.focusOnXY(0, 0);
pad1 = game.input.gamepad.pad1;
pad1.addCallbacks(this, {onDown:function(){
removeLogo();
}});
indicator = game.add.sprite(10,10, 'controller-indicator');
indicator.scale.x = indicator.scale.y = 2;
indicator.animations.frame = 1;
indicator.fixedToCamera = true;
game.input.gamepad.start();
// showing you can set the deadZone for all pads
// you can also set it like game.input.gamepad.pad1.deadZone = 0.25
// default is 0.26 and is sensible enough for an xbox 360 controller as the
// axes seems to hickup at quite high values at times (your mileage may vary)
game.input.gamepad.setDeadZones(0.25);
}
function removeLogo () {
game.input.onDown.remove(removeLogo, this);
logo.kill();
}
function update () {
// Pad "connected or not" indicator
if(game.input.gamepad.supported && game.input.gamepad.active && pad1.connected) {
indicator.animations.frame = 0;
} else {
indicator.animations.frame = 1;
}
game.physics.collide(enemyBullets, tank, bulletHitPlayer, null, this);
for (var i = 0; i < enemies.length; i++)
{
if (enemies[i].alive)
{
enemies[i].update();
game.physics.collide(tank, enemies[i].tank);
game.physics.collide(bullets, enemies[i].tank, bulletHitEnemy, null, this);
}
}
if (pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.3)
{
tank.angle -= 4 * -pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X);
}
if (pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) > 0.3)
{
tank.angle += 4 * pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X);
}
var rightTriggerValue = pad1.buttonValue(Phaser.Gamepad.XBOX360_RIGHT_TRIGGER);
if(rightTriggerValue && rightTriggerValue > 0) {
currentSpeed = 300 * rightTriggerValue;
} else {
if (currentSpeed > 0)
{
currentSpeed -= 4;
}
}
var leftTriggerValue = pad1.buttonValue(Phaser.Gamepad.XBOX360_LEFT_TRIGGER);
if(leftTriggerValue && leftTriggerValue > 0) {
currentSpeed = 150 * -leftTriggerValue;
} else {
if (currentSpeed < 0)
{
currentSpeed += 4;
currentSpeed = (currentSpeed > 0) ? 0 : currentSpeed;
}
}
// if (currentSpeed > 0)
// {
game.physics.velocityFromRotation(tank.rotation, currentSpeed, tank.body.velocity);
// }
land.tilePosition.x = -game.camera.x;
land.tilePosition.y = -game.camera.y;
// Position all the parts and align rotations
shadow.x = tank.x;
shadow.y = tank.y;
shadow.rotation = tank.rotation;
turret.x = tank.x;
turret.y = tank.y;
if (pad1.isDown(Phaser.Gamepad.XBOX360_LEFT_BUMPER)) {
turretOffset -= 3;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_RIGHT_BUMPER)) {
turretOffset += 3;
}
turret.rotation = tank.rotation;
turret.angle += turretOffset;
// turret.rotation = game.physics.angleToPointer(turret);
if (pad1.isDown(Phaser.Gamepad.XBOX360_A))
{
fire();
}
}
function bulletHitPlayer (tank, bullet) {
bullet.kill();
}
function bulletHitEnemy (tank, bullet) {
bullet.kill();
var destroyed = enemies[tank.name].damage();
if (destroyed)
{
var explosionAnimation = explosions.getFirstDead();
explosionAnimation.reset(tank.x, tank.y);
explosionAnimation.play('kaboom', 30, false, true);
}
}
function fire () {
if (game.time.now > nextFire && bullets.countDead() > 0)
{
nextFire = game.time.now + fireRate;
var bullet = bullets.getFirstDead();
bullet.reset(turret.x, turret.y);
bullet.rotation = turret.rotation;
game.physics.velocityFromAngle(bullet.angle, 1000, bullet.body.velocity);
}
}

80
examples/input/gamepad.js Normal file
View file

@ -0,0 +1,80 @@
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
function preload() {
game.load.image('phaser', 'assets/sprites/phaser-dude.png');
game.load.spritesheet('controller-indicator', 'assets/misc/controller-indicator.png', 16,16);
}
var sprite;
var pad1;
var indicator;
function create() {
game.stage.backgroundColor = '#736357';
sprite = game.add.sprite(300, 300, 'phaser');
sprite.anchor.setTo(0.5,0.5);
indicator = game.add.sprite(10,10, 'controller-indicator');
indicator.scale.x = indicator.scale.y = 2;
indicator.animations.frame = 1;
game.input.gamepad.start();
// To listen to buttons from a specific pad listen directly on that pad game.input.gamepad.padX, where X = pad 1-4
pad1 = game.input.gamepad.pad1;
}
function update() {
// Pad "connected or not" indicator
if(game.input.gamepad.supported && game.input.gamepad.active && pad1.connected) {
indicator.animations.frame = 0;
} else {
indicator.animations.frame = 1;
}
// Controls
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1)
{
sprite.x--;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_RIGHT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) > 0.1)
{
sprite.x++;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) < -0.1)
{
sprite.y--;
}
if (pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_DOWN) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1)
{
sprite.y++;
}
if (pad1.justPressed(Phaser.Gamepad.XBOX360_A))
{
sprite.angle += 5;
}
if (pad1.justReleased(Phaser.Gamepad.XBOX360_B))
{
sprite.scale.x += 0.01;
sprite.scale.y = sprite.scale.x;
}
if(pad1.connected) {
var rightStickX = pad1.axis(Phaser.Gamepad.XBOX360_STICK_RIGHT_X);
var rightStickY = pad1.axis(Phaser.Gamepad.XBOX360_STICK_RIGHT_Y);
if(rightStickX) {
sprite.x += rightStickX * 10;
}
if(rightStickY) {
sprite.y += rightStickY * 10;
}
}
}

View file

@ -0,0 +1,68 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
var ufo;
var ufoSpeed = 200;
function preload() {
game.world.setBounds(0,0,800, 600);
game.load.image('ufo', 'assets/sprites/ufo.png');
}
function create() {
// Create a ufo sprite as player.
ufo = game.add.sprite(320, 240, 'ufo');
ufo.anchor.setTo(0.5, 0.5);
// Use Austin Hallock's HTML5 Virtual Game Controller
// https://github.com/austinhallock/html5-virtual-game-controller/
// Note: you must also require gamecontroller.js on your host page.
// Init game controller with left thumb stick
GameController.init({
left: {
type: 'joystick',
joystick: {
touchStart: function() {
// Don't need this, but the event is here if you want it.
},
touchMove: function(joystick_details) {
game.input.joystickLeft = joystick_details;
},
touchEnd: function() {
game.input.joystickLeft = null;
}
}
},
right: {
// We're not using anything on the right for this demo, but you can add buttons, etc.
// See https://github.com/austinhallock/html5-virtual-game-controller/ for examples.
type: 'none'
}
});
// This is an ugly hack to get this to show up over the Phaser Canvas
// (which has a manually set z-index in the example code) and position it in the right place,
// because it's positioned relatively...
// You probably don't need to do this in your game unless your game's canvas is positioned in a manner
// similar to this example page, where the canvas isn't the whole screen.
$('canvas').last().css('z-index', 20);
$('canvas').last().offset( $('canvas').first().offset() );
}
function update() {
// Check key states every frame.
if (game.input.joystickLeft) {
// Move the ufo using the joystick's normalizedX and Y values,
// which range from -1 to 1.
ufo.body.velocity.setTo(game.input.joystickLeft.normalizedX * 200, game.input.joystickLeft.normalizedY * ufoSpeed * -1);
}
else {
ufo.body.velocity.setTo(0, 0);
}
}
function render() {
game.debug.renderText('Use the virtual joystick to move the UFO.', 20, 20);
game.debug.renderText('This requires touch events, so try on your phone.', 20, 40);
}

543
src/input/Gamepad.js Normal file
View file

@ -0,0 +1,543 @@
/**
* @author @karlmacklin <tacklemcclean@gmail.com>
* @copyright 2013 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* The Gamepad class handles looking after gamepad input for your game.
* Remember to call gamepad.start(); expecting input!
*
* HTML5 GAMEPAD API SUPPORT IS AT AN EXPERIMENTAL STAGE!
* At moment of writing this (end of 2013) only Chrome supports parts of it out of the box. Firefox supports it
* via prefs flags (about:config, search gamepad). The browsers map the same controllers differently.
* This class has constans for Windows 7 Chrome mapping of
* XBOX 360 controller.
*
* @class Phaser.Gamepad
* @constructor
* @param {Phaser.Game} game - A reference to the currently running game.
*/
Phaser.Gamepad = function (game) {
/**
* @property {Phaser.Game} game - Local reference to game.
*/
this.game = game;
/**
* @property {Array} _gamepads - The four Phaser Gamepads.
* @private
*/
this._gamepads = [
new Phaser.SinglePad(game,this),
new Phaser.SinglePad(game,this),
new Phaser.SinglePad(game,this),
new Phaser.SinglePad(game,this)
];
/**
* @property {Object} _gamepadIndexMap - Maps the browsers gamepad indices to our Phaser Gamepads
* @private
*/
this._gamepadIndexMap = {};
/**
* @property {Array} _rawPads - The raw state of the gamepads from the browser
* @private
*/
this._rawPads = [];
/**
* @property {boolean} _active - Private flag for whether or not the API is polled
* @private
*/
this._active = false;
/**
* You can disable all Gamepad Input by setting disabled to true. While true all new input related events will be ignored.
* @property {boolean} disabled - The disabled state of the Gamepad.
* @default
*/
this.disabled = false;
/**
* Whether or not gamepads are supported* in current browser. * = This check is actually not accurate at all due to poor implementation.
* @property {boolean} _gamepadSupportAvailable - Gamepad supported in this browser or not.
* @private
* @default
*/
this._gamepadSupportAvailable = !!navigator.webkitGetGamepads || !!navigator.webkitGamepads || (navigator.userAgent.indexOf('Firefox/') != -1);
/**
* Used to check for differences between earlier polls and current state of gamepads.
* @property {Array} _prevRawGamepadTypes
* @private
* @default
*/
this._prevRawGamepadTypes = [];
/**
* Used to check for differences between earlier polls and current state of gamepads.
* @property {Array} _prevTimestamps
* @private
* @default
*/
this._prevTimestamps = [];
/**
* @property {Object} callbackContext - The context under which the callbacks are run.
*/
this.callbackContext = this;
/**
* @property {function} onConnectCallback - This callback is invoked every time any gamepad is connected
*/
this.onConnectCallback = null;
/**
* @property {function} onDisconnectCallback - This callback is invoked every time any gamepad is disconnected
*/
this.onDisconnectCallback = null;
/**
* @property {function} onDownCallback - This callback is invoked every time any gamepad button is pressed down.
*/
this.onDownCallback = null;
/**
* @property {function} onUpCallback - This callback is invoked every time any gamepad button is released.
*/
this.onUpCallback = null;
/**
* @property {function} onAxisCallback - This callback is invoked every time any gamepad axis is changed.
*/
this.onAxisCallback = null;
/**
* @property {function} onFloatCallback - This callback is invoked every time any gamepad button is changed to a value where value > 0 and value < 1.
*/
this.onFloatCallback = null;
/**
* @property {function} _ongamepadconnected - Private callback for Firefox gamepad connection handling
* @private
*/
this._ongamepadconnected = null;
/**
* @property {function} _gamepaddisconnected - Private callback for Firefox gamepad connection handling
* @private
*/
this._gamepaddisconnected = null;
};
Phaser.Gamepad.prototype = {
/**
* Add callbacks to the main Gamepad handler to handle connect/disconnect/button down/button up/axis change/float value buttons
* @method Phaser.Gamepad#addCallbacks
* @param {Object} context - The context under which the callbacks are run.
* @param {Object} callbacks - Object that takes six different callbak methods:
* onConnectCallback, onDisconnectCallback, onDownCallback, onUpCallback, onAxisCallback, onFloatCallback
*/
addCallbacks: function (context, callbacks) {
if (typeof callbacks !== 'undefined') {
this.onConnectCallback = (typeof callbacks.onConnect === 'function') ? callbacks.onConnect : this.onConnectCallback;
this.onDisconnectCallback = (typeof callbacks.onDisconnect === 'function') ? callbacks.onDisconnect : this.onDisconnectCallback;
this.onDownCallback = (typeof callbacks.onDown === 'function') ? callbacks.onDown : this.onDownCallback;
this.onUpCallback = (typeof callbacks.onUp === 'function') ? callbacks.onUp : this.onUpCallback;
this.onAxisCallback = (typeof callbacks.onAxis === 'function') ? callbacks.onAxis : this.onAxisCallback;
this.onFloatCallback = (typeof callbacks.onFloat === 'function') ? callbacks.onFloat : this.onFloatCallback;
}
},
// /**
// * Removes a Button object from the Gamepad manager.
// *
// * @method Phaser.Gamepad#removeKey
// * @param {number} buttoncode - The buttoncode of the button to remove, i.e. Phaser.Gamepad.0 or Phaser.Gamepad.1
// */
// removeButton: function (buttoncode) {
//
// delete (this._hotbuttons[buttoncode]);
//
// },
/**
* Starts the Gamepad event handling.
* This MUST be called manually before Phaser will start polling the Gamepad API.
*
* @method Phaser.Gamepad#start
*/
start: function () {
this._active = true;
var _this = this;
this._ongamepadconnected = function(event) {
var newPad = event.gamepad;
_this._rawPads.push(newPad);
_this._gamepads[newPad.index].connect(newPad);
};
window.addEventListener('gamepadconnected', this._ongamepadconnected, false);
this._ongamepaddisconnected = function(event) {
var removedPad = event.gamepad;
for (var i in _this._rawPads) {
if(_this._rawPads[i].index === removedPad.index) {
_this._rawPads.splice(i,1);
}
}
_this._gamepads[removedPad.index].disconnect();
};
window.addEventListener('gamepaddisconnected', this._ongamepaddisconnected, false);
},
/**
* Main gamepad update loop. Should not be called manually.
* @method Phaser.Gamepad#update
*/
update: function () {
this._pollGamepads();
for (var i = 0; i < this._gamepads.length; i += 1) {
if(this._gamepads[i]._connected) {
this._gamepads[i].pollStatus();
}
}
},
/**
* Updating connected gamepads (for Google Chrome).
* Should not be called manually.
* @method Phaser.Gamepad#_pollGamepads
*/
_pollGamepads: function () {
var rawGamepads = (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) || navigator.webkitGamepads;
if(rawGamepads) {
this._rawPads = [];
var gamepadsChanged = false;
for (var i = 0; i < rawGamepads.length; i += 1) {
if (typeof rawGamepads[i] !== this._prevRawGamepadTypes[i]) {
gamepadsChanged = true;
this._prevRawGamepadTypes[i] = typeof rawGamepads[i];
}
if (rawGamepads[i]) {
this._rawPads.push(rawGamepads[i]);
}
// Support max 4 pads at the moment
if(i === 3) {
break;
}
}
if(gamepadsChanged) {
var validConnections = {rawIndices:{},padIndices:{}};
var singlePad;
for (var j = 0; j < this._gamepads.length; j += 1) {
singlePad = this._gamepads[j];
if(singlePad.connected) {
for(var k = 0; k < this._rawPads.length; k += 1) {
if(this._rawPads[k].index === singlePad.index) {
validConnections.rawIndices[singlePad.index] = true;
validConnections.padIndices[j] = true;
}
}
}
}
for (var l = 0; l < this._gamepads.length; l += 1) {
singlePad = this._gamepads[l];
if(validConnections.padIndices[l]) {
continue;
}
if(this._rawPads.length < 1) {
singlePad.disconnect();
}
for (var m = 0; m < this._rawPads.length; m +=1) {
if(validConnections.padIndices[l]) {
break;
}
var rawPad = this._rawPads[m];
if (rawPad) {
if(validConnections.rawIndices[rawPad.index]) {
singlePad.disconnect();
continue;
} else {
singlePad.connect(rawPad);
validConnections.rawIndices[rawPad.index] = true;
validConnections.padIndices[l] = true;
}
} else {
singlePad.disconnect();
}
}
}
}
}
},
/**
* Sets the deadZone variable for all four gamepads
* @method Phaser.Gamepad#setDeadZones
*/
setDeadZones: function (value) {
for(var i = 0; i < this._gamepads.length; i += 1) {
this._gamepads[i].deadZone = value;
}
},
/**
* Stops the Gamepad event handling.
*
* @method Phaser.Gamepad#stop
*/
stop: function () {
this._active = false;
var _this = this;
window.removeEventListener('gamepadconnected', this._ongamepadconnected);
window.removeEventListener('gamepaddisconnected', this._ongamepaddisconnected);
},
/**
* Reset all buttons/axes of all gamepads
* @method Phaser.Gamepad#reset
*/
reset: function () {
this.update();
for(var i = 0; i < this._gamepads.length; i += 1) {
this._gamepads[i].reset();
}
},
/**
* Returns the "just pressed" state of a button from ANY gamepad connected. Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
* @method Phaser.Gamepad#justPressed
* @param {number} buttonCode - The buttonCode of the button to check for.
* @param {number} [duration=250] - The duration below which the button is considered as being just pressed.
* @return {boolean} True if the button is just pressed otherwise false.
*/
justPressed: function (buttonCode, duration) {
for(var i = 0; i < this._gamepads.length; i += 1) {
if( this._gamepads[i].justPressed(buttonCode, duration) == true ) {
return true;
}
}
return false;
},
/**
* Returns the "just released" state of a button from ANY gamepad connected. Just released is considered as being true if the button was released within the duration given (default 250ms).
* @method Phaser.Gamepad#justPressed
* @param {number} buttonCode - The buttonCode of the button to check for.
* @param {number} [duration=250] - The duration below which the button is considered as being just released.
* @return {boolean} True if the button is just released otherwise false.
*/
justReleased: function (buttonCode, duration) {
for(var i = 0; i < this._gamepads.length; i += 1) {
if( this._gamepads[i].justReleased(buttonCode, duration) == true ) {
return true;
}
}
return false;
},
/**
* Returns true if the button is currently pressed down, on ANY gamepad.
* @method Phaser.Gamepad#isDown
* @param {number} buttonCode - The buttonCode of the button to check for.
* @return {boolean} True if a button is currently down.
*/
isDown: function (buttonCode) {
for(var i = 0; i < this._gamepads.length; i += 1) {
if( this._gamepads[i].isDown(buttonCode) == true ) {
return true;
}
}
return false;
}
};
/**
* If the gamepad input is active or not - if not active it should not be updated from Input.js
* @name Phaser.Gamepad#active
* @property {boolean} active - If the gamepad input is active or not.
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "active", {
get: function () {
return this._active;
}
});
/**
* Whether or not gamepads are supported in current browser.
* @name Phaser.Gamepad#supported
* @property {boolean} supported - Whether or not gamepads are supported in current browser.
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "supported", {
get: function () {
return this._gamepadSupportAvailable;
}
});
/**
* How many live gamepads are currently connected.
* @name Phaser.Gamepad#padsConnected
* @property {boolean} padsConnected - How many live gamepads are currently connected.
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "padsConnected", {
get: function () {
return this._rawPads.length;
}
});
/**
* Gamepad #1
* @name Phaser.Gamepad#pad1
* @property {boolean} pad1 - Gamepad #1;
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "pad1", {
get: function () {
return this._gamepads[0];
}
});
/**
* Gamepad #2
* @name Phaser.Gamepad#pad2
* @property {boolean} pad2 - Gamepad #2
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "pad2", {
get: function () {
return this._gamepads[1];
}
});
/**
* Gamepad #3
* @name Phaser.Gamepad#pad3
* @property {boolean} pad3 - Gamepad #3
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "pad3", {
get: function () {
return this._gamepads[2];
}
});
/**
* Gamepad #4
* @name Phaser.Gamepad#pad4
* @property {boolean} pad4 - Gamepad #4
* @readonly
*/
Object.defineProperty(Phaser.Gamepad.prototype, "pad4", {
get: function () {
return this._gamepads[3];
}
});
Phaser.Gamepad.BUTTON_0 = 0;
Phaser.Gamepad.BUTTON_1 = 1;
Phaser.Gamepad.BUTTON_2 = 2;
Phaser.Gamepad.BUTTON_3 = 3;
Phaser.Gamepad.BUTTON_4 = 4;
Phaser.Gamepad.BUTTON_5 = 5;
Phaser.Gamepad.BUTTON_6 = 6;
Phaser.Gamepad.BUTTON_7 = 7;
Phaser.Gamepad.BUTTON_8 = 8;
Phaser.Gamepad.BUTTON_9 = 9;
Phaser.Gamepad.BUTTON_10 = 10;
Phaser.Gamepad.BUTTON_11 = 11;
Phaser.Gamepad.BUTTON_12 = 12;
Phaser.Gamepad.BUTTON_13 = 13;
Phaser.Gamepad.BUTTON_14 = 14;
Phaser.Gamepad.BUTTON_15 = 15;
Phaser.Gamepad.AXIS_0 = 0;
Phaser.Gamepad.AXIS_1 = 1;
Phaser.Gamepad.AXIS_2 = 2;
Phaser.Gamepad.AXIS_3 = 3;
Phaser.Gamepad.AXIS_4 = 4;
Phaser.Gamepad.AXIS_5 = 5;
Phaser.Gamepad.AXIS_6 = 6;
Phaser.Gamepad.AXIS_7 = 7;
Phaser.Gamepad.AXIS_8 = 8;
Phaser.Gamepad.AXIS_9 = 9;
// Below mapping applies to XBOX 360 Wired and Wireless controller on Google Chrome (tested on Windows 7).
// - Firefox uses different map! Separate amount of buttons and axes. DPAD = axis and not a button.
// In other words - discrepancies when using gamepads.
Phaser.Gamepad.XBOX360_A = 0;
Phaser.Gamepad.XBOX360_B = 1;
Phaser.Gamepad.XBOX360_X = 2;
Phaser.Gamepad.XBOX360_Y = 3;
Phaser.Gamepad.XBOX360_LEFT_BUMPER = 4;
Phaser.Gamepad.XBOX360_RIGHT_BUMPER = 5;
Phaser.Gamepad.XBOX360_LEFT_TRIGGER = 6;
Phaser.Gamepad.XBOX360_RIGHT_TRIGGER = 7;
Phaser.Gamepad.XBOX360_BACK = 8;
Phaser.Gamepad.XBOX360_START = 9;
Phaser.Gamepad.XBOX360_STICK_LEFT_BUTTON = 10;
Phaser.Gamepad.XBOX360_STICK_RIGHT_BUTTON = 11;
Phaser.Gamepad.XBOX360_DPAD_LEFT = 14;
Phaser.Gamepad.XBOX360_DPAD_RIGHT = 15;
Phaser.Gamepad.XBOX360_DPAD_UP = 12;
Phaser.Gamepad.XBOX360_DPAD_DOWN = 13;
Phaser.Gamepad.XBOX360_STICK_LEFT_X = 0;
Phaser.Gamepad.XBOX360_STICK_LEFT_Y = 1;
Phaser.Gamepad.XBOX360_STICK_RIGHT_X = 2;
Phaser.Gamepad.XBOX360_STICK_RIGHT_Y = 3;

172
src/input/GamepadButton.js Normal file
View file

@ -0,0 +1,172 @@
/**
* @author @karlmacklin <tacklemcclean@gmail.com>
* @copyright 2013 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* @class Phaser.GamepadButton
* @classdesc If you need more fine-grained control over the handling of specific buttons you can create and use Phaser.GamepadButton objects.
* @constructor
* @param {Phaser.Game} game - Current game instance.
* @param {number} buttoncode - The button code this GamepadButton is responsible for.
*/
Phaser.GamepadButton = function (game, buttoncode) {
/**
* @property {Phaser.Game} game - A reference to the currently running game.
*/
this.game = game;
/**
* @property {boolean} isDown - The "down" state of the button.
* @default
*/
this.isDown = false;
/**
* @property {boolean} isUp - The "up" state of the button.
* @default
*/
this.isUp = false;
/**
* @property {number} timeDown - The timestamp when the button was last pressed down.
* @default
*/
this.timeDown = 0;
/**
* If the button is down this value holds the duration of that button press and is constantly updated.
* If the button is up it holds the duration of the previous down session.
* @property {number} duration - The number of milliseconds this button has been held down for.
* @default
*/
this.duration = 0;
/**
* @property {number} timeUp - The timestamp when the button was last released.
* @default
*/
this.timeUp = 0;
/**
* @property {number} repeats - If a button is held down this holds down the number of times the button has 'repeated'.
* @default
*/
this.repeats = 0;
/**
* @property {number} value - Button value. Mainly useful for checking analog buttons (like shoulder triggers)
* @default
*/
this.value = 0;
/**
* @property {number} buttonCode - The buttoncode of this button.
*/
this.buttonCode = buttoncode;
/**
* @property {Phaser.Signal} onDown - This Signal is dispatched every time this GamepadButton is pressed down. It is only dispatched once (until the button is released again).
*/
this.onDown = new Phaser.Signal();
/**
* @property {Phaser.Signal} onUp - This Signal is dispatched every time this GamepadButton is pressed down. It is only dispatched once (until the button is released again).
*/
this.onUp = new Phaser.Signal();
/**
* @property {Phaser.Signal} onFloat - This Signal is dispatched every time this GamepadButton changes floating value (between (but not exactly) 0 and 1)
*/
this.onFloat = new Phaser.Signal();
};
Phaser.GamepadButton.prototype = {
/**
* Called automatically by Phaser.SinglePad.
* @method Phaser.GamepadButton#processButtonDown
* @param {Object} value - Button value
* @protected
*/
processButtonDown: function (value) {
if (this.isDown) {
this.duration = this.game.time.now - this.timeDown;
this.repeats++;
}
else {
this.isDown = true;
this.isUp = false;
this.timeDown = this.game.time.now;
this.duration = 0;
this.repeats = 0;
this.value = value;
this.onDown.dispatch(this, value);
}
},
/**
* Called automatically by Phaser.SinglePad.
* @method Phaser.GamepadButton#processButtonUp
* @param {Object} value - Button value
* @protected
*/
processButtonUp: function (value) {
this.isDown = false;
this.isUp = true;
this.timeUp = this.game.time.now;
this.value = value;
this.onUp.dispatch(this, value);
},
/**
* Called automatically by Phaser.Gamepad.
* @method Phaser.GamepadButton#processButtonFloat
* @param {Object} value - Button value
* @protected
*/
processButtonFloat: function (value) {
this.value = value;
this.onFloat.dispatch(this, value);
},
/**
* Returns the "just pressed" state of this button. Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
* @method Phaser.GamepadButton#justPressed
* @param {number} [duration=250] - The duration below which the button is considered as being just pressed.
* @return {boolean} True if the button is just pressed otherwise false.
*/
justPressed: function (duration) {
if (typeof duration === "undefined") {
duration = 250;
}
return (this.isDown && this.duration < duration);
},
/**
* Returns the "just released" state of this button. Just released is considered as being true if the button was released within the duration given (default 250ms).
* @method Phaser.GamepadButton#justPressed
* @param {number} [duration=250] - The duration below which the button is considered as being just released.
* @return {boolean} True if the button is just pressed otherwise false.
*/
justReleased: function (duration) {
if (typeof duration === "undefined") {
duration = 250;
}
return (this.isDown === false && (this.game.time.now - this.timeUp < duration));
}
};

View file

@ -306,6 +306,13 @@ Phaser.Input.prototype = {
*/
mspointer: null,
/**
* The Gamepad Input manager.
* @property {Phaser.Gamepad} gamepad - The Gamepad Input manager.
* @default
*/
gamepad: null,
/**
* A Signal that is dispatched each time a pointer is pressed down.
* @property {Phaser.Signal} onDown
@ -355,6 +362,7 @@ Phaser.Input.prototype = {
this.keyboard = new Phaser.Keyboard(this.game);
this.touch = new Phaser.Touch(this.game);
this.mspointer = new Phaser.MSPointer(this.game);
this.gamepad = new Phaser.Gamepad(this.game);
this.onDown = new Phaser.Signal();
this.onUp = new Phaser.Signal();
@ -394,6 +402,7 @@ Phaser.Input.prototype = {
this.keyboard.stop();
this.touch.stop();
this.mspointer.stop();
this.gamepad.stop();
},
@ -447,6 +456,8 @@ Phaser.Input.prototype = {
this._oldPosition.copyFrom(this.position);
this.mousePointer.update();
if (this.gamepad.active) { this.gamepad.update(); }
this.pointer1.update();
this.pointer2.update();
@ -478,6 +489,7 @@ Phaser.Input.prototype = {
this.keyboard.reset();
this.mousePointer.reset();
this.gamepad.reset();
for (var i = 1; i <= 10; i++)
{

517
src/input/SinglePad.js Normal file
View file

@ -0,0 +1,517 @@
/**
* @author @karlmacklin <tacklemcclean@gmail.com>
* @copyright 2013 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* @class Phaser.SinglePad
* @classdesc A single Phaser Gamepad
* @constructor
* @param {Phaser.Game} game - Current game instance.
* @param {Object} padParent - The parent Phaser.Gamepad object (all gamepads reside under this)
*/
Phaser.SinglePad = function (game, padParent) {
/**
* @property {Phaser.Game} game - Local reference to game.
*/
this.game = game;
/**
* @property {Phaser.Gamepad} padParent - Main Phaser Gamepad object
*/
this._padParent = padParent;
/**
* @property {number} index - The gamepad index as per browsers data
* @default
*/
this._index = null;
/**
* @property {Object} _rawPad - The 'raw' gamepad data.
* @private
*/
this._rawPad = null;
/**
* @property {boolean} _connected - Is this pad connected or not.
* @private
*/
this._connected = false;
/**
* @property {number} _prevTimestamp - Used to check for differences between earlier polls and current state of gamepads.
* @private
*/
this._prevTimestamp = null;
/**
* @property {Array} _rawButtons - The 'raw' button state.
* @private
*/
this._rawButtons = [];
/**
* @property {Array} _buttons - Current Phaser state of the buttons.
* @private
*/
this._buttons = [];
/**
* @property {Array} _axes - Current axes state.
* @private
*/
this._axes = [];
/**
* @property {Array} _hotkeys - Hotkey buttons.
* @private
*/
this._hotkeys = [];
/**
* @property {Object} callbackContext - The context under which the callbacks are run.
*/
this.callbackContext = this;
/**
* @property {function} onConnectCallback - This callback is invoked every time this gamepad is connected
*/
this.onConnectCallback = null;
/**
* @property {function} onDisconnectCallback - This callback is invoked every time this gamepad is disconnected
*/
this.onDisconnectCallback = null;
/**
* @property {function} onDownCallback - This callback is invoked every time a button is pressed down.
*/
this.onDownCallback = null;
/**
* @property {function} onUpCallback - This callback is invoked every time a gamepad button is released.
*/
this.onUpCallback = null;
/**
* @property {function} onAxisCallback - This callback is invoked every time an axis is changed.
*/
this.onAxisCallback = null;
/**
* @property {function} onFloatCallback - This callback is invoked every time a button is changed to a value where value > 0 and value < 1.
*/
this.onFloatCallback = null;
/**
* @property {number} deadZone - Dead zone for axis feedback - within this value you won't trigger updates.
*/
this.deadZone = 0.26;
};
Phaser.SinglePad.prototype = {
/**
* Add callbacks to the this Gamepad to handle connect/disconnect/button down/button up/axis change/float value buttons
* @method Phaser.Gamepad#addCallbacks
* @param {Object} context - The context under which the callbacks are run.
* @param {Object} callbacks - Object that takes six different callbak methods:
* onConnectCallback, onDisconnectCallback, onDownCallback, onUpCallback, onAxisCallback, onFloatCallback
*/
addCallbacks: function (context, callbacks) {
if (typeof callbacks !== 'undefined') {
this.onConnectCallback = (typeof callbacks.onConnect === 'function') ? callbacks.onConnect : this.onConnectCallback;
this.onDisconnectCallback = (typeof callbacks.onDisconnect === 'function') ? callbacks.onDisconnect : this.onDisconnectCallback;
this.onDownCallback = (typeof callbacks.onDown === 'function') ? callbacks.onDown : this.onDownCallback;
this.onUpCallback = (typeof callbacks.onUp === 'function') ? callbacks.onUp : this.onUpCallback;
this.onAxisCallback = (typeof callbacks.onAxis === 'function') ? callbacks.onAxis : this.onAxisCallback;
this.onFloatCallback = (typeof callbacks.onFloat === 'function') ? callbacks.onFloat : this.onFloatCallback;
}
},
/**
* If you need more fine-grained control over a Key you can create a new Phaser.Key object via this method.
* The Key object can then be polled, have events attached to it, etc.
*
* @method Phaser.SinglePad#addButton
* @param {number} buttonCode - The buttonCode of the button, i.e. Phaser.Gamepad.BUTTON_0 or Phaser.Gamepad.BUTTON_1
* @return {Phaser.GamepadButton} The GamepadButton object which you can store locally and reference directly.
*/
addButton: function (buttonCode) {
this._hotkeys[buttonCode] = new Phaser.GamepadButton(this.game, buttonCode);
return this._hotkeys[buttonCode];
},
/**
* Main update function, should be called by Phaser.Gamepad
* @method Phaser.SinglePad#pollStatus
*/
pollStatus: function () {
if (this._rawPad.timestamp && (this._rawPad.timestamp == this._prevTimestamp)) {
return;
}
for (var i = 0; i < this._rawPad.buttons.length; i += 1) {
var buttonValue = this._rawPad.buttons[i];
if (this._rawButtons[i] !== buttonValue) {
if (buttonValue === 1) {
this.processButtonDown(i, buttonValue);
}
else if (buttonValue === 0) {
this.processButtonUp(i, buttonValue);
} else {
this.processButtonFloat(i, buttonValue);
}
this._rawButtons[i] = buttonValue;
}
}
var axes = this._rawPad.axes;
for (var j = 0; j < axes.length; j += 1) {
var axis = axes[j];
if (axis > 0 && axis > this.deadZone ||
axis < 0 && axis < -this.deadZone) {
this.processAxisChange({axis: j, value: axis});
} else {
this.processAxisChange({axis: j, value: 0});
}
}
this._prevTimestamp = this._rawPad.timestamp;
},
/**
* Gamepad connect function, should be called by Phaser.Gamepad
* @param {Object} rawPad - The raw gamepad object
* @method Phaser.SinglePad#connect
*/
connect: function (rawPad) {
var triggerCallback = !this._connected;
this._index = rawPad.index;
this._connected = true;
this._rawPad = rawPad;
this._rawButtons = rawPad.buttons;
this._axes = rawPad.axes;
if (triggerCallback && this._padParent.onConnectCallback) {
this._padParent.onConnectCallback.call(this._padParent.callbackContext, this._index);
}
if (triggerCallback && this.onConnectCallback) {
this.onConnectCallback.call(this.callbackContext);
}
},
/**
* Gamepad disconnect function, should be called by Phaser.Gamepad
* @method Phaser.SinglePad#disconnect
*/
disconnect: function () {
var triggerCallback = this._connected;
this._connected = false;
this._rawPad = undefined;
this._rawButtons = [];
this._buttons = [];
var disconnectingIndex = this._index;
this._index = null;
if (triggerCallback && this._padParent.onDisconnectCallback) {
this._padParent.onDisconnectCallback.call(this._padParent.callbackContext, disconnectingIndex);
}
if (triggerCallback && this.onDisconnectCallback) {
this.onDisconnectCallback.call(this.callbackContext);
}
},
/**
* Handles changes in axis
* @param {Object} axisState - State of the relevant axis
* @method Phaser.SinglePad#processAxisChange
*/
processAxisChange: function (axisState) {
if (this.game.input.disabled || this.game.input.gamepad.disabled) {
return;
}
if (this._axes[axisState.axis] === axisState.value) {
return;
}
this._axes[axisState.axis] = axisState.value;
if (this._padParent.onAxisCallback) {
this._padParent.onAxisCallback.call(this._padParent.callbackContext, axisState, this._index);
}
if (this.onAxisCallback) {
this.onAxisCallback.call(this.callbackContext, axisState);
}
},
/**
* Handles button down press
* @param {number} buttonCode - Which buttonCode of this button
* @param {Object} value - Button value
* @method Phaser.SinglePad#processButtonDown
*/
processButtonDown: function (buttonCode, value) {
if (this.game.input.disabled || this.game.input.gamepad.disabled) {
return;
}
if (this._padParent.onDownCallback) {
this._padParent.onDownCallback.call(this._padParent.callbackContext, buttonCode, value, this._index);
}
if (this.onDownCallback) {
this.onDownCallback.call(this.callbackContext, buttonCode, value);
}
if (this._buttons[buttonCode] && this._buttons[buttonCode].isDown) {
// Key already down and still down, so update
this._buttons[buttonCode].duration = this.game.time.now - this._buttons[buttonCode].timeDown;
}
else {
if (!this._buttons[buttonCode]) {
// Not used this button before, so register it
this._buttons[buttonCode] = {
isDown: true,
timeDown: this.game.time.now,
timeUp: 0,
duration: 0,
value: value
};
}
else {
// Button used before but freshly down
this._buttons[buttonCode].isDown = true;
this._buttons[buttonCode].timeDown = this.game.time.now;
this._buttons[buttonCode].duration = 0;
this._buttons[buttonCode].value = value;
}
}
if (this._hotkeys[buttonCode]) {
this._hotkeys[buttonCode].processButtonDown(value);
}
},
/**
* Handles button release
* @param {number} buttonCode - Which buttonCode of this button
* @param {Object} value - Button value
* @method Phaser.SinglePad#processButtonUp
*/
processButtonUp: function (buttonCode, value) {
if (this.game.input.disabled || this.game.input.gamepad.disabled) {
return;
}
if (this._padParent.onUpCallback) {
this._padParent.onUpCallback.call(this._padParent.callbackContext, buttonCode, value, this._index);
}
if (this.onUpCallback) {
this.onUpCallback.call(this.callbackContext, buttonCode, value);
}
if (this._hotkeys[buttonCode]) {
this._hotkeys[buttonCode].processButtonUp(value);
}
if (this._buttons[buttonCode]) {
this._buttons[buttonCode].isDown = false;
this._buttons[buttonCode].timeUp = this.game.time.now;
this._buttons[buttonCode].value = value;
}
else {
// Not used this key before, so register it
this._buttons[buttonCode] = {
isDown: false,
timeDown: this.game.time.now,
timeUp: this.game.time.now,
duration: 0,
value: value
};
}
},
/**
* Handles buttons with floating values (like analog buttons that acts almost like an axis but still registers like a button)
* @param {number} buttonCode - Which buttonCode of this button
* @param {Object} value - Button value (will range somewhere between 0 and 1, but not specifically 0 or 1.
* @method Phaser.SinglePad#processButtonFloat
*/
processButtonFloat: function (buttonCode, value) {
if (this.game.input.disabled || this.game.input.gamepad.disabled) {
return;
}
if (this._padParent.onFloatCallback) {
this._padParent.onFloatCallback.call(this._padParent.callbackContext, buttonCode, value, this._index);
}
if (this.onFloatCallback) {
this.onFloatCallback.call(this.callbackContext, buttonCode, value);
}
if (!this._buttons[buttonCode]) {
// Not used this button before, so register it
this._buttons[buttonCode] = {
value: value
};
}
else {
// Button used before but freshly down
this._buttons[buttonCode].value = value;
}
if (this._hotkeys[buttonCode]) {
this._hotkeys[buttonCode].processButtonFloat(value);
}
},
/**
* Returns value of requested axis
* @method Phaser.SinglePad#isDown
* @param {number} axisCode - The index of the axis to check
* @return {number} Axis value if available otherwise false
*/
axis: function (axisCode) {
if (this._axes[axisCode]) {
return this._axes[axisCode];
}
return false;
},
/**
* Returns true if the button is currently pressed down.
* @method Phaser.SinglePad#isDown
* @param {number} buttonCode - The buttonCode of the key to check.
* @return {boolean} True if the key is currently down.
*/
isDown: function (buttonCode) {
if (this._buttons[buttonCode]) {
return this._buttons[buttonCode].isDown;
}
return false;
},
/**
* Returns the "just released" state of a button from this gamepad. Just released is considered as being true if the button was released within the duration given (default 250ms).
* @method Phaser.SinglePad#justPressed
* @param {number} buttonCode - The buttonCode of the button to check for.
* @param {number} [duration=250] - The duration below which the button is considered as being just released.
* @return {boolean} True if the button is just released otherwise false.
*/
justReleased: function (buttonCode, duration) {
if (typeof duration === "undefined") {
duration = 250;
}
if (this._buttons[buttonCode] && this._buttons[buttonCode].isDown === false && (this.game.time.now - this._buttons[buttonCode].timeUp < duration)) {
return true;
}
return false;
},
/**
* Returns the "just pressed" state of a button from this gamepad. Just pressed is considered true if the button was pressed down within the duration given (default 250ms).
* @method Phaser.SinglePad#justPressed
* @param {number} buttonCode - The buttonCode of the button to check for.
* @param {number} [duration=250] - The duration below which the button is considered as being just pressed.
* @return {boolean} True if the button is just pressed otherwise false.
*/
justPressed: function (buttonCode, duration) {
if (typeof duration === "undefined") {
duration = 250;
}
if (this._buttons[buttonCode] && this._buttons[buttonCode].isDown && this._buttons[buttonCode].duration < duration) {
return true;
}
return false;
},
/**
* Returns the value of a gamepad button. Intended mainly for cases when you have floating button values, for example
* analog trigger buttons on the XBOX 360 controller
* @method Phaser.SinglePad#buttonValue
* @param {number} buttonCode - The buttonCode of the button to check.
* @return {boolean} Button value if available otherwise false.
*/
buttonValue: function (buttonCode) {
if (this._buttons[buttonCode]) {
return this._buttons[buttonCode].value;
}
return false;
},
/**
* Reset all buttons/axes of this gamepad
* @method Phaser.SinglePad#reset
*/
reset: function () {
for (var i = 0; i < this._buttons.length; i += 1) {
this._buttons[i] = 0;
}
for (var j = 0; j < this._axes.length; j += 1) {
this._axes[j] = 0;
}
}
};
/**
* Whether or not this particular gamepad is connected or not.
* @name Phaser.SinglePad#connected
* @property {boolean} connected - Whether or not this particular gamepad is connected or not.
* @readonly
*/
Object.defineProperty(Phaser.SinglePad.prototype, "connected", {
get: function () {
return this._connected;
}
});
/**
* Gamepad index as per browser data
* @name Phaser.SinglePad#index
* @property {number} index - The gamepad index, used to identify specific gamepads in the browser
* @readonly
*/
Object.defineProperty(Phaser.SinglePad.prototype, "index", {
get: function () {
return this._index;
}
});