Skip to content

Commit 60bea3e

Browse files
committed
docs: custom components typescript section
- added a typescript section to the custom component guide - improved first section
1 parent 0aa49ca commit 60bea3e

File tree

1 file changed

+94
-22
lines changed

1 file changed

+94
-22
lines changed

guides/en/expanding_kaplay/custom_components.md

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@ url: custom_components
66

77
# Custom Components
88

9-
KAPLAY uses a flexible component system that helps you compose game logic.
9+
KAPLAY uses a flexible component system that helps you compose game objects
10+
logic.
1011

11-
Let's take a look at how the default component `lifespan()` is implemented.
12+
Let's take a look at how the default component `lifespan()` is implemented:
1213

1314
```js
1415
function lifespan(time) {
1516
let timer = 0;
17+
1618
return {
1719
id: "lifespan",
1820
update() {
1921
timer -= dt();
22+
2023
if (timer <= 0) {
2124
destroy(this);
2225
}
@@ -25,50 +28,119 @@ function lifespan(time) {
2528
}
2629
```
2730

28-
Components are just plain functions that returns an object. The return object
29-
will contain all the exposed states, methods, and event hooks of the component.
30-
In this case, the `lifespan()` component returns an `id`, which is a string
31-
which serves as an unique identification of the comp. There's also an
32-
`update()`, which is an event hook that'll run every frame. All `this` inside
33-
the component functions refer to the game obj it's attached to.
31+
Components are just functions that returns an object. The return object will
32+
contain all the exposed states, methods, and event hooks of the component.
33+
34+
In this case, the `lifespan()` component returns:
35+
36+
- `id`: unique identification of the comp, used in require, `.unuse()`, etc.
37+
- `update()`: an event hook that'll run every frame and only exists while the
38+
component is attached to a Game Object.
39+
40+
Also, all `this` inside the component functions refer to the **Game Object**
41+
it's attached to.
3442

35-
All special fields:
43+
Here's a list of all special fields you can use in your component:
3644

3745
```js
38-
function mycomp() {
39-
// use closed local variable for internal data
46+
function myComp() {
47+
// Use closed local variable for internal data
4048
let data = 123;
49+
4150
return {
4251
id: "mycomp",
43-
// if this comp requires other comps to work
52+
// If this comp requires other comps to work, we use comp ids
4453
require: ["area", "pos"],
45-
// runs when the obj is added to scene
54+
// Runs when the obj is added to scene
4655
add() {
4756
debug.log("Hi! This should only be fire once.");
4857
},
49-
// runs every frame
58+
// Runs every frame
5059
update() {
51-
// we're using a method from "pos" comp here, so we declare require "pos" above
60+
// We're using a method from "pos" comp here, so we declare require "pos" above
5261
this.move(200, 0);
5362
},
54-
// runs every frame, after update
63+
// Runs every frame, after update
5564
draw() {
5665
drawLine(this.pos, mousePos());
5766
},
58-
// runs when obj is destroyed
67+
// Runs when obj is destroyed
5968
destroy() {
60-
debug.log("Oh bye");
69+
debug.log("Oh bye :<");
6170
},
62-
// what to display in inspect mode
71+
// What to display in debug inspect mode
6372
inspect() {
6473
return "some state that deserves to be shown in inspect mode";
6574
},
6675
};
6776
}
6877
```
6978

70-
Most KAPLAY built-in components are built using public interfaces, feel free to
71-
check them out. Also check out the "drag", "platformer", "doublejump" demos with
72-
their own custom components.
79+
All KAPLAY built-in components are implemented this way. You can check the
80+
source code
81+
[here](https://github.com/kaplayjs/kaplay/tree/master/src/ecs/components)
7382

7483
Check out the [component demo](https://play.kaplayjs.com/?example=component).
84+
85+
## TypeScript
86+
87+
If you're using TypeScript, we recommend creating an specific type for your
88+
component:
89+
90+
```ts
91+
// You can import types from kaplay package
92+
import type { Comp } from "kaplay";
93+
94+
interface MyCustomComp extends Comp {
95+
// you just need to declare new stuff here
96+
myCustomProp: number;
97+
myCustomMethod: (arg: string) => void;
98+
}
99+
100+
function myCustomComp(): MyCustomComp {
101+
return {
102+
id: "myCustomComp",
103+
myCustomProp: 123,
104+
myCustomMethod(arg) {
105+
console.log(arg);
106+
},
107+
};
108+
}
109+
```
110+
111+
When you want to use `this` inside any component method, but TypeScript doesn't
112+
know what type it is, you can type `this` to `GameObj<MyCustomComp>`:
113+
114+
```ts
115+
function myCustomComp(): MyCustomComp {
116+
return {
117+
id: "myCustomComp",
118+
myCustomMethod(this: GameObj<MyCustomComp> arg) {
119+
this.myCustomProp; // typed from MyCustomComp
120+
this.tags // typed from GameObjRaw
121+
},
122+
};
123+
}
124+
```
125+
126+
Even better if you got a component that requires other components, you can use
127+
`GameObj<YourComp | OtherComp>` to type `this`.
128+
129+
```ts
130+
function specie(specie: string): SpecieComp {
131+
return {
132+
id: "specie",
133+
require: ["color"],
134+
135+
specie: specie,
136+
evolve(this: GameObj<SpecieComp>, specie: string) {
137+
this.specie = specie;
138+
this.tag(specie);
139+
},
140+
evil(this: GameObj<SpecieComp | ColorComp>) {
141+
// this.color is typed
142+
this.color = Color.RED;
143+
},
144+
};
145+
}
146+
```

0 commit comments

Comments
 (0)