Skip to content

Commit cc98bdf

Browse files
committed
Refactor: Apply SRP to enhance game architecture
Decompose monolithic Game class into multiple specialized classes to adhere to the Single Responsibility Principle. This improves modularity, testability, and maintainability. Changes include: - **GameWindow.java**: New class to manage the main JFrame, application setup, and includes the `main` method. Replaces GUI setup aspects of the original Game class. - **GameManager.java**: New class responsible for all game logic, state management (score, game over, entity states), game loop timers, and collision detection. Extracts core game mechanics from the original Game class. - **GamePanel.java**: Refactored from `DrawPanel`. Now solely responsible for rendering all game elements (dinosaur, cacti, environment, UI text) based on data from GameManager. Drawing methods moved here from the original Game class. - **Dinosaur.java**: New entity class to manage the state and behavior (e.g., jump logic) of the player's dinosaur. - **Cactus.java**: New entity class (replaces inner class `MyGraph`) to manage the state and properties of cactus obstacles. - **InputHandler.java**: New class dedicated to processing keyboard inputs and translating them into game actions for GameManager. Replaces KeyListener implementation in the original Game class and input action in DrawPanel. - Removed direct drawing, game logic, and input handling responsibilities from the original Game class structure. The `Game.unit` constant is temporarily kept but should ideally move to a Constants class or relevant configuration. This refactoring makes each component of the game more focused, easier to understand, test in isolation, and modify without impacting unrelated parts of the system.
1 parent 40c977a commit cc98bdf

File tree

8 files changed

+546
-354
lines changed

8 files changed

+546
-354
lines changed

Dino_Game_java/Cactus.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package Dino_Game_java;
2+
3+
import java.awt.Rectangle;
4+
5+
// Represents a Cactus entity
6+
class Cactus {
7+
private int x, y, h, p; // x, y position, height, thickness parameter
8+
// Assuming p relates to width calculation. Need a clear definition.
9+
// For simplicity, let's define a width.
10+
private int width;
11+
12+
public Cactus(int x, int y, int h, int p) {
13+
this.x = x;
14+
this.y = y; // y is typically the top-left corner for rendering
15+
this.h = h;
16+
this.p = p;
17+
// Approximate width based on draw() method in original code (p*2 for central part)
18+
// and draw2() which adds more parts. This needs refinement based on exact drawing.
19+
this.width = p * 6; // A rough estimate for collision
20+
}
21+
22+
public void move(int deltaX) {
23+
this.x += deltaX;
24+
}
25+
26+
public int getX() { return x; }
27+
public int getY() { return y; }
28+
public int getH() { return h; }
29+
public int getP() { return p; }
30+
public int getWidth() { return width; } // For collision detection
31+
32+
public Rectangle getBounds() {
33+
// Bounds for collision. Assuming x,y is top-left of the main central pillar.
34+
// The actual drawn shape is more complex. This is a simplification.
35+
return new Rectangle(x, y, p * 2, h); // Central part of main cactus segment
36+
}
37+
}

Dino_Game_java/Dinosaur.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package Dino_Game_java;
2+
3+
import java.awt.Rectangle;
4+
5+
// Represents the Dinosaur entity
6+
class Dinosaur {
7+
private int x, y; // Current position
8+
private int initialY;
9+
private int jumpHeight = 280; // Max height of jump from initialY
10+
private int jumpSpeed = 20;
11+
private boolean jumping = false;
12+
private boolean jumpAscending = false; // True if going up, false if going down
13+
private int width = 5 * Game.unit; // Approximate width
14+
private int height = 10 * Game.unit; // Approximate height (can be more precise)
15+
16+
public Dinosaur(int x, int y) {
17+
this.x = x;
18+
this.y = y;
19+
this.initialY = y;
20+
}
21+
22+
// Initiates the jump sequence
23+
public void startJump() {
24+
if (!jumping) {
25+
jumping = true;
26+
jumpAscending = true;
27+
}
28+
}
29+
30+
// Updates the dinosaur's Y position during a jump
31+
public void updateJump() {
32+
if (jumping) {
33+
if (jumpAscending) {
34+
y -= jumpSpeed; // Move up
35+
if (y <= initialY - jumpHeight) { // Reached peak
36+
y = initialY - jumpHeight;
37+
jumpAscending = false; // Start descending
38+
}
39+
} else {
40+
y += jumpSpeed; // Move down
41+
if (y >= initialY) { // Landed
42+
y = initialY;
43+
jumping = false; // Jump finished
44+
}
45+
}
46+
}
47+
}
48+
49+
public boolean canJump() {
50+
return !jumping;
51+
}
52+
53+
public boolean isJumping() {
54+
return jumping;
55+
}
56+
57+
public int getX() { return x; }
58+
public int getY() { return y; }
59+
public Rectangle getBounds() {
60+
// More accurate bounds needed based on actual drawing
61+
// This is a placeholder
62+
return new Rectangle(x - 2 * Game.unit, y - 16 * Game.unit, 11 * Game.unit, 17 * Game.unit);
63+
}
64+
}

Dino_Game_java/Game.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Static unit from original Game class, can be moved to a Constants class or GameWindow
2+
class Game { // Keep this for unit, or move Game.unit to a Constants file.
3+
static int unit = 10;
4+
}

Dino_Game_java/GameManager.java

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package Dino_Game_java;
2+
3+
import java.awt.event.ActionEvent;
4+
import java.awt.event.ActionListener;
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.Random;
8+
import javax.swing.Timer;
9+
10+
// Manages the game state and logic
11+
class GameManager {
12+
public static final int GROUND_Y = 400; // Y position of the ground
13+
public static final int DINO_INITIAL_X = 180; // Initial X position of the dino
14+
15+
private Dinosaur dinosaur;
16+
private List<Cactus> cacti;
17+
private boolean gameOver;
18+
private int score; // Or use 'jump' variable if it represents horizontal scroll/score
19+
private Timer gameLoopTimer;
20+
private Timer dinoJumpTimer;
21+
22+
private GamePanel gamePanel; // Reference to GamePanel for repaint calls
23+
24+
public GameManager(GamePanel panel) {
25+
this.gamePanel = panel;
26+
this.dinosaur = new Dinosaur(DINO_INITIAL_X, GROUND_Y);
27+
this.cacti = new ArrayList<>();
28+
this.gameOver = false;
29+
this.score = 0;
30+
initTimers();
31+
spawnInitialCacti();
32+
}
33+
34+
private void initTimers() {
35+
// Game loop timer (moves cacti, checks collisions, updates score)
36+
gameLoopTimer = new Timer(40, new ActionListener() {
37+
@Override
38+
public void actionPerformed(ActionEvent e) {
39+
if (!gameOver) {
40+
updateGame();
41+
gamePanel.repaint(); // Request repaint from GamePanel
42+
}
43+
}
44+
});
45+
46+
// Dinosaur jump animation timer
47+
dinoJumpTimer = new Timer(80, new ActionListener() {
48+
@Override
49+
public void actionPerformed(ActionEvent e) {
50+
if (!gameOver) {
51+
dinosaur.updateJump();
52+
if (!dinosaur.isJumping()) { // Stop this timer if jump is complete
53+
// Potentially stop dinoJumpTimer if onEnterPresses is false
54+
}
55+
gamePanel.repaint(); // Request repaint
56+
}
57+
}
58+
});
59+
}
60+
61+
// Spawns initial set of cacti
62+
private void spawnInitialCacti() {
63+
cacti.clear(); // Clear existing cacti
64+
Random rr = new Random();
65+
int nbr = 2; // Number of cacti
66+
int x_start = 600; // Initial x position for the first cactus
67+
int spacing = 300; // Spacing between cacti
68+
69+
for (int it = 0; it < nbr; it++) {
70+
Random r = new Random();
71+
int step = r.nextInt(10) + 1; // For varied height/size
72+
int cactusX = x_start + it * (spacing + r.nextInt(100)); // Add some random spacing
73+
int h_ = 10 + (6 * step) + 2;
74+
int y_ = GROUND_Y - h_; // Position relative to ground
75+
int p_ = 8 + step / 2;
76+
cacti.add(new Cactus(cactusX, y_, h_, p_));
77+
}
78+
}
79+
80+
// Main game update logic
81+
public void updateGame() {
82+
if (gameOver) return;
83+
84+
score += 10; // Represents horizontal scroll or actual score
85+
86+
// Move cacti and check for despawn/respawn
87+
List<Cactus> cactiToRemove = new ArrayList<>();
88+
boolean needsRespawn = false;
89+
for (Cactus cactus : cacti) {
90+
cactus.move(-10); // Move cactus to the left
91+
if (cactus.getX() + cactus.getWidth() < 0) { // If cactus is off-screen
92+
cactiToRemove.add(cactus);
93+
needsRespawn = true;
94+
}
95+
}
96+
cacti.removeAll(cactiToRemove);
97+
98+
if (needsRespawn || cacti.isEmpty()) {
99+
// Simple respawn logic: add one new cactus far to the right
100+
Random r = new Random();
101+
int step = r.nextInt(10) + 1;
102+
int h_ = 10 + (6 * step) + 2;
103+
// Place new cactus off-screen to the right
104+
cacti.add(new Cactus(GameWindow.D_W + r.nextInt(200), GROUND_Y - h_, h_, 8 + step / 2));
105+
}
106+
107+
// Check for collisions
108+
for (Cactus cactus : cacti) {
109+
if (dinosaur.getBounds().intersects(cactus.getBounds())) {
110+
gameOver = true;
111+
// Stop timers on game over
112+
gameLoopTimer.stop();
113+
dinoJumpTimer.stop();
114+
break;
115+
}
116+
}
117+
}
118+
119+
// Starts the game timers
120+
public void startGame() {
121+
if (!gameLoopTimer.isRunning()) {
122+
gameLoopTimer.start();
123+
}
124+
// dinoJumpTimer is started by dinosaur.jump()
125+
}
126+
127+
// Initiates dinosaur jump
128+
public void dinoJump() {
129+
if (!gameOver && dinosaur.canJump()) {
130+
dinosaur.startJump();
131+
if (!dinoJumpTimer.isRunning()) { // Start jump timer if not already running
132+
dinoJumpTimer.start();
133+
}
134+
}
135+
}
136+
137+
// Resets the game state
138+
public void restartGame() {
139+
this.gameOver = false;
140+
this.score = 0;
141+
this.dinosaur = new Dinosaur(DINO_INITIAL_X, GROUND_Y); // Reset dinosaur
142+
spawnInitialCacti(); // Respawn cacti
143+
startGame(); // Restart timers
144+
gamePanel.repaint(); // Request repaint
145+
}
146+
147+
// Getters for rendering
148+
public Dinosaur getDinosaur() { return dinosaur; }
149+
public List<Cactus> getCacti() { return cacti; }
150+
public boolean isGameOver() { return gameOver; }
151+
public int getScore() { return score; }
152+
}

0 commit comments

Comments
 (0)