Dino Game

This commit is contained in:
2025-10-27 10:50:33 +01:00
parent ac2a283da4
commit 7e839c8069

View File

@@ -7,6 +7,9 @@ import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Random; import java.util.Random;
import javax.sound.sampled.*; import javax.sound.sampled.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DinoGame extends JPanel implements ActionListener, KeyListener { public class DinoGame extends JPanel implements ActionListener, KeyListener {
// Game constants // Game constants
@@ -14,151 +17,178 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
private static final int HEIGHT = 400; private static final int HEIGHT = 400;
private static final int GROUND_Y = 320; private static final int GROUND_Y = 320;
private static final int FPS = 60; private static final int FPS = 60;
private static final int GRAVITY = 2; private static final int GRAVITY = 1;
private static final int JUMP_STRENGTH = -22; private static final int JUMP_STRENGTH = -18;
private static final int INITIAL_SPEED = 10;
// Game state private static final int MAX_SPEED = 20;
private Timer timer; private static final int SPEED_INCREMENT = 1;
private static final int HITBOX_INSET = 8;
private boolean gameStarted = false; private boolean gameStarted = false;
private boolean gameOver = false; private boolean gameOver = false;
private boolean paused = false; private boolean paused = false;
private int score = 0; private int score = 0;
private int highScore = 0; private int highScore = 0;
private double gameSpeed = 12.0; private int gameSpeed = INITIAL_SPEED;
private int frameCount = 0; private int frameCount = 0;
private final int dinoX = 50;
// Player private int dinoY;
private int dinoX = 50; private int dinoWidth;
private int dinoY = GROUND_Y - 90; private int dinoHeight;
private int dinoWidth = 44; private int dinoDuckWidth;
private int dinoHeight = 47; private int dinoDuckHeight;
private int velocityY = 0; private int velocityY = 0;
private boolean isJumping = false; private boolean isJumping = false;
private boolean isDucking = false; private boolean isDucking = false;
private int animFrame = 0; private int animFrame = 0;
private int groundY;
// Images
private BufferedImage dinoRun1, dinoRun2, dinoJump, dinoDead; private BufferedImage dinoRun1, dinoRun2, dinoJump, dinoDead;
private BufferedImage dinoDownRun1, dinoDownRun2; private BufferedImage dinoDownRun1, dinoDownRun2;
private BufferedImage cactus1, cactus2, cactus3, cactus4, cactus5, cactus6; private BufferedImage cactus1, cactus2, cactus3, cactus4, cactus5, cactus6;
private BufferedImage birdFly1, birdFly2; private BufferedImage birdFly1, birdFly2;
private BufferedImage cloud, land, gameOverImg, replayImg, hiImg; private BufferedImage cloud, land, gameOverImg, replayImg, hiImg;
private final ArrayList<Obstacle> obstacles = new ArrayList<>();
// Game objects private final ArrayList<Cloud> clouds = new ArrayList<>();
private ArrayList<Obstacle> obstacles = new ArrayList<>();
private ArrayList<Cloud> clouds = new ArrayList<>();
private int landX = 0; private int landX = 0;
private Random rand = new Random(); private final Random rand = new Random();
private int obstacleTimer = 0; private int obstacleTimer = 0;
private int minObstacleDistance = 60;
// Audio private int maxObstacleDistance = 120;
private Clip jumpSound, deadSound, scoreSound; private Clip jumpSound, deadSound, scoreSound;
private long lastScoreTime = 0;
public DinoGame() { public DinoGame() {
setPreferredSize(new Dimension(WIDTH, HEIGHT)); setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.WHITE); setBackground(Color.WHITE);
setFocusable(true); setFocusable(true);
addKeyListener(this); addKeyListener(this);
setDoubleBuffered(true);
loadImages(); loadAssets();
loadSounds(); for (int i = 0; i < 5; i++) {
loadHighScore(); clouds.add(new Cloud(i * 250 + rand.nextInt(100), 50 + rand.nextInt(100)));
// Initialize clouds
for (int i = 0; i < 3; i++) {
clouds.add(new Cloud(rand.nextInt(WIDTH), 50 + rand.nextInt(100)));
} }
resetGameData();
timer = new Timer(1000 / FPS, this); Timer timer = new Timer(1000 / FPS, this);
timer.start(); timer.start();
} }
private void loadImages() { private void loadAssets() {
try { try {
dinoRun1 = ImageIO.read(getClass().getResourceAsStream("/dino-run-1.png")); loadImages();
dinoRun2 = ImageIO.read(getClass().getResourceAsStream("/dino-run-2.png")); } catch (IOException e) {
dinoJump = ImageIO.read(getClass().getResourceAsStream("/dino-jump.png")); String errorMsg = "Error: cannot load image resources.\n" + e.getMessage();
dinoDead = ImageIO.read(getClass().getResourceAsStream("/dino-dead.png")); System.err.println(errorMsg);
dinoDownRun1 = ImageIO.read(getClass().getResourceAsStream("/dino-down-run-1.png")); JOptionPane.showMessageDialog(this, errorMsg, "Error", JOptionPane.ERROR_MESSAGE);
dinoDownRun2 = ImageIO.read(getClass().getResourceAsStream("/dino-down-run-2.png")); System.exit(1);
}
dinoWidth = dinoRun1.getWidth();
dinoHeight = dinoRun1.getHeight();
dinoDuckWidth = dinoDownRun1.getWidth();
dinoDuckHeight = dinoDownRun1.getHeight();
groundY = GROUND_Y - dinoHeight;
dinoY = groundY;
loadSoundsAndHighScore();
}
cactus1 = ImageIO.read(getClass().getResourceAsStream("/cactus-1.png")); private void loadImages() throws IOException {
cactus2 = ImageIO.read(getClass().getResourceAsStream("/cactus-2.png")); dinoRun1 = loadImage("/dino-run-1.png");
cactus3 = ImageIO.read(getClass().getResourceAsStream("/cactus-3.png")); dinoRun2 = loadImage("/dino-run-2.png");
cactus4 = ImageIO.read(getClass().getResourceAsStream("/cactus-4.png")); dinoJump = loadImage("/dino-jump.png");
cactus5 = ImageIO.read(getClass().getResourceAsStream("/cactus-5.png")); dinoDead = loadImage("/dino-dead.png");
cactus6 = ImageIO.read(getClass().getResourceAsStream("/cactus-6.png")); dinoDownRun1 = loadImage("/dino-down-run-1.png");
dinoDownRun2 = loadImage("/dino-down-run-2.png");
cactus1 = loadImage("/cactus-1.png");
cactus2 = loadImage("/cactus-2.png");
cactus3 = loadImage("/cactus-3.png");
cactus4 = loadImage("/cactus-4.png");
cactus5 = loadImage("/cactus-5.png");
cactus6 = loadImage("/cactus-6.png");
birdFly1 = loadImage("/bird-fly-1.png");
birdFly2 = loadImage("/bird-fly-2.png");
cloud = loadImage("/cloud.png");
land = loadImage("/land.png");
gameOverImg = loadImage("/game-over.png");
replayImg = loadImage("/replay.png");
hiImg = loadImage("/hi.png");
}
birdFly1 = ImageIO.read(getClass().getResourceAsStream("/bird-fly-1.png")); private BufferedImage loadImage(String path) throws IOException {
birdFly2 = ImageIO.read(getClass().getResourceAsStream("/bird-fly-2.png")); InputStream is = getClass().getResourceAsStream(path);
if (is == null) {
cloud = ImageIO.read(getClass().getResourceAsStream("/cloud.png")); throw new IOException("Resource not found: " + path);
land = ImageIO.read(getClass().getResourceAsStream("/land.png")); }
gameOverImg = ImageIO.read(getClass().getResourceAsStream("/game-over.png")); try {
replayImg = ImageIO.read(getClass().getResourceAsStream("/replay.png")); return ImageIO.read(is);
hiImg = ImageIO.read(getClass().getResourceAsStream("/hi.png")); } catch (IOException e) {
} catch (Exception e) { throw new IOException("Cannot read image: " + path, e);
System.err.println("Error loading images: " + e.getMessage());
e.printStackTrace();
} }
} }
private void loadSounds() { private void loadSoundsAndHighScore() {
new Thread(() -> {
try {
jumpSound = loadSound("/jump.wav");
deadSound = loadSound("/dead.wav");
scoreSound = loadSound("/score.wav");
loadHighScore();
} catch (Exception e) {
System.err.println("Error loading sounds and high score: " + e.getMessage());
}
}).start();
}
private Clip loadSound(String path) {
try { try {
jumpSound = AudioSystem.getClip(); InputStream is = getClass().getResourceAsStream(path);
jumpSound.open(AudioSystem.getAudioInputStream(getClass().getResourceAsStream("/jump.wav"))); if (is != null) {
InputStream bufferedIs = new BufferedInputStream(is);
deadSound = AudioSystem.getClip(); AudioInputStream ais = AudioSystem.getAudioInputStream(bufferedIs);
deadSound.open(AudioSystem.getAudioInputStream(getClass().getResourceAsStream("/dead.wav"))); Clip clip = AudioSystem.getClip();
clip.open(ais);
scoreSound = AudioSystem.getClip(); return clip;
scoreSound.open(AudioSystem.getAudioInputStream(getClass().getResourceAsStream("/scoreup.wav"))); }
} catch (Exception e) { } catch (Exception e) {
System.err.println("Error loading sounds: " + e.getMessage()); System.err.println("Cannot load sound: " + path + " - " + e.getMessage());
e.printStackTrace();
} }
return null;
} }
private void loadHighScore() { private void loadHighScore() {
try { try {
InputStream is = getClass().getResourceAsStream("/best-scores.txt"); Path scoreFile = Paths.get(System.getProperty("user.home"), "dino-best-scores.txt");
if (is != null) { if (Files.exists(scoreFile)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String content = new String(Files.readAllBytes(scoreFile));
String line = reader.readLine(); highScore = Integer.parseInt(content.trim());
if (line != null) {
highScore = Integer.parseInt(line.trim());
}
reader.close();
} }
} catch (Exception e) { } catch (Exception e) {
highScore = 0; highScore = 0;
System.err.println("Cannot load high score: " + e.getMessage());
} }
} }
private void saveHighScore() { private void saveHighScore() {
try { new Thread(() -> {
// Save to user's home directory since resources folder is read-only try {
String userHome = System.getProperty("user.home"); Path scoreFile = Paths.get(System.getProperty("user.home"), "dino-best-scores.txt");
File scoresFile = new File(userHome, "dino-best-scores.txt"); Files.write(scoreFile, String.valueOf(highScore).getBytes());
PrintWriter writer = new PrintWriter(new FileWriter(scoresFile)); } catch (IOException e) {
writer.println(highScore); System.err.println("Error saving high score: " + e.getMessage());
writer.close(); }
} catch (IOException e) { }).start();
System.err.println("Error saving high score: " + e.getMessage());
}
} }
private void playSound(Clip clip) { private void playSound(Clip clip) {
if (clip != null) { if (clip != null) {
try { new Thread(() -> {
if (clip.isRunning()) { try {
clip.stop(); if (clip.isRunning()) {
clip.stop();
}
clip.setFramePosition(0);
clip.start();
} catch (Exception e) {
// Silently fail
} }
clip.setFramePosition(0); }).start();
clip.start();
} catch (Exception e) {
System.err.println("Error playing audio: " + e.getMessage());
}
} }
} }
@@ -170,85 +200,99 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
} }
if (!gameOver) { if (!gameOver) {
frameCount++; updateGameLogic();
// Update score
if (frameCount % 6 == 0) {
score++;
if (score % 100 == 0) {
playSound(scoreSound);
}
}
// Increase speed
if (frameCount % 600 == 0) {
gameSpeed += 0.5;
}
// Update dino
if (isJumping) {
velocityY += GRAVITY;
dinoY += velocityY;
if (dinoY >= GROUND_Y - 90) {
dinoY = GROUND_Y - 90;
isJumping = false;
velocityY = 0;
}
}
// Animation
if (frameCount % 5 == 0) {
animFrame = (animFrame + 1) % 2;
}
// Update ground
landX -= (int)gameSpeed;
if (land != null && landX <= -land.getWidth()) {
landX = 0;
}
// Update clouds
for (Cloud c : clouds) {
c.x -= 2;
if (cloud != null && c.x < -cloud.getWidth()) {
c.x = WIDTH + rand.nextInt(200);
c.y = 50 + rand.nextInt(100);
}
}
// Spawn obstacles
obstacleTimer++;
if (obstacleTimer > 60 + rand.nextInt(60)) {
spawnObstacle();
obstacleTimer = 0;
}
// Update obstacles
for (int i = obstacles.size() - 1; i >= 0; i--) {
Obstacle obs = obstacles.get(i);
obs.x -= (int)gameSpeed;
if (obs.x < -obs.width) {
obstacles.remove(i);
} else if (checkCollision(obs)) {
gameOver = true;
playSound(deadSound);
if (score > highScore) {
highScore = score;
saveHighScore();
}
}
}
} }
repaint(); repaint();
} }
private void updateGameLogic() {
frameCount++;
updateScoreAndSpeed();
updatePlayer();
updateEnvironment();
spawnAndMoveObstacles();
}
private void updateScoreAndSpeed() {
if (frameCount % 6 == 0) {
score++;
if (score % 100 == 0) {
long currentTime = System.currentTimeMillis();
if (currentTime - lastScoreTime > 100) {
playSound(scoreSound);
lastScoreTime = currentTime;
}
}
}
if (frameCount % 900 == 0 && gameSpeed < MAX_SPEED) {
gameSpeed += SPEED_INCREMENT;
minObstacleDistance = Math.max(40, 60 - ((gameSpeed - INITIAL_SPEED) * 2));
maxObstacleDistance = Math.max(80, 120 - ((gameSpeed - INITIAL_SPEED) * 3));
}
}
private void updatePlayer() {
if (isJumping) {
velocityY += GRAVITY;
dinoY += velocityY;
if (dinoY >= groundY) {
dinoY = groundY;
isJumping = false;
velocityY = 0;
}
}
int animSpeed = Math.max(3, 6 - ((gameSpeed - INITIAL_SPEED) / 2));
if (frameCount % animSpeed == 0) {
animFrame = (animFrame + 1) % 2;
}
}
private void updateEnvironment() {
landX -= gameSpeed;
if (land != null && landX <= -land.getWidth()) {
landX = 0;
}
for (Cloud c : clouds) {
c.x -= 1;
if (cloud != null && c.x < -cloud.getWidth()) {
c.x = WIDTH + rand.nextInt(200);
c.y = 50 + rand.nextInt(100);
}
}
}
private void spawnAndMoveObstacles() {
obstacleTimer++;
int spawnDelay = minObstacleDistance + rand.nextInt(maxObstacleDistance - minObstacleDistance);
if (obstacleTimer > spawnDelay) {
spawnObstacle();
obstacleTimer = 0;
}
for (int i = obstacles.size() - 1; i >= 0; i--) {
Obstacle obs = obstacles.get(i);
obs.x -= gameSpeed;
if (obs.x < -obs.width) {
obstacles.remove(i);
} else if (checkCollision(obs)) {
gameOver = true;
playSound(deadSound);
if (score > highScore) {
highScore = score;
saveHighScore();
}
}
}
}
private void spawnObstacle() { private void spawnObstacle() {
if (!obstacles.isEmpty()) {
Obstacle last = obstacles.get(obstacles.size() - 1);
if (last.x > WIDTH - 200) {
return;
}
}
int birdChance = Math.min(4, ((gameSpeed - INITIAL_SPEED) / 2) + 2);
int type = rand.nextInt(10); int type = rand.nextInt(10);
if (type < 7) { if (type < (10 - birdChance)) {
// Cactus
BufferedImage[] cacti = {cactus1, cactus2, cactus3, cactus4, cactus5, cactus6}; BufferedImage[] cacti = {cactus1, cactus2, cactus3, cactus4, cactus5, cactus6};
BufferedImage cactusImg = cacti[rand.nextInt(cacti.length)]; BufferedImage cactusImg = cacti[rand.nextInt(cacti.length)];
if (cactusImg != null) { if (cactusImg != null) {
@@ -257,38 +301,66 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
cactusImg, false)); cactusImg, false));
} }
} else { } else {
// Bird
if (birdFly1 != null) { if (birdFly1 != null) {
int birdY = GROUND_Y - 44 - rand.nextInt(2) * 80; int birdHeight = birdFly1.getHeight();
obstacles.add(new Obstacle(WIDTH, birdY, 46, 40, birdFly1, true)); int[] heights = {
GROUND_Y - birdHeight, // Basso
GROUND_Y - birdHeight - 100, // Alto
GROUND_Y - birdHeight - 60 // Medio
};
int birdY = heights[rand.nextInt(heights.length)];
obstacles.add(new Obstacle(WIDTH, birdY,
birdFly1.getWidth(), birdFly1.getHeight(),
birdFly1, true));
} }
} }
} }
private Rectangle getDinoHitbox() {
if (isDucking) {
return new Rectangle(
dinoX + HITBOX_INSET,
GROUND_Y - dinoDuckHeight + HITBOX_INSET,
dinoDuckWidth - 2 * HITBOX_INSET,
dinoDuckHeight - 2 * HITBOX_INSET
);
} else {
return new Rectangle(
dinoX + HITBOX_INSET,
dinoY + HITBOX_INSET,
dinoWidth - 2 * HITBOX_INSET,
dinoHeight - 2 * HITBOX_INSET
);
}
}
private boolean checkCollision(Obstacle obs) { private boolean checkCollision(Obstacle obs) {
int dinoActualHeight = isDucking ? 26 : dinoHeight; Rectangle dinoRect = getDinoHitbox();
int dinoActualY = isDucking ? GROUND_Y - 90 : dinoY; Rectangle obsRect = new Rectangle(
obs.x + HITBOX_INSET,
Rectangle dinoRect = new Rectangle(dinoX + 5, dinoActualY + 5, obs.y + HITBOX_INSET,
dinoWidth - 10, dinoActualHeight - 10); obs.width - 2 * HITBOX_INSET,
Rectangle obsRect = new Rectangle(obs.x + 5, obs.y + 5, obs.height - 2 * HITBOX_INSET
obs.width - 10, obs.height - 10); );
return dinoRect.intersects(obsRect); return dinoRect.intersects(obsRect);
} }
private void resetGameData() {
private void reset() {
gameOver = false;
gameStarted = true;
score = 0; score = 0;
gameSpeed = 12.0; gameSpeed = INITIAL_SPEED;
frameCount = 0; frameCount = 0;
dinoY = GROUND_Y - 90; dinoY = groundY;
velocityY = 0; velocityY = 0;
isJumping = false; isJumping = false;
isDucking = false; isDucking = false;
obstacles.clear(); obstacles.clear();
obstacleTimer = 0; obstacleTimer = 0;
minObstacleDistance = 60;
maxObstacleDistance = 120;
}
private void reset() {
gameOver = false;
gameStarted = true;
resetGameData();
} }
@Override @Override
@@ -296,45 +368,40 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
super.paintComponent(g); super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g; Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
// Draw clouds drawClouds(g2d);
drawGround(g2d);
drawDino(g2d);
drawObstacles(g2d);
drawUI(g2d);
drawOverlays(g2d);
}
private void drawClouds(Graphics2D g2d) {
for (Cloud c : clouds) { for (Cloud c : clouds) {
if (cloud != null) { if (cloud != null) {
g2d.drawImage(cloud, c.x, c.y, null); g2d.drawImage(cloud, c.x, c.y, null);
} }
} }
}
// Draw ground private void drawGround(Graphics2D g2d) {
if (land != null) { if (land != null) {
g2d.drawImage(land, landX, GROUND_Y, null); g2d.drawImage(land, landX, GROUND_Y, null);
g2d.drawImage(land, landX + land.getWidth(), GROUND_Y, null); g2d.drawImage(land, landX + land.getWidth(), GROUND_Y, null);
} }
g2d.setColor(new Color(83, 83, 83));
// Draw ground line
g2d.setColor(Color.BLACK);
g2d.fillRect(0, GROUND_Y - 2, WIDTH, 2); g2d.fillRect(0, GROUND_Y - 2, WIDTH, 2);
}
// Draw dino private void drawDino(Graphics2D g2d) {
BufferedImage dinoImg; BufferedImage dinoImg = getDinoImage();
if (gameOver) {
dinoImg = dinoDead;
} else if (isJumping) {
dinoImg = dinoJump;
} else if (isDucking) {
dinoImg = (animFrame == 0) ? dinoDownRun1 : dinoDownRun2;
} else {
dinoImg = (animFrame == 0) ? dinoRun1 : dinoRun2;
}
if (dinoImg != null) { if (dinoImg != null) {
if (isDucking) { if (isDucking) {
g2d.drawImage(dinoImg, dinoX, GROUND_Y - 26, 59, 26, null); g2d.drawImage(dinoImg, dinoX, GROUND_Y - dinoDuckHeight, null);
} else { } else {
g2d.drawImage(dinoImg, dinoX, dinoY, null); g2d.drawImage(dinoImg, dinoX, dinoY, null);
} }
} }
}
// Draw obstacles private void drawObstacles(Graphics2D g2d) {
for (Obstacle obs : obstacles) { for (Obstacle obs : obstacles) {
if (obs.isBird) { if (obs.isBird) {
BufferedImage birdImg = (frameCount % 10 < 5) ? birdFly1 : birdFly2; BufferedImage birdImg = (frameCount % 10 < 5) ? birdFly1 : birdFly2;
@@ -347,17 +414,17 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
} }
} }
} }
}
// Draw score private void drawUI(Graphics2D g2d) {
g2d.setColor(Color.BLACK); g2d.setColor(new Color(83, 83, 83));
g2d.setFont(new Font("Courier New", Font.BOLD, 16)); g2d.setFont(new Font("Courier New", Font.BOLD, 16));
if (hiImg != null && highScore > 0) { if (hiImg != null && highScore > 0) {
g2d.drawImage(hiImg, WIDTH - 200, 20, null); g2d.drawImage(hiImg, WIDTH - 200, 20, null);
g2d.drawString(String.format("%05d", highScore), WIDTH - 150, 35); g2d.drawString(String.format("%05d", highScore), WIDTH - 150, 35);
} }
g2d.drawString(String.format("%05d", score), WIDTH - 80, 35); g2d.drawString(String.format("%05d", score), WIDTH - 80, 35);
}
// Draw game over private void drawOverlays(Graphics2D g2d) {
if (gameOver) { if (gameOver) {
if (gameOverImg != null) { if (gameOverImg != null) {
g2d.drawImage(gameOverImg, WIDTH / 2 - gameOverImg.getWidth() / 2, 100, null); g2d.drawImage(gameOverImg, WIDTH / 2 - gameOverImg.getWidth() / 2, 100, null);
@@ -365,25 +432,45 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
if (replayImg != null) { if (replayImg != null) {
g2d.drawImage(replayImg, WIDTH / 2 - replayImg.getWidth() / 2, 150, null); g2d.drawImage(replayImg, WIDTH / 2 - replayImg.getWidth() / 2, 150, null);
} }
} g2d.setFont(new Font("Arial", Font.BOLD, 18));
g2d.drawString("Press SPACE to restart", WIDTH / 2 - 110, 200);
} else if (!gameStarted) {
g2d.setColor(new Color(83, 83, 83));
g2d.setFont(new Font("Arial", Font.BOLD, 24));
String msg = "Press SPACE to Start";
FontMetrics fm = g2d.getFontMetrics();
int msgWidth = fm.stringWidth(msg);
g2d.drawString(msg, (WIDTH - msgWidth) / 2, HEIGHT / 2);
// Draw start message g2d.setFont(new Font("Arial", Font.PLAIN, 14));
if (!gameStarted) { String controls = "↓ to duck • P to pause";
g2d.setFont(new Font("Arial", Font.BOLD, 20)); msgWidth = g2d.getFontMetrics().stringWidth(controls);
g2d.drawString("Press SPACE to Start", WIDTH / 2 - 120, HEIGHT / 2); g2d.drawString(controls, (WIDTH - msgWidth) / 2, HEIGHT / 2 + 30);
} } else if (paused) {
g2d.setColor(new Color(83, 83, 83));
// Draw pause g2d.setFont(new Font("Arial", Font.BOLD, 36));
if (paused) { String msg = "PAUSED";
g2d.setFont(new Font("Arial", Font.BOLD, 30)); FontMetrics fm = g2d.getFontMetrics();
g2d.drawString("PAUSED", WIDTH / 2 - 60, HEIGHT / 2); int msgWidth = fm.stringWidth(msg);
g2d.drawString(msg, (WIDTH - msgWidth) / 2, HEIGHT / 2);
} }
} }
private BufferedImage getDinoImage() {
if (gameOver) {
return dinoDead;
} else if (isJumping) {
return dinoJump;
} else if (isDucking) {
return (animFrame == 0) ? dinoDownRun1 : dinoDownRun2;
} else {
return (animFrame == 0) ? dinoRun1 : dinoRun2;
}
}
@Override @Override
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
int key = e.getKeyCode(); int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) { if (key == KeyEvent.VK_SPACE) {
if (!gameStarted) { if (!gameStarted) {
gameStarted = true; gameStarted = true;
@@ -395,31 +482,29 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
playSound(jumpSound); playSound(jumpSound);
} }
} }
if (key == KeyEvent.VK_DOWN && !isJumping && gameStarted && !gameOver) { if (key == KeyEvent.VK_DOWN && !isJumping && gameStarted && !gameOver) {
isDucking = true; isDucking = true;
} }
if (key == KeyEvent.VK_UP && !gameStarted) {
if (key == KeyEvent.VK_P && gameStarted && !gameOver) { gameStarted = true;
}
if ((key == KeyEvent.VK_P || key == KeyEvent.VK_ESCAPE) && gameStarted && !gameOver) {
paused = !paused; paused = !paused;
} }
} }
@Override @Override
public void keyReleased(KeyEvent e) { public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) { if (e.getKeyCode() == KeyEvent.VK_DOWN) {
isDucking = false; isDucking = false;
} }
} }
@Override @Override
public void keyTyped(KeyEvent e) {} public void keyTyped(KeyEvent e) {}
private static class Obstacle {
private class Obstacle { int x;
int x, y, width, height; int y, width, height;
BufferedImage img; BufferedImage img;
boolean isBird; boolean isBird;
Obstacle(int x, int y, int width, int height, BufferedImage img, boolean isBird) { Obstacle(int x, int y, int width, int height, BufferedImage img, boolean isBird) {
this.x = x; this.x = x;
this.y = y; this.y = y;
@@ -429,10 +514,9 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
this.isBird = isBird; this.isBird = isBird;
} }
} }
private static class Cloud {
private class Cloud { int x;
int x, y; int y;
Cloud(int x, int y) { Cloud(int x, int y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
@@ -440,27 +524,27 @@ public class DinoGame extends JPanel implements ActionListener, KeyListener {
} }
public static void main(String[] args) { public static void main(String[] args) {
try { SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Java Dino Game");
JFrame frame = new JFrame("Chrome Dino Game"); try {
try { InputStream iconStream = DinoGame.class.getResourceAsStream("/dino-jump.png");
BufferedImage icon = ImageIO.read(DinoGame.class.getResourceAsStream("/dino-jump.png")); if (iconStream != null) {
BufferedImage icon = ImageIO.read(iconStream);
frame.setIconImage(icon); frame.setIconImage(icon);
} catch (IOException e) {
System.err.println("Errore caricamento icona: " + e.getMessage());
e.printStackTrace();
} }
DinoGame game = new DinoGame(); } catch (Exception e) {
frame.add(game); System.err.println("Could not load icon: " + e.getMessage());
frame.pack(); }
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null); DinoGame game = new DinoGame();
frame.setResizable(false); frame.add(game);
frame.setVisible(true); frame.pack();
}); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} catch (Exception e){ frame.setLocationRelativeTo(null);
System.err.println("Error : " + e.getMessage()); frame.setResizable(false);
e.printStackTrace(); frame.setVisible(true);
}
game.requestFocusInWindow();
});
} }
} }