Local Multiplayer
Outloop: Ping Pong is a modular, arcade-style table tennis prototype built in Unity using modern software design principles. This minigame represents one playable activity inside a larger open-world game concept Iโm developing titled Outloop.
The game supports local multiplayer, charged hits, directional control via analog stick input, and modular gameplay logic using design patterns. The entire gameplay is scalable and cleanly structured for future enhancements like AI opponents or online multiplayer.
Strategy
and Command
patternsSince the initial prototype launched on July 30th, Iโve taken Outloop: Ping Pong all the way to MVP status, completing the full game loop. This update represents the first playable vertical slice of the game and reflects an enormous boost in technical depth, polish, and responsiveness.
Major Improvements:
The result is a rock-solid MVP thatโs fun, reactive, and built with scalability in mind. The gameplay loop is now fully playable with clear rules and round transitions โ all crafted through modular, testable code. ๐ฏ
You can read the full design outline and long-term vision for this game in the GDD: Outloop โ Ping Pong (PDF).
This was the initial playable slice where I established player movement, hit detection, and ball interaction โ the foundation for the full game loop. Below is the gameplay footage and core code used to build the prototype.
BallController.cs โ Controls the behavior of the ping pong ball, including force application, max speed clamping, and resets.
public void Serve(Vector3 direction, float speed)
{
if (isServed) return;
rb.useGravity = true;
rb.AddForce(direction * speed);
isServed = true;
}
IBallHitStrategy & SimpleHitStrategy.cs โ Allows different hit types (e.g., lob, curve, smash) to be defined and swapped modularly.
public interface IBallHitStrategy
{
void ApplyHit(Rigidbody ballRb, Transform paddle, float charge, float inputDir);
}
HitDetector.cs โ Detects input, charge state, and triggers hit logic if the ball is within range.
if (isCharging && inRange && InputReleased)
{
float charge = Mathf.Clamp01(chargeTime / maxCharge);
hitStrategy.ApplyHit(ballRb, paddleTransform, charge, inputDirection);
}
Command Pattern: InputHandler delegates player input using ICommand
implementations like MoveCommand
, enabling decoupled, testable player movement logic.
public class MoveCommand : ICommand
{
public void Execute(Vector2 input) => paddle.SetDirection(input);
}
This project is being expanded into a modular collection of minigames within the larger Outloop universe. The goal is to demonstrate flexible, maintainable systems design within Unity โ with gameplay always feeling responsive and fun.