diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c44792c0..be5909a08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -203,6 +203,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Fixed issue where a null/undefined graphics group member graphic would cause a crash, now logs a warning. - Fixed issue where Actor built in components could not be extended because of the way the Actor based type was built. - Actors now use instance properties for built-ins instead of getters - With the ECS refactor you can now subtype built-in `Components` and `.get(Builtin)` will return the correct subtype. diff --git a/sandbox/tests/graphics-group/heart.png b/sandbox/tests/graphics-group/heart.png new file mode 100644 index 000000000..2c830cdc2 Binary files /dev/null and b/sandbox/tests/graphics-group/heart.png differ diff --git a/sandbox/tests/graphics-group/index.html b/sandbox/tests/graphics-group/index.html new file mode 100644 index 000000000..027d22fdb --- /dev/null +++ b/sandbox/tests/graphics-group/index.html @@ -0,0 +1,13 @@ + + + + + + + Graphics Padding Test + + + + + + \ No newline at end of file diff --git a/sandbox/tests/graphics-group/index.ts b/sandbox/tests/graphics-group/index.ts new file mode 100644 index 000000000..bcaba603d --- /dev/null +++ b/sandbox/tests/graphics-group/index.ts @@ -0,0 +1,53 @@ +/// + +var game = new ex.Engine({ + width: 1000, + height: 1000, +}); + +var heartImage = new ex.ImageSource('./heart.png'); + +var loader = new ex.Loader([heartImage]) + +class MyActor2 extends ex.Actor { + constructor() { + super({ + pos: ex.vec(200, 200) + }); + } + onInitialize() { + this.graphics.add( + "interactive", + new ex.GraphicsGroup({ + members: [ + { + graphic: undefined, + offset: ex.vec(8, 8), + }, + { + graphic: heartImage.toSprite(), + offset: ex.vec(8, -16), + }, + ], + }), + { + anchor: ex.vec(0, 0), + } + ); + this.graphics.add( + "noninteractive", + heartImage.toSprite(), + { + anchor: ex.vec(8, 8), + } + ) + } + + onPreUpdate(engine: ex.Engine, delta: number): void { + this.graphics.use("interactive"); + } +} + +game.add(new MyActor2()); + +game.start(loader) \ No newline at end of file diff --git a/src/engine/Graphics/GraphicsGroup.ts b/src/engine/Graphics/GraphicsGroup.ts index 1486021e7..29252f1d4 100644 --- a/src/engine/Graphics/GraphicsGroup.ts +++ b/src/engine/Graphics/GraphicsGroup.ts @@ -3,6 +3,7 @@ import { Graphic, GraphicOptions } from './Graphic'; import { Animation, HasTick } from './Animation'; import { ExcaliburGraphicsContext } from './Context/ExcaliburGraphicsContext'; import { BoundingBox } from '../Collision/Index'; +import { Logger } from '../Util/Log'; export interface GraphicsGroupingOptions { members: (GraphicsGrouping | Graphic)[]; @@ -14,6 +15,7 @@ export interface GraphicsGrouping { } export class GraphicsGroup extends Graphic implements HasTick { + private _logger = Logger.getInstance(); public members: (GraphicsGrouping | Graphic)[] = []; constructor(options: GraphicsGroupingOptions & GraphicOptions) { @@ -43,7 +45,11 @@ export class GraphicsGroup extends Graphic implements HasTick { bb = member.localBounds.combine(bb); } else { const { graphic, offset: pos } = member; - bb = graphic.localBounds.translate(pos).combine(bb); + if (graphic) { + bb = graphic.localBounds.translate(pos).combine(bb); + } else { + this._logger.warnOnce(`Graphics group member has an null or undefined graphic, member definition: ${JSON.stringify(member)}.`); + } } } return bb; @@ -96,6 +102,9 @@ export class GraphicsGroup extends Graphic implements HasTick { graphic = member.graphic; member.offset.clone(pos); } + if (!graphic) { + continue; + } ex.save(); ex.translate(x, y); graphic.draw(ex, pos.x, pos.y); diff --git a/src/engine/Scene.ts b/src/engine/Scene.ts index 5845a2dc1..2b6d33e18 100644 --- a/src/engine/Scene.ts +++ b/src/engine/Scene.ts @@ -418,7 +418,7 @@ implements CanInitialize, CanActivate, CanDeactivate, CanUpdate */ public update(engine: Engine, delta: number) { if (!this.isInitialized) { - throw new Error('Scene update called before it was initialized!'); + throw new Error('Scene update called before it was initialized! Was there an error in actor or entity initialization?'); } this._preupdate(engine, delta);