Skip to content

Commit c93bb7e

Browse files
enemy descent system
1 parent 2fd46b0 commit c93bb7e

File tree

4 files changed

+90
-22
lines changed

4 files changed

+90
-22
lines changed

examples/space-invaders/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>Space Invaders</title>
77
</head>
8-
<body>
8+
<body style="display: flex">
99
<script type="module" src="/src/main.ts"></script>
1010
</body>
1111
</html>

examples/space-invaders/src/components.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,22 @@ export class Velocity extends Component("Velocity")<{
2424
}> {
2525
static readonly idle = new this({ vx: 0, vy: 0, speed: 6 });
2626
static readonly shootUp = new this({ vx: 0, vy: -10, speed: 6 });
27-
28-
static readonly sin = (time: number) => ({ dx: Math.sin(time) * 50, dy: 1 });
2927
}
3028

3129
export class DescentPattern extends Component("DescentPattern")<{
3230
pattern: (time: number) => { dx: number; dy: number };
33-
}> {}
31+
}> {
32+
static readonly sin = new this({
33+
pattern: (time: number) => ({ dx: Math.sin(time * 0.1) * 1, dy: 1 }),
34+
});
35+
36+
static readonly zigZag = new this({
37+
pattern: (time: number) => ({
38+
dx: Math.sin(time * 0.05) > 0 ? 2 : -2,
39+
dy: 1,
40+
}),
41+
});
42+
}
3443

3544
export class Bullet extends Component("Bullet")<{
3645
damage: number;

examples/space-invaders/src/main.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ECS, update } from "@typeonce/ecs";
2-
import Matter from "matter-js";
2+
import Matter, { Render } from "matter-js";
33
import * as PIXI from "pixi.js";
44
import { Collider, Player, Position, Sprite, Velocity } from "./components";
55
import { PLAYER_HEIGHT, PLAYER_WIDTH } from "./constants";
@@ -9,6 +9,7 @@ import {
99
EnemyBulletCollisionSystem,
1010
EnemyDescentSystem,
1111
EnemyDestroySystem,
12+
EnemySpawnSystem,
1213
MovementSystem,
1314
PhysicsSystem,
1415
PlayerInputSystem,
@@ -21,7 +22,22 @@ await app.init({ width: 800, height: 600, backgroundColor: 0x222222 });
2122
document.body.appendChild(app.canvas);
2223

2324
const inputManager = new InputManager();
24-
const engine = Matter.Engine.create();
25+
26+
const engine = Matter.Engine.create({
27+
gravity: { scale: 0 },
28+
});
29+
const render = Render.create({
30+
engine,
31+
element: document.body,
32+
options: {
33+
width: 800,
34+
height: 600,
35+
wireframes: true,
36+
},
37+
});
38+
39+
Render.run(render);
40+
2541
const world = ECS.create<GameEventMap>(
2642
({
2743
registerSystemUpdate,
@@ -36,7 +52,8 @@ const world = ECS.create<GameEventMap>(
3652
PlayerInputSystem(inputManager),
3753
// TODO: it works even when it's not called (not `SystemUpdate`)
3854
ShootingSystem({ app, engine, inputManager })(),
39-
EnemyDescentSystem(),
55+
EnemyDescentSystem()(),
56+
EnemySpawnSystem({ app, engine })(),
4057
EnemyBulletCollisionSystem
4158
);
4259

@@ -55,7 +72,7 @@ const world = ECS.create<GameEventMap>(
5572
initialPosition.y,
5673
PLAYER_WIDTH,
5774
PLAYER_HEIGHT,
58-
{ isStatic: true }
75+
{ isSensor: true }
5976
);
6077
Matter.World.add(engine.world, playerBody);
6178

examples/space-invaders/src/systems.ts

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@ import {
2020
import { DestroyEnemy, type GameEventMap } from "./events";
2121
import type { InputManager } from "./input-manager";
2222

23+
const playerVelocity = queryRequired({ player: Player, velocity: Velocity });
24+
const playerPosition = queryRequired({ player: Player, position: Position });
25+
2326
const moving = query({ position: Position, velocity: Velocity });
2427
const physics = query({ position: Position, collider: Collider });
2528
const pixiRender = query({ position: Position, sprite: Sprite });
26-
const playerVelocity = queryRequired({ player: Player, velocity: Velocity });
27-
const playerPosition = queryRequired({ player: Player, position: Position });
28-
const bullets = queryRequired({ bullet: Bullet, collider: Collider });
29-
const enemies = queryRequired({ enemy: Enemy, collider: Collider });
30-
const descent = queryRequired({
31-
descentPattern: DescentPattern,
32-
position: Position,
33-
});
29+
const bullets = query({ bullet: Bullet, collider: Collider });
30+
const enemies = query({ enemy: Enemy, collider: Collider });
31+
const descent = query({ descentPattern: DescentPattern, position: Position });
3432

3533
export const MovementSystem: SystemUpdate<GameEventMap> = ({
3634
world,
@@ -75,6 +73,50 @@ export const EnemyDescentSystem = () => {
7573
};
7674
};
7775

76+
export const EnemySpawnSystem = ({
77+
app,
78+
engine,
79+
}: {
80+
app: PIXI.Application;
81+
engine: Matter.Engine;
82+
}) => {
83+
let spawnCooldown = 100;
84+
let lastSpawnTime = Number.MAX_VALUE;
85+
return (): SystemUpdate<GameEventMap> =>
86+
({ deltaTime, createEntity, addComponent }) => {
87+
lastSpawnTime += deltaTime;
88+
89+
if (lastSpawnTime >= spawnCooldown) {
90+
lastSpawnTime = 0;
91+
92+
const enemySprite = new PIXI.Sprite(PIXI.Texture.WHITE);
93+
enemySprite.width = 40;
94+
enemySprite.height = 40;
95+
enemySprite.tint = 0x00ff00;
96+
enemySprite.position.set(Math.random() * 800, 0);
97+
app.stage.addChild(enemySprite);
98+
99+
const enemyBody = Matter.Bodies.rectangle(
100+
enemySprite.x,
101+
enemySprite.y,
102+
40,
103+
40,
104+
{ isSensor: true }
105+
);
106+
Matter.World.add(engine.world, enemyBody);
107+
108+
addComponent(
109+
createEntity(),
110+
new Position({ x: enemySprite.x, y: enemySprite.y }),
111+
new Sprite({ sprite: enemySprite }),
112+
new Collider({ body: enemyBody }),
113+
new Enemy({ health: 3 }),
114+
DescentPattern.zigZag
115+
);
116+
}
117+
};
118+
};
119+
78120
export const EnemyBulletCollisionSystem: SystemUpdate<GameEventMap> = ({
79121
world,
80122
emit,
@@ -104,15 +146,15 @@ export const EnemyDestroySystem =
104146
sprite: Sprite,
105147
})(bulletId);
106148

107-
bulletSprite.sprite.sprite.destroy();
108-
Matter.World.remove(engine.world, bulletSprite.collider.body);
109-
destroyEntity(bulletId);
110-
111149
const enemySprite = getComponentRequired({
112150
enemy: Enemy,
113151
collider: Collider,
114152
sprite: Sprite,
115-
})(bulletId);
153+
})(enemyId);
154+
155+
bulletSprite.sprite.sprite.destroy();
156+
Matter.World.remove(engine.world, bulletSprite.collider.body);
157+
destroyEntity(bulletId);
116158

117159
enemySprite.sprite.sprite.destroy();
118160
Matter.World.remove(engine.world, enemySprite.collider.body);
@@ -152,7 +194,7 @@ export const ShootingSystem = ({
152194

153195
const bulletPosition = new Position({
154196
x: position.x,
155-
y: position.y + 10,
197+
y: position.y - 10,
156198
});
157199

158200
const bulletSprite = new PIXI.Sprite(PIXI.Texture.WHITE);

0 commit comments

Comments
 (0)