encompass-cs-docs/content/pong/scoring/_index.md

4.2 KiB

title date weight
Scoring 2019-05-30T16:08:54-07:00 1000

In Pong, your opponent scores a point by getting the ball behind your paddle.

There's a couple of things we need to sort out here: 1) tracking and displaying each player's score, and 2) reacting appropriately when a ball collides with a goal (side) boundary.

Let's start by creating a ScoreComponent.

import { Component } from "encompass-ecs";

export class ScoreComponent extends Component {
    public score: number;
    public player_one: boolean;
}

And let's have a new collision type.

export enum CollisionType {
    ball,
    goal,
    paddle,
    wall,
}

We'll need a new BallGoalCollisionMessage:

import { Entity, Message } from "encompass-ecs";

export class BallGoalCollisionMessage extends Message {
    public ball_entity: Entity;
    public goal_entity: Entity;
}

And some dispatch logic in the CollisionDispatchEngine:

...

switch (collision_message.collision_type_one) {
    case CollisionType.ball:
        switch (collision_message.collision_type_two) {
            case CollisionType.goal: {
                const message = this.emit_message(BallGoalCollisionMessage);
                message.ball_entity = collision_message.entity_one;
                message.goal_entity = collision_message.entity_two;
                break;
            }

...

And a new BallGoalCollisionEngine:

import { Engine, Mutates, Reads } from "encompass-ecs";
import { ScoreComponent } from "game/components/score";
import { BallGoalCollisionMessage } from "game/messages/collisions/ball_goal";
import { World } from "lua-lib/bump";

@Reads(BallGoalCollisionMessage)
@Mutates(ScoreComponent)
export class BallGoalCollisionEngine extends Engine {
    private collision_world: World;

    public initialize(collision_world: World) {
        this.collision_world = collision_world;
    }

    public update() {
        for (const message of this.read_messages(BallGoalCollisionMessage).values()) {
            const score_component = this.make_mutable(message.goal_entity.get_component(ScoreComponent));
            score_component.score += 1;

            message.ball_entity.destroy();
            this.collision_world.remove(message.ball_entity);
        }
    }
}

I've decided we should just attach the ScoreComponent directly to the goal entity for simplicity.

We'll need a way to create our goal entities now.

Let's have a new GoalSpawnMessage:

import { Message } from "encompass-ecs";

export class GoalSpawnMessage extends Message {
    public x: number;
    public y: number;
    public width: number;
    public height: number;
    public player_one: boolean;
}

And a new GoalSpawner:

import { Spawner } from "encompass-ecs";
import { BoundingBoxComponent } from "game/components/bounding_box";
import { CollisionType, CollisionTypesComponent } from "game/components/collision_types";
import { PositionComponent } from "game/components/position";
import { ScoreComponent } from "game/components/score";
import { GoalSpawnMessage } from "game/messages/goal_spawn";
import { World } from "lua-lib/bump";

export class GoalSpawner extends Spawner {
    public spawn_message_type = GoalSpawnMessage;

    private collision_world: World;

    public initialize(collision_world: World) {
        this.collision_world = collision_world;
    }

    public spawn(message: GoalSpawnMessage) {
        const entity = this.create_entity();

        const score_component = entity.add_component(ScoreComponent);
        score_component.score = 0;
        score_component.player_one = message.player_one;

        const boundaries = entity.add_component(BoundingBoxComponent);
        boundaries.width = message.width;
        boundaries.height = message.height;

        const position = entity.add_component(PositionComponent);
        position.x = message.x;
        position.y = message.y;

        const collision_types_component = entity.add_component(CollisionTypesComponent);
        collision_types_component.collision_types = [ CollisionType.goal ];

        this.collision_world.add(
            entity,
            message.x - message.width * 0.5,
            message.y - message.height * 0.5,
            message.width,
            message.height
        );
    }
}