diff --git a/Gruntfile.js b/Gruntfile.js index a8d3e742..a16936a5 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 121e0388..e17e2568 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 00000000..c0b1c000 Binary files /dev/null and b/examples/assets/sprites/maggot.png differ diff --git a/examples/wip/spritebatch1.js b/examples/wip/spritebatch1.js new file mode 100644 index 00000000..07968109 --- /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 00000000..07968109 --- /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 68456755..14074f21 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 e07f6777..39787fc2 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 00000000..3eda688e --- /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;