How to Create a Simple Pong Game in Batch Script
Pong is the foundational benchmark for interactive game programming. Moving beyond Snake (which only moves in 4 cardinal directions and snaps to a grid), Pong requires vector mathematics, tracking an object moving diagonally across an X/Y plane and reversing its velocity exactly when it impacts a wall or a paddle.
Achieving this natively inside a standard Windows Command Prompt without external graphics libraries is an incredible demonstration of loop architecture, variable manipulation, and real-time input.
In this guide, we will demonstrate the core physics engine required to build a single-player "wall-bounce" Pong game natively in Batch.
The Strategy: Velocity Variables
- The Ball (X, Y): Define the starting coordinates of the ball.
- The Velocity (dx, dy): Define the ball's speed and direction.
dx=1means the ball moves right 1 space per frame.dy=1means it moves down 1 space per frame. - The Paddle (Y): Track the paddle's vertical position on the left side of the screen.
- The Box Engine: Loop through the entire terminal screen (
colsxlines). If the current coordinate matches the ball, draw anO. If it matches the paddle, draw a#. - Collision Physics: Every frame,
X = X + dx. IfXhits the right wall (X >= width), we instantly reverse the velocitydx = -dx. This creates a perfect angle bounce. IfXhits the left wall (the paddle column) and it isn't overlapping the paddle, you lose.
Implementation Script (Physics Engine)
This script provides the foundational moving-ball and paddle-collision engine using standard Batch. Because it relies on cls for redrawing the screen, visible flickering is expected in cmd.exe. Windows Terminal handles it slightly better. A true production Pong game would use ANSI escape sequences to eliminate flicker, as described in the Advanced Techniques section below.
@echo off
setlocal EnableDelayedExpansion
mode con: cols=42 lines=22
title Batch Pong Engine
color 0E
:NewGame
set "width=38"
set "height=15"
set /a "ballX=width / 2"
set /a "ballY=height / 2"
set "dx=1"
set "dy=1"
set /a "padY=height / 2"
set "padSize=2"
set "score=0"
set "missed=0"
:GameLoop
set /a "padTop=padY - padSize"
set /a "padBot=padY + padSize"
if !padTop! lss 1 set "padTop=1"
if !padBot! gtr !height! set "padBot=!height!"
cls
echo ==========================================
echo PONG Score: !score! W=Up S=Down
echo ==========================================
for /l %%y in (1,1,!height!) do (
set "row=|"
for /l %%x in (1,1,!width!) do (
set "cell= "
if %%x equ 1 (
if %%y geq !padTop! (
if %%y leq !padBot! (
set "cell=#"
)
)
)
if %%x equ !width! (
set "cell=|"
)
if %%x equ !ballX! (
if %%y equ !ballY! (
set "cell=O"
)
)
set "row=!row!!cell!"
)
echo !row!
)
echo ==========================================
choice /c WSN /n /t 1 /d N >nul 2>&1
set "input=!errorlevel!"
if "!input!"=="1" (
set /a "newPadY=padY - 1"
set /a "newTop=newPadY - padSize"
if !newTop! geq 1 (
set "padY=!newPadY!"
)
)
if "!input!"=="2" (
set /a "newPadY=padY + 1"
set /a "newBot=newPadY + padSize"
if !newBot! leq !height! (
set "padY=!newPadY!"
)
)
set /a "padTop=padY - padSize"
set /a "padBot=padY + padSize"
if !padTop! lss 1 set "padTop=1"
if !padBot! gtr !height! set "padBot=!height!"
set /a "ballX=ballX + dx"
set /a "ballY=ballY + dy"
if !ballX! lss 1 set "ballX=1"
if !ballX! gtr !width! set "ballX=!width!"
if !ballY! lss 1 set "ballY=1"
if !ballY! gtr !height! set "ballY=!height!"
if !ballY! leq 1 (
set "dy=1"
set "ballY=1"
)
if !ballY! geq !height! (
set "dy=-1"
set "ballY=!height!"
)
if !ballX! geq !width! (
set "dx=-1"
set "ballX=!width!"
)
if !ballX! leq 1 (
set "hitPad=0"
if !ballY! geq !padTop! (
if !ballY! leq !padBot! (
set "hitPad=1"
)
)
if "!hitPad!"=="1" (
set "dx=1"
set "ballX=1"
set /a "score=score + 1"
)
if "!hitPad!"=="0" (
set "missed=1"
)
)
if "!missed!"=="1" goto GameOver
goto GameLoop
:GameOver
cls
echo ==========================================
echo GAME OVER!
echo ==========================================
echo.
echo You missed the ball!
echo Final Score: !score!
echo.
set "retry="
set /p "retry= Play Again? (Y/N): "
if /i "!retry!"=="Y" (
set "missed=0"
goto NewGame
)
echo.
echo Thanks for playing!
pause
exit /b
How It Works
- Velocity Vector Modification: The beauty of Pong lies in vector math. By updating the ball's coordinates (
ballX += dx,ballY += dy) unconditionally on every frame, the ball moves diagonally. When the ball hits the top boundary (ballY leq 1), settingdy=1forces it to move downwards on the next frame while preservingdx(the horizontal momentum). This creates natural angle bouncing off walls. - Paddle Bounds Checking: The paddle is 3 cells tall, defined by a center position (
padY) and a configurable half-size (padSize=1). The bounds (padTop = padY - padSize,padBot = padY + padSize) are recalculated after each paddle movement. Before the paddle moves, the script verifies that the new top or bottom edge stays within the playing field, preventing the paddle from extending past the walls. choice /c WSN /t 1 /d N: This enables real-time input without blocking indefinitely.choice /c WSNrestricts valid keys to W (up), S (down), and N (no action). The/t 1parameter waits up to 1 second for a keypress before timing out. The/d Nparameter automatically selects N if the timer expires, so the paddle remains still when no key is pressed. Theerrorlevelis checked from highest to lowest because Batch'sif errorlevel Nevaluates as "errorlevel >= N."- Paddle Collision at Column 1: The paddle occupies column 1 (X=1). The collision check triggers when
ballX leq 1, meaning the ball has reached the paddle column. If the ball's Y coordinate falls within the paddle's range (padToptopadBot), the ball bounces right (dx=1). If not, the game ends. This ensures the ball visually touches the paddle before bouncing, rather than reversing direction one cell away.
Why is Full Pong so Difficult in Batch?
While the engine above handles single-ball, single-paddle physics, a fully-featured Pong game presents additional challenges in Batch:
- Two-player input: Batch's
choicecommand captures only one keypress per frame. Handling two paddles simultaneously (Player 1 with W/S, Player 2 with I/K) is not possible natively, only the first key pressed is registered. - Ball speed scaling: Increasing difficulty by making the ball move faster than 1 cell per frame introduces the risk of the ball "tunneling" through the paddle without triggering a collision check.
- Screen flickering: The
clsapproach causes the entire screen to flash blank between frames. The rendering loop (38 × 15 = 570 cell evaluations per frame) is inherently slow in Batch, compounding the flicker.
Advanced Techniques
To reduce flickering, advanced Batch developers use ANSI escape sequences supported by Windows Terminal. Instead of clearing the entire screen with cls and rebuilding every character, the escape sequence ESC[H (cursor home) repositions the cursor to the top-left corner. The frame is then overwritten in place, eliminating the blank-screen flash. Combined with writing each row as a single echo statement (as this script already does), this approach significantly reduces visual artifacts.
Conclusion
Building a Pong physics engine fundamentally bridges algorithmic scripting and applied mathematics. Teaching a command-line utility to understand X/Y boundaries, vector inversions, and multi-coordinate boundary bounding boxes (if Y >= Top and Y <= Bottom) natively empowers developers to translate almost any physical interaction digitally across arbitrary 2D grids.