Skip to content

Commit

Permalink
feat(components): add destroy method
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaisthorpe committed Jun 17, 2024
1 parent e69f263 commit 71a205a
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/orange-mayflies-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tedengine/ted": minor
---

Add destroy method to components
28 changes: 28 additions & 0 deletions packages/ted/src/actor-components/actor-component.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import TActorComponent from '../actor-components/actor-component';
import TActor from '../core/actor';

describe('TActorComponent', () => {
describe('destroy', () => {
test('should call the "onDestroy" method if available', () => {
const onDestroyMock = jest.fn();
const actor = new TActor();
const actorComponent = new TActorComponent(actor) as any;
actorComponent.onDestroy = onDestroyMock;
actorComponent.destroy();

expect(onDestroyMock).toHaveBeenCalled();
expect(actorComponent.dead).toBe(true);
});

test('should only call the "onDestroy" method once if destroy is called multiple times', () => {
const onDestroyMock = jest.fn();
const actor = new TActor();
const actorComponent = new TActorComponent(actor) as any;
actorComponent.onDestroy = onDestroyMock;
actorComponent.destroy();
actorComponent.destroy();

expect(onDestroyMock).toHaveBeenCalledTimes(1);
});
});
});
22 changes: 21 additions & 1 deletion packages/ted/src/actor-components/actor-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,29 @@ export interface TActorComponentWithOnUpdate extends TActorComponent {
onUpdate(engine: TEngine, delta: number): Promise<void>;
}

export interface TActorComponentWithOnDestroy extends TActorComponent {
onDestroy(): void;
}

const hasOnUpdate = (
state: TActorComponent
state: TActorComponent,
): state is TActorComponentWithOnUpdate =>
(state as TActorComponentWithOnUpdate).onUpdate !== undefined;

const hasOnDestroy = (
state: TActorComponent,
): state is TActorComponentWithOnDestroy =>
(state as TActorComponentWithOnDestroy).onDestroy !== undefined;

/**
* Component for an actor.
* Only contains updater and cannot be rendered.
*/
export default class TActorComponent {
public uuid: string = uuidv4();

public dead = false;

constructor(public actor: TActor) {
// @todo should the compenent itself do this?
actor.components.push(this);
Expand All @@ -37,4 +48,13 @@ export default class TActorComponent {
this.onUpdate(engine, delta);
}
}

public destroy(): void {
if (this.dead) return;

this.dead = true;
if (hasOnDestroy(this)) {
this.onDestroy();
}
}
}
48 changes: 48 additions & 0 deletions packages/ted/src/core/actor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import TActorComponent from '../actor-components/actor-component';
import TActor from './actor';

describe('TActor', () => {
describe('destroy', () => {
test('should set the "dead" flag to true', () => {
const actor = new TActor();
actor.destroy();
expect(actor.dead).toBe(true);
});

test('should call the "destroy" method on each component', () => {
const actor = new TActor();
const component1 = new TActorComponent(actor);
component1.destroy = jest.fn();

const component2 = new TActorComponent(actor);
component2.destroy = jest.fn();

actor.destroy();
expect(component1.destroy).toHaveBeenCalled();
expect(component2.destroy).toHaveBeenCalled();
});

test('should call the "onDestroy" method if available', () => {
const actor = new TActor() as any;
actor.onDestroy = jest.fn();
actor.destroy();
expect(actor.onDestroy).toHaveBeenCalled();
});

test('should only call the "onDestroy" method once if destory is called multiple times', () => {
const actor = new TActor() as any;
actor.onDestroy = jest.fn();
actor.destroy();
actor.destroy();
expect(actor.onDestroy).toHaveBeenCalledTimes(1);
});

test('should remove the actor from the world if it exists', () => {
const actor = new TActor();
const world = { removeActor: jest.fn() };
actor.world = world as any;
actor.destroy();
expect(world.removeActor).toHaveBeenCalledWith(actor);
});
});
});
6 changes: 4 additions & 2 deletions packages/ted/src/core/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,16 @@ export default class TActor {

this.dead = true;

for (const component of this.components) {
component.destroy();
}

if (hasOnDestroy(this)) {
this.onDestroy();
}

if (this.world) {
this.world.removeActor(this);
}

// @todo clean up the components
}
}

0 comments on commit 71a205a

Please sign in to comment.