diff --git a/CHANGELOG.md b/CHANGELOG.md index cf0ad6716..eb0a86f09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -281,6 +281,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Fixes issue where mis-matched coordinate planes on parent/children caused bizarre issues. Now children are forced to inherit their parent's coordinate plane, it will always be the coordinate plane of the top most parent. - Fixed issue with Log ScreenAppender utility where it was not positioned correctly, you can now deeply configure it! ```typescript export interface ScreenAppenderOptions { diff --git a/src/engine/EntityComponentSystem/Components/TransformComponent.ts b/src/engine/EntityComponentSystem/Components/TransformComponent.ts index 6e88d4436..b7e5db25c 100644 --- a/src/engine/EntityComponentSystem/Components/TransformComponent.ts +++ b/src/engine/EntityComponentSystem/Components/TransformComponent.ts @@ -4,10 +4,12 @@ import { Transform } from '../../Math/transform'; import { Component } from '../Component'; import { Entity } from '../Entity'; import { Observable } from '../../Util/Observable'; +import { Logger } from '../../Util/Log'; export class TransformComponent extends Component { - + private _logger = Logger.getInstance(); + private _parentComponent: TransformComponent | null = null; private _transform = new Transform(); public get() { return this._transform; @@ -17,6 +19,7 @@ export class TransformComponent extends Component { const childTxComponent = child.get(TransformComponent); if (childTxComponent) { childTxComponent._transform.parent = this._transform; + childTxComponent._parentComponent = this; } }; onAdd(owner: Entity): void { @@ -28,11 +31,13 @@ export class TransformComponent extends Component { const childTxComponent = child.get(TransformComponent); if (childTxComponent) { childTxComponent._transform.parent = null; + childTxComponent._parentComponent = null; } }); } onRemove(_previousOwner: Entity): void { this._transform.parent = null; + this._parentComponent = null; } /** @@ -57,10 +62,25 @@ export class TransformComponent extends Component { } } + private _coordPlane = CoordPlane.World; /** * The [[CoordPlane|coordinate plane|]] for this transform for the entity. */ - public coordPlane = CoordPlane.World; + public get coordPlane() { + if (this._parentComponent) { + return this._parentComponent.coordPlane; + } + return this._coordPlane; + } + + public set coordPlane(value: CoordPlane) { + if (!this._parentComponent) { + this._coordPlane = value; + } else { + this._logger.warn( + `Cannot set coordinate plane on child entity ${this.owner?.name}, children inherit their coordinate plane from their parents.`); + } + } get pos() { return this._transform.pos; diff --git a/src/spec/TransformComponentSpec.ts b/src/spec/TransformComponentSpec.ts index c4c0627a1..435548936 100644 --- a/src/spec/TransformComponentSpec.ts +++ b/src/spec/TransformComponentSpec.ts @@ -267,6 +267,41 @@ describe('A TransformComponent', () => { expect(child2.get(TransformComponent).get().parent).toBe(null); }); + it('children inherit the top most parent coordinate plane', () => { + const logger = ex.Logger.getInstance(); + spyOn(logger, 'warn'); + const child1 = new ex.Entity([new TransformComponent]); + const child2 = new ex.Entity([new TransformComponent], 'child2'); + const parent = new ex.Entity([new TransformComponent]); + const grandParent = new ex.Entity([new TransformComponent]); + + parent.addChild(child1); + parent.addChild(child2); + grandParent.addChild(parent); + + expect(child1.children).toEqual([]); + expect(parent.children).toEqual([child1, child2]); + expect(grandParent.children).toEqual([parent]); + + // inherits top most parent + grandParent.get(TransformComponent).coordPlane = ex.CoordPlane.World; + expect(parent.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.World); + expect(child1.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.World); + expect(child2.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.World); + + // inherits top most parent + grandParent.get(TransformComponent).coordPlane = ex.CoordPlane.Screen; + expect(parent.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.Screen); + expect(child1.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.Screen); + expect(child2.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.Screen); + + // Can't change and logs warning + child2.get(TransformComponent).coordPlane = ex.CoordPlane.World; + expect(child2.get(TransformComponent).coordPlane).toBe(ex.CoordPlane.Screen); + expect(logger.warn).toHaveBeenCalledWith( + 'Cannot set coordinate plane on child entity child2, children inherit their coordinate plane from their parents.'); + }); + it('can be cloned', () => { const transform = new TransformComponent(); const owner = new ex.Entity([transform]);