Dodge The Obstacles

1. Introduction

This is a lane-based car dodging game developed in Java Swing. The player controls a car that moves left or right across five lanes to avoid incoming traffic. Each obstacle is a randomly generated vehicle, and the game speeds up over time, increasing the challenge. The game ends upon collision, displaying an explosion effect and the player's score.

The game features animated sprites, multiple obstacle lanes, real-time movement, collision detection, sound effects, and a custom Game Over sequence. Assets include car images, road background, explosion graphics, and sound effects.

2. Key Features

1. Lane Movement: The player moves the car left or right using arrow keys across 5 predefined lanes.
2. Random Obstacle Generation: Obstacles appear randomly in lanes at fixed intervals and scroll downward.
3. Collision Detection: If a player's car overlaps with an obstacle vertically within the same lane, the game ends.
4. Scoring System: Points are awarded when obstacles leave the screen without hitting the player.
5. Sound Feedback: Background sounds include collision, explosion, and scoring beeps.
6. Dynamic Animation: All images are rendered and updated using the paint() method and a Swing Timer.

3. How the Game Logic Works

1. Timer-Driven Updates: A Swing Timer triggers every 10 milliseconds, calling actionPerformed() to update obstacle positions, spawn new ones, and refresh the screen.

2. Obstacle Generation: At every spawn interval, the game randomly chooses which lanes receive new obstacle cars, adding them at the top of the screen.

3. Obstacle Motion: Obstacles in all five lanes are stored in separate ArrayList<Integer>s that track their Y-axis positions. These values are incremented each frame to simulate falling movement.

4. Obstacle Cleanup + Scoring:
    • The method remove_obstacles() runs continuously to check if the first obstacle in each lane has moved off the screen (Y > 600).
    • If so, that obstacle is removed from the list, and the score is incremented.
    • This ensures memory efficiency and prevents unnecessary collision checks on invisible objects.
    • A score sound is played every time an obstacle is successfully dodged.

5. Player Position: The player moves in 100-pixel steps (lane-sized) left or right, and boundaries are enforced to keep the player within the screen limits.

4. How Game Over Works (Collision + Stack Safety)

1. Collision Detection: The check_collision() method calculates the player's vertical boundaries and compares them with the top and bottom Y-coordinates of the nearest 1–2 obstacles in the same lane.
2. Overlap Check: A collision is detected if the obstacle and the player overlap vertically, i.e., if:
    obstacle_top ≤ player_bottom and player_top ≤ obstacle_bottom.

3. Triggering Game Over: When a collision is found, the endGame() method is called.

4. Overlap Prevention: To prevent multiple calls to endGame() (due to frame repaint overlaps or event queue flooding), the following logic is used:
    • The method starts with a guard clause: if (gameOver) return;
    • This ensures that the game logic halts at the first execution and ignores all stacked repaint/collision calls that come after.

5. Game Over Effects: When triggered:
    • The timer stops.
    • The player’s car image changes to an explosion.
    • A “Game Over” dialog is displayed showing the final score.
    • The application exits immediately using System.exit(0).


5. Technical Design Summary

1. Graphics Rendering: All visual updates occur in the overridden paint(Graphics g) method, redrawing the road, obstacles, and player sprite.
2. Event Handling: The game listens for KeyEvent for player input and ActionEvent for timed updates.
3. Object Management: Obstacles are stored per lane using five ArrayList<Integer> collections that track Y-positions.
4. Sound Engine: Sounds are triggered using AudioInputStream and Clip from javax.sound.sampled.
5. Player Restrictions: The car is prevented from moving out of bounds horizontally by boundary checks before repainting.