feat: display score & game over, code cleanup
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
package eu.midnightdust.yaytris;
|
||||
|
||||
import eu.midnightdust.yaytris.game.Space;
|
||||
import eu.midnightdust.yaytris.ui.ScoreMenu;
|
||||
import eu.midnightdust.yaytris.ui.TetrisUI;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class Tetris {
|
||||
public static final Random random = new Random();
|
||||
public static Space space;
|
||||
public static Timer timer;
|
||||
public static TetrisUI ui;
|
||||
private static Space space;
|
||||
private static Timer timer;
|
||||
private static TetrisUI ui;
|
||||
private static TimerTask gravityTask;
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
@@ -23,4 +26,35 @@ public class Tetris {
|
||||
space = new Space();
|
||||
ui = new TetrisUI();
|
||||
}
|
||||
|
||||
public static TetrisUI getUi() {
|
||||
return ui;
|
||||
}
|
||||
|
||||
public static Space getSpace() {
|
||||
return space;
|
||||
}
|
||||
|
||||
public static void resetSpace() {
|
||||
space = new Space();
|
||||
}
|
||||
|
||||
public static void startGame() {
|
||||
space.spawnTetromino();
|
||||
gravityTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (space.getCurrentTetromino() != null) {
|
||||
space.getCurrentTetromino().fall(1);
|
||||
ui.getGamePanel().repaint();
|
||||
}
|
||||
}
|
||||
};
|
||||
timer.scheduleAtFixedRate(gravityTask, 1, Settings.difficulty.getTimerPeriod());
|
||||
}
|
||||
public static void stopGame() {
|
||||
gravityTask.cancel();
|
||||
if (ui.getMenuPanel() instanceof ScoreMenu) ((ScoreMenu) Tetris.ui.getMenuPanel()).gameOver();
|
||||
ui.transferFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package eu.midnightdust.yaytris.game;
|
||||
|
||||
import eu.midnightdust.yaytris.Tetris;
|
||||
import eu.midnightdust.yaytris.ui.ScoreMenu;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.*;
|
||||
|
||||
@@ -78,6 +81,7 @@ public class Space {
|
||||
}
|
||||
}
|
||||
this.score += combo;
|
||||
if (Tetris.getUi().getMenuPanel() instanceof ScoreMenu) ((ScoreMenu)Tetris.getUi().getMenuPanel()).updateScore(this.score);
|
||||
//System.out.println(score);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,34 +20,20 @@ public class Tetromino {
|
||||
public void fall(int length) {
|
||||
Vec2i newPos = centerPos.offset(Vec2i.of(0, length));
|
||||
if (collidesVertically(newPos)) {
|
||||
if (fallLength < 1) System.out.println("Game over!");
|
||||
int[] affectedLines = new int[this.collision.length];
|
||||
int line = centerPos.getY();
|
||||
for (int i = 0; i < this.collision.length; i++) {
|
||||
affectedLines[i] = line;
|
||||
line++;
|
||||
}
|
||||
Tetris.space.onLinesChanged(this, affectedLines);
|
||||
Tetris.space.spawnTetromino();
|
||||
Tetris.getSpace().onLinesChanged(this, affectedLines);
|
||||
if (fallLength >= 1) Tetris.getSpace().spawnTetromino();
|
||||
else Tetris.stopGame();
|
||||
}
|
||||
fallLength += 1;
|
||||
centerPos = newPos;
|
||||
}
|
||||
|
||||
private boolean collidesVertically(Vec2i newPos) {
|
||||
if (Tetris.space == null) return false;
|
||||
boolean collides = newPos.getY() + this.collision.length > Tetris.space.getMapHeight(); // Bottom check
|
||||
if (!collides) {
|
||||
for (int i = 0; i < collision[0].length; i++) {
|
||||
int maxCollisionY = collision.length - 1;
|
||||
while (collision[maxCollisionY][i] == 0) maxCollisionY--;
|
||||
if (newPos.getY()+maxCollisionY >= Tetris.space.getGameMap().length) continue;
|
||||
collides |= Tetris.space.getGameMap()[newPos.getY() + maxCollisionY][newPos.getX() + i] != null; // Check for other tetrominos
|
||||
}
|
||||
}
|
||||
return collides;
|
||||
}
|
||||
|
||||
public void move(int xOffset) {
|
||||
Vec2i newPos = centerPos.offset(Vec2i.of(xOffset, 0));
|
||||
if (collidesHorizontally(newPos, xOffset)) {
|
||||
@@ -56,15 +42,34 @@ public class Tetromino {
|
||||
centerPos = newPos;
|
||||
}
|
||||
|
||||
private boolean collidesVertically(Vec2i newPos) {
|
||||
if (Tetris.getSpace() == null) return false;
|
||||
|
||||
boolean collides = newPos.getY() + this.collision.length > Tetris.getSpace().getMapHeight(); // Bottom check
|
||||
|
||||
if (!collides) { // Check for other tetrominos
|
||||
for (int i = 0; i < collision[0].length; i++) {
|
||||
int maxCollisionY = collision.length - 1;
|
||||
while (collision[maxCollisionY][i] == 0) maxCollisionY--; // Figure out the collision box's bounding
|
||||
|
||||
if (newPos.getY()+maxCollisionY >= Tetris.getSpace().getMapHeight() || newPos.getX() + i >= Tetris.getSpace().getMapWidth()) continue;
|
||||
collides |= Tetris.getSpace().getGameMap()[newPos.getY() + maxCollisionY][newPos.getX() + i] != null;
|
||||
}
|
||||
}
|
||||
return collides;
|
||||
}
|
||||
|
||||
private boolean collidesHorizontally(Vec2i newPos, int xOffset) {
|
||||
if (Tetris.space == null) return false;
|
||||
boolean collides = newPos.getX() < 0 || newPos.getX() + collision[0].length > Tetris.space.getGameMap()[0].length;
|
||||
if (!collides) {
|
||||
if (Tetris.getSpace() == null) return false;
|
||||
|
||||
boolean collides = newPos.getX() < 0 || newPos.getX() + collision[0].length > Tetris.getSpace().getMapWidth(); // Side check
|
||||
if (!collides) { // Check for other tetrominos
|
||||
for (int i = 0; i < collision.length; i++) {
|
||||
int maxCollisionX = xOffset > 0 ? collision[i].length - 1 : 0;
|
||||
while (collision[i][maxCollisionX] == 0) maxCollisionX += xOffset > 0 ? -1 : 1;
|
||||
if (newPos.getY()+maxCollisionX >= Tetris.space.getGameMap().length) continue;
|
||||
collides |= Tetris.space.getGameMap()[newPos.getY() + i][newPos.getX() + maxCollisionX] != null; // Check for other tetrominos
|
||||
while (collision[i][maxCollisionX] == 0) maxCollisionX += xOffset > 0 ? -1 : 1; // Figure out the collision box's bounding
|
||||
|
||||
if (newPos.getY()+maxCollisionX >= Tetris.getSpace().getMapHeight()) continue;
|
||||
collides |= Tetris.getSpace().getGameMap()[newPos.getY() + i][newPos.getX() + maxCollisionX] != null;
|
||||
}
|
||||
}
|
||||
return collides;
|
||||
|
||||
@@ -25,11 +25,11 @@ public class GameCanvas extends JPanel {
|
||||
super.paintComponent(graphics);
|
||||
if (graphics == null) return;
|
||||
|
||||
for (int y = 0; y < Tetris.space.getGameMapWithTetromino().length; y++) {
|
||||
for (int x = 0; x < Tetris.space.getGameMapWithTetromino()[y].length; x++) {
|
||||
Color color = Tetris.space.getGameMapWithTetromino()[y][x];
|
||||
for (int y = 0; y < Tetris.getSpace().getMapHeight(); y++) {
|
||||
for (int x = 0; x < Tetris.getSpace().getMapWidth(); x++) {
|
||||
Color color = Tetris.getSpace().getGameMapWithTetromino()[y][x];
|
||||
if (color == null) continue;
|
||||
int blockSize = (int) Math.ceil((float) (this.getWidth() - this.getInsets().left - this.getInsets().right) / Tetris.space.getGameMapWithTetromino()[0].length);
|
||||
int blockSize = (int) Math.ceil((float) (this.getWidth() - this.getInsets().left - this.getInsets().right) / Tetris.getSpace().getMapWidth());
|
||||
//graphics.setXORMode(withAlpha(color,0));
|
||||
graphics.drawImage(texture, x*blockSize +getInsets().left, y*blockSize + getInsets().top, blockSize, blockSize, color, this);
|
||||
graphics.setColor(withAlpha(color, 120));
|
||||
|
||||
34
src/main/java/eu/midnightdust/yaytris/ui/ScoreMenu.java
Normal file
34
src/main/java/eu/midnightdust/yaytris/ui/ScoreMenu.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package eu.midnightdust.yaytris.ui;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class ScoreMenu extends AbstractMenu {
|
||||
final TetrisUI ui;
|
||||
final JLabel gameOverLabel;
|
||||
final JLabel currentScoreLabel;
|
||||
|
||||
ScoreMenu(int x, int y, int width, int height, TetrisUI ui) {
|
||||
this.ui = ui;
|
||||
this.setBounds(x, y, width, height);
|
||||
this.setLayout(null);
|
||||
|
||||
this.gameOverLabel = new JLabel();
|
||||
this.add(gameOverLabel);
|
||||
|
||||
this.currentScoreLabel = new JLabel("Score: 0");
|
||||
this.add(currentScoreLabel);
|
||||
|
||||
JButton backButton = new JButton("Zurück");
|
||||
backButton.addActionListener(ui::openMainMenu);
|
||||
this.add(backButton);
|
||||
}
|
||||
|
||||
public void updateScore(int score) {
|
||||
this.currentScoreLabel.setText("Score: %s".formatted(score));
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
public void gameOver() {
|
||||
this.gameOverLabel.setText("Game over :(");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package eu.midnightdust.yaytris.ui;
|
||||
|
||||
import eu.midnightdust.yaytris.Settings;
|
||||
import eu.midnightdust.yaytris.Tetris;
|
||||
import eu.midnightdust.yaytris.game.Space;
|
||||
|
||||
@@ -12,10 +11,8 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.io.IOException;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static eu.midnightdust.yaytris.Settings.guiScale;
|
||||
import static eu.midnightdust.yaytris.Tetris.timer;
|
||||
|
||||
public class TetrisUI extends JFrame implements KeyListener {
|
||||
JLabel titleLabel;
|
||||
@@ -76,25 +73,22 @@ public class TetrisUI extends JFrame implements KeyListener {
|
||||
return gamePanel;
|
||||
}
|
||||
|
||||
public JPanel getMenuPanel() {
|
||||
return menuPanel;
|
||||
}
|
||||
|
||||
public void startGame(ActionEvent actionEvent) {
|
||||
Tetris.space.spawnTetromino();
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Tetris.space.getCurrentTetromino() != null) {
|
||||
Tetris.space.getCurrentTetromino().fall(1);
|
||||
Tetris.ui.getGamePanel().repaint();
|
||||
}
|
||||
}
|
||||
}, 1, Settings.difficulty.getTimerPeriod());
|
||||
Tetris.startGame();
|
||||
//this.remove(menuPanel);
|
||||
//menuPanel = null;
|
||||
this.openScoreMenu(actionEvent);
|
||||
this.requestFocus();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
public void openMainMenu(ActionEvent actionEvent) {
|
||||
if (this.menuPanel != null) this.remove(menuPanel);
|
||||
Tetris.resetSpace();
|
||||
rescale();
|
||||
menuPanel = new MainMenu(scale(170), scale(40), scale(220), scale(226), this);
|
||||
menuPanel.setBackground(Color.DARK_GRAY);
|
||||
@@ -112,6 +106,15 @@ public class TetrisUI extends JFrame implements KeyListener {
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
public void openScoreMenu(ActionEvent actionEvent) {
|
||||
if (this.menuPanel != null) this.remove(menuPanel);
|
||||
menuPanel = new ScoreMenu(scale(170), scale(40), scale(220), scale(226), this);
|
||||
menuPanel.setBackground(Color.DARK_GRAY);
|
||||
menuPanel.setBorder(new LineBorder(Color.GRAY, scale(2)));
|
||||
this.add(menuPanel);
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
// Source: https://stackoverflow.com/a/19746437
|
||||
private void setWindowPosition(JFrame window, int screen) {
|
||||
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
@@ -139,44 +142,36 @@ public class TetrisUI extends JFrame implements KeyListener {
|
||||
window.setLocation(windowPosX, windowPosY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
//System.out.println("Typed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
//System.out.println("Pressed");
|
||||
if (e.getKeyCode() == KeyEvent.VK_E) {
|
||||
Tetris.space.spawnTetromino();
|
||||
//Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3);
|
||||
}
|
||||
else if (e.getKeyCode() == KeyEvent.VK_W) {
|
||||
Tetris.space.getCurrentTetromino().rotate();
|
||||
//Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3);
|
||||
}
|
||||
else if (e.getKeyCode() == KeyEvent.VK_D) {
|
||||
Tetris.space.getCurrentTetromino().move(1);
|
||||
//Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3);
|
||||
}
|
||||
else if (e.getKeyCode() == KeyEvent.VK_A) {
|
||||
Tetris.space.getCurrentTetromino().move(-1);
|
||||
//Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3);
|
||||
}
|
||||
else if (e.getKeyCode() == KeyEvent.VK_S) {
|
||||
Tetris.space.getCurrentTetromino().fall(1);
|
||||
//Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3);
|
||||
}
|
||||
else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
|
||||
Tetris.space.getCurrentTetromino().fall(12);
|
||||
//Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3);
|
||||
switch (e.getKeyCode()) {
|
||||
case KeyEvent.VK_E:
|
||||
Tetris.getSpace().spawnTetromino();
|
||||
break;
|
||||
case KeyEvent.VK_UP:
|
||||
case KeyEvent.VK_W:
|
||||
Tetris.getSpace().getCurrentTetromino().rotate();
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:
|
||||
case KeyEvent.VK_D:
|
||||
Tetris.getSpace().getCurrentTetromino().move(1);
|
||||
break;
|
||||
case KeyEvent.VK_LEFT:
|
||||
case KeyEvent.VK_A:
|
||||
Tetris.getSpace().getCurrentTetromino().move(-1);
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:
|
||||
case KeyEvent.VK_S:
|
||||
Tetris.getSpace().getCurrentTetromino().fall(1);
|
||||
break;
|
||||
case KeyEvent.VK_SPACE:
|
||||
Tetris.getSpace().getCurrentTetromino().fall(12);
|
||||
break;
|
||||
}
|
||||
gamePanel.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
//System.out.println("Released");
|
||||
|
||||
}
|
||||
// Unused (But required overrides)
|
||||
@Override public void keyReleased(KeyEvent e) {}
|
||||
@Override public void keyTyped(KeyEvent e) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user