Source file unity-csharp/arcade-classics/pong/PongMatch.cs from the GDnD code examples. Download raw file
// GDnD wiki example
// Demonstrates: the game loop owning score and serve state, and subscribing to a ball event
// Related pages: [[overview-arcade-classics-as-learning-projects]], [[unity-gamemanager-pattern]], [[observer-pattern]]
using UnityEngine;
// Minimal match controller: owns the two scores, serves the ball, and re-serves
// after each point. This is the smallest version of the central-state ownership
// idea that grows into [[unity-gamemanager-pattern]] in later projects.
public class PongMatch : MonoBehaviour
{
[SerializeField] private Ball2D ball;
[SerializeField] private int pointsToWin = 11;
public int LeftScore { get; private set; }
public int RightScore { get; private set; }
private void OnEnable()
{
// Subscribe in OnEnable / unsubscribe in OnDisable to avoid leaks — see [[observer-pattern]].
if (ball != null)
{
ball.Scored += OnScored;
}
}
private void OnDisable()
{
if (ball != null)
{
ball.Scored -= OnScored;
}
}
private void Start()
{
ServeTowardRandomSide();
}
private void OnScored(int direction)
{
// direction +1 → ball exited right, so the left (player) scores, and vice versa.
if (direction > 0)
{
LeftScore++;
}
else
{
RightScore++;
}
Debug.Log($"Score — Left {LeftScore} : {RightScore} Right");
if (LeftScore >= pointsToWin || RightScore >= pointsToWin)
{
Debug.Log(LeftScore > RightScore ? "Left player wins!" : "Right player wins!");
LeftScore = 0;
RightScore = 0;
}
// Serve toward the player who just conceded.
ball.Serve(direction > 0 ? +1 : -1);
}
private void ServeTowardRandomSide()
{
ball.Serve(Random.value < 0.5f ? -1 : +1);
}
}