Skip to content

Commit 35924ea

Browse files
committed
feat: implement Signal v1.0
1 parent 2abfd49 commit 35924ea

File tree

5 files changed

+107
-5
lines changed

5 files changed

+107
-5
lines changed

packages/editors/model/src/PlayerBehavior.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@ import {
66
Input,
77
type InputDevicePreference,
88
SceneProperty,
9-
SceneActorComponent
9+
SceneActorComponent,
10+
Signal,
11+
type SignalEvent
1012
} from "@jolly-pixel/engine";
1113

1214
export interface PlayerProperties extends BehaviorProperties {
1315
speed: number;
1416
}
1517

1618
export class PlayerBehavior extends Behavior<PlayerProperties> {
19+
@Signal()
20+
onPlayerPunch: SignalEvent;
21+
1722
@SceneProperty({ type: "number" })
1823
speed = 0.05;
1924

@@ -33,9 +38,6 @@ export class PlayerBehavior extends Behavior<PlayerProperties> {
3338
}
3439

3540
awake() {
36-
console.log({
37-
isTouchpadAvailable: this.actor.gameInstance.input.isTouchpadAvailable()
38-
});
3941
this.actor.threeObject.rotateX(-Math.PI / 2);
4042

4143
this.model.animation.setClipNameRewriter((name) => name.slice(name.indexOf("|") + 1).toLowerCase());
@@ -68,6 +70,7 @@ export class PlayerBehavior extends Behavior<PlayerProperties> {
6870
}
6971
else if (input.isMouseButtonDown("left")) {
7072
this.model.animation.play("punch_jab");
73+
this.onPlayerPunch.emit();
7174
}
7275
else {
7376
this.model.animation.play("idle_loop");
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Import Third-party Dependencies
2+
import "reflect-metadata";
3+
4+
// CONSTANTS
5+
const kActorComponentSignalKey = Symbol("ActorComponentSignalKey");
6+
7+
export interface SignalMetadata {
8+
signals: Set<string>;
9+
}
10+
11+
export type SignalListener<T extends unknown[]> = (...args: T[]) => void;
12+
13+
export class SignalEvent<T extends unknown[] = []> {
14+
private listeners: SignalListener<T>[] = [];
15+
16+
emit(...args: T) {
17+
this.listeners.forEach((listener) => {
18+
listener(...args as any);
19+
});
20+
}
21+
22+
connect(
23+
listener: SignalListener<T>
24+
) {
25+
this.listeners.push(listener);
26+
}
27+
28+
disconnect(
29+
listener: SignalListener<T>
30+
) {
31+
const index = this.listeners.indexOf(listener);
32+
if (index !== -1) {
33+
this.listeners.splice(index, 1);
34+
}
35+
}
36+
37+
clear() {
38+
this.listeners = [];
39+
}
40+
}
41+
42+
export function Signal(): PropertyDecorator {
43+
return function fn(
44+
object: Object,
45+
propertyName: string | symbol
46+
): void {
47+
const metadata = getActorComponentMetadata(object);
48+
if (metadata) {
49+
metadata.signals.add(propertyName.toString());
50+
}
51+
else {
52+
const metadata = createActorComponentMetadata();
53+
metadata.signals.add(propertyName.toString());
54+
55+
Reflect.defineMetadata(
56+
kActorComponentSignalKey,
57+
metadata,
58+
object
59+
);
60+
}
61+
};
62+
}
63+
64+
function createActorComponentMetadata(): SignalMetadata {
65+
return {
66+
signals: new Set<string>()
67+
};
68+
}
69+
70+
export function getActorComponentMetadata(
71+
object: Object
72+
): SignalMetadata | undefined {
73+
return Reflect.getMetadata(kActorComponentSignalKey, object);
74+
}

packages/engine/src/actor/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
export * from "./Actor.js";
22
export * from "./ActorComponent.js";
33
export * from "./ActorTree.js";
4+
export {
5+
Signal,
6+
SignalEvent,
7+
type SignalListener
8+
} from "./Signal.js";

packages/engine/src/components/script/BehaviorDecorators.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ export type SceneActorComponentType =
8181
| typeof SpriteRenderer
8282
| typeof TextRenderer
8383
| typeof TiledMapRenderer
84-
| typeof ActorComponent;
84+
| typeof ActorComponent
85+
| any;
8586

8687
export function SceneActorComponent(
8788
classObject: SceneActorComponentType

packages/engine/src/components/script/BehaviorInitializer.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import {
77
Input,
88
type InputListenerMetadata
99
} from "../../controls/Input.class.js";
10+
import {
11+
SignalEvent,
12+
getActorComponentMetadata
13+
} from "../../actor/Signal.js";
1014
import { Behavior } from "./Behavior.js";
1115
import {
1216
getBehaviorMetadata,
@@ -68,11 +72,26 @@ export class BehaviorInitializer {
6872
}
6973

7074
load(): void {
75+
this.#bindSignalHandlers();
7176
this.#resolveProperties();
7277
this.#resolveActorComponents();
7378
this.#resolveInputListeners();
7479
}
7580

81+
#bindSignalHandlers() {
82+
const metadata = getActorComponentMetadata(
83+
Object.getPrototypeOf(this.#behavior)
84+
);
85+
if (!metadata) {
86+
return;
87+
}
88+
89+
const { signals } = metadata;
90+
for (const propertyName of signals) {
91+
this.#behavior[propertyName] = new SignalEvent();
92+
}
93+
}
94+
7695
#resolveInputListeners(): void {
7796
const { input } = this.#behavior.actor.gameInstance;
7897

0 commit comments

Comments
 (0)