--- title: "Scoring" date: 2019-05-30T16:08:54-07:00 weight: 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. ```ts 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. ```ts export enum CollisionType { ball, goal, paddle, wall, } ``` We'll need a new BallGoalCollisionMessage: ```ts 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: ```ts ... 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: ```ts 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: ```ts 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: ```ts 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 ); } } ```