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