# Title
**Java Snake Game (Swing) — Case Study**
---
# Introduction of the Game
A lightweight, beginner-friendly Snake game implemented in Java using **Swing/AWT**. The g
---
# About the Game
* Desktop (Swing) application.
* Grid-based movement (snake moves by fixed DOT_SIZE steps).
* Uses a Swing `Timer` for the game loop (actionPerformed → update → repaint).
* Two Java classes in `src/com/zetcode`: `Snake` (main JFrame) and `Board` (game logic + r
---
# Features of the Game
* Arrow-key controls (left/right/up/down) with direction-locking to avoid immediate revers
* Random placement of apples (food).
* Snake grows when it eats an apple.
* Collision detection: self-collision and wall collision → game over.
* Simple sprite rendering using `ImageIcon` and `[Link]`.
* Timer-driven deterministic update loop (DELAY). ([GitHub][2])
---
# Flowchart of the Game (ASCII)
```
[Start]
↓
[Init UI + loadImages + initGame]
↓
[Start Timer -> Game Loop]
↓
[On Timer tick]
↓
[1) process input (key adapter updates direction)]
↓
[2) move snake body positions]
↓
[3) check if apple eaten -> if yes increase dots + place new apple]
↓
[4) check collisions (self/walls) -> if collision stop timer & set inGame=false]
↓
[5) repaint() -> paintComponent() -> draw images or draw "Game Over"]
↓
[Repeat until inGame == false]
↓
[End]
```
(You can convert this to a UML activity diagram for the report.)
---
# Architecture (component-level)
* **UI Layer**: `Snake` (JFrame) — creates window and adds the `Board` JPanel.
* **Game Layer**: `Board` (JPanel) — contains game state arrays, logic for movement, colli
* **Event Layer**: `TAdapter` (inner class of `Board`) — keyboard events to change directi
* **Timing**: `[Link]` used to trigger repeated updates via `actionPerformed`.
* **Resources**: `src/resources/*` — images (`[Link]`, `[Link]`, `[Link]`) used in r
---
# Frontend and Backend Chart
(For a simple Swing game the distinction is conceptual: frontend == view + input; backend
| Layer |
| ---------------------------- | ---------------------------------------------------------
| Frontend (View + Input) | Window, re
| Backend (Game state & Logic) | Snake body array, apple coordinates, collision detection,
---
# Files in `src` (and explanation + code)
Below are the two Java source files in `src/com/zetcode` used by the repo. I present a rea
---
## 1) `[Link]`
**Purpose:** Application entry point — creates the main JFrame window and places the `Boar
**Code:**
```java
package [Link];
import [Link];
import [Link];
public class Snake extends JFrame {
public Snake() {
initUI();
}
private void initUI() {
add(new Board());
setResizable(false);
pack();
setTitle("Snake");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
[Link](() -> {
JFrame ex = new Snake();
[Link](true);
});
}
}
```
**Explanation (short):**
* `main` schedules UI creation on the EDT (`[Link]`).
* The `Snake` frame adds a `Board` instance (the game canvas), disables resizing (so colli
**Source:** repository raw file. ([GitHub][1])
---
## 2) `[Link]`
**Purpose:** All game logic, rendering, key handling, timer, and resource loading. This cl
**Code (readable):**
```java
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class Board extends JPanel implements ActionListener {
private final int B_WIDTH = 300;
private final int B_HEIGHT = 300;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 900;
private final int RAND_POS = 29;
private final int DELAY = 140;
private final int x[] = new int[ALL_DOTS];
private final int y[] = new int[ALL_DOTS];
private int dots;
private int apple_x;
private int apple_y;
private boolean leftDirection = false;
private boolean rightDirection = true;
private boolean upDirection = false;
private boolean downDirection = false;
private boolean inGame = true;
private Timer timer;
private Image ball;
private Image apple;
private Image head;
public Board() {
initBoard();
}
private void initBoard() {
addKeyListener(new TAdapter());
setBackground([Link]);
setFocusable(true);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
loadImages();
initGame();
}
private void loadImages() {
ImageIcon iid = new ImageIcon("src/resources/[Link]");
ball = [Link]();
ImageIcon iia = new ImageIcon("src/resources/[Link]");
apple = [Link]();
ImageIcon iih = new ImageIcon("src/resources/[Link]");
head = [Link]();
}
private void initGame() {
dots = 3;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();
timer = new Timer(DELAY, this);
[Link]();
}
@Override
public void paintComponent(Graphics g) {
[Link](g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
[Link](apple, apple_x, apple_y, this);
for (int z = 0; z < dots; z++) {
if (z == 0) {
[Link](head, x[z], y[z], this);
} else {
[Link](ball, x[z], y[z], this);
}
}
[Link]().sync();
} else {
gameOver(g);
}
}
private void gameOver(Graphics g) {
String msg = "Game Over";
Font small = new Font("Helvetica", [Link], 14);
FontMetrics metr = getFontMetrics(small);
[Link]([Link]);
[Link](small);
[Link](msg, (B_WIDTH - [Link](msg)) / 2, B_HEIGHT / 2);
}
private void checkApple() {
if ((x[0] == apple_x) && (y[0] == apple_y)) {
dots++;
locateApple();
}
}
private void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (leftDirection) {
x[0] -= DOT_SIZE;
}
if (rightDirection) {
x[0] += DOT_SIZE;
}
if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}
private void checkCollision() {
for (int z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}
if (y[0] >= B_HEIGHT) {
inGame = false;
}
if (y[0] < 0) {
inGame = false;
}
if (x[0] >= B_WIDTH) {
inGame = false;
}
if (x[0] < 0) {
inGame = false;
}
if (!inGame) {
[Link]();
}
}
private void locateApple() {
int r = (int) ([Link]() * RAND_POS);
apple_x = (r * DOT_SIZE);
r = (int) ([Link]() * RAND_POS);
apple_y = (r * DOT_SIZE);
}
@Override
public void actionPerformed(ActionEvent e) {
if (inGame) {
checkApple();
checkCollision();
move();
}
repaint();
}
private class TAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
int key = [Link]();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
}
}
}
```
**Explanation (short, focused on OOP):**
* `Board` encapsulates state arrays `x[], y[]` representing snake segment coordinates.
* `dots` stores current snake length (number of visible segments).
* Movement implemented by shifting array indices upward (`x[z] = x[z-1]`) — a common simpl
* Direction booleans encode the current direction; input handling sets them with reversal
* Collision logic uses coordinate equality checks (simple and deterministic).
* Rendering is immediate mode: `paintComponent` → `doDrawing` draws apple and snake parts
* `Timer` serves as the game loop driving `actionPerformed` updates at fixed DELAY.
**Source:** repository raw file. ([GitHub][2])
---
# Summary Table (quick reference)
| File | Role | Key methods/fields
| ----------------- | ---------------------- | -------------------------------------------
| `[Link]` | App entry / JFrame | `main`, `initUI()`
| `[Link]` | Game logic + rendering | `initGame()`, `move()`, `checkApple()`, `ch
| `resources/*.png` | Visual assets | `[Link]`, `[Link]`, `[Link]`
Sources: repo raw files and README/tutorial. ([GitHub][1])
---
# Output Explanation (what you see when you run it)
1. The application window titled **"Snake"** opens with a 300×300 black board.
2. A single apple image is drawn at a random grid coordinate (multiples of 10).
3. The snake (head image + body images) starts with length 3 at initial coordinates.
4. Arrow keys move the snake. On each Timer tick: input is read (via state booleans), `mov
5. On game over the string "Game Over" is centered in white. ([GitHub][2])
---
# Conclusion (critical, no-nonsense)
This implementation is intentionally minimal and educational — perfect for demonstrating c
* **Hard-coded magic numbers**: Board size, DOT_SIZE, RAND_POS, DELAY are constants in `Bo
* **Tight coupling to file paths**: `ImageIcon("src/resources/...")` expects a specific wo
* **Array-based snake with fixed max length** (`ALL_DOTS = 900`) — better to use dynamic `
* **No separation of model vs view**: `Board` mixes rendering and logic. For larger projec
* **No score tracking or restart mechanic**: No `score` field, no way to restart without r
* **Collision precision**: Uses exact equality of pixel coordinates; reliant on consistent
* **Input handling** relies on booleans and KeyAdapter; consider buffering direction chang
Include these critiques in your "Improvements" subsection — they show you can think beyond
---
# SDG Mapping
* **SDG 4 — Quality Education**: The project is a learning resource teaching programming,
* **SDG 9 — Industry, Innovation and Infrastructure**: Demonstrates software prototyping a
(Explain in your submission how this small educational repo supports learning and technica