mirror of
https://github.com/photonstorm/phaser
synced 2024-12-03 18:10:10 +00:00
Integrated SAT. Fixed lots of examples. Fixed documentation. Added new examples and built new phaser.js file for testing.
This commit is contained in:
parent
45518b3ecd
commit
4505aa50f6
35 changed files with 4065 additions and 2261 deletions
|
@ -112,6 +112,7 @@ module.exports = function (grunt) {
|
|||
'src/sound/SoundManager.js',
|
||||
'src/utils/Debug.js',
|
||||
'src/utils/Color.js',
|
||||
'src/physics/arcade/SAT.js',
|
||||
'src/physics/arcade/ArcadePhysics.js',
|
||||
'src/physics/arcade/Body.js',
|
||||
'src/particles/Particles.js',
|
||||
|
|
|
@ -67,6 +67,7 @@ Significant API changes:
|
|||
* Body.customSeparateCallback allows you to set your own callback when two Bodies need to separate rather than using the built-in method.
|
||||
* Body.collideCallback allows you to set a callback that is fired whenever the Body is hit on any of its active faces.
|
||||
* Body.allowCollision has been renamed to Body.checkCollision.
|
||||
* Body.rebound is a boolean that controls if a body will exchange velocity on collision. Set to false to allow it to be 'pushed' (see new examples).
|
||||
|
||||
|
||||
New features:
|
||||
|
@ -167,6 +168,7 @@ Updates:
|
|||
* Removed ArcadePhysics binding to the QuadTree, so it can now be used independantly of the physics system.
|
||||
* Removed ArcadePhysics.preUpdate and postUpdate as neither are needed any more.
|
||||
* Body.bottom and Body.right are no longer rounded, so will give accurate sub-pixel values.
|
||||
* Fixed lots of documentation in the Emitter class.
|
||||
|
||||
|
||||
Bug Fixes:
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
<script src="$path/src/utils/Debug.js"></script>
|
||||
<script src="$path/src/utils/Color.js"></script>
|
||||
|
||||
<script src="$path/src/physics/arcade/SAT.js"></script>
|
||||
<script src="$path/src/physics/arcade/ArcadePhysics.js"></script>
|
||||
<script src="$path/src/physics/arcade/Body.js"></script>
|
||||
|
||||
|
|
3398
build/phaser.js
3398
build/phaser.js
File diff suppressed because it is too large
Load diff
22
build/phaser.min.js
vendored
22
build/phaser.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -110,6 +110,10 @@
|
|||
}
|
||||
],
|
||||
"collision": [
|
||||
{
|
||||
"file": "body+scale.js",
|
||||
"title": "body scale"
|
||||
},
|
||||
{
|
||||
"file": "bounding+box.js",
|
||||
"title": "bounding box"
|
||||
|
@ -118,6 +122,10 @@
|
|||
"file": "group+vs+group.js",
|
||||
"title": "group vs group"
|
||||
},
|
||||
{
|
||||
"file": "group+vs+self.js",
|
||||
"title": "group vs self"
|
||||
},
|
||||
{
|
||||
"file": "larger+bounding+box.js",
|
||||
"title": "larger bounding box"
|
||||
|
@ -130,10 +138,6 @@
|
|||
"file": "process+callback.js",
|
||||
"title": "process callback"
|
||||
},
|
||||
{
|
||||
"file": "sprite+tiles.js",
|
||||
"title": "sprite tiles"
|
||||
},
|
||||
{
|
||||
"file": "sprite+vs+group.js",
|
||||
"title": "sprite vs group"
|
||||
|
@ -142,10 +146,6 @@
|
|||
"file": "sprite+vs+sprite.js",
|
||||
"title": "sprite vs sprite"
|
||||
},
|
||||
{
|
||||
"file": "transform.js",
|
||||
"title": "transform"
|
||||
},
|
||||
{
|
||||
"file": "vertical+collision.js",
|
||||
"title": "vertical collision"
|
||||
|
|
|
@ -136,6 +136,7 @@
|
|||
<script src="../src/utils/Debug.js"></script>
|
||||
<script src="../src/utils/Color.js"></script>
|
||||
|
||||
<script src="../src/physics/arcade/SAT.js"></script>
|
||||
<script src="../src/physics/arcade/ArcadePhysics.js"></script>
|
||||
<script src="../src/physics/arcade/Body.js"></script>
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@
|
|||
<script src="../src/utils/Debug.js"></script>
|
||||
<script src="../src/utils/Color.js"></script>
|
||||
|
||||
<script src="../src/physics/arcade/SAT.js"></script>
|
||||
<script src="../src/physics/arcade/ArcadePhysics.js"></script>
|
||||
<script src="../src/physics/arcade/Body.js"></script>
|
||||
|
||||
|
|
BIN
examples/assets/sprites/bluemetal_32x32x4.png
Normal file
BIN
examples/assets/sprites/bluemetal_32x32x4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 687 B |
46
examples/collision/body scale.js
Normal file
46
examples/collision/body scale.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.spritesheet('gameboy', 'assets/sprites/gameboy_seize_color_40x60.png', 40, 60);
|
||||
|
||||
}
|
||||
|
||||
var sprite;
|
||||
var sprite2;
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#124184';
|
||||
|
||||
// Here we're tweening the scale of the sprite, which translates to the scale of the Body as well
|
||||
// The collision will carry on working even against the scaled body.
|
||||
|
||||
sprite = game.add.sprite(200, 300, 'gameboy', 2);
|
||||
sprite.name = 'green';
|
||||
sprite.anchor.setTo(0.5, 0.5);
|
||||
sprite.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(600, 270, 'gameboy', 3);
|
||||
sprite2.name = 'yellow';
|
||||
sprite2.body.rebound = false;
|
||||
|
||||
sprite2.body.velocity.x = -200;
|
||||
|
||||
game.add.tween(sprite.scale).to( { x: 3, y: 3 }, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
game.physics.collide(sprite, sprite2);
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.renderPolygon(sprite.body.polygons, 'rgb(255,0,0)');
|
||||
game.debug.renderPolygon(sprite2.body.polygons, 'rgb(255,0,0)');
|
||||
|
||||
}
|
|
@ -14,16 +14,15 @@ function create() {
|
|||
|
||||
game.stage.backgroundColor = '#2d2d2d';
|
||||
|
||||
sprite1 = game.add.sprite(50, 200, 'atari');
|
||||
sprite1 = game.add.sprite(150, 300, 'atari');
|
||||
sprite1.name = 'atari';
|
||||
sprite1.body.velocity.x = 100;
|
||||
|
||||
// This adjusts the collision body size.
|
||||
// 100x100 is the new width/height.
|
||||
// This adjusts the collision body size to be 104 x 104.
|
||||
// See the offset bounding box for another example.
|
||||
sprite1.body.setSize(100, 100, 0, 0);
|
||||
sprite1.body.setSize(104, 104, 0, 0);
|
||||
sprite1.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(700, 220, 'mushroom');
|
||||
sprite2 = game.add.sprite(700, 320, 'mushroom');
|
||||
sprite2.name = 'mushroom';
|
||||
sprite2.body.velocity.x = -100;
|
||||
|
||||
|
@ -40,16 +39,13 @@ function collisionHandler (obj1, obj2) {
|
|||
|
||||
game.stage.backgroundColor = '#992d2d';
|
||||
|
||||
console.log(obj1.name + ' collided with ' + obj2.name);
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.renderSpriteInfo(sprite1, 32, 32);
|
||||
game.debug.renderSpriteCollision(sprite1, 32, 400);
|
||||
game.debug.renderBodyInfo(sprite1, 32, 32);
|
||||
|
||||
game.debug.renderSpriteBody(sprite1);
|
||||
game.debug.renderSpriteBody(sprite2);
|
||||
game.debug.renderPolygon(sprite1.body.polygons, 'rgb(255,0,0)');
|
||||
game.debug.renderPolygon(sprite2.body.polygons, 'rgb(255,0,0)');
|
||||
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ function preload() {
|
|||
var sprite;
|
||||
var bullets;
|
||||
var veggies;
|
||||
var bulletTime = 0;
|
||||
var cursors;
|
||||
|
||||
var bulletTime = 0;
|
||||
var bullet;
|
||||
|
||||
function create() {
|
||||
|
@ -44,23 +45,26 @@ function create() {
|
|||
|
||||
sprite = game.add.sprite(400, 550, 'phaser');
|
||||
|
||||
// Stop the following keys from propagating up to the browser
|
||||
game.input.keyboard.addKeyCapture([ Phaser.Keyboard.LEFT, Phaser.Keyboard.RIGHT, Phaser.Keyboard.SPACEBAR ]);
|
||||
cursors = game.input.keyboard.createCursorKeys();
|
||||
game.input.keyboard.addKeyCapture([ Phaser.Keyboard.SPACEBAR ]);
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
// As we don't need to exchange any velocities or motion we can the 'overlap' check instead of 'collide'
|
||||
game.physics.overlap(bullets, veggies, collisionHandler, null, this);
|
||||
|
||||
sprite.body.velocity.x = 0;
|
||||
sprite.body.velocity.y = 0;
|
||||
|
||||
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
|
||||
if (cursors.left.isDown)
|
||||
{
|
||||
sprite.body.velocity.x = -200;
|
||||
sprite.body.velocity.x = -300;
|
||||
}
|
||||
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
|
||||
else if (cursors.right.isDown)
|
||||
{
|
||||
sprite.body.velocity.x = 200;
|
||||
sprite.body.velocity.x = 300;
|
||||
}
|
||||
|
||||
if (game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR))
|
||||
|
@ -68,9 +72,6 @@ function update() {
|
|||
fireBullet();
|
||||
}
|
||||
|
||||
// As we don't need to exchange any velocities or motion we can use the faster 'overlap' check instead of 'collide':
|
||||
game.physics.overlap(bullets, veggies, collisionHandler, null, this);
|
||||
|
||||
}
|
||||
|
||||
function fireBullet () {
|
||||
|
@ -83,7 +84,7 @@ function fireBullet () {
|
|||
{
|
||||
bullet.reset(sprite.x + 6, sprite.y - 8);
|
||||
bullet.body.velocity.y = -300;
|
||||
bulletTime = game.time.now + 250;
|
||||
bulletTime = game.time.now + 150;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,9 +92,12 @@ function fireBullet () {
|
|||
|
||||
// Called if the bullet goes out of the screen
|
||||
function resetBullet (bullet) {
|
||||
|
||||
bullet.kill();
|
||||
|
||||
}
|
||||
|
||||
// Called if the bullet hits one of the veg sprites
|
||||
function collisionHandler (bullet, veg) {
|
||||
|
||||
bullet.kill();
|
||||
|
|
40
examples/collision/group vs self.js
Normal file
40
examples/collision/group vs self.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.spritesheet('spinner', 'assets/sprites/bluemetal_32x32x4.png', 32, 32);
|
||||
|
||||
}
|
||||
|
||||
var sprites;
|
||||
|
||||
function create() {
|
||||
|
||||
// Here we create a group, populate it with sprites, give them all a random velocity
|
||||
// and then check the group against itself for collision
|
||||
|
||||
sprites = game.add.group();
|
||||
|
||||
for (var i = 0; i < 30; i++)
|
||||
{
|
||||
var s = sprites.create(game.rnd.integerInRange(100, 700), game.rnd.integerInRange(32, 200), 'spinner');
|
||||
s.animations.add('spin', [0,1,2,3]);
|
||||
s.play('spin', 20, true);
|
||||
s.body.velocity.x = game.rnd.integerInRange(-200, 200);
|
||||
s.body.velocity.y = game.rnd.integerInRange(-200, 200);
|
||||
}
|
||||
|
||||
sprites.setAll('body.collideWorldBounds', true);
|
||||
sprites.setAll('body.bounce.x', 1);
|
||||
sprites.setAll('body.bounce.y', 1);
|
||||
sprites.setAll('body.friction', 0);
|
||||
sprites.setAll('body.minBounceVelocity', 0);
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
game.physics.collide(sprites);
|
||||
|
||||
}
|
|
@ -15,14 +15,14 @@ function create() {
|
|||
|
||||
game.stage.backgroundColor = '#2d2d2d';
|
||||
|
||||
sprite1 = game.add.sprite(50, 200, 'atari');
|
||||
sprite1 = game.add.sprite(130, 200, 'atari');
|
||||
sprite1.name = 'atari';
|
||||
sprite1.body.velocity.x = 100;
|
||||
|
||||
// In this example the new collision box is much larger than the original sprite
|
||||
sprite1.body.setSize(400, 50, -100, 20);
|
||||
sprite1.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(700, 220, 'mushroom');
|
||||
sprite2 = game.add.sprite(700, 210, 'mushroom');
|
||||
sprite2.name = 'mushroom';
|
||||
sprite2.body.velocity.x = -100;
|
||||
|
||||
|
@ -39,13 +39,13 @@ function collisionHandler (obj1, obj2) {
|
|||
|
||||
game.stage.backgroundColor = '#992d2d';
|
||||
|
||||
console.log(obj1.name + ' collided with ' + obj2.name);
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.renderRectangle(sprite1.body);
|
||||
game.debug.renderRectangle(sprite2.body);
|
||||
game.debug.renderBodyInfo(sprite1, 32, 32);
|
||||
|
||||
game.debug.renderPolygon(sprite1.body.polygons, 'rgb(255,0,0)');
|
||||
game.debug.renderPolygon(sprite2.body.polygons, 'rgb(255,0,0)');
|
||||
|
||||
}
|
||||
|
|
|
@ -15,15 +15,13 @@ function create() {
|
|||
|
||||
game.stage.backgroundColor = '#2d2d2d';
|
||||
|
||||
sprite1 = game.add.sprite(50, 200, 'atari');
|
||||
sprite1 = game.add.sprite(150, 200, 'atari');
|
||||
sprite1.name = 'atari';
|
||||
sprite1.body.velocity.x = 100;
|
||||
|
||||
// This adjusts the collision body size.
|
||||
// 100x50 is the new width/height.
|
||||
// This adjusts the collision body size to be a 100x50 box.
|
||||
// 50, 25 is the X and Y offset of the newly sized box.
|
||||
// In this case the box is 50px in and 25px down.
|
||||
sprite1.body.setSize(100, 50, 50, 25);
|
||||
sprite1.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(700, 220, 'mushroom');
|
||||
sprite2.name = 'mushroom';
|
||||
|
@ -42,13 +40,13 @@ function collisionHandler (obj1, obj2) {
|
|||
|
||||
game.stage.backgroundColor = '#992d2d';
|
||||
|
||||
console.log(obj1.name + ' collided with ' + obj2.name);
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.renderRectangle(sprite1.body);
|
||||
game.debug.renderRectangle(sprite2.body);
|
||||
game.debug.renderBodyInfo(sprite1, 32, 32);
|
||||
|
||||
game.debug.renderPolygon(sprite1.body.polygons, 'rgb(255,0,0)');
|
||||
game.debug.renderPolygon(sprite2.body.polygons, 'rgb(255,0,0)');
|
||||
|
||||
}
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.spritesheet('tiles', 'assets/tiles/platformer_tiles.png', 16, 16);
|
||||
game.load.image('carrot', 'assets/sprites/carrot.png');
|
||||
|
||||
}
|
||||
|
||||
var tiles;
|
||||
var sprite;
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#2d2d2d';
|
||||
|
||||
tiles = game.add.group();
|
||||
|
||||
for (var x = 0; x < 40; x++)
|
||||
{
|
||||
var tile = tiles.create(100 + (x * 16), 300, 'tiles', 4);
|
||||
tile.body.immovable = true;
|
||||
}
|
||||
|
||||
sprite = game.add.sprite(300, 150, 'carrot');
|
||||
sprite.name = 'mushroom';
|
||||
sprite.body.collideWorldBounds = true;
|
||||
sprite.body.velocity.x = 40;
|
||||
sprite.body.velocity.y = 120;
|
||||
sprite.body.bounce.setTo(1, 1);
|
||||
|
||||
game.input.onDown.add(carryOn, this);
|
||||
|
||||
}
|
||||
|
||||
function carryOn() {
|
||||
|
||||
game.paused = false;
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
// object1, object2, collideCallback, processCallback, callbackContext
|
||||
game.physics.collide(sprite, tiles, collisionHandler, null, this);
|
||||
|
||||
}
|
||||
|
||||
function collisionHandler (s, t) {
|
||||
|
||||
t.alpha = 0.5;
|
||||
|
||||
console.log('---------------------------------------------');
|
||||
console.log(t.body);
|
||||
|
||||
game.paused = true;
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
// game.debug.renderSpriteInfo(sprite1, 32, 32);
|
||||
// game.debug.renderSpriteCollision(sprite1, 32, 400);
|
||||
|
||||
game.debug.renderSpriteBody(sprite);
|
||||
// game.debug.renderSpriteBody(sprite2);
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
|
||||
|
||||
function preload() {
|
||||
|
||||
|
@ -10,12 +10,13 @@ function preload() {
|
|||
|
||||
var sprite;
|
||||
var group;
|
||||
var cursors;
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#2d2d2d';
|
||||
|
||||
// This will check Sprite vs. Group collision
|
||||
// This example will check Sprite vs. Group collision
|
||||
|
||||
sprite = game.add.sprite(32, 200, 'phaser');
|
||||
sprite.name = 'phaser-dude';
|
||||
|
@ -24,7 +25,7 @@ function create() {
|
|||
|
||||
for (var i = 0; i < 50; i++)
|
||||
{
|
||||
var c = group.create(100 + Math.random() * 700, game.world.randomY, 'veggies', game.rnd.integerInRange(0, 36));
|
||||
var c = group.create(game.rnd.integerInRange(100, 770), game.rnd.integerInRange(0, 570), 'veggies', game.rnd.integerInRange(0, 36));
|
||||
c.name = 'veg' + i;
|
||||
c.body.immovable = true;
|
||||
}
|
||||
|
@ -32,58 +33,51 @@ function create() {
|
|||
for (var i = 0; i < 20; i++)
|
||||
{
|
||||
// Here we'll create some chillis which the player can pick-up. They are still part of the same Group.
|
||||
var c = group.create(100 + Math.random() * 700, game.world.randomY, 'veggies', 17);
|
||||
var c = group.create(game.rnd.integerInRange(100, 770), game.rnd.integerInRange(0, 570), 'veggies', 17);
|
||||
c.name = 'chilli' + i;
|
||||
c.body.immovable = true;
|
||||
}
|
||||
|
||||
game.input.keyboard.addKeyCapture([ Phaser.Keyboard.LEFT, Phaser.Keyboard.RIGHT, Phaser.Keyboard.UP, Phaser.Keyboard.DOWN ]);
|
||||
cursors = game.input.keyboard.createCursorKeys();
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
game.physics.collide(sprite, group, collisionHandler, null, this);
|
||||
game.physics.collide(group, group);
|
||||
|
||||
sprite.body.velocity.x = 0;
|
||||
sprite.body.velocity.y = 0;
|
||||
|
||||
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
|
||||
if (cursors.left.isDown)
|
||||
{
|
||||
sprite.body.velocity.x = -200;
|
||||
}
|
||||
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
|
||||
else if (cursors.right.isDown)
|
||||
{
|
||||
sprite.body.velocity.x = 200;
|
||||
}
|
||||
|
||||
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
|
||||
if (cursors.up.isDown)
|
||||
{
|
||||
sprite.body.velocity.y = -200;
|
||||
}
|
||||
else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN))
|
||||
else if (cursors.down.isDown)
|
||||
{
|
||||
sprite.body.velocity.y = 200;
|
||||
}
|
||||
|
||||
game.physics.collide(sprite, group, collisionHandler, null, this);
|
||||
|
||||
}
|
||||
|
||||
function collisionHandler (obj1, obj2) {
|
||||
function collisionHandler (player, veg) {
|
||||
|
||||
// If the player collides with the chillis then they get eaten :)
|
||||
// The chilli frame ID is 17
|
||||
|
||||
console.log('Hit', obj2.name);
|
||||
|
||||
if (obj2.frame == 17)
|
||||
if (veg.frame == 17)
|
||||
{
|
||||
obj2.kill();
|
||||
veg.kill();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function render () {
|
||||
|
||||
// game.debug.renderQuadTree(game.physics.quadTree);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.image('atari', 'assets/sprites/atari130xe.png');
|
||||
game.load.image('mushroom', 'assets/sprites/mushroom2.png');
|
||||
game.load.image('flectrum', 'assets/sprites/flectrum.png');
|
||||
|
||||
}
|
||||
|
||||
var testGroup;
|
||||
var sprite1;
|
||||
var sprite2;
|
||||
var sprite3;
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#2d2d2d';
|
||||
|
||||
game.world.setBounds(-1000, -1000, 2000, 2000);
|
||||
|
||||
testGroup = game.add.group();
|
||||
|
||||
test2();
|
||||
|
||||
}
|
||||
|
||||
function test1 () {
|
||||
|
||||
// Test 1 - 2 sprites in world space (seems to work fine with local transform?)
|
||||
sprite1 = game.add.sprite(-600, 200, 'atari');
|
||||
sprite1.name = 'atari';
|
||||
// sprite1.body.setSize(100, 100, 0, 0);
|
||||
|
||||
sprite2 = game.add.sprite(-100, 220, 'mushroom');
|
||||
sprite2.name = 'mushroom';
|
||||
|
||||
game.camera.focusOn(sprite1);
|
||||
game.camera.x += 300;
|
||||
|
||||
game.input.onDown.add(go1, this);
|
||||
|
||||
}
|
||||
|
||||
function test2 () {
|
||||
|
||||
// 1 sprite in world space (seems to work fine with local transform?) and 1 in a group
|
||||
|
||||
sprite1 = testGroup.create(0, -150, 'atari');
|
||||
sprite1.name = 'atari';
|
||||
sprite1.body.immovable = true;
|
||||
// sprite1.body.setSize(100, 100, 0, 0);
|
||||
|
||||
sprite2 = game.add.sprite(-100, 140, 'mushroom');
|
||||
sprite2.name = 'mushroom';
|
||||
|
||||
sprite3 = game.add.sprite(-200, 150, 'flectrum');
|
||||
sprite3.name = 'tall';
|
||||
|
||||
testGroup.x = -600;
|
||||
testGroup.y = 200;
|
||||
|
||||
game.camera.focusOn(sprite2);
|
||||
game.camera.x -= 300;
|
||||
|
||||
game.input.onDown.add(go2, this);
|
||||
|
||||
}
|
||||
|
||||
function go1 () {
|
||||
|
||||
sprite1.body.velocity.x = 100;
|
||||
sprite2.body.velocity.x = -100;
|
||||
|
||||
}
|
||||
|
||||
function go2 () {
|
||||
|
||||
sprite2.body.velocity.x = -100;
|
||||
|
||||
}
|
||||
|
||||
function update () {
|
||||
|
||||
game.physics.collide(sprite1, sprite2, collisionHandler, null, this);
|
||||
|
||||
// sprite3.angle += 0.5;
|
||||
|
||||
}
|
||||
|
||||
function collisionHandler (obj1, obj2) {
|
||||
|
||||
game.stage.backgroundColor = '#992d2d';
|
||||
|
||||
console.log(obj1.name + ' collided with ' + obj2.name);
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
// game.debug.renderSpriteInfo(sprite1, 32, 32);
|
||||
// game.debug.renderSpriteCollision(sprite1, 32, 400);
|
||||
|
||||
game.debug.renderSpriteCoords(sprite1, 32, 32);
|
||||
game.debug.renderSpriteCoords(sprite2, 300, 32);
|
||||
|
||||
game.debug.renderCameraInfo(game.camera, 32, 500);
|
||||
|
||||
game.debug.renderSpriteBody(sprite1);
|
||||
game.debug.renderSpriteBody(sprite2);
|
||||
game.debug.renderSpriteBody(sprite3);
|
||||
|
||||
game.debug.renderGroupInfo(testGroup, 500, 500);
|
||||
game.debug.renderPixel(testGroup.x, testGroup.y, 'rgb(255,255,0)');
|
||||
|
||||
}
|
|
@ -16,7 +16,7 @@ function create() {
|
|||
emitter = game.add.emitter(0, 0, 200);
|
||||
|
||||
emitter.makeParticles('diamond');
|
||||
emitter.gravity = 10;
|
||||
emitter.gravity = 200;
|
||||
|
||||
game.input.onDown.add(particleBurst, this);
|
||||
|
||||
|
|
|
@ -17,9 +17,8 @@ function create() {
|
|||
|
||||
emitter.minParticleSpeed.setTo(-200, -300);
|
||||
emitter.maxParticleSpeed.setTo(200, -400);
|
||||
emitter.gravity = 8;
|
||||
emitter.gravity = 150;
|
||||
emitter.bounce.setTo(0.5, 0.5);
|
||||
emitter.particleDrag.x = 10;
|
||||
emitter.angularDrag = 30;
|
||||
|
||||
emitter.start(false, 8000, 400);
|
||||
|
@ -28,6 +27,6 @@ function create() {
|
|||
|
||||
function update() {
|
||||
|
||||
game.physics.collide(emitter, emitter);
|
||||
game.physics.collide(emitter);
|
||||
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ function create() {
|
|||
flyer.body.bounce.setTo(0.8, 0.8);
|
||||
|
||||
// This sets the gravity the sprite responds to in the world, as a point
|
||||
// Leave x=0 and set y=8 to simulate falling
|
||||
flyer.body.gravity.setTo(0, 8);
|
||||
// Leave x=0 and set y=80 to simulate falling
|
||||
flyer.body.gravity.setTo(0, 80);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ function create() {
|
|||
// displays it on-screen
|
||||
// and assign it to a variable
|
||||
ball = game.add.sprite(400, 200, 'ball');
|
||||
|
||||
knocker = game.add.sprite(400, 200, 'dude');
|
||||
knocker.body.immovable = true;
|
||||
|
||||
// This gets it moving
|
||||
ball.body.velocity.setTo(200, 200);
|
||||
|
@ -33,38 +35,38 @@ function create() {
|
|||
ball.body.bounce.setTo(1, 1);
|
||||
|
||||
// This sets the gravity the sprite responds to in the world, as a point
|
||||
// Here we leave x=0 and set y=8 to simulate falling
|
||||
ball.body.gravity.setTo(0, 8);
|
||||
// Here we leave x=0 and set y=80 to simulate falling
|
||||
ball.body.gravity.setTo(0, 80);
|
||||
|
||||
}
|
||||
|
||||
// Move the knocker with the arrow keys
|
||||
function update () {
|
||||
|
||||
// Enable physics between the knocker and the ball
|
||||
game.physics.collide(knocker, ball);
|
||||
|
||||
if (cursors.up.isDown)
|
||||
{
|
||||
knocker.body.velocity.y = -400;
|
||||
knocker.body.velocity.y = -300;
|
||||
}
|
||||
else if (cursors.down.isDown)
|
||||
{
|
||||
knocker.body.velocity.y = 400;
|
||||
knocker.body.velocity.y = 300;
|
||||
}
|
||||
else if (cursors.left.isDown)
|
||||
{
|
||||
knocker.body.velocity.x = -400;
|
||||
knocker.body.velocity.x = -300;
|
||||
}
|
||||
else if (cursors.right.isDown)
|
||||
{
|
||||
knocker.body.velocity.x = 400;
|
||||
knocker.body.velocity.x = 300;
|
||||
}
|
||||
else
|
||||
{
|
||||
knocker.body.velocity.setTo(0, 0);
|
||||
}
|
||||
|
||||
// Enable physics between the knocker and the ball
|
||||
game.physics.collide(knocker, ball);
|
||||
|
||||
}
|
||||
|
||||
function render () {
|
||||
|
|
|
@ -31,8 +31,8 @@ function create() {
|
|||
image.body.bounce.setTo(0.8, 0.8);
|
||||
|
||||
// This sets the gravity the sprite responds to in the world, as a point
|
||||
// Leave x=0 and set y=8 to simulate falling
|
||||
image.body.gravity.setTo(0, 8);
|
||||
// Leave x=0 and set y=180 to simulate falling
|
||||
image.body.gravity.setTo(0, 180);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ var launchVelocity = 0;
|
|||
function create() {
|
||||
|
||||
// set global gravity
|
||||
game.physics.gravity.y = 100;
|
||||
game.physics.gravity.y = 200;
|
||||
game.stage.backgroundColor = '#0072bc';
|
||||
|
||||
var graphics = game.add.graphics(0,0);
|
||||
|
|
|
@ -28,7 +28,61 @@ function create() {
|
|||
var bg = game.add.sprite(0, 0, bmd);
|
||||
bg.body.moves = false;
|
||||
|
||||
test10();
|
||||
test12();
|
||||
|
||||
}
|
||||
|
||||
function test12() {
|
||||
|
||||
// game.physics.gravity.y = 150;
|
||||
|
||||
sprite = game.add.sprite(200, 300, 'gameboy', 0);
|
||||
sprite.name = 'red';
|
||||
sprite.body.collideWorldBounds = true;
|
||||
sprite.body.checkCollision.right = false;
|
||||
// sprite.body.checkCollision.up = false;
|
||||
// sprite.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(400, 358, 'gameboy', 2);
|
||||
sprite2.name = 'green';
|
||||
sprite2.body.collideWorldBounds = true;
|
||||
sprite2.body.bounce.setTo(0.9, 0.9);
|
||||
|
||||
game.input.onDown.add(launch12, this);
|
||||
|
||||
}
|
||||
|
||||
function launch12() {
|
||||
|
||||
sprite2.body.velocity.x = -200;
|
||||
// sprite2.body.velocity.y = -60;
|
||||
|
||||
}
|
||||
|
||||
function test11() {
|
||||
|
||||
// game.physics.gravity.y = 150;
|
||||
|
||||
sprite = game.add.sprite(300, 200, 'gameboy', 0);
|
||||
sprite.name = 'red';
|
||||
sprite.body.collideWorldBounds = true;
|
||||
// sprite.body.checkCollision.down = false;
|
||||
// sprite.body.checkCollision.up = false;
|
||||
sprite.body.checkCollision.right = false;
|
||||
// sprite.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(290, 400, 'gameboy', 2);
|
||||
sprite2.name = 'green';
|
||||
sprite2.body.collideWorldBounds = true;
|
||||
sprite2.body.bounce.setTo(0.9, 0.9);
|
||||
|
||||
game.input.onDown.add(launch11, this);
|
||||
|
||||
}
|
||||
|
||||
function launch11() {
|
||||
|
||||
sprite2.body.velocity.y = -200;
|
||||
|
||||
}
|
||||
|
||||
|
|
50
examples/wip/body angle.js
Normal file
50
examples/wip/body angle.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.image('arrow', 'assets/sprites/longarrow.png');
|
||||
|
||||
}
|
||||
|
||||
var sprite;
|
||||
var cursors;
|
||||
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#124184';
|
||||
|
||||
sprite = game.add.sprite(400, 300, 'arrow');
|
||||
|
||||
cursors = game.input.keyboard.createCursorKeys();
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
sprite.body.velocity.x = 0;
|
||||
sprite.body.velocity.y = 0;
|
||||
sprite.body.angularVelocity = 0;
|
||||
|
||||
if (cursors.left.isDown)
|
||||
{
|
||||
sprite.body.angularVelocity = -100;
|
||||
}
|
||||
else if (cursors.right.isDown)
|
||||
{
|
||||
sprite.body.angularVelocity = 100;
|
||||
}
|
||||
|
||||
if (cursors.up.isDown)
|
||||
{
|
||||
game.physics.velocityFromAngle(sprite.angle, 300, sprite.body.velocity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.renderBodyInfo(sprite, 16, 24);
|
||||
|
||||
}
|
48
examples/wip/body scale.js
Normal file
48
examples/wip/body scale.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.spritesheet('gameboy', 'assets/sprites/gameboy_seize_color_40x60.png', 40, 60);
|
||||
|
||||
}
|
||||
|
||||
var sprite;
|
||||
var sprite2;
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#124184';
|
||||
|
||||
// Here we're tweening the scale of the sprite, which translates to the scale of the Body as well
|
||||
// The collision will carry on working even against the scaled body.
|
||||
|
||||
sprite = game.add.sprite(200, 300, 'gameboy', 2);
|
||||
sprite.name = 'green';
|
||||
// sprite.anchor.setTo(0.5, 0.5);
|
||||
sprite.body.immovable = true;
|
||||
|
||||
sprite2 = game.add.sprite(600, 300, 'gameboy', 3);
|
||||
sprite2.name = 'yellow';
|
||||
sprite2.body.rebound = false;
|
||||
|
||||
// sprite2.body.velocity.x = -200;
|
||||
|
||||
game.add.tween(sprite2).to( { x: 0 }, 3000, Phaser.Easing.Linear.None, true);
|
||||
|
||||
// game.add.tween(sprite.scale).to( { x: 3, y: 3 }, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
game.physics.collide(sprite, sprite2);
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
game.debug.renderPolygon(sprite.body.polygons, 'rgb(255,0,0)');
|
||||
game.debug.renderPolygon(sprite2.body.polygons, 'rgb(255,0,0)');
|
||||
|
||||
}
|
|
@ -15,7 +15,7 @@ var platform;
|
|||
function create() {
|
||||
|
||||
// Our ball sprite
|
||||
ball = game.add.sprite(420, 100, 'wizball');
|
||||
ball = game.add.sprite(440, 100, 'wizball');
|
||||
ball.anchor.setTo(0.5, 0.5);
|
||||
|
||||
ball.body.customSeparateX = true;
|
||||
|
@ -42,25 +42,20 @@ function update() {
|
|||
circle.y = ball.y;
|
||||
|
||||
// This is a rect vs. rect collision. The callback will check the circle.
|
||||
game.physics.overlap(ball, platform, null, processCallback, this);
|
||||
game.physics.overlap(ball, platform, collisionCallback, processCallback, this);
|
||||
|
||||
}
|
||||
|
||||
function collisionCallback(a, b) {
|
||||
|
||||
ball.body.y -= 10;
|
||||
ball.body.velocity.y *= -1 * ball.body.bounce.y;
|
||||
|
||||
}
|
||||
|
||||
function processCallback(a, b) {
|
||||
|
||||
// console.log('p', a.y, b.y);
|
||||
|
||||
if (Phaser.Circle.intersectsRectangle(circle, platform.body))
|
||||
{
|
||||
console.log('boom', ball.body.overlapX, ball.body.overlapY);
|
||||
// ball.body.x = ball.body.x - ball.body.overlapX;
|
||||
// ball.body.velocity.x = platform.body.velocity.x - ball.body.velocity.x * ball.body.bounce.x;
|
||||
|
||||
ball.body.y -= 10;
|
||||
ball.body.velocity.y *= -1 * ball.body.bounce.y;
|
||||
}
|
||||
|
||||
return true;
|
||||
return (Phaser.Circle.intersectsRectangle(circle, platform.body));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,6 @@
|
|||
<meta charset="UTF-8" />
|
||||
<title>phaser</title>
|
||||
<base href="../"></base>
|
||||
<script src="wip/SAT.js" type="text/javascript"></script>
|
||||
<?php
|
||||
require('../../build/config.php');
|
||||
|
||||
|
|
|
@ -1,76 +1,40 @@
|
|||
|
||||
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
|
||||
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
|
||||
|
||||
function preload() {
|
||||
|
||||
game.load.image('arrow', 'assets/sprites/asteroids_ship.png');
|
||||
game.load.image('ball', 'assets/sprites/shinyball.png');
|
||||
game.load.spritesheet('gameboy', 'assets/sprites/gameboy_seize_color_40x60.png', 40, 60);
|
||||
game.load.spritesheet('spinner', 'assets/sprites/bluemetal_32x32x4.png', 32, 32);
|
||||
|
||||
}
|
||||
|
||||
var gameboy;
|
||||
var sprites;
|
||||
var bmd;
|
||||
|
||||
function create() {
|
||||
|
||||
game.stage.backgroundColor = '#124184';
|
||||
|
||||
bmd = game.add.bitmapData(800, 600);
|
||||
bmd.fillStyle('#ffffff');
|
||||
var bg = game.add.sprite(0, 0, bmd);
|
||||
bg.body.moves = false;
|
||||
|
||||
game.physics.gravity.y = 250;
|
||||
// game.physics.gravity.x = 250;
|
||||
// Here we create a group, populate it with sprites, give them all a random velocity
|
||||
// and then check the group against itself for collision
|
||||
|
||||
sprites = game.add.group();
|
||||
|
||||
for (var i = 0; i < 20; i++)
|
||||
for (var i = 0; i < 30; i++)
|
||||
{
|
||||
var s = sprites.create(game.rnd.integerInRange(100, 700), game.rnd.integerInRange(32, 200), 'ball');
|
||||
s.body.velocity.x = game.rnd.integerInRange(-400, 400);
|
||||
var s = sprites.create(game.rnd.integerInRange(100, 700), game.rnd.integerInRange(32, 200), 'spinner');
|
||||
s.animations.add('spin', [0,1,2,3]);
|
||||
s.play('spin', 20, true);
|
||||
s.body.velocity.x = game.rnd.integerInRange(-200, 200);
|
||||
s.body.velocity.y = game.rnd.integerInRange(-200, 200);
|
||||
s.name = 'ball' + i;
|
||||
}
|
||||
|
||||
sprites.setAll('body.collideWorldBounds', true);
|
||||
sprites.setAll('body.bounce.x', 0.9);
|
||||
sprites.setAll('body.bounce.y', 0.9);
|
||||
sprites.setAll('body.minBounceVelocity', 0.8);
|
||||
|
||||
gameboy = game.add.sprite(300, 50, 'gameboy', 0);
|
||||
gameboy.name = 'gameboy';
|
||||
gameboy.body.collideWorldBounds = true;
|
||||
gameboy.body.bounce.setTo(0.9, 0.9);
|
||||
gameboy.body.velocity.x = game.rnd.integerInRange(-400, 400);
|
||||
gameboy.body.velocity.y = game.rnd.integerInRange(-200, 200);
|
||||
sprites.setAll('body.bounce.x', 1);
|
||||
sprites.setAll('body.bounce.y', 1);
|
||||
sprites.setAll('body.friction', 0);
|
||||
sprites.setAll('body.minBounceVelocity', 0);
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
game.physics.collide(gameboy, sprites);
|
||||
game.physics.collide(sprites);
|
||||
|
||||
// sprite.rotation = sprite.body.angle;
|
||||
|
||||
// if (sprite)
|
||||
// {
|
||||
// bmd.fillStyle('#ffff00');
|
||||
// bmd.fillRect(sprite.body.center.x, sprite.body.center.y, 2, 2);
|
||||
// }
|
||||
|
||||
// if (sprite2)
|
||||
// {
|
||||
// bmd.fillStyle('#ff00ff');
|
||||
// bmd.fillRect(sprite2.body.center.x, sprite2.body.center.y, 2, 2);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
Phaser.Particles.Arcade.Emitter = function (game, x, y, maxParticles) {
|
||||
|
||||
/**
|
||||
* The total number of particles in this emitter.
|
||||
* @property {number} maxParticles - The total number of particles in this emitter..
|
||||
* @default
|
||||
*/
|
||||
|
@ -36,7 +35,8 @@ Phaser.Particles.Arcade.Emitter = function (game, x, y, maxParticles) {
|
|||
this.name = 'emitter' + this.game.particles.ID++;
|
||||
|
||||
/**
|
||||
* @property {Description} type - Description.
|
||||
* @property {number} type - Internal Phaser Type value.
|
||||
* @protected
|
||||
*/
|
||||
this.type = Phaser.EMITTER;
|
||||
|
||||
|
@ -65,140 +65,114 @@ Phaser.Particles.Arcade.Emitter = function (game, x, y, maxParticles) {
|
|||
this.height = 1;
|
||||
|
||||
/**
|
||||
* The minimum possible velocity of a particle.
|
||||
* The default value is (-100,-100).
|
||||
* @property {Phaser.Point} minParticleSpeed
|
||||
* @property {Phaser.Point} minParticleSpeed - The minimum possible velocity of a particle.
|
||||
* @default
|
||||
*/
|
||||
this.minParticleSpeed = new Phaser.Point(-100, -100);
|
||||
|
||||
/**
|
||||
* The maximum possible velocity of a particle.
|
||||
* The default value is (100,100).
|
||||
* @property {Phaser.Point} maxParticleSpeed
|
||||
* @property {Phaser.Point} maxParticleSpeed - The maximum possible velocity of a particle.
|
||||
* @default
|
||||
*/
|
||||
this.maxParticleSpeed = new Phaser.Point(100, 100);
|
||||
|
||||
/**
|
||||
* The minimum possible scale of a particle.
|
||||
* The default value is 1.
|
||||
* @property {number} minParticleScale
|
||||
* @property {number} minParticleScale - The minimum possible scale of a particle.
|
||||
* @default
|
||||
*/
|
||||
this.minParticleScale = 1;
|
||||
|
||||
/**
|
||||
* The maximum possible scale of a particle.
|
||||
* The default value is 1.
|
||||
* @property {number} maxParticleScale
|
||||
* @property {number} maxParticleScale - The maximum possible scale of a particle.
|
||||
* @default
|
||||
*/
|
||||
this.maxParticleScale = 1;
|
||||
|
||||
/**
|
||||
* The minimum possible angular velocity of a particle. The default value is -360.
|
||||
* @property {number} minRotation
|
||||
* @property {number} minRotation - The minimum possible angular velocity of a particle.
|
||||
* @default
|
||||
*/
|
||||
this.minRotation = -360;
|
||||
|
||||
/**
|
||||
* The maximum possible angular velocity of a particle. The default value is 360.
|
||||
* @property {number} maxRotation
|
||||
* @property {number} maxRotation - The maximum possible angular velocity of a particle.
|
||||
* @default
|
||||
*/
|
||||
this.maxRotation = 360;
|
||||
|
||||
/**
|
||||
* Sets the <code>gravity.y</code> of each particle to this value on launch.
|
||||
* @property {number} gravity
|
||||
* @property {number} gravity - Sets the `body.gravity.y` of each particle sprite to this value on launch.
|
||||
* @default
|
||||
*/
|
||||
this.gravity = 2;
|
||||
this.gravity = 100;
|
||||
|
||||
/**
|
||||
* Set your own particle class type here.
|
||||
* @property {Description} particleClass
|
||||
* @property {any} particleClass - For emitting your own particle class types.
|
||||
* @default
|
||||
*/
|
||||
this.particleClass = null;
|
||||
|
||||
/**
|
||||
* The friction component of particles launched from the emitter.
|
||||
* @property {number} particleFriction
|
||||
* @property {number} particleFriction - The friction component of particles launched from the emitter.
|
||||
* @default
|
||||
*/
|
||||
this.particleFriction = 0;
|
||||
|
||||
/**
|
||||
* The angular drag component of particles launched from the emitter if they are rotating.
|
||||
* @property {number} angularDrag
|
||||
* @property {number} angularDrag - The angular drag component of particles launched from the emitter if they are rotating.
|
||||
* @default
|
||||
*/
|
||||
this.angularDrag = 0;
|
||||
|
||||
/**
|
||||
* How often a particle is emitted in ms (if emitter is started with Explode === false).
|
||||
* @property {boolean} frequency
|
||||
* @property {boolean} frequency - How often a particle is emitted in ms (if emitter is started with Explode === false).
|
||||
* @default
|
||||
*/
|
||||
this.frequency = 100;
|
||||
|
||||
/**
|
||||
* How long each particle lives once it is emitted in ms. Default is 2 seconds.
|
||||
* Set lifespan to 'zero' for particles to live forever.
|
||||
* @property {number} lifespan
|
||||
* @property {number} lifespan - How long each particle lives once it is emitted in ms. Default is 2 seconds. Set lifespan to 'zero' for particles to live forever.
|
||||
* @default
|
||||
*/
|
||||
this.lifespan = 2000;
|
||||
|
||||
/**
|
||||
* How much each particle should bounce on each axis. 1 = full bounce, 0 = no bounce.
|
||||
* @property {Phaser.Point} bounce
|
||||
* @property {Phaser.Point} bounce - How much each particle should bounce on each axis. 1 = full bounce, 0 = no bounce.
|
||||
*/
|
||||
this.bounce = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* Internal helper for deciding how many particles to launch.
|
||||
* @property {number} _quantity
|
||||
* @property {number} _quantity - Internal helper for deciding how many particles to launch.
|
||||
* @private
|
||||
* @default
|
||||
*/
|
||||
this._quantity = 0;
|
||||
|
||||
/**
|
||||
* Internal helper for deciding when to launch particles or kill them.
|
||||
* @property {number} _timer
|
||||
* @property {number} _timer - Internal helper for deciding when to launch particles or kill them.
|
||||
* @private
|
||||
* @default
|
||||
*/
|
||||
this._timer = 0;
|
||||
|
||||
/**
|
||||
* Internal counter for figuring out how many particles to launch.
|
||||
* @property {number} _counter
|
||||
* @property {number} _counter - Internal counter for figuring out how many particles to launch.
|
||||
* @private
|
||||
* @default
|
||||
*/
|
||||
this._counter = 0;
|
||||
|
||||
/**
|
||||
* Internal helper for the style of particle emission (all at once, or one at a time).
|
||||
* @property {boolean} _explode
|
||||
* @property {boolean} _explode - Internal helper for the style of particle emission (all at once, or one at a time).
|
||||
* @private
|
||||
* @default
|
||||
*/
|
||||
this._explode = true;
|
||||
|
||||
/**
|
||||
* Determines whether the emitter is currently emitting particles.
|
||||
* It is totally safe to directly toggle this.
|
||||
* @property {boolean} on
|
||||
* @property {boolean} on - Determines whether the emitter is currently emitting particles. It is totally safe to directly toggle this.
|
||||
* @default
|
||||
*/
|
||||
this.on = false;
|
||||
|
||||
/**
|
||||
* Determines whether the emitter is being updated by the core game loop.
|
||||
* @property {boolean} exists
|
||||
* @property {boolean} exists - Determines whether the emitter is being updated by the core game loop.
|
||||
* @default
|
||||
*/
|
||||
this.exists = true;
|
||||
|
@ -272,27 +246,19 @@ Phaser.Particles.Arcade.Emitter.prototype.update = function () {
|
|||
* This function generates a new array of particle sprites to attach to the emitter.
|
||||
*
|
||||
* @method Phaser.Particles.Arcade.Emitter#makeParticles
|
||||
* @param {Description} keys - Description.
|
||||
* @param {number} frames - Description.
|
||||
* @param {number} quantity - The number of particles to generate when using the "create from image" option.
|
||||
* @param {number} collide - Description.
|
||||
* @param {boolean} collideWorldBounds - Description.
|
||||
* @return This Emitter instance (nice for chaining stuff together, if you're into that).
|
||||
* @param {array|string} keys - A string or an array of strings that the particle sprites will use as their texture. If an array one is picked at random.
|
||||
* @param {array|number} frames - A frame number, or array of frames that the sprite will use. If an array one is picked at random.
|
||||
* @param {number} quantity - The number of particles to generate.
|
||||
* @param {boolean} [collide=false] - Sets the checkCollision.none flag on the particle sprites body.
|
||||
* @param {boolean} [collideWorldBounds=false] - A particle can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World.
|
||||
* @return {Phaser.Particles.Arcade.Emitter} This Emitter instance.
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.makeParticles = function (keys, frames, quantity, collide, collideWorldBounds) {
|
||||
|
||||
if (typeof frames == 'undefined')
|
||||
{
|
||||
frames = 0;
|
||||
}
|
||||
|
||||
quantity = quantity || this.maxParticles;
|
||||
collide = collide || 0;
|
||||
|
||||
if (typeof collideWorldBounds == 'undefined')
|
||||
{
|
||||
collideWorldBounds = false;
|
||||
}
|
||||
if (typeof frames === 'undefined') { frames = 0; }
|
||||
if (typeof quantity === 'undefined') { quantity = this.maxParticles; }
|
||||
if (typeof collide === 'undefined') { collide = false; }
|
||||
if (typeof collideWorldBounds === 'undefined') { collideWorldBounds = false; }
|
||||
|
||||
var particle;
|
||||
var i = 0;
|
||||
|
@ -301,14 +267,14 @@ Phaser.Particles.Arcade.Emitter.prototype.makeParticles = function (keys, frames
|
|||
|
||||
while (i < quantity)
|
||||
{
|
||||
if (this.particleClass == null)
|
||||
if (this.particleClass === null)
|
||||
{
|
||||
if (typeof keys == 'object')
|
||||
if (typeof keys === 'object')
|
||||
{
|
||||
rndKey = this.game.rnd.pick(keys);
|
||||
}
|
||||
|
||||
if (typeof frames == 'object')
|
||||
if (typeof frames === 'object')
|
||||
{
|
||||
rndFrame = this.game.rnd.pick(frames);
|
||||
}
|
||||
|
@ -320,7 +286,7 @@ Phaser.Particles.Arcade.Emitter.prototype.makeParticles = function (keys, frames
|
|||
// particle = new this.particleClass(this.game);
|
||||
// }
|
||||
|
||||
if (collide > 0)
|
||||
if (collide)
|
||||
{
|
||||
particle.body.checkCollision.any = true;
|
||||
particle.body.checkCollision.none = false;
|
||||
|
@ -347,9 +313,9 @@ Phaser.Particles.Arcade.Emitter.prototype.makeParticles = function (keys, frames
|
|||
}
|
||||
|
||||
/**
|
||||
* Call this function to turn off all the particles and the emitter.
|
||||
* @method Phaser.Particles.Arcade.Emitter#kill
|
||||
*/
|
||||
* Call this function to turn off all the particles and the emitter.
|
||||
* @method Phaser.Particles.Arcade.Emitter#kill
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.kill = function () {
|
||||
|
||||
this.on = false;
|
||||
|
@ -359,10 +325,9 @@ Phaser.Particles.Arcade.Emitter.prototype.kill = function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* Handy for bringing game objects "back to life". Just sets alive and exists back to true.
|
||||
* In practice, this is most often called by <code>Object.reset()</code>.
|
||||
* @method Phaser.Particles.Arcade.Emitter#revive
|
||||
*/
|
||||
* Handy for bringing game objects "back to life". Just sets alive and exists back to true.
|
||||
* @method Phaser.Particles.Arcade.Emitter#revive
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.revive = function () {
|
||||
|
||||
this.alive = true;
|
||||
|
@ -371,27 +336,19 @@ Phaser.Particles.Arcade.Emitter.prototype.revive = function () {
|
|||
}
|
||||
|
||||
/**
|
||||
* Call this function to start emitting particles.
|
||||
* @method Phaser.Particles.Arcade.Emitter#start
|
||||
* @param {boolean} explode - Whether the particles should all burst out at once.
|
||||
* @param {number} lifespan - How long each particle lives once emitted. 0 = forever.
|
||||
* @param {number} frequency - Ignored if Explode is set to true. Frequency is how often to emit a particle in ms.
|
||||
* @param {number} quantity - How many particles to launch. 0 = "all of the particles".
|
||||
*/
|
||||
* Call this function to start emitting particles.
|
||||
* @method Phaser.Particles.Arcade.Emitter#start
|
||||
* @param {boolean} [explode=true] - Whether the particles should all burst out at once.
|
||||
* @param {number} [lifespan=0] - How long each particle lives once emitted. 0 = forever.
|
||||
* @param {number} [frequency=250] - Ignored if Explode is set to true. Frequency is how often to emit a particle in ms.
|
||||
* @param {number} [quantity=0] - How many particles to launch. 0 = "all of the particles".
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.start = function (explode, lifespan, frequency, quantity) {
|
||||
|
||||
if (typeof explode !== 'boolean')
|
||||
{
|
||||
explode = true;
|
||||
}
|
||||
|
||||
lifespan = lifespan || 0;
|
||||
|
||||
// How many ms between emissions?
|
||||
frequency = frequency || 250;
|
||||
|
||||
// Total number of particles to emit
|
||||
quantity = quantity || 0;
|
||||
if (typeof explode === 'undefined') { explode = true; }
|
||||
if (typeof lifespan === 'undefined') { lifespan = 0; }
|
||||
if (typeof frequency === 'undefined') { frequency = 250; }
|
||||
if (typeof quantity === 'undefined') { quantity = 0; }
|
||||
|
||||
this.revive();
|
||||
|
||||
|
@ -417,9 +374,9 @@ Phaser.Particles.Arcade.Emitter.prototype.start = function (explode, lifespan, f
|
|||
}
|
||||
|
||||
/**
|
||||
* This function can be used both internally and externally to emit the next particle.
|
||||
* @method Phaser.Particles.Arcade.Emitter#emitParticle
|
||||
*/
|
||||
* This function can be used both internally and externally to emit the next particle.
|
||||
* @method Phaser.Particles.Arcade.Emitter#emitParticle
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.emitParticle = function () {
|
||||
|
||||
var particle = this.getFirstExists(false);
|
||||
|
@ -485,8 +442,8 @@ Phaser.Particles.Arcade.Emitter.prototype.emitParticle = function () {
|
|||
/**
|
||||
* A more compact way of setting the width and height of the emitter.
|
||||
* @method Phaser.Particles.Arcade.Emitter#setSize
|
||||
* @param {number} width - The desired width of the emitter (particles are spawned randomly within these dimensions).
|
||||
* @param {number} height - The desired height of the emitter.
|
||||
* @param {number} width - The desired width of the emitter (particles are spawned randomly within these dimensions).
|
||||
* @param {number} height - The desired height of the emitter.
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.setSize = function (width, height) {
|
||||
|
||||
|
@ -498,8 +455,8 @@ Phaser.Particles.Arcade.Emitter.prototype.setSize = function (width, height) {
|
|||
/**
|
||||
* A more compact way of setting the X velocity range of the emitter.
|
||||
* @method Phaser.Particles.Arcade.Emitter#setXSpeed
|
||||
* @param {number} min - The minimum value for this range.
|
||||
* @param {number} max - The maximum value for this range.
|
||||
* @param {number} [min=0] - The minimum value for this range.
|
||||
* @param {number} [max=0] - The maximum value for this range.
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.setXSpeed = function (min, max) {
|
||||
|
||||
|
@ -514,8 +471,8 @@ Phaser.Particles.Arcade.Emitter.prototype.setXSpeed = function (min, max) {
|
|||
/**
|
||||
* A more compact way of setting the Y velocity range of the emitter.
|
||||
* @method Phaser.Particles.Arcade.Emitter#setYSpeed
|
||||
* @param {number} min - The minimum value for this range.
|
||||
* @param {number} max - The maximum value for this range.
|
||||
* @param {number} [min=0] - The minimum value for this range.
|
||||
* @param {number} [max=0] - The maximum value for this range.
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.setYSpeed = function (min, max) {
|
||||
|
||||
|
@ -530,8 +487,8 @@ Phaser.Particles.Arcade.Emitter.prototype.setYSpeed = function (min, max) {
|
|||
/**
|
||||
* A more compact way of setting the angular velocity constraints of the emitter.
|
||||
* @method Phaser.Particles.Arcade.Emitter#setRotation
|
||||
* @param {number} min - The minimum value for this range.
|
||||
* @param {number} max - The maximum value for this range.
|
||||
* @param {number} [min=0] - The minimum value for this range.
|
||||
* @param {number} [max=0] - The maximum value for this range.
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.setRotation = function (min, max) {
|
||||
|
||||
|
@ -544,14 +501,17 @@ Phaser.Particles.Arcade.Emitter.prototype.setRotation = function (min, max) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Change the emitter's midpoint to match the midpoint of a <code>Object</code>.
|
||||
* Change the emitters center to match the center of any object with a `center` property, such as a Sprite.
|
||||
* @method Phaser.Particles.Arcade.Emitter#at
|
||||
* @param {object} object - The <code>Object</code> that you want to sync up with.
|
||||
* @param {object|Phaser.Sprite} object - The object that you wish to match the center with.
|
||||
*/
|
||||
Phaser.Particles.Arcade.Emitter.prototype.at = function (object) {
|
||||
|
||||
this.emitX = object.center.x;
|
||||
this.emitY = object.center.y;
|
||||
if (object.center)
|
||||
{
|
||||
this.emitX = object.center.x;
|
||||
this.emitY = object.center.y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,18 @@ Phaser.Physics.Arcade = function (game) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @type {number}
|
||||
*/
|
||||
Phaser.Physics.Arcade.RECT = 0;
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @type {number}
|
||||
*/
|
||||
Phaser.Physics.Arcade.CIRCLE = 1;
|
||||
|
||||
Phaser.Physics.Arcade.prototype = {
|
||||
|
||||
/**
|
||||
|
@ -327,7 +339,7 @@ Phaser.Physics.Arcade.prototype = {
|
|||
collideHandler: function (object1, object2, collideCallback, processCallback, callbackContext, overlapOnly) {
|
||||
|
||||
// Only collide valid objects
|
||||
if (typeof object2 === 'undefined' && object1.type === Phaser.GROUP)
|
||||
if (typeof object2 === 'undefined' && (object1.type === Phaser.GROUP || object1.type === Phaser.EMITTER))
|
||||
{
|
||||
this.collideGroupVsSelf(object1, collideCallback, processCallback, callbackContext, overlapOnly);
|
||||
return;
|
||||
|
|
|
@ -211,6 +211,12 @@ Phaser.Physics.Arcade.Body = function (sprite) {
|
|||
*/
|
||||
this.facing = Phaser.NONE;
|
||||
|
||||
/**
|
||||
* @property {boolean} rebound - A Body set to rebound will exchange velocity with another Body during collision. Set to false to allow this body to be 'pushed' rather than exchange velocity.
|
||||
* @default
|
||||
*/
|
||||
this.rebound = true;
|
||||
|
||||
/**
|
||||
* @property {boolean} immovable - An immovable Body will not receive any impacts or exchanges of velocity from other bodies.
|
||||
* @default
|
||||
|
@ -289,6 +295,22 @@ Phaser.Physics.Arcade.Body = function (sprite) {
|
|||
*/
|
||||
this.blockedPoint = new Phaser.Point(0, 0);
|
||||
|
||||
/**
|
||||
* @property {Phaser.Physics.Arcade.RECT|Phaser.Physics.Arcade.CIRCLE} type - The type of SAT Shape.
|
||||
*/
|
||||
this.type = Phaser.Physics.Arcade.RECT;
|
||||
|
||||
/**
|
||||
* @property {SAT.Box|SAT.Circle|SAT.Polygon} shape - The SAT Collision shape.
|
||||
*/
|
||||
this.shape = new SAT.Box(new SAT.Vector(this.x, this.y), this.width, this.height);
|
||||
|
||||
/**
|
||||
* @property {SAT.Polygon} polygons - The SAT Polygons, as derived from the Shape.
|
||||
* @private
|
||||
*/
|
||||
this.polygons = this.shape.toPolygon();
|
||||
|
||||
/**
|
||||
* @property {number} _dx - Internal cache var.
|
||||
* @private
|
||||
|
@ -314,10 +336,10 @@ Phaser.Physics.Arcade.Body = function (sprite) {
|
|||
this._sy = sprite.scale.y;
|
||||
|
||||
/**
|
||||
* @property {number} _average - Internal cache var.
|
||||
* @property {array} _distances - Internal cache var.
|
||||
* @private
|
||||
*/
|
||||
this.polygons = new SAT.Box(new SAT.Vector(this.x, this.y), this.width, this.height).toPolygon();
|
||||
this._distances = [0, 0, 0, 0];
|
||||
|
||||
this._debug = 0;
|
||||
|
||||
|
@ -325,6 +347,22 @@ Phaser.Physics.Arcade.Body = function (sprite) {
|
|||
|
||||
Phaser.Physics.Arcade.Body.prototype = {
|
||||
|
||||
setCircle: function (radius) {
|
||||
|
||||
this.shape = new SAT.Circle(new SAT.Vector(this.x, this.y), radius);
|
||||
this.polygons = null;
|
||||
this.type = Phaser.Physics.Arcade.CIRCLE;
|
||||
|
||||
},
|
||||
|
||||
setBox: function () {
|
||||
|
||||
this.shape = new SAT.Box(new SAT.Vector(this.x, this.y), this.width, this.height);
|
||||
this.polygons = this.shape.toPolygon();
|
||||
this.type = Phaser.Physics.Arcade.RECT;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method.
|
||||
*
|
||||
|
@ -340,8 +378,10 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.halfWidth = Math.floor(this.width / 2);
|
||||
this.halfHeight = Math.floor(this.height / 2);
|
||||
|
||||
// Scale by the difference between this and what it was previously
|
||||
this.polygons.scale(scaleX / this._sx, scaleY / this._sy);
|
||||
if (this.polygons)
|
||||
{
|
||||
this.polygons.scale(scaleX / this._sx, scaleY / this._sy);
|
||||
}
|
||||
|
||||
this._sx = scaleX;
|
||||
this._sy = scaleY;
|
||||
|
@ -395,8 +435,7 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.applyMotion();
|
||||
}
|
||||
|
||||
this.polygons.pos.x = this.x;
|
||||
this.polygons.pos.y = this.y;
|
||||
this.syncPosition();
|
||||
|
||||
},
|
||||
|
||||
|
@ -573,22 +612,7 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.velocity.y = -this.maxVelocity.y;
|
||||
}
|
||||
|
||||
this.polygons.pos.x = this.x;
|
||||
this.polygons.pos.y = this.y;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks for an overlap between this Body and the given Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#overlap
|
||||
* @param {Phaser.Physics.Arcade.Body} body - The Body that collided.
|
||||
* @param {SAT.Response} response - SAT Response handler.
|
||||
* @return {boolean} True if the two bodies overlap, otherwise false.
|
||||
*/
|
||||
overlap: function (body, response) {
|
||||
|
||||
return SAT.testPolygonPolygon(this.polygons, body.polygons, response);
|
||||
this.syncPosition();
|
||||
|
||||
},
|
||||
|
||||
|
@ -664,6 +688,34 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
|
||||
},
|
||||
|
||||
/**
|
||||
* Subtracts the given Vector from this Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#sub
|
||||
* @protected
|
||||
* @param {SAT.Vector} v - The vector to substract from this Body.
|
||||
*/
|
||||
sub: function (v) {
|
||||
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the given Vector from this Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#add
|
||||
* @protected
|
||||
* @param {SAT.Vector} v - The vector to add to this Body.
|
||||
*/
|
||||
add: function (v) {
|
||||
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Separation response handler.
|
||||
*
|
||||
|
@ -675,7 +727,11 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
give: function (body, response) {
|
||||
|
||||
this.add(response.overlapV);
|
||||
this.rebound(body);
|
||||
|
||||
if (this.rebound)
|
||||
{
|
||||
this.processRebound(body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -690,7 +746,11 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
take: function (body, response) {
|
||||
|
||||
this.sub(response.overlapV);
|
||||
this.rebound(body);
|
||||
|
||||
if (this.rebound)
|
||||
{
|
||||
this.processRebound(body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -708,7 +768,10 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.sub(response.overlapV);
|
||||
body.add(response.overlapV);
|
||||
|
||||
this.exchange(body);
|
||||
if (this.rebound)
|
||||
{
|
||||
this.exchange(body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -721,9 +784,9 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
exchange: function (body) {
|
||||
|
||||
if (this.mass === body.mass)
|
||||
if (this.mass === body.mass && this.speed > 0 && body.speed > 0)
|
||||
{
|
||||
// A direct velocity exchange
|
||||
// A direct velocity exchange (as they are both moving and have the same mass)
|
||||
this._dx = body.velocity.x;
|
||||
this._dy = body.velocity.y;
|
||||
|
||||
|
@ -762,11 +825,11 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
/**
|
||||
* Rebound the velocity of this Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#rebound
|
||||
* @method Phaser.Physics.Arcade#processRebound
|
||||
* @protected
|
||||
* @param {Phaser.Physics.Arcade.Body} body - The Body that collided.
|
||||
*/
|
||||
rebound: function (body) {
|
||||
processRebound: function (body) {
|
||||
|
||||
this.velocity.x = body.velocity.x - this.velocity.x * this.bounce.x;
|
||||
this.velocity.y = body.velocity.y - this.velocity.y * this.bounce.y;
|
||||
|
@ -774,8 +837,99 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks for an overlap between this Body and the given Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#overlap
|
||||
* @param {Phaser.Physics.Arcade.Body} body - The Body that is being checked against this Body.
|
||||
* @param {SAT.Response} response - SAT Response handler.
|
||||
* @return {boolean} True if the two bodies overlap, otherwise false.
|
||||
*/
|
||||
overlap: function (body, response) {
|
||||
|
||||
if (this.type === Phaser.Physics.Arcade.RECT && body.type === Phaser.Physics.Arcade.RECT)
|
||||
{
|
||||
return SAT.testPolygonPolygon(this.polygons, body.polygons, response);
|
||||
}
|
||||
else if (this.type === Phaser.Physics.Arcade.CIRCLE && body.type === Phaser.Physics.Arcade.CIRCLE)
|
||||
{
|
||||
return SAT.testCircleCircle(this.shape, body.shape, response);
|
||||
}
|
||||
else if (this.type === Phaser.Physics.Arcade.RECT && body.type === Phaser.Physics.Arcade.CIRCLE)
|
||||
{
|
||||
return SAT.testPolygonCircle(this.polygons, body.shape, response);
|
||||
}
|
||||
else if (this.type === Phaser.Physics.Arcade.CIRCLE && body.type === Phaser.Physics.Arcade.RECT)
|
||||
{
|
||||
return SAT.testCirclePolygon(this.shape, body.polygons, response);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* This separates this Body from the given Body unless a customSeparateCallback is set.
|
||||
* It assumes they have already been overlap checked and the resulting overlap is stored in overlapX and overlapY.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#separate
|
||||
* @protected
|
||||
* @param {Phaser.Physics.Arcade.Body} body - The Body to be separated from this one.
|
||||
* @param {SAT.Response} response - SAT Response handler.
|
||||
* @return {boolean}
|
||||
*/
|
||||
separate: function (body, response) {
|
||||
|
||||
if (this.customSeparateCallback)
|
||||
{
|
||||
return this.customSeparateCallback.call(this.customSeparateContext, this, response);
|
||||
}
|
||||
|
||||
this._distances[0] = body.right - this.x; // Distance of B to face on left side of A
|
||||
this._distances[1] = this.right - body.x; // Distance of B to face on right side of A
|
||||
this._distances[2] = body.bottom - this.y; // Distance of B to face on bottom side of A
|
||||
this._distances[3] = this.bottom - body.y; // Distance of B to face on top side of A
|
||||
|
||||
if (response.overlapN.x)
|
||||
{
|
||||
// Which is smaller? Left or Right?
|
||||
if (this._distances[0] < this._distances[1])
|
||||
{
|
||||
// console.log(this.sprite.name, 'collided on the LEFT with', body.sprite.name, response);
|
||||
this.hitLeft(body, response);
|
||||
}
|
||||
else if (this._distances[1] < this._distances[0])
|
||||
{
|
||||
// console.log(this.sprite.name, 'collided on the RIGHT with', body.sprite.name, response);
|
||||
this.hitRight(body, response);
|
||||
}
|
||||
}
|
||||
else if (response.overlapN.y)
|
||||
{
|
||||
// Which is smaller? Top or Bottom?
|
||||
if (this._distances[2] < this._distances[3])
|
||||
{
|
||||
// console.log(this.sprite.name, 'collided on the TOP with', body.sprite.name, response);
|
||||
this.hitTop(body, response);
|
||||
}
|
||||
else if (this._distances[3] < this._distances[2])
|
||||
{
|
||||
// console.log(this.sprite.name, 'collided on the BOTTOM with', body.sprite.name, response);
|
||||
this.hitBottom(body, response);
|
||||
}
|
||||
}
|
||||
|
||||
this.syncPosition();
|
||||
body.syncPosition();
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Process a collision with the left face of this Body.
|
||||
* Collision and separation can be further checked by setting a collideCallback.
|
||||
* This callback will be sent 4 parameters: The face of collision, this Body, the colliding Body and the SAT Response.
|
||||
* If the callback returns true then separation, rebounds and the touching flags will all be set.
|
||||
* If it returns false this will be skipped and must be handled manually.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#hitLeft
|
||||
* @protected
|
||||
|
@ -784,13 +938,13 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
hitLeft: function (body, response) {
|
||||
|
||||
// We know that Body is overlapping with This on the left-hand side
|
||||
if ((body.deltaX() < 0 && !this.checkCollision.right) || (body.deltaX() > 0 && !this.checkCollision.left))
|
||||
// We know that Body is overlapping with This on the left hand side (deltaX < 0 = moving left, > 0 = moving right)
|
||||
if (body.speed > 0 && (body.deltaX() <= 0 || (body.deltaX() > 0 && !this.checkCollision.left)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((body.deltaY() < 0 && !this.checkCollision.down) || (body.deltaY() > 0 && !this.checkCollision.up) || (body.deltaY() > 0 && !this.checkCollision.up) || (body.deltaY() > 0 && !this.checkCollision.down))
|
||||
if (this.collideCallback && !this.collideCallback.call(this.collideCallbackContext, Phaser.LEFT, this, body, response))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -823,15 +977,14 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.x -= this.right - this.game.world.bounds.right;
|
||||
}
|
||||
|
||||
if (this.collideCallback)
|
||||
{
|
||||
this.collideCallback.call(this.collideCallbackContext, Phaser.LEFT, this, body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Process a collision with the right face of this Body.
|
||||
* Collision and separation can be further checked by setting a collideCallback.
|
||||
* This callback will be sent 4 parameters: The face of collision, this Body, the colliding Body and the SAT Response.
|
||||
* If the callback returns true then separation, rebounds and the touching flags will all be set.
|
||||
* If it returns false this will be skipped and must be handled manually.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#hitRight
|
||||
* @protected
|
||||
|
@ -840,13 +993,13 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
hitRight: function (body, response) {
|
||||
|
||||
// We know that Body is overlapping with This on the right-hand side
|
||||
if ((body.deltaX() < 0 && !this.checkCollision.right) || (body.deltaX() > 0 && !this.checkCollision.left))
|
||||
// We know that Body is overlapping with This on the right hand side (deltaX < 0 = moving left, > 0 = moving right)
|
||||
if (body.speed > 0 && (body.deltaX() >= 0 || (body.deltaX() < 0 && !this.checkCollision.right)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((body.deltaY() < 0 && !this.checkCollision.down) || (body.deltaY() > 0 && !this.checkCollision.up) || (body.deltaY() > 0 && !this.checkCollision.up) || (body.deltaY() > 0 && !this.checkCollision.down))
|
||||
if (this.collideCallback && !this.collideCallback.call(this.collideCallbackContext, Phaser.RIGHT, this, body))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -879,15 +1032,14 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.x += this.game.world.bounds.x - this.x;
|
||||
}
|
||||
|
||||
if (this.collideCallback)
|
||||
{
|
||||
this.collideCallback.call(this.collideCallbackContext, Phaser.RIGHT, this, body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Process a collision with the top face of this Body.
|
||||
* Collision and separation can be further checked by setting a collideCallback.
|
||||
* This callback will be sent 4 parameters: The face of collision, this Body, the colliding Body and the SAT Response.
|
||||
* If the callback returns true then separation, rebounds and the touching flags will all be set.
|
||||
* If it returns false this will be skipped and must be handled manually.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#hitTop
|
||||
* @protected
|
||||
|
@ -896,8 +1048,13 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
hitTop: function (body, response) {
|
||||
|
||||
// We know that Body is overlapping with This on the top side (deltaY > 0 = moving down < 0 = moving up)
|
||||
if ((body.deltaY() > 0 && (!this.checkCollision.up || !this.checkCollision.down)) || (body.deltaY() < 0 && (!this.checkCollision.down || !this.checkCollision.up)))
|
||||
// We know that Body is overlapping with This on the bottom side (deltaY < 0 = moving up, > 0 = moving down)
|
||||
if (body.speed > 0 && (body.deltaY() <= 0 || (body.deltaY() > 0 && !this.checkCollision.up)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.collideCallback && !this.collideCallback.call(this.collideCallbackContext, Phaser.UP, this, body))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -930,15 +1087,14 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.y -= this.bottom - this.game.world.bounds.bottom;
|
||||
}
|
||||
|
||||
if (this.collideCallback)
|
||||
{
|
||||
this.collideCallback.call(this.collideCallbackContext, Phaser.UP, this, body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Process a collision with the bottom face of this Body.
|
||||
* Collision and separation can be further checked by setting a collideCallback.
|
||||
* This callback will be sent 4 parameters: The face of collision, this Body, the colliding Body and the SAT Response.
|
||||
* If the callback returns true then separation, rebounds and the touching flags will all be set.
|
||||
* If it returns false this will be skipped and must be handled manually.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#hitBottom
|
||||
* @protected
|
||||
|
@ -947,8 +1103,13 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
hitBottom: function (body, response) {
|
||||
|
||||
// We know that Body is overlapping with This on the bottom side (deltaY > 0 = moving down < 0 = moving up)
|
||||
if ((body.deltaY() < 0 && (!this.checkCollision.down || !this.checkCollision.up)) || (body.deltaY() < 0 && (!this.checkCollision.down || !this.checkCollision.up)))
|
||||
// We know that Body is overlapping with This on the bottom side (deltaY < 0 = moving up, > 0 = moving down)
|
||||
if (body.speed > 0 && (body.deltaY() >= 0 || (body.deltaY() < 0 && !this.checkCollision.down)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.collideCallback && !this.collideCallback.call(this.collideCallbackContext, Phaser.DOWN, this, body))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -981,102 +1142,25 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.y += this.game.world.bounds.y - this.y;
|
||||
}
|
||||
|
||||
if (this.collideCallback)
|
||||
{
|
||||
this.collideCallback.call(this.collideCallbackContext, Phaser.DOWN, this, body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Subtracts the given Vector from this Body.
|
||||
* Internal method that syncs the Body coordinates with the SAT shape and polygon positions.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#sub
|
||||
* @method Phaser.Physics.Arcade#syncPosition
|
||||
* @protected
|
||||
* @param {SAT.Vector} v - The vector to substract from this Body.
|
||||
*/
|
||||
sub: function (v) {
|
||||
syncPosition: function () {
|
||||
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.shape.pos.x = this.x;
|
||||
this.shape.pos.y = this.y;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the given Vector from this Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#add
|
||||
* @protected
|
||||
* @param {SAT.Vector} v - The vector to add to this Body.
|
||||
*/
|
||||
add: function (v) {
|
||||
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* This separates this Body from the given Body unless a customSeparateCallback is set.
|
||||
* It assumes they have already been overlap checked and the resulting overlap is stored in overlapX and overlapY.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#separate
|
||||
* @protected
|
||||
* @param {Phaser.Physics.Arcade.Body} body - The Body to be separated from this one.
|
||||
* @param {SAT.Response} response - SAT Response handler.
|
||||
* @return {boolean}
|
||||
*/
|
||||
separate: function (body, response) {
|
||||
|
||||
if (this.customSeparateCallback)
|
||||
if (this.polygons)
|
||||
{
|
||||
return this.customSeparateCallback.call(this.customSeparateContext, this, response);
|
||||
this.polygons.pos.x = this.x;
|
||||
this.polygons.pos.y = this.y;
|
||||
}
|
||||
|
||||
var distances = [
|
||||
(body.right - this.x), // distance of box 'b' to face on 'left' side of 'a'.
|
||||
(this.right - body.x), // distance of box 'b' to face on 'right' side of 'a'.
|
||||
(body.bottom - this.y), // distance of box 'b' to face on 'bottom' side of 'a'.
|
||||
(this.bottom - body.y) // distance of box 'b' to face on 'top' side of 'a'.
|
||||
];
|
||||
|
||||
if (response.overlapN.x)
|
||||
{
|
||||
// Which is smaller? Left or Right?
|
||||
if (distances[0] < distances[1])
|
||||
{
|
||||
console.log(this.sprite.name, 'collided on the LEFT with', body.sprite.name, response);
|
||||
this.hitLeft(body, response);
|
||||
}
|
||||
else if (distances[1] < distances[0])
|
||||
{
|
||||
console.log(this.sprite.name, 'collided on the RIGHT with', body.sprite.name, response);
|
||||
this.hitRight(body, response);
|
||||
}
|
||||
}
|
||||
else if (response.overlapN.y)
|
||||
{
|
||||
// Which is smaller? Top or Bottom?
|
||||
if (distances[2] < distances[3])
|
||||
{
|
||||
console.log(this.sprite.name, 'collided on the TOP with', body.sprite.name, response);
|
||||
this.hitTop(body, response);
|
||||
}
|
||||
else if (distances[3] < distances[2])
|
||||
{
|
||||
console.log(this.sprite.name, 'collided on the BOTTOM with', body.sprite.name, response);
|
||||
this.hitBottom(body, response);
|
||||
}
|
||||
}
|
||||
|
||||
this.polygons.pos.x = this.x;
|
||||
this.polygons.pos.y = this.y;
|
||||
|
||||
body.polygons.pos.x = body.x;
|
||||
body.polygons.pos.y = body.y;
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1152,9 +1236,17 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.halfWidth = Math.floor(this.width / 2);
|
||||
this.halfHeight = Math.floor(this.height / 2);
|
||||
this.offset.setTo(offsetX, offsetY);
|
||||
|
||||
this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
|
||||
|
||||
if (this.type === Phaser.Physics.Arcade.RECT)
|
||||
{
|
||||
this.setBox();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setCircle();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1177,8 +1269,14 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
this.y = this.preY;
|
||||
this.rotation = this.preRotation;
|
||||
|
||||
this.polygons.pos.x = this.x;
|
||||
this.polygons.pos.y = this.y;
|
||||
this.shape.pos.x = this.x;
|
||||
this.shape.pos.y = this.y;
|
||||
|
||||
if (this.polygons)
|
||||
{
|
||||
this.polygons.pos.x = this.x;
|
||||
this.polygons.pos.y = this.y;
|
||||
}
|
||||
|
||||
this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
|
||||
|
||||
|
@ -1303,20 +1401,3 @@ Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "right", {
|
|||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* @name Phaser.Physics.Arcade.Body#movingLeft
|
||||
* @property {boolean} movingLeft - True if this Body is moving left, based on its angle and speed.
|
||||
*/
|
||||
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "movingLeft", {
|
||||
|
||||
/**
|
||||
* True if this Body is moving left, based on its angle and speed.
|
||||
* @method movingLeft
|
||||
* @return {boolean}
|
||||
*/
|
||||
get: function () {
|
||||
return (this.speed > 0 && this.angle >= 0 && this.angle <= 0);
|
||||
},
|
||||
|
||||
});
|
||||
|
|
862
src/physics/arcade/SAT.js
Normal file
862
src/physics/arcade/SAT.js
Normal file
|
@ -0,0 +1,862 @@
|
|||
// Version 0.2 - Copyright 2013 - Jim Riecken <jimr@jimr.ca>
|
||||
//
|
||||
// Released under the MIT License - https://github.com/jriecken/sat-js
|
||||
//
|
||||
// A simple library for determining intersections of circles and
|
||||
// polygons using the Separating Axis Theorem.
|
||||
/** @preserve SAT.js - Version 0.2 - Copyright 2013 - Jim Riecken <jimr@jimr.ca> - released under the MIT License. https://github.com/jriecken/sat-js */
|
||||
|
||||
/*global define: false, module: false*/
|
||||
/*jshint shadow:true, sub:true, forin:true, noarg:true, noempty:true,
|
||||
eqeqeq:true, bitwise:true, strict:true, undef:true,
|
||||
curly:true, browser:true */
|
||||
|
||||
// Create a UMD wrapper for SAT. Works in:
|
||||
//
|
||||
// - Plain browser via global SAT variable
|
||||
// - AMD loader (like require.js)
|
||||
// - Node.js
|
||||
//
|
||||
// The quoted properties all over the place are used so that the Closure Compiler
|
||||
// does not mangle the exposed API in advanced mode.
|
||||
/**
|
||||
* @param {*} root - The global scope
|
||||
* @param {Function} factory - Factory that creates SAT module
|
||||
*/
|
||||
(function (root, factory) {
|
||||
"use strict";
|
||||
if (typeof define === 'function' && define['amd']) {
|
||||
define(factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
module['exports'] = factory();
|
||||
} else {
|
||||
root['SAT'] = factory();
|
||||
}
|
||||
}(this, function () {
|
||||
"use strict";
|
||||
|
||||
var SAT = {};
|
||||
|
||||
//
|
||||
// ## Vector
|
||||
//
|
||||
// Represents a vector in two dimensions with `x` and `y` properties.
|
||||
|
||||
|
||||
// Create a new Vector, optionally passing in the `x` and `y` coordinates. If
|
||||
// a coordinate is not specified, it will be set to `0`
|
||||
/**
|
||||
* @param {?number=} x The x position.
|
||||
* @param {?number=} y The y position.
|
||||
* @constructor
|
||||
*/
|
||||
function Vector(x, y) {
|
||||
this['x'] = x || 0;
|
||||
this['y'] = y || 0;
|
||||
}
|
||||
SAT['Vector'] = Vector;
|
||||
// Alias `Vector` as `V`
|
||||
SAT['V'] = Vector;
|
||||
|
||||
|
||||
// Copy the values of another Vector into this one.
|
||||
/**
|
||||
* @param {Vector} other The other Vector.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['copy'] = Vector.prototype.copy = function(other) {
|
||||
this['x'] = other['x'];
|
||||
this['y'] = other['y'];
|
||||
return this;
|
||||
};
|
||||
|
||||
// Change this vector to be perpendicular to what it was before. (Effectively
|
||||
// roatates it 90 degrees in a clockwise direction)
|
||||
/**
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['perp'] = Vector.prototype.perp = function() {
|
||||
var x = this['x'];
|
||||
this['x'] = this['y'];
|
||||
this['y'] = -x;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Rotate this vector (counter-clockwise) by the specified angle (in radians).
|
||||
/**
|
||||
* @param {number} angle The angle to rotate (in radians)
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['rotate'] = Vector.prototype.rotate = function (angle) {
|
||||
var x = this['x'];
|
||||
var y = this['y'];
|
||||
this['x'] = x * Math.cos(angle) - y * Math.sin(angle);
|
||||
this['y'] = x * Math.sin(angle) + y * Math.cos(angle);
|
||||
return this;
|
||||
};
|
||||
|
||||
// Rotate this vector (counter-clockwise) by the specified angle (in radians) which has already been calculated into sin and cos.
|
||||
/**
|
||||
* @param {number} sin - The Math.sin(angle)
|
||||
* @param {number} cos - The Math.cos(angle)
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['rotatePrecalc'] = Vector.prototype.rotatePrecalc = function (sin, cos) {
|
||||
var x = this['x'];
|
||||
var y = this['y'];
|
||||
this['x'] = x * cos - y * sin;
|
||||
this['y'] = x * sin + y * cos;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Reverse this vector.
|
||||
/**
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['reverse'] = Vector.prototype.reverse = function() {
|
||||
this['x'] = -this['x'];
|
||||
this['y'] = -this['y'];
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
// Normalize this vector. (make it have length of `1`)
|
||||
/**
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['normalize'] = Vector.prototype.normalize = function() {
|
||||
var d = this.len();
|
||||
if(d > 0) {
|
||||
this['x'] = this['x'] / d;
|
||||
this['y'] = this['y'] / d;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// Add another vector to this one.
|
||||
/**
|
||||
* @param {Vector} other The other Vector.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['add'] = Vector.prototype.add = function(other) {
|
||||
this['x'] += other['x'];
|
||||
this['y'] += other['y'];
|
||||
return this;
|
||||
};
|
||||
|
||||
// Subtract another vector from this one.
|
||||
/**
|
||||
* @param {Vector} other The other Vector.
|
||||
* @return {Vector} This for chaiing.
|
||||
*/
|
||||
Vector.prototype['sub'] = Vector.prototype.sub = function(other) {
|
||||
this['x'] -= other['x'];
|
||||
this['y'] -= other['y'];
|
||||
return this;
|
||||
};
|
||||
|
||||
// Scale this vector. An independant scaling factor can be provided
|
||||
// for each axis, or a single scaling factor that will scale both `x` and `y`.
|
||||
/**
|
||||
* @param {number} x The scaling factor in the x direction.
|
||||
* @param {?number=} y The scaling factor in the y direction. If this
|
||||
* is not specified, the x scaling factor will be used.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['scale'] = Vector.prototype.scale = function(x,y) {
|
||||
this['x'] *= x;
|
||||
this['y'] *= y || x;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Project this vector on to another vector.
|
||||
/**
|
||||
* @param {Vector} other The vector to project onto.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['project'] = Vector.prototype.project = function(other) {
|
||||
var amt = this.dot(other) / other.len2();
|
||||
this['x'] = amt * other['x'];
|
||||
this['y'] = amt * other['y'];
|
||||
return this;
|
||||
};
|
||||
|
||||
// Project this vector onto a vector of unit length. This is slightly more efficient
|
||||
// than `project` when dealing with unit vectors.
|
||||
/**
|
||||
* @param {Vector} other The unit vector to project onto.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['projectN'] = Vector.prototype.projectN = function(other) {
|
||||
var amt = this.dot(other);
|
||||
this['x'] = amt * other['x'];
|
||||
this['y'] = amt * other['y'];
|
||||
return this;
|
||||
};
|
||||
|
||||
// Reflect this vector on an arbitrary axis.
|
||||
/**
|
||||
* @param {Vector} axis The vector representing the axis.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['reflect'] = Vector.prototype.reflect = function(axis) {
|
||||
var x = this['x'];
|
||||
var y = this['y'];
|
||||
this.project(axis).scale(2);
|
||||
this['x'] -= x;
|
||||
this['y'] -= y;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Reflect this vector on an arbitrary axis (represented by a unit vector). This is
|
||||
// slightly more efficient than `reflect` when dealing with an axis that is a unit vector.
|
||||
/**
|
||||
* @param {Vector} axis The unit vector representing the axis.
|
||||
* @return {Vector} This for chaining.
|
||||
*/
|
||||
Vector.prototype['reflectN'] = Vector.prototype.reflectN = function(axis) {
|
||||
var x = this['x'];
|
||||
var y = this['y'];
|
||||
this.projectN(axis).scale(2);
|
||||
this['x'] -= x;
|
||||
this['y'] -= y;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Get the dot product of this vector and another.
|
||||
/**
|
||||
* @param {Vector} other The vector to dot this one against.
|
||||
* @return {number} The dot product.
|
||||
*/
|
||||
Vector.prototype['dot'] = Vector.prototype.dot = function(other) {
|
||||
return this['x'] * other['x'] + this['y'] * other['y'];
|
||||
};
|
||||
|
||||
// Get the squared length of this vector.
|
||||
/**
|
||||
* @return {number} The length^2 of this vector.
|
||||
*/
|
||||
Vector.prototype['len2'] = Vector.prototype.len2 = function() {
|
||||
return this.dot(this);
|
||||
};
|
||||
|
||||
// Get the length of this vector.
|
||||
/**
|
||||
* @return {number} The length of this vector.
|
||||
*/
|
||||
Vector.prototype['len'] = Vector.prototype.len = function() {
|
||||
return Math.sqrt(this.len2());
|
||||
};
|
||||
|
||||
// ## Circle
|
||||
//
|
||||
// Represents a circle with a position and a radius.
|
||||
|
||||
// Create a new circle, optionally passing in a position and/or radius. If no position
|
||||
// is given, the circle will be at `(0,0)`. If no radius is provided, the circle will
|
||||
// have a radius of `0`.
|
||||
/**
|
||||
* @param {Vector=} pos A vector representing the position of the center of the circle
|
||||
* @param {?number=} r The radius of the circle
|
||||
* @constructor
|
||||
*/
|
||||
function Circle(pos, r) {
|
||||
this['pos'] = pos || new Vector();
|
||||
this['r'] = r || 0;
|
||||
}
|
||||
SAT['Circle'] = Circle;
|
||||
|
||||
// ## Polygon
|
||||
//
|
||||
// Represents a *convex* polygon with any number of points (specified in counter-clockwise order)
|
||||
//
|
||||
// The edges/normals of the polygon will be calculated on creation and stored in the
|
||||
// `edges` and `normals` properties. If you change the polygon's points, you will need
|
||||
// to call `recalc` to recalculate the edges/normals.
|
||||
|
||||
// Create a new polygon, passing in a position vector, and an array of points (represented
|
||||
// by vectors relative to the position vector). If no position is passed in, the position
|
||||
// of the polygon will be `(0,0)`.
|
||||
/**
|
||||
* @param {Vector=} pos A vector representing the origin of the polygon. (all other
|
||||
* points are relative to this one)
|
||||
* @param {Array.<Vector>=} points An array of vectors representing the points in the polygon,
|
||||
* in counter-clockwise order.
|
||||
* @constructor
|
||||
*/
|
||||
function Polygon(pos, points) {
|
||||
this['pos'] = pos || new Vector();
|
||||
this['points'] = points || [];
|
||||
this.recalc();
|
||||
}
|
||||
SAT['Polygon'] = Polygon;
|
||||
|
||||
// Recalculates the edges and normals of the polygon. This **must** be called
|
||||
// if the `points` array is modified at all and the edges or normals are to be
|
||||
// accessed.
|
||||
/**
|
||||
* @return {Polygon} This for chaining.
|
||||
*/
|
||||
Polygon.prototype['recalc'] = Polygon.prototype.recalc = function() {
|
||||
// The edges here are the direction of the `n`th edge of the polygon, relative to
|
||||
// the `n`th point. If you want to draw a given edge from the edge value, you must
|
||||
// first translate to the position of the starting point.
|
||||
this['edges'] = [];
|
||||
// The normals here are the direction of the normal for the `n`th edge of the polygon, relative
|
||||
// to the position of the `n`th point. If you want to draw an edge normal, you must first
|
||||
// translate to the position of the starting point.
|
||||
this['normals'] = [];
|
||||
var points = this['points'];
|
||||
var len = points.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var p1 = points[i];
|
||||
var p2 = i < len - 1 ? points[i + 1] : points[0];
|
||||
var e = new Vector().copy(p2).sub(p1);
|
||||
var n = new Vector().copy(e).perp().normalize();
|
||||
this['edges'].push(e);
|
||||
this['normals'].push(n);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// Rotates this polygon counter-clockwise around the origin of *its local coordinate system* (i.e. `pos`).
|
||||
//
|
||||
// Note: You do **not** need to call `recalc` after rotation.
|
||||
/**
|
||||
* @param {number} angle The angle to rotate (in radians)
|
||||
* @return {Polygon} This for chaining.
|
||||
*/
|
||||
Polygon.prototype['rotate'] = Polygon.prototype.rotate = function(angle) {
|
||||
var i;
|
||||
var points = this['points'];
|
||||
var edges = this['edges'];
|
||||
var normals = this['normals'];
|
||||
var len = points.length;
|
||||
|
||||
// Calc it just the once, rather than 4 times per array element
|
||||
var cos = Math.cos(angle);
|
||||
var sin = Math.sin(angle);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
points[i].rotatePrecalc(sin, cos);
|
||||
edges[i].rotatePrecalc(sin, cos);
|
||||
normals[i].rotatePrecalc(sin, cos);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// Rotates this polygon counter-clockwise around the origin of *its local coordinate system* (i.e. `pos`).
|
||||
//
|
||||
// Note: You do **not** need to call `recalc` after rotation.
|
||||
/**
|
||||
* @param {number} angle The angle to rotate (in radians)
|
||||
* @return {Polygon} This for chaining.
|
||||
*/
|
||||
Polygon.prototype['scale'] = Polygon.prototype.scale = function(x, y) {
|
||||
var i;
|
||||
var points = this['points'];
|
||||
var edges = this['edges'];
|
||||
var normals = this['normals'];
|
||||
var len = points.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
points[i].scale(x,y);
|
||||
edges[i].scale(x,y);
|
||||
normals[i].scale(x,y);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// Translates the points of this polygon by a specified amount relative to the origin of *its own coordinate
|
||||
// system* (i.e. `pos`).
|
||||
//
|
||||
// This is most useful to change the "center point" of a polygon.
|
||||
//
|
||||
// Note: You do **not** need to call `recalc` after translation.
|
||||
/**
|
||||
* @param {number} x The horizontal amount to translate.
|
||||
* @param {number} y The vertical amount to translate.
|
||||
* @return {Polygon} This for chaining.
|
||||
*/
|
||||
Polygon.prototype['translate'] = Polygon.prototype.translate = function (x, y) {
|
||||
var i;
|
||||
var points = this['points'];
|
||||
var len = points.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
points[i].x += x;
|
||||
points[i].y += y;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// ## Box
|
||||
//
|
||||
// Represents an axis-aligned box, with a width and height.
|
||||
|
||||
|
||||
// Create a new box, with the specified position, width, and height. If no position
|
||||
// is given, the position will be `(0,0)`. If no width or height are given, they will
|
||||
// be set to `0`.
|
||||
/**
|
||||
* @param {Vector=} pos A vector representing the top-left of the box.
|
||||
* @param {?number=} w The width of the box.
|
||||
* @param {?number=} h The height of the box.
|
||||
* @constructor
|
||||
*/
|
||||
function Box(pos, w, h) {
|
||||
this['pos'] = pos || new Vector();
|
||||
this['w'] = w || 0;
|
||||
this['h'] = h || 0;
|
||||
}
|
||||
SAT['Box'] = Box;
|
||||
|
||||
// Returns a polygon whose edges are the same as this box.
|
||||
/**
|
||||
* @return {Polygon} A new Polygon that represents this box.
|
||||
*/
|
||||
Box.prototype['toPolygon'] = Box.prototype.toPolygon = function() {
|
||||
var pos = this['pos'];
|
||||
var w = this['w'];
|
||||
var h = this['h'];
|
||||
return new Polygon(new Vector(pos['x'], pos['y']), [
|
||||
new Vector(), new Vector(w, 0),
|
||||
new Vector(w,h), new Vector(0,h)
|
||||
]);
|
||||
};
|
||||
|
||||
// ## Response
|
||||
//
|
||||
// An object representing the result of an intersection. Contains:
|
||||
// - The two objects participating in the intersection
|
||||
// - The vector representing the minimum change necessary to extract the first object
|
||||
// from the second one (as well as a unit vector in that direction and the magnitude
|
||||
// of the overlap)
|
||||
// - Whether the first object is entirely inside the second, and vice versa.
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function Response() {
|
||||
this['a'] = null;
|
||||
this['b'] = null;
|
||||
this['overlapN'] = new Vector();
|
||||
this['overlapV'] = new Vector();
|
||||
this.clear();
|
||||
}
|
||||
SAT['Response'] = Response;
|
||||
|
||||
// Set some values of the response back to their defaults. Call this between tests if
|
||||
// you are going to reuse a single Response object for multiple intersection tests (recommented
|
||||
// as it will avoid allcating extra memory)
|
||||
/**
|
||||
* @return {Response} This for chaining
|
||||
*/
|
||||
Response.prototype['clear'] = Response.prototype.clear = function() {
|
||||
this['aInB'] = true;
|
||||
this['bInA'] = true;
|
||||
this['overlap'] = Number.MAX_VALUE;
|
||||
return this;
|
||||
};
|
||||
|
||||
// ## Object Pools
|
||||
|
||||
// A pool of `Vector` objects that are used in calculations to avoid
|
||||
// allocating memory.
|
||||
/**
|
||||
* @type {Array.<Vector>}
|
||||
*/
|
||||
var T_VECTORS = [];
|
||||
for (var i = 0; i < 10; i++) { T_VECTORS.push(new Vector()); }
|
||||
|
||||
// A pool of arrays of numbers used in calculations to avoid allocating
|
||||
// memory.
|
||||
/**
|
||||
* @type {Array.<Array.<number>>}
|
||||
*/
|
||||
var T_ARRAYS = [];
|
||||
for (var i = 0; i < 5; i++) { T_ARRAYS.push([]); }
|
||||
|
||||
// ## Helper Functions
|
||||
|
||||
// Flattens the specified array of points onto a unit vector axis,
|
||||
// resulting in a one dimensional range of the minimum and
|
||||
// maximum value on that axis.
|
||||
/**
|
||||
* @param {Array.<Vector>} points The points to flatten.
|
||||
* @param {Vector} normal The unit vector axis to flatten on.
|
||||
* @param {Array.<number>} result An array. After calling this function,
|
||||
* result[0] will be the minimum value,
|
||||
* result[1] will be the maximum value.
|
||||
*/
|
||||
function flattenPointsOn(points, normal, result) {
|
||||
var min = Number.MAX_VALUE;
|
||||
var max = -Number.MAX_VALUE;
|
||||
var len = points.length;
|
||||
for (var i = 0; i < len; i++ ) {
|
||||
// The magnitude of the projection of the point onto the normal
|
||||
var dot = points[i].dot(normal);
|
||||
if (dot < min) { min = dot; }
|
||||
if (dot > max) { max = dot; }
|
||||
}
|
||||
result[0] = min; result[1] = max;
|
||||
}
|
||||
|
||||
// Check whether two convex polygons are separated by the specified
|
||||
// axis (must be a unit vector).
|
||||
/**
|
||||
* @param {Vector} aPos The position of the first polygon.
|
||||
* @param {Vector} bPos The position of the second polygon.
|
||||
* @param {Array.<Vector>} aPoints The points in the first polygon.
|
||||
* @param {Array.<Vector>} bPoints The points in the second polygon.
|
||||
* @param {Vector} axis The axis (unit sized) to test against. The points of both polygons
|
||||
* will be projected onto this axis.
|
||||
* @param {Response=} response A Response object (optional) which will be populated
|
||||
* if the axis is not a separating axis.
|
||||
* @return {boolean} true if it is a separating axis, false otherwise. If false,
|
||||
* and a response is passed in, information about how much overlap and
|
||||
* the direction of the overlap will be populated.
|
||||
*/
|
||||
function isSeparatingAxis(aPos, bPos, aPoints, bPoints, axis, response) {
|
||||
var rangeA = T_ARRAYS.pop();
|
||||
var rangeB = T_ARRAYS.pop();
|
||||
// The magnitude of the offset between the two polygons
|
||||
var offsetV = T_VECTORS.pop().copy(bPos).sub(aPos);
|
||||
var projectedOffset = offsetV.dot(axis);
|
||||
// Project the polygons onto the axis.
|
||||
flattenPointsOn(aPoints, axis, rangeA);
|
||||
flattenPointsOn(bPoints, axis, rangeB);
|
||||
// Move B's range to its position relative to A.
|
||||
rangeB[0] += projectedOffset;
|
||||
rangeB[1] += projectedOffset;
|
||||
// Check if there is a gap. If there is, this is a separating axis and we can stop
|
||||
if (rangeA[0] > rangeB[1] || rangeB[0] > rangeA[1]) {
|
||||
T_VECTORS.push(offsetV);
|
||||
T_ARRAYS.push(rangeA);
|
||||
T_ARRAYS.push(rangeB);
|
||||
return true;
|
||||
}
|
||||
// This is not a separating axis. If we're calculating a response, calculate the overlap.
|
||||
if (response) {
|
||||
var overlap = 0;
|
||||
// A starts further left than B
|
||||
if (rangeA[0] < rangeB[0]) {
|
||||
response['aInB'] = false;
|
||||
// A ends before B does. We have to pull A out of B
|
||||
if (rangeA[1] < rangeB[1]) {
|
||||
overlap = rangeA[1] - rangeB[0];
|
||||
response['bInA'] = false;
|
||||
// B is fully inside A. Pick the shortest way out.
|
||||
} else {
|
||||
var option1 = rangeA[1] - rangeB[0];
|
||||
var option2 = rangeB[1] - rangeA[0];
|
||||
overlap = option1 < option2 ? option1 : -option2;
|
||||
}
|
||||
// B starts further left than A
|
||||
} else {
|
||||
response['bInA'] = false;
|
||||
// B ends before A ends. We have to push A out of B
|
||||
if (rangeA[1] > rangeB[1]) {
|
||||
overlap = rangeA[0] - rangeB[1];
|
||||
response['aInB'] = false;
|
||||
// A is fully inside B. Pick the shortest way out.
|
||||
} else {
|
||||
var option1 = rangeA[1] - rangeB[0];
|
||||
var option2 = rangeB[1] - rangeA[0];
|
||||
overlap = option1 < option2 ? option1 : -option2;
|
||||
}
|
||||
}
|
||||
// If this is the smallest amount of overlap we've seen so far, set it as the minimum overlap.
|
||||
var absOverlap = Math.abs(overlap);
|
||||
if (absOverlap < response['overlap']) {
|
||||
response['overlap'] = absOverlap;
|
||||
response['overlapN'].copy(axis);
|
||||
if (overlap < 0) {
|
||||
response['overlapN'].reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
T_VECTORS.push(offsetV);
|
||||
T_ARRAYS.push(rangeA);
|
||||
T_ARRAYS.push(rangeB);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculates which Vornoi region a point is on a line segment.
|
||||
// It is assumed that both the line and the point are relative to `(0,0)`
|
||||
//
|
||||
// | (0) |
|
||||
// (-1) [S]--------------[E] (1)
|
||||
// | (0) |
|
||||
/**
|
||||
* @param {Vector} line The line segment.
|
||||
* @param {Vector} point The point.
|
||||
* @return {number} LEFT_VORNOI_REGION (-1) if it is the left region,
|
||||
* MIDDLE_VORNOI_REGION (0) if it is the middle region,
|
||||
* RIGHT_VORNOI_REGION (1) if it is the right region.
|
||||
*/
|
||||
function vornoiRegion(line, point) {
|
||||
var len2 = line.len2();
|
||||
var dp = point.dot(line);
|
||||
// If the point is beyond the start of the line, it is in the
|
||||
// left vornoi region.
|
||||
if (dp < 0) { return LEFT_VORNOI_REGION; }
|
||||
// If the point is beyond the end of the line, it is in the
|
||||
// right vornoi region.
|
||||
else if (dp > len2) { return RIGHT_VORNOI_REGION; }
|
||||
// Otherwise, it's in the middle one.
|
||||
else { return MIDDLE_VORNOI_REGION; }
|
||||
}
|
||||
// Constants for Vornoi regions
|
||||
/**
|
||||
* @const
|
||||
*/
|
||||
var LEFT_VORNOI_REGION = -1;
|
||||
/**
|
||||
* @const
|
||||
*/
|
||||
var MIDDLE_VORNOI_REGION = 0;
|
||||
/**
|
||||
* @const
|
||||
*/
|
||||
var RIGHT_VORNOI_REGION = 1;
|
||||
|
||||
// ## Collision Tests
|
||||
|
||||
// Check if two circles collide.
|
||||
/**
|
||||
* @param {Circle} a The first circle.
|
||||
* @param {Circle} b The second circle.
|
||||
* @param {Response=} response Response object (optional) that will be populated if
|
||||
* the circles intersect.
|
||||
* @return {boolean} true if the circles intersect, false if they don't.
|
||||
*/
|
||||
function testCircleCircle(a, b, response) {
|
||||
// Check if the distance between the centers of the two
|
||||
// circles is greater than their combined radius.
|
||||
var differenceV = T_VECTORS.pop().copy(b['pos']).sub(a['pos']);
|
||||
var totalRadius = a['r'] + b['r'];
|
||||
var totalRadiusSq = totalRadius * totalRadius;
|
||||
var distanceSq = differenceV.len2();
|
||||
// If the distance is bigger than the combined radius, they don't intersect.
|
||||
if (distanceSq > totalRadiusSq) {
|
||||
T_VECTORS.push(differenceV);
|
||||
return false;
|
||||
}
|
||||
// They intersect. If we're calculating a response, calculate the overlap.
|
||||
if (response) {
|
||||
var dist = Math.sqrt(distanceSq);
|
||||
response['a'] = a;
|
||||
response['b'] = b;
|
||||
response['overlap'] = totalRadius - dist;
|
||||
response['overlapN'].copy(differenceV.normalize());
|
||||
response['overlapV'].copy(differenceV).scale(response['overlap']);
|
||||
response['aInB']= a['r'] <= b['r'] && dist <= b['r'] - a['r'];
|
||||
response['bInA'] = b['r'] <= a['r'] && dist <= a['r'] - b['r'];
|
||||
}
|
||||
T_VECTORS.push(differenceV);
|
||||
return true;
|
||||
}
|
||||
SAT['testCircleCircle'] = testCircleCircle;
|
||||
|
||||
// Check if a polygon and a circle collide.
|
||||
/**
|
||||
* @param {Polygon} polygon The polygon.
|
||||
* @param {Circle} circle The circle.
|
||||
* @param {Response=} response Response object (optional) that will be populated if
|
||||
* they interset.
|
||||
* @return {boolean} true if they intersect, false if they don't.
|
||||
*/
|
||||
function testPolygonCircle(polygon, circle, response) {
|
||||
// Get the position of the circle relative to the polygon.
|
||||
var circlePos = T_VECTORS.pop().copy(circle['pos']).sub(polygon['pos']);
|
||||
var radius = circle['r'];
|
||||
var radius2 = radius * radius;
|
||||
var points = polygon['points'];
|
||||
var len = points.length;
|
||||
var edge = T_VECTORS.pop();
|
||||
var point = T_VECTORS.pop();
|
||||
|
||||
// For each edge in the polygon:
|
||||
for (var i = 0; i < len; i++) {
|
||||
var next = i === len - 1 ? 0 : i + 1;
|
||||
var prev = i === 0 ? len - 1 : i - 1;
|
||||
var overlap = 0;
|
||||
var overlapN = null;
|
||||
|
||||
// Get the edge.
|
||||
edge.copy(polygon['edges'][i]);
|
||||
// Calculate the center of the circle relative to the starting point of the edge.
|
||||
point.copy(circlePos).sub(points[i]);
|
||||
|
||||
// If the distance between the center of the circle and the point
|
||||
// is bigger than the radius, the polygon is definitely not fully in
|
||||
// the circle.
|
||||
if (response && point.len2() > radius2) {
|
||||
response['aInB'] = false;
|
||||
}
|
||||
|
||||
// Calculate which Vornoi region the center of the circle is in.
|
||||
var region = vornoiRegion(edge, point);
|
||||
// If it's the left region:
|
||||
if (region === LEFT_VORNOI_REGION) {
|
||||
// We need to make sure we're in the RIGHT_VORNOI_REGION of the previous edge.
|
||||
edge.copy(polygon['edges'][prev]);
|
||||
// Calculate the center of the circle relative the starting point of the previous edge
|
||||
var point2 = T_VECTORS.pop().copy(circlePos).sub(points[prev]);
|
||||
region = vornoiRegion(edge, point2);
|
||||
if (region === RIGHT_VORNOI_REGION) {
|
||||
// It's in the region we want. Check if the circle intersects the point.
|
||||
var dist = point.len();
|
||||
if (dist > radius) {
|
||||
// No intersection
|
||||
T_VECTORS.push(circlePos);
|
||||
T_VECTORS.push(edge);
|
||||
T_VECTORS.push(point);
|
||||
T_VECTORS.push(point2);
|
||||
return false;
|
||||
} else if (response) {
|
||||
// It intersects, calculate the overlap.
|
||||
response['bInA'] = false;
|
||||
overlapN = point.normalize();
|
||||
overlap = radius - dist;
|
||||
}
|
||||
}
|
||||
T_VECTORS.push(point2);
|
||||
// If it's the right region:
|
||||
} else if (region === RIGHT_VORNOI_REGION) {
|
||||
// We need to make sure we're in the left region on the next edge
|
||||
edge.copy(polygon['edges'][next]);
|
||||
// Calculate the center of the circle relative to the starting point of the next edge.
|
||||
point.copy(circlePos).sub(points[next]);
|
||||
region = vornoiRegion(edge, point);
|
||||
if (region === LEFT_VORNOI_REGION) {
|
||||
// It's in the region we want. Check if the circle intersects the point.
|
||||
var dist = point.len();
|
||||
if (dist > radius) {
|
||||
// No intersection
|
||||
T_VECTORS.push(circlePos);
|
||||
T_VECTORS.push(edge);
|
||||
T_VECTORS.push(point);
|
||||
return false;
|
||||
} else if (response) {
|
||||
// It intersects, calculate the overlap.
|
||||
response['bInA'] = false;
|
||||
overlapN = point.normalize();
|
||||
overlap = radius - dist;
|
||||
}
|
||||
}
|
||||
// Otherwise, it's the middle region:
|
||||
} else {
|
||||
// Need to check if the circle is intersecting the edge,
|
||||
// Change the edge into its "edge normal".
|
||||
var normal = edge.perp().normalize();
|
||||
// Find the perpendicular distance between the center of the
|
||||
// circle and the edge.
|
||||
var dist = point.dot(normal);
|
||||
var distAbs = Math.abs(dist);
|
||||
// If the circle is on the outside of the edge, there is no intersection.
|
||||
if (dist > 0 && distAbs > radius) {
|
||||
// No intersection
|
||||
T_VECTORS.push(circlePos);
|
||||
T_VECTORS.push(normal);
|
||||
T_VECTORS.push(point);
|
||||
return false;
|
||||
} else if (response) {
|
||||
// It intersects, calculate the overlap.
|
||||
overlapN = normal;
|
||||
overlap = radius - dist;
|
||||
// If the center of the circle is on the outside of the edge, or part of the
|
||||
// circle is on the outside, the circle is not fully inside the polygon.
|
||||
if (dist >= 0 || overlap < 2 * radius) {
|
||||
response['bInA'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the smallest overlap we've seen, keep it.
|
||||
// (overlapN may be null if the circle was in the wrong Vornoi region).
|
||||
if (overlapN && response && Math.abs(overlap) < Math.abs(response['overlap'])) {
|
||||
response['overlap'] = overlap;
|
||||
response['overlapN'].copy(overlapN);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the final overlap vector - based on the smallest overlap.
|
||||
if (response) {
|
||||
response['a'] = polygon;
|
||||
response['b'] = circle;
|
||||
response['overlapV'].copy(response['overlapN']).scale(response['overlap']);
|
||||
}
|
||||
T_VECTORS.push(circlePos);
|
||||
T_VECTORS.push(edge);
|
||||
T_VECTORS.push(point);
|
||||
return true;
|
||||
}
|
||||
SAT['testPolygonCircle'] = testPolygonCircle;
|
||||
|
||||
// Check if a circle and a polygon collide.
|
||||
//
|
||||
// **NOTE:** This is slightly less efficient than polygonCircle as it just
|
||||
// runs polygonCircle and reverses everything at the end.
|
||||
/**
|
||||
* @param {Circle} circle The circle.
|
||||
* @param {Polygon} polygon The polygon.
|
||||
* @param {Response=} response Response object (optional) that will be populated if
|
||||
* they interset.
|
||||
* @return {boolean} true if they intersect, false if they don't.
|
||||
*/
|
||||
function testCirclePolygon(circle, polygon, response) {
|
||||
// Test the polygon against the circle.
|
||||
var result = testPolygonCircle(polygon, circle, response);
|
||||
if (result && response) {
|
||||
// Swap A and B in the response.
|
||||
var a = response['a'];
|
||||
var aInB = response['aInB'];
|
||||
response['overlapN'].reverse();
|
||||
response['overlapV'].reverse();
|
||||
response['a'] = response['b'];
|
||||
response['b'] = a;
|
||||
response['aInB'] = response['bInA'];
|
||||
response['bInA'] = aInB;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
SAT['testCirclePolygon'] = testCirclePolygon;
|
||||
|
||||
// Checks whether polygons collide.
|
||||
/**
|
||||
* @param {Polygon} a The first polygon.
|
||||
* @param {Polygon} b The second polygon.
|
||||
* @param {Response=} response Response object (optional) that will be populated if
|
||||
* they interset.
|
||||
* @return {boolean} true if they intersect, false if they don't.
|
||||
*/
|
||||
function testPolygonPolygon(a, b, response) {
|
||||
var aPoints = a['points'];
|
||||
var aLen = aPoints.length;
|
||||
var bPoints = b['points'];
|
||||
var bLen = bPoints.length;
|
||||
// If any of the edge normals of A is a separating axis, no intersection.
|
||||
for (var i = 0; i < aLen; i++) {
|
||||
if (isSeparatingAxis(a['pos'], b['pos'], aPoints, bPoints, a['normals'][i], response)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If any of the edge normals of B is a separating axis, no intersection.
|
||||
for (var i = 0;i < bLen; i++) {
|
||||
if (isSeparatingAxis(a['pos'], b['pos'], aPoints, bPoints, b['normals'][i], response)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Since none of the edge normals of A or B are a separating axis, there is an intersection
|
||||
// and we've already calculated the smallest overlap (in isSeparatingAxis). Calculate the
|
||||
// final overlap vector.
|
||||
if (response) {
|
||||
response['a'] = a;
|
||||
response['b'] = b;
|
||||
response['overlapV'].copy(response['overlapN']).scale(response['overlap']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
SAT['testPolygonPolygon'] = testPolygonPolygon;
|
||||
|
||||
return SAT;
|
||||
}));
|
|
@ -1,754 +0,0 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2013 Photon Storm Ltd.
|
||||
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Physics Body is linked to a single Sprite. All physics operations should be performed against the body rather than
|
||||
* the Sprite itself. For example you can set the velocity, acceleration, bounce values etc all on the Body.
|
||||
*
|
||||
* @class Phaser.Physics.Arcade.Body
|
||||
* @classdesc Arcade Physics Body Constructor
|
||||
* @constructor
|
||||
* @param {Phaser.Sprite} sprite - The Sprite object this physics body belongs to.
|
||||
*/
|
||||
Phaser.Physics.Arcade.Body = function (sprite) {
|
||||
|
||||
/**
|
||||
* @property {Phaser.Sprite} sprite - Reference to the parent Sprite.
|
||||
*/
|
||||
this.sprite = sprite;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Game} game - Local reference to game.
|
||||
*/
|
||||
this.game = sprite.game;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
|
||||
*/
|
||||
this.offset = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {number} x - The x position of the physics body.
|
||||
* @readonly
|
||||
*/
|
||||
this.x = sprite.x;
|
||||
|
||||
/**
|
||||
* @property {number} y - The y position of the physics body.
|
||||
* @readonly
|
||||
*/
|
||||
this.y = sprite.y;
|
||||
|
||||
/**
|
||||
* @property {number} preX - The previous x position of the physics body.
|
||||
* @readonly
|
||||
*/
|
||||
this.preX = sprite.x;
|
||||
|
||||
/**
|
||||
* @property {number} preY - The previous y position of the physics body.
|
||||
* @readonly
|
||||
*/
|
||||
this.preY = sprite.y;
|
||||
|
||||
/**
|
||||
* @property {number} preRotation - The previous rotation of the physics body.
|
||||
* @readonly
|
||||
*/
|
||||
this.preRotation = sprite.angle;
|
||||
|
||||
/**
|
||||
* @property {number} width - The calculated width of the physics body.
|
||||
*/
|
||||
this.width = sprite.currentFrame.sourceSizeW;
|
||||
|
||||
/**
|
||||
* @property {number} height - The calculated height of the physics body.
|
||||
*/
|
||||
this.height = sprite.currentFrame.sourceSizeH;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} center - The center coordinate of the Physics Body.
|
||||
*/
|
||||
this.center = new Phaser.Point(this.x + this.halfWidth, this.y + this.halfHeight);
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} motionVelocity - The data from the updateMotion function.
|
||||
*/
|
||||
this.motionVelocity = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} velocity - The velocity in pixels per second sq. of the Body.
|
||||
*/
|
||||
this.velocity = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} acceleration - The velocity in pixels per second sq. of the Body.
|
||||
*/
|
||||
this.acceleration = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {number} speed - The speed in pixels per second sq. of the Body.
|
||||
*/
|
||||
this.speed = 0;
|
||||
|
||||
/**
|
||||
* @property {number} angle - The angle of the Body in radians.
|
||||
*/
|
||||
this.angle = 0;
|
||||
|
||||
/**
|
||||
* @property {number} minBounceVelocity - The minimum bounce velocity (could just be the bounce value?).
|
||||
*/
|
||||
// this.minBounceVelocity = 0.5;
|
||||
|
||||
this._debug = 0;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} gravity - The gravity applied to the motion of the Body.
|
||||
*/
|
||||
this.gravity = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} bounce - The elasticitiy of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity.
|
||||
*/
|
||||
this.bounce = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} minVelocity - When a body rebounds off another the minVelocity is checked, if the new velocity is lower than the minVelocity the body is stopped.
|
||||
* @default
|
||||
*/
|
||||
this.minVelocity = new Phaser.Point(20, 20);
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} maxVelocity - The maximum velocity in pixels per second sq. that the Body can reach.
|
||||
* @default
|
||||
*/
|
||||
this.maxVelocity = new Phaser.Point(10000, 10000);
|
||||
|
||||
/**
|
||||
* @property {number} angularVelocity - The angular velocity in pixels per second sq. of the Body.
|
||||
* @default
|
||||
*/
|
||||
this.angularVelocity = 0;
|
||||
|
||||
/**
|
||||
* @property {number} angularAcceleration - The angular acceleration in pixels per second sq. of the Body.
|
||||
* @default
|
||||
*/
|
||||
this.angularAcceleration = 0;
|
||||
|
||||
/**
|
||||
* @property {number} angularDrag - The angular drag applied to the rotation of the Body.
|
||||
* @default
|
||||
*/
|
||||
this.angularDrag = 0;
|
||||
|
||||
/**
|
||||
* @property {number} maxAngular - The maximum angular velocity in pixels per second sq. that the Body can reach.
|
||||
* @default
|
||||
*/
|
||||
this.maxAngular = 1000;
|
||||
|
||||
/**
|
||||
* @property {number} mass - The mass of the Body.
|
||||
* @default
|
||||
*/
|
||||
this.mass = 1;
|
||||
|
||||
/**
|
||||
* Set the allowCollision properties to control which directions collision is processed for this Body.
|
||||
* For example allowCollision.up = false means it won't collide when the collision happened while moving up.
|
||||
* @property {object} allowCollision - An object containing allowed collision.
|
||||
*/
|
||||
this.allowCollision = { none: false, any: true, up: true, down: true, left: true, right: true };
|
||||
|
||||
/**
|
||||
* This object is populated with boolean values when the Body collides with another.
|
||||
* touching.up = true means the collision happened to the top of this Body for example.
|
||||
* @property {object} touching - An object containing touching results.
|
||||
*/
|
||||
this.touching = { none: true, up: false, down: false, left: false, right: false };
|
||||
|
||||
/**
|
||||
* @property {boolean} immovable - An immovable Body will not receive any impacts or exchanges of velocity from other bodies.
|
||||
* @default
|
||||
*/
|
||||
this.immovable = false;
|
||||
|
||||
/**
|
||||
* @property {boolean} moves - Set to true to allow the Physics system to move this Body, other false to move it manually.
|
||||
* @default
|
||||
*/
|
||||
this.moves = true;
|
||||
|
||||
/**
|
||||
* @property {number} rotation - The amount the parent Sprite is rotated. Note: You cannot rotate an AABB.
|
||||
* @default
|
||||
*/
|
||||
this.rotation = 0;
|
||||
|
||||
/**
|
||||
* @property {boolean} allowRotation - Allow angular rotation? This will cause the Sprite to be rotated via angularVelocity, etc. Note that the AABB remains un-rotated.
|
||||
* @default
|
||||
*/
|
||||
this.allowRotation = true;
|
||||
|
||||
/**
|
||||
* @property {boolean} allowGravity - Allow this Body to be influenced by the global Gravity value? Note: It will always be influenced by the local gravity value.
|
||||
* @default
|
||||
*/
|
||||
this.allowGravity = true;
|
||||
|
||||
/**
|
||||
* This flag allows you to disable the custom x separation that takes place by Physics.Arcade.separate.
|
||||
* Used in combination with your own collision processHandler you can create whatever type of collision response you need.
|
||||
* @property {boolean} customSeparateX - Use a custom separation system or the built-in one?
|
||||
* @default
|
||||
*/
|
||||
this.customSeparateX = false;
|
||||
|
||||
/**
|
||||
* This flag allows you to disable the custom y separation that takes place by Physics.Arcade.separate.
|
||||
* Used in combination with your own collision processHandler you can create whatever type of collision response you need.
|
||||
* @property {boolean} customSeparateY - Use a custom separation system or the built-in one?
|
||||
* @default
|
||||
*/
|
||||
this.customSeparateY = false;
|
||||
|
||||
/**
|
||||
* When this body collides with another, the amount of overlap is stored here.
|
||||
* @property {number} overlapX - The amount of horizontal overlap during the collision.
|
||||
*/
|
||||
this.overlapX = 0;
|
||||
|
||||
/**
|
||||
* When this body collides with another, the amount of overlap is stored here.
|
||||
* @property {number} overlapY - The amount of vertical overlap during the collision.
|
||||
*/
|
||||
this.overlapY = 0;
|
||||
|
||||
/**
|
||||
* @property {number} friction - The amount of friction this body experiences during motion.
|
||||
* @default
|
||||
*/
|
||||
this.friction = 0;
|
||||
|
||||
/**
|
||||
* A Body can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World.
|
||||
* @property {boolean} collideWorldBounds - Should the Body collide with the World bounds?
|
||||
*/
|
||||
this.collideWorldBounds = false;
|
||||
|
||||
/**
|
||||
* This object is populated with boolean values when the Body collides with the World bounds or a Tile.
|
||||
* For example if blocked.up is true then the Body cannot move up.
|
||||
* @property {object} blocked - An object containing on which faces this Body is blocked from moving, if any.
|
||||
*/
|
||||
this.blocked = { up: false, down: false, left: false, right: false };
|
||||
|
||||
/**
|
||||
* @property {number} _dx - Internal cache var.
|
||||
* @private
|
||||
*/
|
||||
this._dx = 0;
|
||||
|
||||
/**
|
||||
* @property {number} _dy - Internal cache var.
|
||||
* @private
|
||||
*/
|
||||
this._dy = 0;
|
||||
|
||||
/**
|
||||
* @property {number} _sx - Internal cache var.
|
||||
* @private
|
||||
*/
|
||||
this._sx = sprite.scale.x;
|
||||
|
||||
/**
|
||||
* @property {number} _sy - Internal cache var.
|
||||
* @private
|
||||
*/
|
||||
this._sy = sprite.scale.y;
|
||||
|
||||
this.shape = new SAT.Box(new SAT.Vector(this.x, this.y), this.width, this.height);
|
||||
this.polygon = this.shape.toPolygon();
|
||||
this.response = new SAT.Response();
|
||||
|
||||
};
|
||||
|
||||
Phaser.Physics.Arcade.Body.prototype = {
|
||||
|
||||
/**
|
||||
* Internal method.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#updateBounds
|
||||
* @protected
|
||||
*/
|
||||
updateBounds: function (centerX, centerY, scaleX, scaleY) {
|
||||
|
||||
// if (scaleX != this._sx || scaleY != this._sy)
|
||||
// {
|
||||
// this.width = this.sourceWidth * scaleX;
|
||||
// this.height = this.sourceHeight * scaleY;
|
||||
// this.halfWidth = Math.floor(this.width / 2);
|
||||
// this.halfHeight = Math.floor(this.height / 2);
|
||||
// this._sx = scaleX;
|
||||
// this._sy = scaleY;
|
||||
// this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
|
||||
// }
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#preUpdate
|
||||
* @protected
|
||||
*/
|
||||
preUpdate: function () {
|
||||
|
||||
// this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x;
|
||||
// this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y;
|
||||
|
||||
this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;
|
||||
this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;
|
||||
// this.preRotation = this.sprite.angle;
|
||||
this.preRotation = this.sprite.rotation;
|
||||
|
||||
// This all needs to move - because a body may start the preUpdate already touching something
|
||||
this.blocked.up = false;
|
||||
this.blocked.down = false;
|
||||
this.blocked.left = false;
|
||||
this.blocked.right = false;
|
||||
|
||||
this.x = this.preX;
|
||||
this.y = this.preY;
|
||||
// this.rotation = this.preRotation;
|
||||
|
||||
this.speed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y);
|
||||
this.angle = Math.atan2(this.velocity.y, this.velocity.x);
|
||||
|
||||
this._debug++;
|
||||
|
||||
if (this.moves)
|
||||
{
|
||||
if (this.collideWorldBounds)
|
||||
{
|
||||
this.checkWorldBounds();
|
||||
}
|
||||
|
||||
this.game.physics.updateMotion(this);
|
||||
|
||||
this.applyMotion();
|
||||
}
|
||||
|
||||
this.polygon.pos.x = this.x;
|
||||
this.polygon.pos.y = this.y;
|
||||
|
||||
if (this.deltaZ() !== 0)
|
||||
{
|
||||
// this.polygon.rotate(this.sprite.rotation);
|
||||
// console.log(this.sprite.rotation);
|
||||
}
|
||||
// this.polygon.rotate(this.game.math.degToRad(this.rotation));
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method used to check the Body against the World Bounds.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#checkWorldBounds
|
||||
* @protected
|
||||
*/
|
||||
checkWorldBounds: function () {
|
||||
|
||||
if (this.x <= this.game.world.bounds.x)
|
||||
{
|
||||
this.overlapX = this.game.world.bounds.x - this.x;
|
||||
this.blocked.left = true;
|
||||
// console.log(this._debug, 'cwl', this.overlapX, this.x, this.game.world.bounds.x);
|
||||
}
|
||||
else if (this.right >= this.game.world.bounds.right)
|
||||
{
|
||||
this.overlapX = this.right - this.game.world.bounds.right;
|
||||
this.blocked.right = true;
|
||||
// console.log(this._debug, 'cwr', this.overlapX, this.x, this.game.world.bounds.x);
|
||||
}
|
||||
|
||||
if (this.y <= this.game.world.bounds.y)
|
||||
{
|
||||
this.overlapY = this.game.world.bounds.y - this.y;
|
||||
this.blocked.up = true;
|
||||
// console.log(this._debug, 'cwu', this.overlapY, this.y, this.height, this.bottom, this.game.world.bounds.bottom);
|
||||
}
|
||||
else if (this.bottom >= this.game.world.bounds.bottom)
|
||||
{
|
||||
this.overlapY = this.bottom - this.game.world.bounds.bottom;
|
||||
this.blocked.down = true;
|
||||
// console.log(this._debug, 'cwd', this.overlapY, this.y, this.height, this.bottom, this.game.world.bounds.bottom);
|
||||
}
|
||||
|
||||
this.blockedPoint.setTo(this.x, this.y);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#applyMotion
|
||||
* @protected
|
||||
*/
|
||||
applyMotion: function () {
|
||||
|
||||
if (this.friction > 0 && this.acceleration.isZero())
|
||||
{
|
||||
if (this.speed > this.friction)
|
||||
{
|
||||
this.speed -= this.friction;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.speed = 0;
|
||||
}
|
||||
|
||||
this.velocity.x = Math.cos(this.angle) * this.speed;
|
||||
this.velocity.y = Math.sin(this.angle) * this.speed;
|
||||
}
|
||||
|
||||
// overlapX/Y values at this point will be penetration into the bounds and DELTA WILL BE ZERO
|
||||
if (this.blocked.left)
|
||||
{
|
||||
// Separate
|
||||
this.x += this.overlapX;
|
||||
|
||||
// console.log(this._debug, 'blocked left', this.x, this.overlapX);
|
||||
|
||||
this.velocity.x *= -this.bounce.x;
|
||||
|
||||
this._dx = this.game.time.physicsElapsed * (this.velocity.x + this.motionVelocity.x / 2);
|
||||
|
||||
// if (this._dx > this.minBounceVelocity)
|
||||
if (Math.abs(this.velocity.x) > this.minVelocity.x)
|
||||
{
|
||||
this.x += this._dx;
|
||||
this.velocity.x += this.motionVelocity.x;
|
||||
// console.log(this._debug, 'blocked left', this._dx, 'overlap', this.overlapX, 'delta', this.deltaX(), 'newy', this.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Kill it dead :)
|
||||
this.preX = this.x; // because we don't want any delta from a separation
|
||||
this.velocity.x = 0;
|
||||
this.motionVelocity.x = 0;
|
||||
// console.log(this._debug, 'blocked left KILL', this._dx, 'overlap', this.overlapX, 'delta', this.deltaX(), 'newy', this.x);
|
||||
}
|
||||
}
|
||||
else if (this.blocked.right)
|
||||
{
|
||||
// Separate
|
||||
this.x -= this.overlapX;
|
||||
|
||||
this.velocity.x *= -this.bounce.x;
|
||||
|
||||
this._dx = this.game.time.physicsElapsed * (this.velocity.x + this.motionVelocity.x / 2);
|
||||
|
||||
if (this._dx < -this.minBounceVelocity)
|
||||
{
|
||||
this.x += this._dx;
|
||||
this.velocity.x += this.motionVelocity.x;
|
||||
// console.log(this._debug, 'blocked right', this._dx, 'overlap', this.overlapX, 'delta', this.deltaX(), 'newy', this.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Kill it dead :)
|
||||
this.preX = this.x; // because we don't want any delta from a separation
|
||||
this.velocity.x = 0;
|
||||
this.motionVelocity.x = 0;
|
||||
// console.log(this._debug, 'blocked right KILL', this._dx, 'overlap', this.overlapX, 'delta', this.deltaX(), 'newy', this.x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.x += this.game.time.physicsElapsed * (this.velocity.x + this.motionVelocity.x / 2);
|
||||
this.velocity.x += this.motionVelocity.x;
|
||||
}
|
||||
|
||||
// overlapX/Y values at this point will be penetration into the bounds and DELTA WILL BE ZERO
|
||||
if (this.blocked.up)
|
||||
{
|
||||
// Separate
|
||||
this.y += this.overlapY;
|
||||
|
||||
this.velocity.y *= -this.bounce.y;
|
||||
|
||||
this._dy = this.game.time.physicsElapsed * (this.velocity.y + this.motionVelocity.y / 2);
|
||||
|
||||
// if (this._dy > this.minBounceVelocity)
|
||||
if (Math.abs(this.velocity.y) > this.minVelocity.y)
|
||||
{
|
||||
this.y += this._dy;
|
||||
this.velocity.y += this.motionVelocity.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Kill it dead :)
|
||||
this.preY = this.y; // because we don't want any delta from a separation
|
||||
this.velocity.y = 0;
|
||||
this.motionVelocity.y = 0;
|
||||
// console.log(this._debug, 'void1', this.velocity.y, 'delta', this.deltaY());
|
||||
}
|
||||
}
|
||||
else if (this.blocked.down)
|
||||
{
|
||||
// Separate
|
||||
this.y -= this.overlapY;
|
||||
|
||||
this.velocity.y *= -this.bounce.y;
|
||||
|
||||
this._dy = this.game.time.physicsElapsed * (this.velocity.y + this.motionVelocity.y / 2);
|
||||
|
||||
// if (this._dy < -this.minBounceVelocity)
|
||||
if (Math.abs(this.velocity.y) > this.minVelocity.y)
|
||||
{
|
||||
this.y += this._dy;
|
||||
this.velocity.y += this.motionVelocity.y;
|
||||
// console.log(this._debug, 'rb', this._dy, 'delta', this.deltaY(), 'newy', this.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Kill it dead :)
|
||||
this.preY = this.y; // because we don't want any delta from a separation
|
||||
this.velocity.y = 0;
|
||||
this.motionVelocity.y = 0;
|
||||
// console.log(this._debug, 'void1', this.velocity.y, 'delta', this.deltaY());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.y += this.game.time.physicsElapsed * (this.velocity.y + this.motionVelocity.y / 2);
|
||||
this.velocity.y += this.motionVelocity.y;
|
||||
}
|
||||
|
||||
if (this.velocity.x > this.maxVelocity.x)
|
||||
{
|
||||
this.velocity.x = this.maxVelocity.x;
|
||||
}
|
||||
else if (this.velocity.x < -this.maxVelocity.x)
|
||||
{
|
||||
this.velocity.x = -this.maxVelocity.x;
|
||||
}
|
||||
|
||||
if (this.velocity.y > this.maxVelocity.y)
|
||||
{
|
||||
this.velocity.y = this.maxVelocity.y;
|
||||
}
|
||||
else if (this.velocity.y < -this.maxVelocity.y)
|
||||
{
|
||||
this.velocity.y = -this.maxVelocity.y;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
collide: function (body) {
|
||||
|
||||
this.response.clear();
|
||||
|
||||
// if (this._debug === 100)
|
||||
// {
|
||||
// console.log(this.sprite.name, this.polygon);
|
||||
// }
|
||||
|
||||
if (SAT.testPolygonPolygon(this.polygon, body.polygon, this.response))
|
||||
{
|
||||
|
||||
// b1.pos.sub(r.overlapV);
|
||||
// sprite.body.velocity.x *= -sprite.body.bounce.x;
|
||||
|
||||
this.velocity.x = 0;
|
||||
|
||||
// separate
|
||||
this.x += Math.ceil(Math.abs(this.response.overlapV.x));
|
||||
this.y += Math.ceil(Math.abs(this.response.overlapV.y));
|
||||
|
||||
console.log(this.response, this.deltaX());
|
||||
|
||||
console.log('sprite moved to', this.x, this.deltaX());
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method. This is called directly before the sprites are sent to the renderer.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#postUpdate
|
||||
* @protected
|
||||
*/
|
||||
postUpdate: function () {
|
||||
|
||||
if (this.moves)
|
||||
{
|
||||
this.sprite.x += this.deltaX();
|
||||
this.sprite.y += this.deltaY();
|
||||
|
||||
this.sprite.worldTransform[2] += this.deltaX();
|
||||
this.sprite.worldTransform[5] += this.deltaY();
|
||||
|
||||
this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
|
||||
|
||||
this.rotation = this.preRotation;
|
||||
|
||||
if (this.allowRotation)
|
||||
{
|
||||
// this.sprite.angle += this.deltaZ();
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets all Body values (velocity, acceleration, rotation, etc)
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#reset
|
||||
*/
|
||||
reset: function () {
|
||||
|
||||
this.velocity.setTo(0, 0);
|
||||
this.acceleration.setTo(0, 0);
|
||||
|
||||
this.angularVelocity = 0;
|
||||
this.angularAcceleration = 0;
|
||||
this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;
|
||||
this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;
|
||||
this.preRotation = this.sprite.angle;
|
||||
|
||||
this.x = this.preX;
|
||||
this.y = this.preY;
|
||||
this.rotation = this.preRotation;
|
||||
|
||||
this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the absolute delta x value.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade.Body#deltaAbsX
|
||||
* @return {number} The absolute delta value.
|
||||
*/
|
||||
deltaAbsX: function () {
|
||||
return (this.deltaX() > 0 ? this.deltaX() : -this.deltaX());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the absolute delta y value.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade.Body#deltaAbsY
|
||||
* @return {number} The absolute delta value.
|
||||
*/
|
||||
deltaAbsY: function () {
|
||||
return (this.deltaY() > 0 ? this.deltaY() : -this.deltaY());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the delta x value. The difference between Body.x now and in the previous step.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade.Body#deltaX
|
||||
* @return {number} The delta value. Positive if the motion was to the right, negative if to the left.
|
||||
*/
|
||||
deltaX: function () {
|
||||
return this.x - this.preX;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the delta y value. The difference between Body.y now and in the previous step.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade.Body#deltaY
|
||||
* @return {number} The delta value. Positive if the motion was downwards, negative if upwards.
|
||||
*/
|
||||
deltaY: function () {
|
||||
return this.y - this.preY;
|
||||
},
|
||||
|
||||
deltaZ: function () {
|
||||
return this.rotation - this.preRotation;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Phaser.Physics.Arcade.Body.prototype.constructor = Phaser.Physics.Arcade.Body;
|
||||
|
||||
/**
|
||||
* @name Phaser.Physics.Arcade.Body#bottom
|
||||
* @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height)
|
||||
*/
|
||||
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "bottom", {
|
||||
|
||||
/**
|
||||
* The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property.
|
||||
* @method bottom
|
||||
* @return {number}
|
||||
*/
|
||||
get: function () {
|
||||
return this.y + this.height;
|
||||
},
|
||||
|
||||
/**
|
||||
* The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property.
|
||||
* @method bottom
|
||||
* @param {number} value
|
||||
*/
|
||||
set: function (value) {
|
||||
|
||||
if (value <= this.y)
|
||||
{
|
||||
this.height = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.height = (this.y - value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* @name Phaser.Physics.Arcade.Body#right
|
||||
* @property {number} right - The right value of this Body (same as Body.x + Body.width)
|
||||
*/
|
||||
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "right", {
|
||||
|
||||
/**
|
||||
* The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties.
|
||||
* However it does affect the width property.
|
||||
* @method right
|
||||
* @return {number}
|
||||
*/
|
||||
get: function () {
|
||||
return this.x + this.width;
|
||||
},
|
||||
|
||||
/**
|
||||
* The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties.
|
||||
* However it does affect the width property.
|
||||
* @method right
|
||||
* @param {number} value
|
||||
*/
|
||||
set: function (value) {
|
||||
|
||||
if (value <= this.x)
|
||||
{
|
||||
this.width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.width = this.x + value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
Loading…
Reference in a new issue