Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit 24fe366

Browse files
committedOct 11, 2023
Add types to TypeScript files
Make the necessary changes to the .ts files, which started as copies of .the .js files, so they successfully compile as TypeScript. This means adding type annotations and making other changes to pass TypeScript's compilation checks.
1 parent 3638ce4 commit 24fe366

File tree

5 files changed

+50
-30
lines changed

5 files changed

+50
-30
lines changed
 

‎scripts/gameMethods.ts

+16-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import Globals from "./globals.js";
44
import * as Utils from "./utilities.js";
55

6-
export function Tick(runtime)
6+
// TypeScript note: import the MonsterInstance class so it can be used as a type
7+
import MonsterInstance from "./monster.js";
8+
9+
export function Tick(runtime: IRuntime)
710
{
811
// The tick event runs every frame. The game needs to be advanced
912
// by the amount of time in delta-time, also known as dt.
@@ -14,7 +17,8 @@ export function Tick(runtime)
1417

1518
// Next handle all monster's movement. Note this calls a method in
1619
// the custom MonsterInstance class defined in Monster.js.
17-
for (const monsterInstance of runtime.objects.Monster.instances())
20+
// TypeScript note: iterate Monster instances as the custom MonsterInstance class.
21+
for (const monsterInstance of runtime.objects.Monster.instances<MonsterInstance>())
1822
{
1923
monsterInstance.Move();
2024
}
@@ -39,19 +43,19 @@ export function Tick(runtime)
3943
}
4044

4145
// Finally, always display score in the status text object.
42-
const statusTextInstance = runtime.objects.Status.getFirstInstance();
46+
const statusTextInstance = runtime.objects.Status.getFirstInstance()!;
4347
statusTextInstance.text = "Score: " + Globals.score;
4448
}
4549

46-
function MovePlayer(runtime)
50+
function MovePlayer(runtime: IRuntime)
4751
{
4852
// Use a playerInst local variable as a shorthand way to refer to
4953
// the playerInstance global variable in this function, since
5054
// it is used many times. Similarly create local variables to
5155
// reference runtime.keyboard and runtime.dt.
5256
const playerInst = Globals.playerInstance;
5357
const dt = runtime.dt;
54-
const keyboard = runtime.keyboard;
58+
const keyboard = runtime.keyboard!;
5559

5660
// The player is destroyed if a monster catches them. Don't try to
5761
// handle the player movement if the only instance was destroyed.
@@ -88,12 +92,12 @@ function MovePlayer(runtime)
8892
runtime.layout.scrollTo(playerInst.x, playerInst.y);
8993

9094
// Always make the player look in the direction of the mouse cursor
91-
const mouse = runtime.mouse;
95+
const mouse = runtime.mouse!;
9296
playerInst.angle = Utils.angleTo(playerInst.x, playerInst.y,
9397
mouse.getMouseX(), mouse.getMouseY());
9498
}
9599

96-
function MoveBullet(inst, dt)
100+
function MoveBullet(inst: InstanceType.Bullet, dt: number)
97101
{
98102
// Move bullets forward at their angle at a speed of 600 pixels per second.
99103
// This is similar to the Bullet behavior's movement.
@@ -102,7 +106,7 @@ function MoveBullet(inst, dt)
102106
inst.y += Math.sin(inst.angle) * speed * dt;
103107
}
104108

105-
function CheckBulletHitMonster(bulletInstance, runtime)
109+
function CheckBulletHitMonster(bulletInstance: InstanceType.Bullet, runtime: IRuntime)
106110
{
107111
// Save a reference to the Explosion object type to help
108112
// keep the code short and readable.
@@ -111,7 +115,7 @@ function CheckBulletHitMonster(bulletInstance, runtime)
111115
// Check if a bullet has collided with any monster. To do this it
112116
// must check against every Monster instance. This is similar to
113117
// what the 'Is overlapping' condition does.
114-
for (const monsterInstance of runtime.objects.Monster.instances())
118+
for (const monsterInstance of runtime.objects.Monster.instances<MonsterInstance>())
115119
{
116120
// Test if the bullet instance overlaps this monster instance,
117121
// indicating a collision.
@@ -140,7 +144,7 @@ function CheckBulletHitMonster(bulletInstance, runtime)
140144
}
141145
}
142146

143-
function FadeExplosion(inst, dt)
147+
function FadeExplosion(inst: InstanceType.Explosion, dt: number)
144148
{
145149
// Fade out explosions over 0.5 seconds, and destroy it once it
146150
// becomes invisible. This is similar to the Fade behavior.
@@ -150,7 +154,7 @@ function FadeExplosion(inst, dt)
150154
inst.destroy();
151155
}
152156

153-
export function OnMouseDown(e, runtime)
157+
export function OnMouseDown(e: MouseEvent, runtime: IRuntime)
154158
{
155159
// The left mouse button is number 0. Ignore any other mouse buttons.
156160
if (e.button !== 0)
@@ -172,7 +176,7 @@ export function OnMouseDown(e, runtime)
172176
bulletInstance.angle = playerInst.angle;
173177
}
174178

175-
export function OnKeyDown(e, runtime)
179+
export function OnKeyDown(e: KeyboardEvent, runtime: IRuntime)
176180
{
177181
// Pressing space when the player is destroyed restarts the game.
178182
if (!Globals.playerInstance && e.key === " ")

‎scripts/globals.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@ const Globals = {
1717

1818
// There is only ever one instance of Player and GameOverText.
1919
// They are stored here for convenience to make it easier to access them.
20-
playerInstance: null,
21-
gameOverTextInstance: null
20+
// TypeScript note: with the object syntax used here, the initial 'null'
21+
// values would normally deduce the type as 'null', meaning it can only
22+
// ever hold the value 'null'! Use the <Type> syntax to override the
23+
// type so we can force them to be optional references to instances.
24+
playerInstance: <InstanceType.Player | null> null,
25+
gameOverTextInstance: <InstanceType.GameOverText | null> null
2226
};
2327

2428
// Export the object representing global variables.

‎scripts/main.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ runOnStartup(async runtime =>
2727
() => OnBeforeProjectStart(runtime));
2828
});
2929

30-
function OnBeforeProjectStart(runtime)
30+
function OnBeforeProjectStart(runtime: IRuntime)
3131
{
3232
// Just before the project starts, add a "beforelayoutstart" event
3333
// handler to set up the initial state of the layout. This is also
@@ -40,19 +40,19 @@ function OnBeforeProjectStart(runtime)
4040
runtime.addEventListener("tick", () => GameMethods.Tick(runtime));
4141

4242
// The player fires bullets when clicking, which is done in a mousedown event.
43-
runtime.addEventListener("mousedown", e => GameMethods.OnMouseDown(e, runtime));
43+
runtime.addEventListener("mousedown", e => GameMethods.OnMouseDown(e as MouseEvent, runtime));
4444

4545
// Restart the game when pressing spacebar if the player was destroyed,
4646
// which is done in a keydown event.
47-
runtime.addEventListener("keydown", e => GameMethods.OnKeyDown(e, runtime));
47+
runtime.addEventListener("keydown", e => GameMethods.OnKeyDown(e as KeyboardEvent, runtime));
4848

4949
// Create a new monster instance every 3 seconds.
5050
setInterval(() => MonsterInstance.Create(runtime), 3000);
5151
}
5252

5353
// This is called every time the layout starts, just before 'On start of
5454
// layout'. Set up the initial state of the layout.
55-
function OnBeforeLayoutStart(runtime)
55+
function OnBeforeLayoutStart(runtime: IRuntime)
5656
{
5757
// Store the only Player and GameOverText instances as globals.
5858
// Note this is done every time the layout is started, since restarting
@@ -61,10 +61,13 @@ function OnBeforeLayoutStart(runtime)
6161
Globals.gameOverTextInstance = runtime.objects.GameOverText.getFirstInstance();
6262

6363
// Hide the "Game over" text.
64-
Globals.gameOverTextInstance.isVisible = false;
64+
// TypeScript note: the 'property!' syntax is used to tell TypeScript that the
65+
// property will not be null. It's used in a few places where we know something
66+
// won't be null, but the type is optional as it depends on the runtime state.
67+
Globals.gameOverTextInstance!.isVisible = false;
6568

6669
// Start all monsters pointing at a random angle.
67-
for (const monsterInstance of runtime.objects.Monster.instances())
70+
for (const monsterInstance of runtime.objects.Monster.instances<MonsterInstance>())
6871
{
6972
monsterInstance.angleDegrees = runtime.random() * 360;
7073
}

‎scripts/monster.ts

+14-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@ import * as Utils from "./utilities.js";
66
// This is a custom class used to represent instances of the Monster
77
// object type in JavaScript code. Note the call to setInstanceClass()
88
// in runOnStartup in Main.js, which tells Construct to use this class
9-
// instead of the default, which is ISpriteInstance for Sprite objects.
10-
// Note the class must derive from the default class ISpriteInstance.
9+
// instead of the default.
10+
// Note the class must derive from the default class InstanceType.Monster.
1111
// This is a very useful way to add custom logic to objects in your
1212
// game, since you can easily add new properties and functions.
13-
export default class MonsterInstance extends globalThis.ISpriteInstance
13+
// TypeScript note: make sure custom instance classes derive from the
14+
// instance-specific types under the InstanceType namespace, since
15+
// Construct generates specific instance types for every object type.
16+
export default class MonsterInstance extends InstanceType.Monster
1417
{
18+
// TypeScript note: TypeScript requires class properties to be
19+
// declared with their type outside the constructor like this,
20+
// so it knows ahead of time what class properties are available.
21+
health: number;
22+
speed: number;
23+
1524
constructor()
1625
{
1726
super();
@@ -25,7 +34,7 @@ export default class MonsterInstance extends globalThis.ISpriteInstance
2534

2635
// This is called every 3 seconds to create a new monster just
2736
// outside the right edge of the layout.
28-
static Create(runtime)
37+
static Create(runtime: IRuntime)
2938
{
3039
runtime.objects.Monster.createInstance("Main",
3140
1500, runtime.random() * 1024);
@@ -80,7 +89,7 @@ export default class MonsterInstance extends globalThis.ISpriteInstance
8089
// that won't affect the global.
8190
Globals.playerInstance = null;
8291

83-
Globals.gameOverTextInstance.isVisible = true;
92+
Globals.gameOverTextInstance!.isVisible = true;
8493
}
8594
}
8695
}

‎scripts/utilities.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,34 @@
55
// import all of them, or specific methods only, etc.
66

77
// Calculate the angle in radians between two points.
8-
export function angleTo(x1, y1, x2, y2)
8+
export function angleTo(x1: number, y1: number, x2: number, y2: number)
99
{
1010
return Math.atan2(y2 - y1, x2 - x1);
1111
}
1212

1313
// Calculate the distance between two points.
14-
export function distanceTo(x1, y1, x2, y2)
14+
export function distanceTo(x1: number, y1: number, x2: number, y2: number)
1515
{
1616
return Math.hypot(x2 - x1, y2 - y1);
1717
}
1818

1919
// Test if a given instance is outside the bounds of the layout.
20-
export function IsOutsideLayout(inst)
20+
export function IsOutsideLayout(inst: ISpriteInstance)
2121
{
2222
const layout = inst.layout;
2323
return inst.x < 0 || inst.y < 0 ||
2424
inst.x > layout.width || inst.y > layout.height;
2525
}
2626

2727
// Convert x from degrees to radians.
28-
export function toRadians(x)
28+
export function toRadians(x: number)
2929
{
3030
return x * (Math.PI / 180);
3131
}
3232

3333
// Rotate from angle 'start' towards angle 'end' by the angle
3434
// 'step' (all in radians).
35-
export function angleRotate(start, end, step)
35+
export function angleRotate(start: number, end: number, step: number)
3636
{
3737
const ss = Math.sin(start);
3838
const cs = Math.cos(start);

0 commit comments

Comments
 (0)
This repository has been archived.