From b2263c16c63ecc8c975831409887e1ac6414a0a0 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 4 Sep 2013 04:54:43 +0100 Subject: [PATCH] Patched the QuadTree, now working a whole lot better but am worried it's still working out too many collisions. --- examples/quadtree.php | 29 ++++++++++++++++++++-- src/math/QuadTree.js | 56 ++++++++++++++++++++++++------------------- src/utils/Debug.js | 25 +++++++++++++++++++ 3 files changed, 84 insertions(+), 26 deletions(-) diff --git a/examples/quadtree.php b/examples/quadtree.php index 642a9a3c..2948f88a 100644 --- a/examples/quadtree.php +++ b/examples/quadtree.php @@ -20,15 +20,20 @@ } var ship; + var total; + var aliens; function create() { - for (var i = 0; i < 50; i++) + aliens = []; + + for (var i = 0; i < 100; i++) { var s = game.add.sprite(game.world.randomX, game.world.randomY, 'baddie'); s.body.collideWorldBounds = true; s.body.bounce.setTo(1, 1); - s.body.velocity.setTo(50 + Math.random() * 50, 50 + Math.random() * 50); + s.body.velocity.setTo(10 + Math.random() * 10, 10 + Math.random() * 10); + aliens.push(s); } ship = game.add.sprite(400, 400, 'ship'); @@ -39,6 +44,18 @@ function update() { + for (var i = 0; i < aliens.length; i++) + { + aliens[i].alpha = 0.3; + } + + total = game.physics.quadTree.retrieve(ship); + + for (var i = 0; i < total.length; i++) + { + total[i].sprite.alpha = 1; + } + if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { ship.body.velocity.x -= 2; @@ -61,6 +78,14 @@ function render() { + for (var i = 0; i < aliens.length; i++) + { + game.debug.renderRectangle(aliens[i].bounds); + } + + game.debug.renderText(total.length, 32, 32); + game.debug.renderQuadTree(game.physics.quadTree); + game.debug.renderRectangle(ship); } diff --git a/src/math/QuadTree.js b/src/math/QuadTree.js index a4626e71..3eeaf7cf 100644 --- a/src/math/QuadTree.js +++ b/src/math/QuadTree.js @@ -44,14 +44,14 @@ Phaser.QuadTree = function (x, y, width, height, maxObjects, maxLevels, level) { this.level = level || 0; this.bounds = { - x: x, - y: y, + x: Math.round(x), + y: Math.round(y), width: width, height: height, - subWidth: Math.floor(width / 2 ), - subHeight: Math.floor(height / 2 ), - right: x + Math.floor(width / 2 ), - bottom: y + Math.floor(height / 2 ) + subWidth: Math.floor(width / 2), + subHeight: Math.floor(height / 2), + right: Math.round(x) + Math.floor(width / 2), + bottom: Math.round(y) + Math.floor(height / 2) }; this.objects = []; @@ -65,18 +65,20 @@ Phaser.QuadTree.prototype = { * Split the node into 4 subnodes */ split: function() { + + this.level + 1; // top right node - this.nodes[0] = new Phaser.QuadTree(this.bounds.right, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level + 1); + this.nodes[0] = new Phaser.QuadTree(this.bounds.right, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); // top left node - this.nodes[1] = new Phaser.QuadTree(this.bounds.x, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level + 1); + this.nodes[1] = new Phaser.QuadTree(this.bounds.x, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); // bottom left node - this.nodes[2] = new Phaser.QuadTree(this.bounds.x, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level + 1); + this.nodes[2] = new Phaser.QuadTree(this.bounds.x, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); // bottom right node - this.nodes[3] = new Phaser.QuadTree(this.bounds.right, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level + 1); + this.nodes[3] = new Phaser.QuadTree(this.bounds.right, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level); }, @@ -89,30 +91,36 @@ Phaser.QuadTree.prototype = { var index = -1; - // Duplicated comparisons, but they only get checked once in the flow so it saves creating temp. vars - + // var verticalMidpoint = this.bounds.x + (this.bounds.width / 2); + var verticalMidpoint = this.bounds.right; + // var horizontalMidpoint = this.bounds.y + (this.bounds.height / 2); + var horizontalMidpoint = this.bounds.bottom; + + var topQuadrant = (rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom); + var bottomQuadrant = (rect.y > this.bounds.bottom); + // rect can completely fit within the left quadrants - if (rect.x < this.bounds.bottom && rect.right < this.bounds.bottom) + if (rect.x < verticalMidpoint && rect.right < verticalMidpoint) { - if ((rect.y < this.bounds.right && rect.bottom < this.bounds.right)) + if (topQuadrant) { // rect can completely fit within the top quadrants index = 1; } - else if ((rect.y > this.bounds.right)) + else if (bottomQuadrant) { // rect can completely fit within the bottom quadrants index = 2; } } - else if (rect.x > this.bounds.bottom) + else if (rect.x > verticalMidpoint) { // rect can completely fit within the right quadrants - if ((rect.y < this.bounds.right && rect.bottom < this.bounds.right)) + if (topQuadrant) { index = 0; } - else if ((rect.y > this.bounds.right)) + else if (bottomQuadrant) { index = 3; } @@ -135,7 +143,7 @@ Phaser.QuadTree.prototype = { // if we have subnodes ... // if (typeof this.nodes[0] !== 'undefined') - if (this.nodes[0]) + if (this.nodes[0] != null) { index = this.getIndex(body.bounds); @@ -152,7 +160,7 @@ Phaser.QuadTree.prototype = { { // Split if we don't already have subnodes // if (typeof this.nodes[0] === 'undefined') - if (!this.nodes[0]) + if (this.nodes[0] == null) { this.split(); } @@ -180,9 +188,9 @@ Phaser.QuadTree.prototype = { * @param Object pRect bounds of the object to be checked, with x, y, width, height * @Return Array array with all detected objects */ - retrieve: function (rect) { + retrieve: function (sprite) { - var index = this.getIndex(rect); + var index = this.getIndex(sprite.body.bounds); var returnObjects = this.objects; // if we have subnodes ... @@ -192,14 +200,14 @@ Phaser.QuadTree.prototype = { // if rect fits into a subnode .. if (index !== -1) { - returnObjects = returnObjects.concat(this.nodes[index].retrieve(rect)); + returnObjects = returnObjects.concat(this.nodes[index].retrieve(sprite)); } else { // if rect does not fit into a subnode, check it against all subnodes for (var i = 0, len = this.nodes.length; i < len; i++) { - returnObjects = returnObjects.concat(this.nodes[i].retrieve(rect)); + returnObjects = returnObjects.concat(this.nodes[i].retrieve(sprite)); } } } diff --git a/src/utils/Debug.js b/src/utils/Debug.js index 6adf4169..3fd0d5f0 100644 --- a/src/utils/Debug.js +++ b/src/utils/Debug.js @@ -105,6 +105,31 @@ Phaser.Utils.Debug.prototype = { }, + renderQuadTree: function (quadtree, color) { + + color = color || 'rgba(255,0,0,0.3)'; + + this.start(); + + var bounds = quadtree.bounds; + + if (quadtree.nodes.length === 0) + { + this.context.strokeStyle = color; + this.context.strokeRect(bounds.x, bounds.y, bounds.width, bounds.height); + } + else + { + for (var i = 0; i < quadtree.nodes.length; i++) + { + this.renderQuadTree(quadtree.nodes[i]); + } + } + + this.stop(); + + }, + renderSpriteCorners: function (sprite, showText, showBounds, color) { if (this.context == null)