From b1be4e07317fa31dce9c9ff878cd4846ec72d134 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Fri, 27 Jun 2025 23:22:34 +0200 Subject: [PATCH] feat: input handling! --- .../java/eu/midnightdust/yaytris/Tetris.java | 2 + .../eu/midnightdust/yaytris/game/Space.java | 59 +++++++++++++++++-- .../midnightdust/yaytris/game/Tetromino.java | 43 +++++++++++--- .../midnightdust/yaytris/ui/GameCanvas.java | 11 ++-- .../eu/midnightdust/yaytris/ui/MainMenu.java | 2 +- .../eu/midnightdust/yaytris/ui/TetrisUI.java | 59 ++++++++++++++++--- 6 files changed, 147 insertions(+), 29 deletions(-) diff --git a/src/main/java/eu/midnightdust/yaytris/Tetris.java b/src/main/java/eu/midnightdust/yaytris/Tetris.java index d246f71..2684b9f 100644 --- a/src/main/java/eu/midnightdust/yaytris/Tetris.java +++ b/src/main/java/eu/midnightdust/yaytris/Tetris.java @@ -4,8 +4,10 @@ import eu.midnightdust.yaytris.game.Space; import eu.midnightdust.yaytris.ui.TetrisUI; import javax.swing.*; +import java.util.Random; public class Tetris { + public static final Random random = new Random(); public static Space space; static TetrisUI ui; diff --git a/src/main/java/eu/midnightdust/yaytris/game/Space.java b/src/main/java/eu/midnightdust/yaytris/game/Space.java index ca5fbb5..195649a 100644 --- a/src/main/java/eu/midnightdust/yaytris/game/Space.java +++ b/src/main/java/eu/midnightdust/yaytris/game/Space.java @@ -3,18 +3,59 @@ package eu.midnightdust.yaytris.game; import java.awt.Color; import java.util.*; +import static eu.midnightdust.yaytris.Tetris.random; + public class Space { private final Color[][] gameMap; // Bereits abgesetzte Tetrominos werden nur noch als einzelne Farben ('Blobs') auf der Karte abgespeichert + private TetrominoShape nextShape; + private Tetromino currentTetromino; public Space() { - gameMap = new Color[7][12]; - for (int x = 0; x < gameMap.length; x++) { - for (int y = 0; y < gameMap[x].length; y++) { - if (Math.random() < 0.5f) { - gameMap[x][y] = Color.getHSBColor((float) Math.random(), 1.f, 1.f); + gameMap = new Color[12][7]; + nextShape = getNextShape(); + + Tetromino mino = new Tetromino(TetrominoShape.T); + mino.move(-2); + mino.fall(10); + onLinesChanged(mino, 9, 10, 11); + Tetromino mina = new Tetromino(TetrominoShape.LINE); + mina.move(1); + mina.rotate(); + mina.fall(11); + onLinesChanged(mina, 9, 10, 11); + } + + public void spawnTetromino() { + currentTetromino = new Tetromino(nextShape); + nextShape = getNextShape(); + } + + public TetrominoShape getNextShape() { + return TetrominoShape.values()[random.nextInt(TetrominoShape.values().length)]; + } + + public int getMapWidth() { + return gameMap[0].length; + } + + public int getMapHeight() { + return gameMap.length; + } + + public Color[][] getGameMapWithTetromino() { + Color[][] tempGameMap = new Color[gameMap.length][gameMap[0].length]; + for (int y = 0; y < tempGameMap.length; y++) { + System.arraycopy(gameMap[y], 0, tempGameMap[y], 0, tempGameMap[y].length); + if (currentTetromino != null) { + Color[] newBlobs = currentTetromino.getLine(y); + for (int i = 0; i < newBlobs.length; i++) { + if (newBlobs[i] == null) continue; + tempGameMap[y][i] = newBlobs[i]; } } } + + return tempGameMap; } public Color[][] getGameMap() { @@ -25,6 +66,7 @@ public class Space { int combo = 0; Set completedLines = new TreeSet<>(); for (int line : lines) { + if (line > getMapHeight()) continue; Color[] newBlobs = tetromino.getLine(line); for (int i = 0; i < newBlobs.length; i++) { if (newBlobs[i] == null) continue; @@ -39,9 +81,14 @@ public class Space { for (int completedIndex = 0; completedIndex < completedLines.size(); completedIndex++) { // Remove completed lines int line = completedLines.toArray(new Integer[0])[completedIndex]; for (int i = line+completedIndex; i >= 0; i--) { - gameMap[i] = gameMap[i-1]; + if (i >= getMapHeight()) continue; + gameMap[i] = (i-1 < 0) ? new Color[gameMap[i].length] : gameMap[i-1]; } } return combo; } + + public Tetromino getCurrentTetromino() { + return currentTetromino; + } } diff --git a/src/main/java/eu/midnightdust/yaytris/game/Tetromino.java b/src/main/java/eu/midnightdust/yaytris/game/Tetromino.java index f88bace..9870042 100644 --- a/src/main/java/eu/midnightdust/yaytris/game/Tetromino.java +++ b/src/main/java/eu/midnightdust/yaytris/game/Tetromino.java @@ -1,5 +1,6 @@ package eu.midnightdust.yaytris.game; +import eu.midnightdust.yaytris.Tetris; import eu.midnightdust.yaytris.util.Vec2i; import java.awt.*; @@ -12,18 +13,40 @@ public class Tetromino { public Tetromino(TetrominoShape shape) { this.shape = shape; this.collision = shape.boundary; - this.centerPos = Vec2i.of(0, 0); + this.centerPos = Vec2i.of(2, 0); } public void fall(int length) { - centerPos = centerPos.offset(Vec2i.of(0, length)); + Vec2i newPos = centerPos.offset(Vec2i.of(0, length)); + if (Tetris.space != null && newPos.getY()+this.collision.length > Tetris.space.getMapHeight()) { + 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(); + } + centerPos = newPos; + } + + public void move(int xOffset) { + Vec2i newPos = centerPos.offset(Vec2i.of(xOffset, 0)); + if (Tetris.space == null || newPos.getX() < 0 || newPos.getX() + collision[0].length > Tetris.space.getGameMap()[0].length) { + return; + } + centerPos = newPos; } public void rotate() { - int[][] newCollision = new int[collision[0].length][collision.length]; - for (int i = 0; i < collision.length; i++) { - for (int j = 0; j < collision[i].length; j++) { - newCollision[j][i] = collision[i][j]; + int M = collision.length; + int N = collision[0].length; + + int[][] newCollision = new int[N][M]; + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + newCollision[j][M-i-1] = collision[i][j]; } } this.collision = newCollision; @@ -32,8 +55,12 @@ public class Tetromino { public Color[] getLine(int line) { Color[] l = new Color[7]; for (int i = 0; i < l.length; i++) { - if (collision.length < line-centerPos.getX() && collision[line-centerPos.getX()][i] != 0) - l[i] = shape.color; + int relY = line - centerPos.getY(); + if (relY >= collision.length || relY < 0) continue; + int relX = i-centerPos.getX(); + if (relX >= collision[relY].length || relX < 0) continue; + + if (collision[relY][relX] != 0) l[i] = shape.color; } return l; } diff --git a/src/main/java/eu/midnightdust/yaytris/ui/GameCanvas.java b/src/main/java/eu/midnightdust/yaytris/ui/GameCanvas.java index 9e69be0..546d75c 100644 --- a/src/main/java/eu/midnightdust/yaytris/ui/GameCanvas.java +++ b/src/main/java/eu/midnightdust/yaytris/ui/GameCanvas.java @@ -25,20 +25,17 @@ public class GameCanvas extends JPanel { super.paintComponent(graphics); if (graphics == null) return; - //graphics.clearRect(this.getX(), this.getY(), this.getWidth(), this.getHeight()); - for (int x = 0; x < Tetris.space.getGameMap().length; x++) { - for (int y = 0; y < Tetris.space.getGameMap()[x].length; y++) { - Color color = Tetris.space.getGameMap()[x][y]; + 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]; if (color == null) continue; - int blockSize = (this.getWidth()-this.getInsets().right)/Tetris.space.getGameMap().length; + int blockSize = (int) Math.ceil((float) (this.getWidth() - this.getInsets().left - this.getInsets().right) / Tetris.space.getGameMapWithTetromino()[0].length); //graphics.setXORMode(color); graphics.drawImage(texture, x*blockSize +getInsets().left, y*blockSize + getInsets().top, blockSize, blockSize, color, this); graphics.setColor(withAlpha(color, 100)); graphics.fillRect(x*blockSize +getInsets().left, y*blockSize + getInsets().top, blockSize, blockSize); } } - //this.paint(graphics); - //super.paintComponent(graphics); } public static Color withAlpha(Color color, int alpha) { return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); diff --git a/src/main/java/eu/midnightdust/yaytris/ui/MainMenu.java b/src/main/java/eu/midnightdust/yaytris/ui/MainMenu.java index 6e5381a..421a4a6 100644 --- a/src/main/java/eu/midnightdust/yaytris/ui/MainMenu.java +++ b/src/main/java/eu/midnightdust/yaytris/ui/MainMenu.java @@ -11,7 +11,7 @@ public class MainMenu extends AbstractMenu { this.setLayout(null); JButton startButton = new JButton("Start"); - startButton.addActionListener(ui::openSettings); + startButton.addActionListener(ui::startGame); this.add(startButton); JButton settingsButton = new JButton("Einstellungen"); diff --git a/src/main/java/eu/midnightdust/yaytris/ui/TetrisUI.java b/src/main/java/eu/midnightdust/yaytris/ui/TetrisUI.java index 6a7052c..4e614df 100644 --- a/src/main/java/eu/midnightdust/yaytris/ui/TetrisUI.java +++ b/src/main/java/eu/midnightdust/yaytris/ui/TetrisUI.java @@ -1,5 +1,6 @@ package eu.midnightdust.yaytris.ui; +import eu.midnightdust.yaytris.Tetris; import eu.midnightdust.yaytris.game.Space; import javax.imageio.ImageIO; @@ -7,11 +8,13 @@ import javax.swing.*; import javax.swing.border.LineBorder; import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.io.IOException; import static eu.midnightdust.yaytris.Settings.guiScale; -public class TetrisUI extends JFrame { +public class TetrisUI extends JFrame implements KeyListener { JLabel titleLabel; GameCanvas gamePanel; JPanel menuPanel; @@ -44,6 +47,7 @@ public class TetrisUI extends JFrame { this.add(gamePanel); rescale(); + this.addKeyListener(this); openMainMenu(null); this.setVisible(true); @@ -65,6 +69,13 @@ public class TetrisUI extends JFrame { //if (label.getFont() != null) label.setFont(label.getFont().deriveFont((float) label.getFont().getSize() * guiScale)); } + public void startGame(ActionEvent actionEvent) { + //this.remove(menuPanel); + //menuPanel = null; + this.requestFocus(); + this.repaint(); + } + public void openMainMenu(ActionEvent actionEvent) { if (this.menuPanel != null) this.remove(menuPanel); rescale(); @@ -85,22 +96,19 @@ public class TetrisUI extends JFrame { } // Source: https://stackoverflow.com/a/19746437 - private void setWindowPosition(JFrame window, int screen) - { + private void setWindowPosition(JFrame window, int screen) { GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] allDevices = env.getScreenDevices(); int topLeftX, topLeftY, screenX, screenY, windowPosX, windowPosY; - if (screen < allDevices.length && screen > -1) - { + if (screen < allDevices.length && screen > -1) { topLeftX = allDevices[screen].getDefaultConfiguration().getBounds().x; topLeftY = allDevices[screen].getDefaultConfiguration().getBounds().y; screenX = allDevices[screen].getDefaultConfiguration().getBounds().width; screenY = allDevices[screen].getDefaultConfiguration().getBounds().height; } - else - { + else { topLeftX = allDevices[0].getDefaultConfiguration().getBounds().x; topLeftY = allDevices[0].getDefaultConfiguration().getBounds().y; @@ -113,4 +121,41 @@ public class TetrisUI extends JFrame { 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_W) { + Tetris.space.spawnTetromino(); + //Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3); + } + else if (e.getKeyCode() == KeyEvent.VK_S) { + 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_SPACE) { + Tetris.space.getCurrentTetromino().fall(1); + //Tetris.space.onLinesChanged(Tetris.space.getCurrentTetromino(), 0, 1, 2, 3); + } + gamePanel.repaint(); + } + + @Override + public void keyReleased(KeyEvent e) { + //System.out.println("Released"); + + } }