Skip to content

Commit c4a5db4

Browse files
committed
Added component groups.
1 parent c01ca1c commit c4a5db4

File tree

2 files changed

+118
-48
lines changed

2 files changed

+118
-48
lines changed

src/ComponentRegistry.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// create a singleton class
22
import Component from "./Component.ts";
3+
import { addBit } from "@serbanghita-gamedev/bitmask";
34

45
type ComponentConstructor<TProps extends NonNullable<object>, TComp extends Component<TProps>> = new (properties: TProps) => TComp;
56

@@ -8,6 +9,8 @@ export default class ComponentRegistry {
89

910
private bitmask: bigint = 1n;
1011
private components: Map<string, typeof Component> = new Map();
12+
private componentGroups: Map<string, { components: (typeof Component)[]; bitmask: bigint }> = new Map();
13+
private componentToGroupMap: Map<bigint, string> = new Map();
1114

1215
private constructor() {}
1316

@@ -46,7 +49,28 @@ export default class ComponentRegistry {
4649
return component;
4750
}
4851

52+
public registerComponentGroup<T extends Array<ComponentConstructor<any, any>>>(groupName: string, components: [...T]) {
53+
let groupBitmask = 0n;
54+
for (const component of components) {
55+
groupBitmask = addBit(groupBitmask, component.prototype.bitmask);
56+
this.componentToGroupMap.set(component.prototype.bitmask, groupName);
57+
}
58+
this.componentGroups.set(groupName, { components, bitmask: groupBitmask });
59+
}
60+
61+
public getComponentGroup(groupName: string): { components: (typeof Component)[]; bitmask: bigint } | undefined {
62+
return this.componentGroups.get(groupName);
63+
}
64+
65+
public getComponentGroupName(componentBitmask: bigint): string | undefined {
66+
return this.componentToGroupMap.get(componentBitmask);
67+
}
68+
4969
public getLastBitmask() {
5070
return this.bitmask;
5171
}
72+
73+
public reset() {
74+
ComponentRegistry.instance = new ComponentRegistry();
75+
}
5276
}
Lines changed: 94 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,117 @@
11
import ComponentRegistry from "../ComponentRegistry.ts";
2-
import { Body, PositionOnScreen } from "../fixtures.ts";
2+
import { Body, Keyboard, PositionOnScreen } from "../fixtures.ts";
3+
import { afterAll, afterEach, describe } from "vitest";
34

45
describe("ComponentRegistry", () => {
5-
it("constructor", () => {
6-
const reg = ComponentRegistry.getInstance();
7-
expect(reg).toBeInstanceOf(ComponentRegistry);
6+
afterEach(() => {
7+
ComponentRegistry.getInstance().reset();
88
});
99

10-
it("registerComponent", () => {
11-
const reg = ComponentRegistry.getInstance();
12-
expect(reg).toBeInstanceOf(ComponentRegistry);
10+
describe("components", () => {
11+
it("constructor", () => {
12+
const reg = ComponentRegistry.getInstance();
13+
expect(reg).toBeInstanceOf(ComponentRegistry);
14+
});
1315

14-
reg.registerComponent(Body);
15-
reg.registerComponent(PositionOnScreen);
16+
it("registerComponent", () => {
17+
const reg = ComponentRegistry.getInstance();
18+
expect(reg).toBeInstanceOf(ComponentRegistry);
1619

17-
expect(reg.getLastBitmask()).toBe(4n);
20+
reg.registerComponent(Body);
21+
reg.registerComponent(PositionOnScreen);
1822

19-
const body1 = new Body({ width: 10, height: 20 });
20-
const body2 = new Body({ width: 30, height: 40 });
21-
const body3 = new Body({ width: 50, height: 60 });
23+
expect(reg.getLastBitmask()).toBe(4n);
2224

23-
const position1 = new PositionOnScreen({ x: 1, y: 2 });
24-
const position2 = new PositionOnScreen({ x: 3, y: 4 });
25-
const position3 = new PositionOnScreen({ x: 5, y: 6 });
25+
const body1 = new Body({ width: 10, height: 20 });
26+
const body2 = new Body({ width: 30, height: 40 });
27+
const body3 = new Body({ width: 50, height: 60 });
2628

27-
expect(body1.bitmask).toBe(2n);
28-
expect(body2.bitmask).toBe(2n);
29-
expect(body3.bitmask).toBe(2n);
29+
const position1 = new PositionOnScreen({ x: 1, y: 2 });
30+
const position2 = new PositionOnScreen({ x: 3, y: 4 });
31+
const position3 = new PositionOnScreen({ x: 5, y: 6 });
3032

31-
expect(position1.bitmask).toBe(4n);
32-
expect(position2.bitmask).toBe(4n);
33-
expect(position3.bitmask).toBe(4n);
33+
expect(body1.bitmask).toBe(2n);
34+
expect(body2.bitmask).toBe(2n);
35+
expect(body3.bitmask).toBe(2n);
3436

35-
// Extra safety check that the properties of the class were successfully set.
36-
expect(body1.properties.width).toBe(10);
37-
expect(body1.properties.height).toBe(20);
37+
expect(position1.bitmask).toBe(4n);
38+
expect(position2.bitmask).toBe(4n);
39+
expect(position3.bitmask).toBe(4n);
3840

39-
expect(body2.properties.width).toBe(30);
40-
expect(body2.properties.height).toBe(40);
41+
// Extra safety check that the properties of the class were successfully set.
42+
expect(body1.properties.width).toBe(10);
43+
expect(body1.properties.height).toBe(20);
4144

42-
expect(body3.properties.width).toBe(50);
43-
expect(body3.properties.height).toBe(60);
45+
expect(body2.properties.width).toBe(30);
46+
expect(body2.properties.height).toBe(40);
4447

45-
expect(position1.properties.x).toBe(1);
46-
expect(position1.properties.y).toBe(2);
48+
expect(body3.properties.width).toBe(50);
49+
expect(body3.properties.height).toBe(60);
4750

48-
expect(position2.properties.x).toBe(3);
49-
expect(position2.properties.y).toBe(4);
51+
expect(position1.properties.x).toBe(1);
52+
expect(position1.properties.y).toBe(2);
5053

51-
expect(position3.properties.x).toBe(5);
52-
expect(position3.properties.y).toBe(6);
53-
});
54+
expect(position2.properties.x).toBe(3);
55+
expect(position2.properties.y).toBe(4);
5456

55-
it("registerComponents", () => {
56-
const reg = ComponentRegistry.getInstance();
57-
reg.registerComponents([Body, PositionOnScreen]);
57+
expect(position3.properties.x).toBe(5);
58+
expect(position3.properties.y).toBe(6);
59+
});
5860

59-
expect(reg.getComponent("Body")).toBe(Body);
60-
expect(reg.getComponent("PositionOnScreen")).toBe(PositionOnScreen);
61-
});
61+
it("registerComponents", () => {
62+
const reg = ComponentRegistry.getInstance();
63+
reg.registerComponents([Body, PositionOnScreen]);
64+
65+
expect(reg.getComponent("Body")).toBe(Body);
66+
expect(reg.getComponent("PositionOnScreen")).toBe(PositionOnScreen);
67+
});
6268

63-
it("getComponent", () => {
64-
const reg = ComponentRegistry.getInstance();
65-
reg.registerComponent(Body);
66-
reg.registerComponent(PositionOnScreen);
69+
it("getComponent", () => {
70+
const reg = ComponentRegistry.getInstance();
71+
reg.registerComponent(Body);
72+
reg.registerComponent(PositionOnScreen);
73+
74+
expect(reg.getComponent("Body")).toBe(Body);
75+
expect(reg.getComponent("PositionOnScreen")).toBe(PositionOnScreen);
76+
});
77+
});
6778

68-
expect(reg.getComponent("Body")).toBe(Body);
69-
expect(reg.getComponent("PositionOnScreen")).toBe(PositionOnScreen);
79+
describe("component groups", () => {
80+
it("getComponentGroup", () => {
81+
const reg = ComponentRegistry.getInstance();
82+
83+
reg.registerComponent(Body);
84+
reg.registerComponent(PositionOnScreen);
85+
reg.registerComponent(Keyboard);
86+
87+
reg.registerComponentGroup("group1", [Body, PositionOnScreen]);
88+
reg.registerComponentGroup("group2", [Keyboard]);
89+
90+
expect(reg.getComponentGroup("group0")).toBeUndefined();
91+
expect(reg.getComponentGroup("group1")).toEqual(
92+
expect.objectContaining({
93+
bitmask: 6n,
94+
components: [Body, PositionOnScreen],
95+
}),
96+
);
97+
expect(reg.getComponentGroup("group2")).toEqual(
98+
expect.objectContaining({
99+
bitmask: 8n,
100+
components: [Keyboard],
101+
}),
102+
);
103+
});
104+
105+
it("getComponentGroupName", () => {
106+
const reg = ComponentRegistry.getInstance();
107+
108+
reg.registerComponent(Body);
109+
reg.registerComponentGroup("group1", [Body]);
110+
111+
const a = reg.getComponentGroup("group1");
112+
113+
expect(reg.getComponentGroupName(1n)).toBeUndefined();
114+
expect(reg.getComponentGroupName(2n)).toEqual("group1");
115+
});
70116
});
71117
});

0 commit comments

Comments
 (0)