encompass-cs-docs/content/pong/ball/moving.md

3.2 KiB

title date weight
Moving 2019-05-23T18:10:17-07:00 20

We already have MotionMessages and a MotionEngine. So it seems logical to re-use these structures for our ball.

What is actually going to be sending out the MotionMessages?

What is the main characteristic of the ball in Pong? That's right - it is continuously moving. In other words, it has velocity.

Let's make a VelocityComponent. In game/components/velocity.ts:

import { Component } from "encompass-ecs";

export class VelocityComponent extends Component {
    public x: number;
    public y: number;
}

Let's also create a VelocityEngine.

What does our VelocityEngine actually do? Basically, if something has both a PositionComponent and VelocityComponent, we want the PositionComponent to update based on the VelocityComponent every frame.

It turns out Encompass provides a structure for this pattern, called a Detector. Let's use it now.

In game/engines/velocity.ts:

import { Detector, Emits, Entity } from "encompass-ecs";
import { PositionComponent } from "game/components/position";
import { VelocityComponent } from "game/components/velocity";
import { MotionMessage } from "game/messages/component/motion";

@Emits(MotionMessage)
@Detects(PositionComponent, VelocityComponent)
export class VelocityEngine extends Detector {
    protected detect(entity: Entity) {
        const position_component = entity.get_component(PositionComponent);
        const velocity_component = entity.get_component(VelocityComponent);

        const motion_message = this.emit_component_message(MotionMessage, position_component);
        motion_message.x = velocity_component.x;
        motion_message.y = velocity_component.y;
    }
}

A Detector, like a Spawner, is an engine with one required method: detect.

When an Entity has all of the components specified in @Detects, it begins to track the Entity. Each frame, it calls its detect method on that Entity.

So, our VelocityEngine will track everything with a PositionComponent and VelocityComponent and create a MotionMessage every frame.

Let's add our new Engine to the WorldBuilder:

world_builder.add_engine(VelocityEngine);

And add our new VelocityComponent in the BallSpawner.

const velocity_component = ball_entity.add_component(VelocityComponent);
velocity_component.x = 50;
velocity_component.y = -50;

Actually lets get rid of that magic value by adding velocity to the BallSpawnMessage.

game/messages/ball_spawn.ts

import { Message } from "encompass-ecs";

export class BallSpawnMessage extends Message {
    public x: number;
    public y: number;
    public size: number;
    public x_velocity: number;
    public y_velocity: number;
}

game/engines/spawners/ball.ts

const velocity_component = ball_entity.add_component(VelocityComponent);
velocity_component.x = message.x_velocity;
velocity_component.y = message.y_velocity;

game/game.ts

ball_spawn_message.x_velocity = 50;
ball_spawn_message.y_velocity = -50;

Let's run the game again.

Still pretty boring but we're getting somewhere.