Motion helper functions added to the ArcadePhysics class.

This commit is contained in:
Richard Davey
2013-09-04 16:12:58 +01:00
parent 128bdccd79
commit 10bc22b717
4 changed files with 518 additions and 49 deletions
+98
View File
@@ -0,0 +1,98 @@
<!DOCTYPE HTML>
<html>
<head>
<title>phaser.js - a new beginning</title>
<?php
require('js.php');
?>
</head>
<body>
<script type="text/javascript">
(function () {
var game = new Phaser.Game(800, 600, Phaser.CANVAS, '', { preload: preload, create: create, update: update, render: render });
function preload() {
game.load.image('car', 'assets/sprites/car90.png');
game.load.image('ship', 'assets/sprites/xenon2_ship.png');
game.load.image('baddie', 'assets/sprites/space-baddie.png');
}
var car;
var ship;
var total;
var aliens;
function create() {
aliens = [];
for (var i = 0; i < 50; i++)
{
var s = game.add.sprite(game.world.randomX, game.world.randomY, 'baddie');
s.name = 'alien' + s;
s.body.collideWorldBounds = true;
s.body.bounce.setTo(1, 1);
s.body.velocity.setTo(10 + Math.random() * 40, 10 + Math.random() * 40);
aliens.push(s);
}
car = game.add.sprite(400, 300, 'car');
car.anchor.setTo(0.5, 0.5);
car.body.collideWorldBounds = true;
car.body.bounce.setTo(0.5, 0.5);
car.body.allowRotation = true;
ship = game.add.sprite(400, 400, 'ship');
ship.body.collideWorldBounds = true;
ship.body.bounce.setTo(0.5, 0.5);
}
function update() {
car.body.velocity.x = 0;
car.body.velocity.y = 0;
car.body.angularVelocity = 0;
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
car.body.angularVelocity = -200;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
car.body.angularVelocity = 200;
}
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
{
car.body.velocity.copyFrom(game.physics.velocityFromAngle(car.angle, 300));
}
game.physics.collideGroup(aliens);
// total = game.physics.overlap(ship);
}
function render() {
// game.debug.renderQuadTree(game.physics.quadTree);
// game.debug.renderRectangle(ship.body.bounds);
// game.debug.renderText('total: ' + total.length, 32, 50);
// game.debug.renderText('up: ' + ship.body.touching.up, 32, 70);
// game.debug.renderText('down: ' + ship.body.touching.down, 32, 90);
// game.debug.renderText('left: ' + ship.body.touching.left, 32, 110);
// game.debug.renderText('right: ' + ship.body.touching.right, 32, 130);
}
})();
</script>
</body>
</html>
+7 -11
View File
@@ -25,17 +25,15 @@
function create() {
// game.world.setSize(2000, 2000);
aliens = [];
for (var i = 0; i < 10; i++)
for (var i = 0; i < 50; i++)
{
var s = game.add.sprite(game.world.randomX, game.world.randomY, 'baddie');
s.name = 'alien' + s;
s.body.collideWorldBounds = true;
s.body.bounce.setTo(1, 1);
s.body.velocity.setTo(10 + Math.random() * 10, 10 + Math.random() * 10);
s.body.velocity.setTo(10 + Math.random() * 40, 10 + Math.random() * 40);
aliens.push(s);
}
@@ -47,13 +45,6 @@
function update() {
// total = game.physics.overlap(ship);
for (var i = 0; i < aliens.length; i++)
{
game.physics.separate(ship.body, aliens[i].body);
}
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
ship.body.velocity.x -= 2;
@@ -72,6 +63,9 @@
ship.body.velocity.y += 2;
}
game.physics.collideGroup(aliens);
// total = game.physics.overlap(ship);
}
function render() {
@@ -79,6 +73,8 @@
game.debug.renderQuadTree(game.physics.quadTree);
game.debug.renderRectangle(ship.body.bounds);
// game.debug.renderText('total: ' + total.length, 32, 50);
game.debug.renderText('up: ' + ship.body.touching.up, 32, 70);
game.debug.renderText('down: ' + ship.body.touching.down, 32, 90);
game.debug.renderText('left: ' + ship.body.touching.left, 32, 110);
+409 -35
View File
@@ -19,16 +19,6 @@ Phaser.Physics.Arcade = function (game) {
*/
this.maxLevels = 4;
this.NONE = 0;
this.UP = 1;
this.DOWN = 2;
this.LEFT = 3;
this.RIGHT = 4;
this.CEILING = 1;
this.FLOOR = 2;
this.WALL = 5;
this.ANY = 6;
this.OVERLAP_BIAS = 4;
this.TILE_OVERLAP = false;
@@ -50,12 +40,6 @@ Phaser.Physics.Arcade = function (game) {
Phaser.Physics.Arcade.prototype = {
collide: function (objectOrGroup1, objectOrGroup2, notifyCallback) {
return this.overlap(objectOrGroup1, objectOrGroup2, notifyCallback, this.separate);
},
updateMotion: function (body) {
// Rotation
@@ -153,20 +137,49 @@ Phaser.Physics.Arcade.prototype = {
},
/**
* Checks for overlaps between two objects using the world QuadTree. Can be GameObject vs. GameObject, GameObject vs. Group or Group vs. Group.
* Note: Does not take the objects scrollFactor into account. All overlaps are check in world space.
* @param object1 The first GameObject or Group to check. If null the world.group is used.
* @param object2 The second GameObject or Group to check.
* @param notifyCallback A callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you passed them to Collision.overlap.
* @param processCallback A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then notifyCallback will only be called if processCallback returns true.
* @returns {boolean} true if the objects overlap, otherwise false.
*/
overlap: function (object1, object2, notifyCallback, processCallback) {
// Collides the given object with everything in the world quadtree
collide: function (object, notifyCallback, callbackContext) {
return this.overlap(object, null, notifyCallback, this.separate, callbackContext);
},
collideGroup: function (group, notifyCallback, callbackContext) {
notifyCallback = notifyCallback || null;
callbackContext = callbackContext || notifyCallback;
for (var g = 0, len = group.length; g < len; g++)
{
for (var i = 0, gi = group.length; i < gi; i++)
{
if (this.separate(group[g].body, group[i].body))
{
if (notifyCallback)
{
notifyCallback.call(callbackContext, group[g], group[i].sprite);
}
}
}
}
},
/**
* Checks for overlaps between two objects using the world QuadTree. Can be GameObject vs. GameObject, GameObject vs. Group or Group vs. Group.
* Note: Does not take the objects scrollFactor into account. All overlaps are check in world space.
* @param object1 The first GameObject or Group to check. If null the world.group is used.
* @param object2 The second GameObject or Group to check.
* @param notifyCallback A callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you passed them to Collision.overlap.
* @param processCallback A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then notifyCallback will only be called if processCallback returns true.
* @returns {boolean} true if the objects overlap, otherwise false.
*/
overlap: function (object1, object2, notifyCallback, processCallback, callbackContext) {
object2 = object2 || null;
notifyCallback = notifyCallback || null;
processCallback = processCallback || this.separate;
callbackContext = callbackContext || this;
// Get the ships top-most ID. If the length of that ID is 1 then we can ignore every other result,
// it's simply not colliding with anything :)
@@ -175,20 +188,18 @@ Phaser.Physics.Arcade.prototype = {
for (var i = 0, len = potentials.length; i < len; i++)
{
if (this.separate(object1.body, potentials[i]).body)
if (processCallback.call(callbackContext, object1.body, potentials[i]))
{
if (notifyCallback)
{
notifyCallback.call(callbackContext, object1, potentials[i].sprite);
}
output.push(potentials[i]);
}
}
if (output.length > 0)
{
return output;
}
else
{
return null;
}
return (output.length);
},
@@ -410,4 +421,367 @@ Phaser.Physics.Arcade.prototype = {
}
},
/**
* Given the angle and speed calculate the velocity and return it as a Point
*
* @param angle The angle (in degrees) calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
* @param speed The speed it will move, in pixels per second sq
*
* @return A Point where Point.x contains the velocity x value and Point.y contains the velocity y value
*/
velocityFromAngle: function (angle, speed, point) {
speed = speed || 0;
point = point || new Phaser.Point;
var a = this.game.math.degToRad(angle);
return point.setTo((Math.cos(a) * speed), (Math.sin(a) * speed));
},
/**
* Sets the source Sprite x/y velocity so it will move directly towards the destination Sprite at the speed given (in pixels per second)<br>
* If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.<br>
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.<br>
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.<br>
* If you need the object to accelerate, see accelerateTowardsObject() instead
* Note: Doesn't take into account acceleration, maxVelocity or drag (if you set drag or acceleration too high this object may not move at all)
*
* @param source The Sprite on which the velocity will be set
* @param dest The Sprite where the source object will move to
* @param speed The speed it will move, in pixels per second (default is 60 pixels/sec)
* @param maxTime Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the source will arrive at destination in the given number of ms
*/
moveTowardsObject: function (source, dest, speed, maxTime) {
speed = speed || 60;
maxTime = maxTime || 0;
var a = this.angleBetween(source, dest);
if (maxTime > 0)
{
var d = this.distanceBetween(source, dest);
// We know how many pixels we need to move, but how fast?
speed = d / (maxTime / 1000);
}
source.body.velocity.x = Math.cos(a) * speed;
source.body.velocity.y = Math.sin(a) * speed;
},
/**
* Sets the x/y acceleration on the source Sprite so it will move towards the destination Sprite at the speed given (in pixels per second)<br>
* You must give a maximum speed value, beyond which the Sprite won't go any faster.<br>
* If you don't need acceleration look at moveTowardsObject() instead.
*
* @param source The Sprite on which the acceleration will be set
* @param dest The Sprite where the source object will move towards
* @param speed The speed it will accelerate in pixels per second
* @param xSpeedMax The maximum speed in pixels per second in which the sprite can move horizontally
* @param ySpeedMax The maximum speed in pixels per second in which the sprite can move vertically
*/
accelerateTowardsObject: function (source, dest, speed, xSpeedMax, ySpeedMax) {
xSpeedMax = xSpeedMax || 1000;
ySpeedMax = ySpeedMax || 1000;
var a = this.angleBetween(source, dest);
source.body.velocity.x = 0;
source.body.velocity.y = 0;
source.body.acceleration.x = Math.cos(a) * speed;
source.body.acceleration.y = Math.sin(a) * speed;
source.body.maxVelocity.x = xSpeedMax;
source.body.maxVelocity.y = ySpeedMax;
},
/**
* Move the given Sprite towards the mouse pointer coordinates at a steady velocity
* If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.<br>
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.<br>
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.<br>
*
* @param source The Sprite to move
* @param speed The speed it will move, in pixels per second (default is 60 pixels/sec)
* @param maxTime Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the source will arrive at destination in the given number of ms
*/
moveTowardsMouse: function (source, speed, maxTime) {
speed = speed || 60;
maxTime = maxTime || 0;
var a = this.angleBetweenMouse(source);
if (maxTime > 0)
{
var d = this.distanceToMouse(source);
// We know how many pixels we need to move, but how fast?
speed = d / (maxTime / 1000);
}
source.body.velocity.x = Math.cos(a) * speed;
source.body.velocity.y = Math.sin(a) * speed;
},
/**
* Sets the x/y acceleration on the source Sprite so it will move towards the mouse coordinates at the speed given (in pixels per second)<br>
* You must give a maximum speed value, beyond which the Sprite won't go any faster.<br>
* If you don't need acceleration look at moveTowardsMouse() instead.
*
* @param source The Sprite on which the acceleration will be set
* @param speed The speed it will accelerate in pixels per second
* @param xSpeedMax The maximum speed in pixels per second in which the sprite can move horizontally
* @param ySpeedMax The maximum speed in pixels per second in which the sprite can move vertically
*/
accelerateTowardsMouse: function (source, speed, xSpeedMax, ySpeedMax) {
xSpeedMax = xSpeedMax || 1000;
ySpeedMax = ySpeedMax || 1000;
var a = this.angleBetweenMouse(source);
source.body.velocity.x = 0;
source.body.velocity.y = 0;
source.body.acceleration.x = Math.cos(a) * speed;
source.body.acceleration.y = Math.sin(a) * speed;
source.body.maxVelocity.x = xSpeedMax;
source.body.maxVelocity.y = ySpeedMax;
},
/**
* Sets the x/y velocity on the source Sprite so it will move towards the target coordinates at the speed given (in pixels per second)<br>
* If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.<br>
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.<br>
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.<br>
*
* @param source The Sprite to move
* @param target The Point coordinates to move the source Sprite towards
* @param speed The speed it will move, in pixels per second (default is 60 pixels/sec)
* @param maxTime Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the source will arrive at destination in the given number of ms
*/
moveTowardsPoint: function (source, target, speed, maxTime) {
speed = speed || 60;
maxTime = maxTime || 0;
var a = this.angleBetweenPoint(source, target);
if (maxTime > 0)
{
var d = this.distanceToPoint(source, target);
// We know how many pixels we need to move, but how fast?
speed = d / (maxTime / 1000);
}
source.body.velocity.x = Math.cos(a) * speed;
source.body.velocity.y = Math.sin(a) * speed;
},
/**
* Sets the x/y acceleration on the source Sprite so it will move towards the target coordinates at the speed given (in pixels per second)<br>
* You must give a maximum speed value, beyond which the Sprite won't go any faster.<br>
* If you don't need acceleration look at moveTowardsPoint() instead.
*
* @param source The Sprite on which the acceleration will be set
* @param target The Point coordinates to move the source Sprite towards
* @param speed The speed it will accelerate in pixels per second
* @param xSpeedMax The maximum speed in pixels per second in which the sprite can move horizontally
* @param ySpeedMax The maximum speed in pixels per second in which the sprite can move vertically
*/
accelerateTowardsPoint: function (source, target, speed, xSpeedMax, ySpeedMax) {
xSpeedMax = xSpeedMax || 1000;
ySpeedMax = ySpeedMax || 1000;
var a = this.angleBetweenPoint(source, target);
source.body.velocity.x = 0;
source.body.velocity.y = 0;
source.body.acceleration.x = Math.cos(a) * speed;
source.body.acceleration.y = Math.sin(a) * speed;
source.body.maxVelocity.x = xSpeedMax;
source.body.maxVelocity.y = ySpeedMax;
},
/**
* Find the distance (in pixels, rounded) between two Sprites, taking their origin into account
*
* @param a The first Sprite
* @param b The second Sprite
* @return int Distance (in pixels)
*/
distanceBetween: function (a, b) {
var dx = a.center.x - b.center.x;
var dy = a.center.y - b.center.y;
return Math.sqrt(dx * dx + dy * dy);
},
/**
* Find the distance (in pixels, rounded) from an Sprite to the given Point, taking the source origin into account
*
* @param a The Sprite
* @param target The Point
* @return int Distance (in pixels)
*/
distanceToPoint: function (a, target) {
var dx = a.center.x - target.x;
var dy = a.center.y - target.y;
return Math.sqrt(dx * dx + dy * dy);
},
/**
* Find the distance (in pixels, rounded) from the object x/y and the mouse x/y
*
* @param a The Sprite to test against
* @return int The distance between the given sprite and the mouse coordinates
*/
distanceToMouse: function (a) {
var dx = a.center.x - this.game.input.x;
var dy = a.center.y - this.game.input.y;
return Math.sqrt(dx * dx + dy * dy);
},
/**
* Find the angle (in radians) between an Sprite and an Point. The source sprite takes its x/y and origin into account.
* The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
*
* @param a The Sprite to test from
* @param target The Point to angle the Sprite towards
* @param asDegrees If you need the value in degrees instead of radians, set to true
*
* @return Number The angle (in radians unless asDegrees is true)
*/
angleBetweenPoint: function (a, target, asDegrees) {
asDegrees = asDegrees || false;
var dx = target.x - a.center.x;
var dy = target.y - a.center.y;
if (asDegrees)
{
return this.game.math.radToDeg(Math.atan2(dy, dx));
}
else
{
return Math.atan2(dy, dx);
}
},
/**
* Find the angle (in radians) between the two Sprite, taking their x/y and origin into account.
* The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
*
* @param a The Sprite to test from
* @param b The Sprite to test to
* @param asDegrees If you need the value in degrees instead of radians, set to true
*
* @return Number The angle (in radians unless asDegrees is true)
*/
angleBetween: function (a, b, asDegrees) {
asDegrees = asDegrees || false;
var dx = b.center.x - a.center.x;
var dy = b.center.y - a.center.y;
if (asDegrees)
{
return this.game.math.radToDeg(Math.atan2(dy, dx));
}
else
{
return Math.atan2(dy, dx);
}
},
/**
* Given the GameObject and speed calculate the velocity and return it as an Point based on the direction the sprite is facing
*
* @param parent The Sprite to get the facing value from
* @param speed The speed it will move, in pixels per second sq
*
* @return An Point where Point.x contains the velocity x value and Point.y contains the velocity y value
*/
velocityFromFacing: function (parent, speed) {
/*
var a;
if (parent.facing == Collision.LEFT)
{
a = this._game.math.degreesToRadians(180);
}
else if (parent.facing == Collision.RIGHT)
{
a = this._game.math.degreesToRadians(0);
}
else if (parent.facing == Collision.UP)
{
a = this._game.math.degreesToRadians(-90);
}
else if (parent.facing == Collision.DOWN)
{
a = this._game.math.degreesToRadians(90);
}
return new Point(Math.cos(a) * speed, Math.sin(a) * speed);
*/
},
/**
* Find the angle (in radians) between an Sprite and the mouse, taking their x/y and origin into account.
* The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
*
* @param a The Object to test from
* @param asDegrees If you need the value in degrees instead of radians, set to true
*
* @return Number The angle (in radians unless asDegrees is true)
*/
angleBetweenMouse: function (a, asDegrees) {
asDegrees = asDegrees || false;
var dx = this.game.input.x - a.bounds.x;
var dy = this.game.input.y - a.bounds.y;
if (asDegrees)
{
return this.game.math.radToDeg(Math.atan2(dy, dx));
}
else
{
return Math.atan2(dy, dx);
}
}
};
+4 -3
View File
@@ -38,10 +38,11 @@ Phaser.Physics.Arcade.Body = function (sprite) {
this.maxAngular = 1000;
this.mass = 1;
this.quadTreeIndex = [];
this.quadTreeIDs = [];
this.quadTreeIndex = -1;
// Allow collision
this.allowCollision = { any: true, up: true, down: true, left: true, right: true };
this.allowCollision = { none: false, any: true, up: true, down: true, left: true, right: true };
this.touching = { none: true, up: false, down: false, left: false, right: false };
this.wasTouching = { none: true, up: false, down: false, left: false, right: false };
@@ -99,7 +100,7 @@ Phaser.Physics.Arcade.Body.prototype = {
this.bounds.x = this.x;
this.bounds.y = this.y;
if (this.allowCollisions & this.ANY)
if (this.allowCollision.none == false && this.sprite.visible && this.sprite.alive)
{
this.quadTreeIDs = [];
this.quadTreeIndex = -1;