Skip to content

Commit 7e12075

Browse files
committed
Buttons are now cleanly destroyed if part of a Group without leaving their InputHandler running.
You can now safely destroy a Group and the 'destroyChildren' boolean will propogate fully down the display list. Calling destroy on an already destroyed object would throw a run-time error. Now checked for and aborted. Calling destroy while in an Input Event callback now works for either the parent Group or the calling object itself. In Group.destroy the default for 'destroyChildren' was false. It's now `true` as this is a far more likely requirement when destroying a Group. All GameObjects now have a 'destroyChildren' boolean as a parameter to their destroy method. It's default is true and the value propogates down its children.
1 parent 53c10ca commit 7e12075

9 files changed

Lines changed: 201 additions & 20 deletions

File tree

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Significant API changes:
8181
* Phaser.StageScaleMode has been renamed to ScaleManager and moved from the system folder to the core folder. It's still available under game.scale.
8282
* If your game references the old Phaser.StageScaleMode consts like SHOW_ALL you need to update them to Phaser.ScaleManager, i.e. Phaser.ScaleManager.SHOW_ALL.
8383
* Time.physicsElapsed is no longer bound or clamped, be wary of this if you use the value anywhere in your code.
84+
* In Group.destroy the default for 'destroyChildren' was false. It's now `true` as this is a far more likely requirement when destroying a Group.
8485

8586

8687
New features:
@@ -120,6 +121,7 @@ New features:
120121
* StateManager.start can now have as many parameters as you like. The order is: start(key, clearWorld, clearCache, ...) - they are passed to State.init() (NOT create!)
121122
* Loader.script now has callback (and callbackContext) parameters, so you can specify a function to run once the JS has been injected into the body.
122123
* Phaser.Timer.stop has a new parameter: clearEvents (default true), if true all the events in Timer will be cleared, otherwise they will remain (fixes #383)
124+
* All GameObjects now have a 'destroyChildren' boolean as a parameter to their destroy method. It's default is true and the value propogates down its children.
123125

124126

125127
Updates:
@@ -177,7 +179,10 @@ Bug Fixes:
177179
* Phaser.Timer will no longer resume if it was previously paused and the game loses focus and then resumes (fixes #383)
178180
* Tweens now resume correctly if the game pauses (focus loss) while they are paused.
179181
* Tweens don't double pause if they were already paused and the game pauses.
180-
182+
* Buttons are now cleanly destroyed if part of a Group without leaving their InputHandler running.
183+
* You can now safely destroy a Group and the 'destroyChildren' boolean will propogate fully down the display list.
184+
* Calling destroy on an already destroyed object would throw a run-time error. Now checked for and aborted.
185+
* Calling destroy while in an Input Event callback now works for either the parent Group or the calling object itself.
181186

182187

183188
TO DO:

examples/wip/group destroy.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
2+
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
3+
4+
function preload() {
5+
6+
game.load.image('atari1', 'assets/sprites/atari130xe.png');
7+
game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png');
8+
game.load.image('starfield', 'assets/misc/starfield.jpg');
9+
game.load.bitmapFont('carrier', 'assets/fonts/carrier_command.png', 'assets/fonts/carrier_command.xml', null, 0, 24);
10+
game.load.spritesheet('button', 'assets/buttons/button_sprite_sheet.png', 193, 71);
11+
12+
}
13+
14+
var group;
15+
var DaddyGroup;
16+
17+
function create() {
18+
19+
DaddyGroup = game.add.group();
20+
21+
group = game.add.group();
22+
23+
// Testing Group.destroy with different object types:
24+
25+
var sprite = game.make.sprite(300, 100, 'atari1');
26+
27+
var graphics = game.make.graphics(0, 0);
28+
graphics.beginFill(0xFF3300);
29+
graphics.moveTo(0,50);
30+
graphics.lineTo(250, 50);
31+
graphics.lineTo(100, 100);
32+
graphics.lineTo(250, 220);
33+
graphics.lineTo(50, 220);
34+
graphics.lineTo(0, 50);
35+
graphics.endFill();
36+
37+
var tilesprite = game.make.tileSprite(600, 100, 200, 200, 'starfield');
38+
tilesprite.autoScroll(0, 100);
39+
40+
var bitmaptext = game.make.bitmapText(100, 300, 'carrier', 'bitmap text', 32);
41+
42+
var text = game.make.text(100, 350, "normal text");
43+
text.font = 'Arial Black';
44+
text.fontSize = 60;
45+
text.fill = '#ff0044';
46+
47+
var button = game.make.button(100, 450, 'button', actionOnClick, this, 2, 1, 0);
48+
49+
group.add(sprite);
50+
group.add(graphics);
51+
group.add(tilesprite);
52+
group.add(bitmaptext);
53+
group.add(text);
54+
group.add(button);
55+
56+
DaddyGroup.add(group);
57+
58+
game.input.onDown.add(actionOnClick, this);
59+
60+
}
61+
62+
function actionOnClick() {
63+
64+
DaddyGroup.destroy();
65+
66+
}
67+
68+
function update() {
69+
}
70+
71+
function render() {
72+
}

src/core/Group.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,11 +1137,13 @@ Phaser.Group.prototype.removeBetween = function (startIndex, endIndex) {
11371137
* Destroys this Group. Removes all children, then removes the container from the display list and nulls references.
11381138
*
11391139
* @method Phaser.Group#destroy
1140-
* @param {boolean} [destroyChildren=false] - Should every child of this Group have its destroy method called?
1140+
* @param {boolean} [destroyChildren=true] - Should every child of this Group have its destroy method called?
11411141
*/
11421142
Phaser.Group.prototype.destroy = function (destroyChildren) {
11431143

1144-
if (typeof destroyChildren === 'undefined') { destroyChildren = false; }
1144+
if (this.game === null) { return; }
1145+
1146+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
11451147

11461148
if (destroyChildren)
11471149
{
@@ -1151,7 +1153,7 @@ Phaser.Group.prototype.destroy = function (destroyChildren) {
11511153
{
11521154
if (this.children[0].parent)
11531155
{
1154-
this.children[0].destroy();
1156+
this.children[0].destroy(destroyChildren);
11551157
}
11561158
}
11571159
while (this.children.length > 0);

src/gameobjects/BitmapText.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,13 @@ Phaser.BitmapText.prototype.postUpdate = function () {
201201
/**
202202
* Destroy this BitmapText instance. This will remove any filters and un-parent any children.
203203
* @method Phaser.BitmapText.prototype.destroy
204+
* @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
204205
*/
205-
Phaser.BitmapText.prototype.destroy = function() {
206+
Phaser.BitmapText.prototype.destroy = function(destroyChildren) {
207+
208+
if (this.game === null) { return; }
209+
210+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
206211

207212
if (this.parent)
208213
{
@@ -211,9 +216,26 @@ Phaser.BitmapText.prototype.destroy = function() {
211216

212217
var i = this.children.length;
213218

214-
while (i--)
219+
if (destroyChildren)
220+
{
221+
while (i--)
222+
{
223+
if (this.children[i].destroy)
224+
{
225+
this.children[i].destroy(destroyChildren);
226+
}
227+
else
228+
{
229+
this.removeChild(this.children[i]);
230+
}
231+
}
232+
}
233+
else
215234
{
216-
this.removeChild(this.children[i]);
235+
while (i--)
236+
{
237+
this.removeChild(this.children[i]);
238+
}
217239
}
218240

219241
this.exists = false;

src/gameobjects/Graphics.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,11 @@ Phaser.Graphics.prototype.postUpdate = function () {
138138
* Destroy this Graphics instance.
139139
*
140140
* @method Phaser.Graphics.prototype.destroy
141+
* @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
141142
*/
142-
Phaser.Graphics.prototype.destroy = function() {
143+
Phaser.Graphics.prototype.destroy = function(destroyChildren) {
144+
145+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
143146

144147
this.clear();
145148

@@ -148,6 +151,23 @@ Phaser.Graphics.prototype.destroy = function() {
148151
this.parent.remove(this);
149152
}
150153

154+
var i = this.children.length;
155+
156+
if (destroyChildren)
157+
{
158+
while (i--)
159+
{
160+
this.children[i].destroy(destroyChildren);
161+
}
162+
}
163+
else
164+
{
165+
while (i--)
166+
{
167+
this.removeChild(this.children[i]);
168+
}
169+
}
170+
151171
this.exists = false;
152172
this.visible = false;
153173

src/gameobjects/Image.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,13 @@ Phaser.Image.prototype.kill = function() {
366366
*
367367
* @method Phaser.Image#destroy
368368
* @memberof Phaser.Image
369+
* @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
369370
*/
370-
Phaser.Image.prototype.destroy = function() {
371+
Phaser.Image.prototype.destroy = function(destroyChildren) {
372+
373+
if (this.game === null) { return; }
374+
375+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
371376

372377
if (this.parent)
373378
{
@@ -386,9 +391,19 @@ Phaser.Image.prototype.destroy = function() {
386391

387392
var i = this.children.length;
388393

389-
while (i--)
394+
if (destroyChildren)
390395
{
391-
this.removeChild(this.children[i]);
396+
while (i--)
397+
{
398+
this.children[i].destroy(destroyChildren);
399+
}
400+
}
401+
else
402+
{
403+
while (i--)
404+
{
405+
this.removeChild(this.children[i]);
406+
}
392407
}
393408

394409
this.alive = false;

src/gameobjects/Sprite.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,13 @@ Phaser.Sprite.prototype.kill = function() {
489489
*
490490
* @method Phaser.Sprite#destroy
491491
* @memberof Phaser.Sprite
492+
* @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
492493
*/
493-
Phaser.Sprite.prototype.destroy = function() {
494+
Phaser.Sprite.prototype.destroy = function(destroyChildren) {
495+
496+
if (this.game === null) { return; }
497+
498+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
494499

495500
if (this.parent)
496501
{
@@ -519,9 +524,19 @@ Phaser.Sprite.prototype.destroy = function() {
519524

520525
var i = this.children.length;
521526

522-
while (i--)
527+
if (destroyChildren)
523528
{
524-
this.removeChild(this.children[i]);
529+
while (i--)
530+
{
531+
this.children[i].destroy(destroyChildren);
532+
}
533+
}
534+
else
535+
{
536+
while (i--)
537+
{
538+
this.removeChild(this.children[i]);
539+
}
525540
}
526541

527542
this.alive = false;

src/gameobjects/Text.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,13 @@ Phaser.Text.prototype.postUpdate = function () {
181181

182182
/**
183183
* @method Phaser.Text.prototype.destroy
184+
* @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
184185
*/
185-
Phaser.Text.prototype.destroy = function () {
186+
Phaser.Text.prototype.destroy = function (destroyChildren) {
187+
188+
if (this.game === null) { return; }
189+
190+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
186191

187192
if (this.parent)
188193
{
@@ -203,9 +208,19 @@ Phaser.Text.prototype.destroy = function () {
203208

204209
var i = this.children.length;
205210

206-
while (i--)
211+
if (destroyChildren)
207212
{
208-
this.removeChild(this.children[i]);
213+
while (i--)
214+
{
215+
this.children[i].destroy(destroyChildren);
216+
}
217+
}
218+
else
219+
{
220+
while (i--)
221+
{
222+
this.removeChild(this.children[i]);
223+
}
209224
}
210225

211226
this.exists = false;

src/gameobjects/TileSprite.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,13 @@ Phaser.TileSprite.prototype.loadTexture = function (key, frame) {
276276
*
277277
* @method Phaser.TileSprite#destroy
278278
* @memberof Phaser.TileSprite
279+
* @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called?
279280
*/
280-
Phaser.TileSprite.prototype.destroy = function() {
281+
Phaser.TileSprite.prototype.destroy = function(destroyChildren) {
282+
283+
if (this.game === null) { return; }
284+
285+
if (typeof destroyChildren === 'undefined') { destroyChildren = true; }
281286

282287
if (this.filters)
283288
{
@@ -295,9 +300,19 @@ Phaser.TileSprite.prototype.destroy = function() {
295300

296301
var i = this.children.length;
297302

298-
while (i--)
303+
if (destroyChildren)
299304
{
300-
this.removeChild(this.children[i]);
305+
while (i--)
306+
{
307+
this.children[i].destroy(destroyChildren);
308+
}
309+
}
310+
else
311+
{
312+
while (i--)
313+
{
314+
this.removeChild(this.children[i]);
315+
}
301316
}
302317

303318
this.exists = false;

0 commit comments

Comments
 (0)