From 58e44f75e38a045f1b26a68289255d82d09ec1b9 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Fri, 14 Feb 2014 01:39:01 +0000 Subject: [PATCH] SpriteBatch converted. It's an extended Group and Batch merged and works amazingly :) Ported over the maggots demo to test and wow! --- Gruntfile.js | 1 + build/config.php | 1 + examples/assets/sprites/maggot.png | Bin 0 -> 5320 bytes examples/wip/spritebatch1.js | 62 +++++++++++++++++++++++++++ labs/code/004 maggot batch.js | 62 +++++++++++++++++++++++++++ src/Phaser.js | 1 + src/gameobjects/GameObjectFactory.js | 18 ++++++++ src/gameobjects/SpriteBatch.js | 35 +++++++++++++++ 8 files changed, 180 insertions(+) create mode 100644 examples/assets/sprites/maggot.png create mode 100644 examples/wip/spritebatch1.js create mode 100644 labs/code/004 maggot batch.js create mode 100644 src/gameobjects/SpriteBatch.js diff --git a/Gruntfile.js b/Gruntfile.js index a8d3e742a..a16936a57 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -95,6 +95,7 @@ module.exports = function (grunt) { 'src/gameobjects/Button.js', 'src/gameobjects/Graphics.js', 'src/gameobjects/RenderTexture.js', + 'src/gameobjects/SpriteBatch.js', 'src/system/Canvas.js', 'src/system/StageScaleMode.js', diff --git a/build/config.php b/build/config.php index 121e0388c..e17e25682 100644 --- a/build/config.php +++ b/build/config.php @@ -141,6 +141,7 @@ + diff --git a/examples/assets/sprites/maggot.png b/examples/assets/sprites/maggot.png new file mode 100644 index 0000000000000000000000000000000000000000..c0b1c0007bbb27e947f61afe1257f079418c7163 GIT binary patch literal 5320 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 H)yw|^5el)I literal 0 HcmV?d00001 diff --git a/examples/wip/spritebatch1.js b/examples/wip/spritebatch1.js new file mode 100644 index 000000000..07968109b --- /dev/null +++ b/examples/wip/spritebatch1.js @@ -0,0 +1,62 @@ + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update }); + +function preload() { + + game.load.image('maggot', 'assets/sprites/maggot.png'); + +} + +var batch; +var dudeBoundsPadding = 100; +var dudeBounds = new Phaser.Rectangle(-dudeBoundsPadding, -dudeBoundsPadding, 800 + dudeBoundsPadding * 2, 600 + dudeBoundsPadding * 2); +var tick = 0; + +function create() { + + batch = game.add.spriteBatch(); + + var total = (game.renderType === Phaser.WEBGL) ? 10000 : 100; + + for (var i = 0; i < total; i++) + { + var dude = batch.create(game.world.randomX, game.world.randomY, 'maggot'); + + dude.anchor.set(0.5); + dude.scale.set(0.8 + Math.random() * 0.3); + dude.direction = Math.random() * Math.PI * 2; + dude.turningSpeed = Math.random() - 0.8; + dude.speed = (2 + Math.random() * 2) * 0.2; + dude.offset = Math.random() * 100; + } + +} + +function update() { + + batch.forEach(updateMaggot, this, false); + + tick += 0.1; + +} + +function updateMaggot(dude) { + + dude.scale.y = 0.95 + Math.sin(tick + dude.offset) * 0.05 + dude.direction += dude.turningSpeed * 0.01; + dude.position.x += Math.sin(dude.direction) * (dude.speed * dude.scale.y); + dude.position.y += Math.cos(dude.direction) * (dude.speed * dude.scale.y); + dude.rotation = -dude.direction + Math.PI; + + // wrap the dudes by testing their bounds.. + if (dude.position.x < dudeBounds.x) + dude.position.x += dudeBounds.width; + else if (dude.position.x > dudeBounds.x + dudeBounds.width) + dude.position.x -= dudeBounds.width; + + if (dude.position.y < dudeBounds.y) + dude.position.y += dudeBounds.height; + else if (dude.position.y > dudeBounds.y + dudeBounds.height) + dude.position.y -= dudeBounds.height; + +} diff --git a/labs/code/004 maggot batch.js b/labs/code/004 maggot batch.js new file mode 100644 index 000000000..07968109b --- /dev/null +++ b/labs/code/004 maggot batch.js @@ -0,0 +1,62 @@ + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update }); + +function preload() { + + game.load.image('maggot', 'assets/sprites/maggot.png'); + +} + +var batch; +var dudeBoundsPadding = 100; +var dudeBounds = new Phaser.Rectangle(-dudeBoundsPadding, -dudeBoundsPadding, 800 + dudeBoundsPadding * 2, 600 + dudeBoundsPadding * 2); +var tick = 0; + +function create() { + + batch = game.add.spriteBatch(); + + var total = (game.renderType === Phaser.WEBGL) ? 10000 : 100; + + for (var i = 0; i < total; i++) + { + var dude = batch.create(game.world.randomX, game.world.randomY, 'maggot'); + + dude.anchor.set(0.5); + dude.scale.set(0.8 + Math.random() * 0.3); + dude.direction = Math.random() * Math.PI * 2; + dude.turningSpeed = Math.random() - 0.8; + dude.speed = (2 + Math.random() * 2) * 0.2; + dude.offset = Math.random() * 100; + } + +} + +function update() { + + batch.forEach(updateMaggot, this, false); + + tick += 0.1; + +} + +function updateMaggot(dude) { + + dude.scale.y = 0.95 + Math.sin(tick + dude.offset) * 0.05 + dude.direction += dude.turningSpeed * 0.01; + dude.position.x += Math.sin(dude.direction) * (dude.speed * dude.scale.y); + dude.position.y += Math.cos(dude.direction) * (dude.speed * dude.scale.y); + dude.rotation = -dude.direction + Math.PI; + + // wrap the dudes by testing their bounds.. + if (dude.position.x < dudeBounds.x) + dude.position.x += dudeBounds.width; + else if (dude.position.x > dudeBounds.x + dudeBounds.width) + dude.position.x -= dudeBounds.width; + + if (dude.position.y < dudeBounds.y) + dude.position.y += dudeBounds.height; + else if (dude.position.y > dudeBounds.y + dudeBounds.height) + dude.position.y -= dudeBounds.height; + +} diff --git a/src/Phaser.js b/src/Phaser.js index 684567559..14074f21f 100644 --- a/src/Phaser.js +++ b/src/Phaser.js @@ -35,6 +35,7 @@ var Phaser = Phaser || { CANVAS_FILTER: 14, WEBGL_FILTER: 15, ELLIPSE: 16, + SPRITEBATCH: 16, NONE: 0, LEFT: 1, diff --git a/src/gameobjects/GameObjectFactory.js b/src/gameobjects/GameObjectFactory.js index e07f67770..39787fc2e 100644 --- a/src/gameobjects/GameObjectFactory.js +++ b/src/gameobjects/GameObjectFactory.js @@ -109,6 +109,24 @@ Phaser.GameObjectFactory.prototype = { }, + /** + * A Group is a container for display objects that allows for fast pooling, recycling and collision checks. + * + * @method Phaser.GameObjectFactory#spriteBatch + * @param {any} parent - The parent Group or DisplayObjectContainer that will hold this group, if any. + * @param {string} [name='group'] - A name for this Group. Not used internally but useful for debugging. + * @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World. + * @return {Phaser.Group} The newly created group. + */ + spriteBatch: function (parent, name, addToStage) { + + if (typeof name === 'undefined') { name = 'group'; } + if (typeof addToStage === 'undefined') { addToStage = false; } + + return new Phaser.SpriteBatch(this.game, parent, name, addToStage); + + }, + /** * Creates a new Sound object. * diff --git a/src/gameobjects/SpriteBatch.js b/src/gameobjects/SpriteBatch.js new file mode 100644 index 000000000..3eda688ed --- /dev/null +++ b/src/gameobjects/SpriteBatch.js @@ -0,0 +1,35 @@ +/** +* @author Richard Davey +* @copyright 2014 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* Phaser SpriteBatch constructor. +* @class Phaser.SpriteBatch +* @classdesc A Group is a container for display objects that allows for fast pooling and object recycling. Groups can be nested within other Groups and have their own local transforms. +* @constructor +* @param {Phaser.Game} game - A reference to the currently running game. +* @param {Phaser.Group|Phaser.Sprite} parent - The parent Group, DisplayObject or DisplayObjectContainer that this Group will be added to. If undefined or null it will use game.world. +* @param {string} [name=group] - A name for this Group. Not used internally but useful for debugging. +* @param {boolean} [addToStage=false] - If set to true this Group will be added directly to the Game.Stage instead of Game.World. +*/ +Phaser.SpriteBatch = function (game, parent, name, addToStage) { + + PIXI.SpriteBatch.call(this); + + Phaser.Group.call(this, game, parent, name, addToStage); + + /** + * @property {number} type - Internal Phaser Type value. + * @protected + */ + this.type = Phaser.SPRITEBATCH; + +}; + +// Phaser.SpriteBatch.prototype = Object.create(Phaser.Group.prototype); + +Phaser.SpriteBatch.prototype = Phaser.Utils.extend(true, Phaser.SpriteBatch.prototype, Phaser.Group.prototype, PIXI.SpriteBatch.prototype); + +Phaser.SpriteBatch.prototype.constructor = Phaser.SpriteBatch;