
This article documents rebuilding the classic game Pong using Unity’s Entity Component System (ECS) framework. The game features a ball and two paddles—one player-controlled, one AI-controlled—where players earn points when opponents miss the ball.
Entity Components
The implementation defines four key component structures:


[GenerateAuthoringComponent]
public struct PongPaddle : IComponentData { }
[GenerateAuthoringComponent]
public struct Ball : IComponentData { }
[GenerateAuthoringComponent]
public struct AI : IComponentData { }
[GenerateAuthoringComponent]
public struct Speed : IComponentData
{
public float value;
}
Player Paddle Movement System
The player paddle responds to vertical input (up/down axes) and constrains movement within bounds:
public class PongPaddleMovementSystem : SystemBase
{
protected override void OnUpdate()
{
float movement = Input.GetAxis("Vertical");
float dt = Time.DeltaTime;
Entities.WithAll<Player, PongPaddle>()
.ForEach((ref Translation translation, in Speed speed) => {
translation.Value.y += dt * movement * speed.value;
translation.Value.y = math.clamp(translation.Value.y, -4, 4);
}).Schedule();
}
}
AI Paddle Movement
The AI paddle tracks the ball’s Y-position with a dead zone to prevent constant jittering:
public class PongAIPaddleMovementSystem : SystemBase
{
protected override void OnUpdate()
{
float deltaTime = Time.DeltaTime;
float3 ballPos = EntityManager.CreateEntityQuery(
typeof(Translation), typeof(Ball))
.GetSingleton<Translation>().Value;
Entities.WithAll<AI>()
.ForEach((ref Translation translation, in Speed speed) => {
float dist = math.abs(ballPos.y - translation.Value.y);
float dir = math.select(-1, 1, ballPos.y > translation.Value.y);
dir = math.select(0, dir, dist > 0.3f);
translation.Value.y += speed.value * deltaTime * dir;
translation.Value.y = math.clamp(translation.Value.y, -4, 4);
}).Schedule();
}
}
Scoring System
The scoring system determines points based on ball position relative to paddles:
public class ScoreCalculationSystem : SystemBase
{
GameHandler m_handler;
protected override void OnUpdate()
{
// Queries retrieve ball and paddle positions
// If ball.x <= player.x, AI scores
// If ball.x >= ai.x, player scores
}
}
Suggested Enhancements
- Advanced physics reflection based on paddle contact location and movement
- Two-player mode with both players controlling dual paddles
- Power-ups triggered when the ball contacts paddles
- Improved AI using trajectory calculations for ball prediction
Source Code
Full implementation available on my GitHub repository.