OOP-Projects-Java

Log | Files | Refs | README

commit 1a133cd163753a6956847718a0709023367f1b04
parent 0472daaf6cc67b214e3020c10ff9e1c238007e40
Author: William Lindholm <William_Lindholm@outlook.com>
Date:   Tue, 21 Mar 2023 11:33:54 +0100

Mostly finished tetris game

Diffstat:
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/I_Block.java | 24+++++++++---------------
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/J_Block.java | 27++++++++++++++++++++++++++-
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/L_Block.java | 22+++++++++++++++++++++-
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/O_Block.java | 22+++++++++++++++++++++-
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/Poly.java | 78++++++++++++++++++++++++++++++++++++++++++++----------------------------------
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/S_Block.java | 22+++++++++++++++++++++-
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/T_Block.java | 22+++++++++++++++++++++-
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/Tile.java | 38++++++++++++++++++++------------------
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/Tileable.java | 10++++++----
MOOP2023_a22willi_a21liltr_assignment4/src/blocks/Z_Block.java | 24+++++++++++++++++++++++-
MOOP2023_a22willi_a21liltr_assignment4/src/game/BlockFactory.java | 39++++++++++++++++++++++++++++++++++-----
MOOP2023_a22willi_a21liltr_assignment4/src/game/Board.java | 282+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
MOOP2023_a22willi_a21liltr_assignment4/src/game/GUI.java | 58+++++++++++++++++++++++++++++++++++++++++++++++++++++-----
MOOP2023_a22willi_a21liltr_assignment4/src/game/Game.java | 41++++++++++++++++++++++++++---------------
14 files changed, 509 insertions(+), 200 deletions(-)

diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/I_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/I_Block.java @@ -3,20 +3,14 @@ package blocks; import java.awt.Color; public class I_Block extends Poly { - - //holds the information that dictates what shape the object becomes on the board - public int[][] Shape = { - {1, 0}, - {1, 0}, - {1, 0}, - {1, 1}, - }; - - private Color color; - + + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { { 1 }, { 1 }, { 1 }, { 1 }, }; + public I_Block(int x, int y) { super(x, y); - color = Color.green; + super.setColor(Color.cyan); } @Override @@ -24,9 +18,9 @@ public class I_Block extends Poly { // TODO Auto-generated method stub return Shape; } - + @Override - public Color getColor() { - return color; + public void rotate() { + Shape = super.rotateRight(Shape); } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/J_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/J_Block.java @@ -1,5 +1,30 @@ package blocks; -public class J_Block { +import java.awt.Color; +public class J_Block extends Poly { + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { { 0, 1 }, { 0, 1 }, { 1, 1 }, }; + + public J_Block(int x, int y) { + super(x, y); + super.setColor(Color.blue); + } + + @Override + public int[][] getShape() { + // TODO Auto-generated method stub + return Shape; + } + + @Override + public void rotate() { + Shape = super.rotateRight(Shape); + } + + public int[][] rotateRight(int[][] shape) { + + return shape; + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/L_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/L_Block.java @@ -1,5 +1,25 @@ package blocks; -public class L_Block { +import java.awt.Color; +public class L_Block extends Poly { + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { { 1, 0 }, { 1, 0 }, { 1, 1 }, }; + + public L_Block(int x, int y) { + super(x, y); + super.setColor(Color.orange); + } + + @Override + public int[][] getShape() { + // TODO Auto-generated method stub + return Shape; + } + + @Override + public void rotate() { + Shape = super.rotateRight(Shape); + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/O_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/O_Block.java @@ -1,5 +1,25 @@ package blocks; -public class O_Block { +import java.awt.Color; +public class O_Block extends Poly { + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { { 1, 1 }, { 1, 1 }, }; + + public O_Block(int x, int y) { + super(x, y); + super.setColor(Color.yellow); + } + + @Override + public int[][] getShape() { + // TODO Auto-generated method stub + return Shape; + } + + @Override + public void rotate() { + Shape = super.rotateRight(Shape); + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Poly.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Poly.java @@ -2,55 +2,65 @@ package blocks; import java.awt.Color; -public class Poly { - private boolean falling; - - private int posX, posY; - - +public abstract class Poly implements Tileable { + private int posX, posY; + private boolean occupied; + + private Color color; + public Poly(int x, int y) { this.posX = x; this.posY = y; + occupied = false; } - - public void rotateRight() { - - } - - public void rotateLeft() { - - } - - public boolean isFalling() { - return this.falling; - } - - public void setFailling(boolean falling) { - this.falling = falling; + + public int[][] rotateRight(int[][] shape) { + int h = shape.length; + int w = shape[0].length; + int[][] rotatedShape = new int[w][h]; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + rotatedShape[x][h - 1 - y] = shape[y][x]; + } + } + return rotatedShape; } - + + public abstract void rotate(); + public void move(int x, int y) { this.posX += x; this.posY += y; } - - - public boolean getFalling() { - return falling; - } - + public int[] getPos() { - int[] pos = {posX, posY}; + int[] pos = { posX, posY }; return pos; } - + public int[][] getShape() { return null; } - - + + public void setColor(Color color) { + this.color = color; + } + public Color getColor() { - //if no other value is set, red will be the default color. - return Color.red; + // if no other value is set, red will be the default color. + return color; + } + + public boolean isOccupied() { + return occupied; + } + + public void setOccupied(boolean occupied) { + this.occupied = occupied; + } + + public int[][] rotateRight() { + // TODO Auto-generated method stub + return null; } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/S_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/S_Block.java @@ -1,5 +1,25 @@ package blocks; -public class S_Block { +import java.awt.Color; +public class S_Block extends Poly { + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { { 0, 1, 1 }, { 1, 1, 0 }, }; + + public S_Block(int x, int y) { + super(x, y); + super.setColor(Color.green); + } + + @Override + public int[][] getShape() { + // TODO Auto-generated method stub + return Shape; + } + + @Override + public void rotate() { + Shape = super.rotateRight(Shape); + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/T_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/T_Block.java @@ -1,5 +1,25 @@ package blocks; -public class T_Block implements Tileable { +import java.awt.Color; +public class T_Block extends Poly { + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { { 0, 1, 0 }, { 1, 1, 1 }, }; + + public T_Block(int x, int y) { + super(x, y); + super.setColor(Color.magenta); + } + + @Override + public int[][] getShape() { + // TODO Auto-generated method stub + return Shape; + } + + @Override + public void rotate() { + Shape = super.rotateRight(Shape); + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Tile.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Tile.java @@ -4,32 +4,34 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; - -public class Tile { - int posX; - int posY; +public class Tile implements Tileable { Color color; - - - - public Tile(int x, int y, Color color) { + boolean occupied; + + public Tile(boolean occupied) { + this.occupied = occupied; + } + + public Tile(Color color) { this.color = color; - this.posX = x; - this.posY = y; + this.occupied = true; } - + public void setColor(Color color) { this.color = color; } - + public Color getColor() { return color; } - - public int[] getPos() { - int[] positions = {posX, posY}; - return positions; + + @Override + public void setOccupied(boolean occupied) { + this.occupied = occupied; } - - + + public boolean isOccupied() { + return occupied; + } + } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Tileable.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Tileable.java @@ -3,11 +3,13 @@ package blocks; import java.awt.Color; public interface Tileable { - //public int[][] getShape(); + public boolean isOccupied(); - //public Color getColor(); + void setOccupied(boolean state); + + public Color getColor(); - //public void rotateRight(); + public void setColor(Color color); + - //public void setPosition(int x, int y); } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Z_Block.java b/OOP2023_a22willi_a21liltr_assignment4/src/blocks/Z_Block.java @@ -1,5 +1,27 @@ package blocks; -public class Z_Block { +import java.awt.Color; +public class Z_Block extends Poly { + // holds the information that dictates what shape the object becomes on the + // board + public int[][] Shape = { + + { 1, 1, 0 }, { 0, 1, 1 }, }; + + public Z_Block(int x, int y) { + super(x, y); + super.setColor(Color.red); + } + + @Override + public int[][] getShape() { + // TODO Auto-generated method stub + return Shape; + } + + @Override + public void rotate() { + Shape = super.rotateRight(Shape); + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/game/BlockFactory.java b/OOP2023_a22willi_a21liltr_assignment4/src/game/BlockFactory.java @@ -1,17 +1,46 @@ package game; import blocks.I_Block; + +import java.util.Random; + import blocks.*; public class BlockFactory { - + + private static Random random; private int[] spawnPos; - - public Poly generatePoly() { - return new I_Block(spawnPos[0], spawnPos[1]); + + public BlockFactory() { + random = new Random(); } - + + public Poly generatePoly(int type) { + switch (type) { + case 0: + return new Z_Block(spawnPos[0], spawnPos[1]); + case 1: + return new I_Block(spawnPos[0], spawnPos[1]); + case 2: + return new J_Block(spawnPos[0], spawnPos[1]); + case 3: + return new L_Block(spawnPos[0], spawnPos[1]); + case 4: + return new S_Block(spawnPos[0], spawnPos[1]); + case 5: + return new O_Block(spawnPos[0], spawnPos[1]); + case 6: + return new T_Block(spawnPos[0], spawnPos[1]); + default: + return new O_Block(spawnPos[0], spawnPos[1]); + } + } + public void setSpawn(int[] spawnPos) { this.spawnPos = spawnPos; } + + public Poly generateRandomPoly() { + return generatePoly(random.nextInt(0, 6)); + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/game/Board.java b/OOP2023_a22willi_a21liltr_assignment4/src/game/Board.java @@ -3,6 +3,7 @@ package game; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.Graphics; import java.util.ArrayList; @@ -14,136 +15,221 @@ import blocks.Tileable; import blocks.Poly; public class Board extends JPanel { - //size of window - private final Dimension size = new Dimension(595, 797); - //size of each individual tile - private final int tileSize = 20; - - private Poly[][] grid; - + // size of window + private final Dimension size = new Dimension(290, 790); + + private final Color backgroundColor = Color.DARK_GRAY; + + // size of each individual tile + private final int tileSize = 25; + + private int score; + + private Tileable[][] grid; + private ArrayList<Poly> polys = new ArrayList<Poly>(); - - private Poly fallingPoly; private boolean polyFalling; - + public Board() { - grid = new Poly[Math.abs(size.width / tileSize)][Math.abs(size.height / tileSize)]; + grid = new Tileable[Math.abs(size.width / tileSize)][Math.abs(size.height / tileSize)]; setBorder(BorderFactory.createLineBorder(Color.black)); polyFalling = false; + score = 0; + fillGrid(); + } + + public void fillGrid() { + for (int x = 0; x < grid[0].length; x++) { + for (int y = 0; y < grid.length; y++) { + grid[y][x] = new Tile(false); + } + } + } + + public void detectFullRow() { + for (int row = 0; row < grid[0].length; row++) { + for (int col = 0; col < grid.length; col++) { + if (!(grid[col][row].isOccupied())) { + break; + // System.out.println("Found occupied tile at: " + col + ":" + row); + } + if (col == grid.length - 1) { + score += 10; + clearRow(row); + tileFall(row); + } + } + } + } + + private void clearRow(int rowNumber) { + System.out.println("Clearing row: " + rowNumber); + for (int col = 0; col < grid.length; col++) { + grid[col][rowNumber].setOccupied(false); + grid[col][rowNumber].setColor(backgroundColor); + } } + public void givePoints(int amount) { + score += amount; + } + public Dimension getSize() { return this.size; } - + public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.gray); draw(g); } - - - public void addPoly(Poly poly) { - polys.add(poly); - } - - public int[] getPrefferedSpawn() { - int[] spawn = {grid.length / 2, 2}; - return spawn; - } - - /* - public void drawPoly(Poly poly) { - for (int x = 0; x < poly.getShape().length; x++) { - for (int y = 0; y < poly.getShape()[0].length; y++) { - addTile(new Tile(grid.length / 2, 2, Color.red), x, y); - } + + public boolean move(Poly poly, int x, int y) { + if (clear(poly, x, y)) { + poly.move(x, y); + return true; } - }*/ - - /* - public void drawPoly(Tileable poly) { - fallingPoly = (Poly) poly; + return false; + } + + private boolean clear(Poly poly, int x, int y) { int[][] shape = poly.getShape(); - for (int x = 0; x < shape.length; x++) { - for (int y = 0; y < shape[0].length; y++) { - Tile tile = new Tile(grid.length / 2, 2, poly.getColor()); - grid[tile.getPos()[0] + y][tile.getPos()[1] + x] = tile; - addTile(new Tile(grid.length / 2, 2, Color.red), x, y); - } - } - }*/ - - /* - private void addTile(Tile tile, int x, int y) { - grid[tile.getPos()[0] + y][tile.getPos()[1] + x] = tile; - }*/ - - /** - * Draws the grid (this code needs fixing) - * @param g - */ - - /** - public void draw(Graphics g) { - for (int x = 0; x < grid.length; x++) { - for (int y = 0; y < grid[0].length; y++) { - - - int posX = x*tileSize; - int posY = y*tileSize; - - - if (grid[x][y] != null) { - int[][] shape = grid[x][y].getShape(); - for (int i = 0; i < shape.length; i++) { - for (int j = 0; j < shape[0].length; j++) { - if (shape[i][j] == 1) { - - System.out.println("drawing tile at position: " + (posX + (i * tileSize))+ " " + (posY + (j * tileSize))); - g.setColor(grid[x][y].getColor()); - g.fillRect(posX + (i * tileSize), posY + (j * tileSize), tileSize, tileSize); - } + int[] position = poly.getPos(); + + // iterate over every "tile" in poly shape + for (int i = 0; i < shape.length; i++) { + for (int j = 0; j < shape[0].length; j++) { + int realX = position[0] + j; + int realY = position[1] + i; + if (shape[i][j] == 1) { + // check X direction + if (x != 0) { + if (realX + x >= grid.length || realX + x < 0) { + return false; + } + if (grid[realX + x][realY].isOccupied()) { + return false; + } + } + + // check y direction + if (y != 0) { + if (realY + y >= grid[0].length - 1) { + return false; + } + if (grid[realX][realY + y].isOccupied()) { + return false; } } } - else { - g.setColor(Color.gray); - //g.fillRect(posX, posY, tileSize, tileSize); + } + } + + return true; + } + + public Poly getFallingPoly() { + if (!(polys.isEmpty())) { + return polys.get(polys.size() - 1); + } + return null; + } + + public void freeze(Poly poly) { + int[][] shape = poly.getShape(); + int[] position = poly.getPos(); + for (int i = 0; i < shape.length; i++) { + for (int j = 0; j < shape[0].length; j++) { + if (shape[i][j] == 1) { + grid[position[0] + j][position[1] + i] = new Tile(poly.getColor()); } } } - }**/ - + polyFalling = false; + polys.remove(poly); + } + + public boolean isFalling() { + return polyFalling; + } + + public void fall(Poly poly) { + polyFalling = true; + if (move(poly, 0, 1)) { + return; + } else { + freeze(poly); + } + } + + public void tileFall(int row) { + for (int j = row; j > 0; j--) { + System.out.println("moving row " + j + " to " + (j - 1)); + for (int i = grid.length - 1; i >= 0; i--) { + grid[i][j] = grid[i][j - 1]; + } + } + } + + public boolean hasLost() { + for (int i = 0; i < grid.length; i++) { + if (grid[i][0].isOccupied()) { + return true; + } + } + return false; + } + + public void addPoly(Poly poly) { + polys.add(poly); + polyFalling = true; + } + + public int[] getPrefferedSpawn() { + int[] spawn = { grid.length / 2, 0 }; + return spawn; + } + private void clearBoard(Graphics g) { - g.setColor(Color.DARK_GRAY); + g.setColor(backgroundColor); g.fillRect(0, 0, size.width, size.height); } - + public void draw(Graphics g) { clearBoard(g); - for (Poly poly : polys) { - g.setColor(poly.getColor()); - int[][] shape = poly.getShape(); - - for (int i = 0; i < shape.length; i++) { - for (int j = 0; j < shape[0].length; j++) { - if (shape[i][j] == 1) { - System.out.println("Drawing poly at" + poly.getPos()[0]+ " " + (i*tileSize) + " : " + poly.getPos()[1]+(j*tileSize)); - g.fillRect(poly.getPos()[0] * tileSize + (i * tileSize), poly.getPos()[1] * tileSize + (j * tileSize), tileSize, tileSize); + + // show score + g.setColor(Color.white); + String scoreText = "Score: " + String.valueOf(score); + g.setFont(new Font("Helvetica", Font.PLAIN, tileSize)); + g.drawString(scoreText, tileSize, g.getFontMetrics().getHeight()); + + // draw polys + if (polys.size() > 0) { + for (Poly poly : polys) { + g.setColor(poly.getColor()); + int[][] shape = poly.getShape(); + + for (int i = 0; i < shape.length; i++) { + for (int j = 0; j < shape[0].length; j++) { + if (shape[i][j] == 1) { + g.fillRect(poly.getPos()[0] * tileSize + (j * tileSize), + poly.getPos()[1] * tileSize + (i * tileSize), tileSize, tileSize); + } } - } + } } } - } - - /** - private void generateGrid(Graphics g) { - for (int x = 0; x < Math.abs(size.width / tileSize); x++) { - for (int y = 0; y < Math.abs(size.height / tileSize); y++) { - grid[y][x] = new Cell(g, y, x, size); + + // draw tiles + for (int x = 0; x < grid[0].length; x++) { + for (int y = 0; y < grid.length; y++) { + if (grid[y][x].isOccupied()) { + g.setColor(grid[y][x].getColor()); + g.fillRect(y * tileSize, x * tileSize, tileSize, tileSize); + } } } - }**/ + } } diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/game/GUI.java b/OOP2023_a22willi_a21liltr_assignment4/src/game/GUI.java @@ -4,21 +4,69 @@ import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import javax.swing.JFrame; -public class GUI { +public class GUI extends JFrame implements KeyListener { Board board; - + JFrame frame; + public GUI(Board board) { this.board = board; - JFrame frame = new JFrame("Tetris"); + frame = new JFrame("Tetris"); + frame.addKeyListener(this); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(board.getSize()); frame.setResizable(false); - + frame.add(board); - + frame.setVisible(true); } + + @Override + public void keyTyped(KeyEvent e) { + // TODO Auto-generated method stub + + } + + @Override + + public void keyPressed(KeyEvent e) { + switch (e.getKeyCode()) { + // spaceBar + case 32: + movePoly(0, 1); + break; + // left + case 37: + movePoly(-1, 0); + break; + // right + case 39: + movePoly(1, 0); + break; + // rotate + case 38: + if (board.getFallingPoly() != null) { + board.getFallingPoly().rotate(); + } + } + + board.repaint(); + } + + @Override + public void keyReleased(KeyEvent e) { + // TODO Auto-generated method stub + + } + + private void movePoly(int x, int y) { + if (board.getFallingPoly() != null) { + board.move(board.getFallingPoly(), x, y); + } + } } \ No newline at end of file diff --git a/OOP2023_a22willi_a21liltr_assignment4/src/game/Game.java b/OOP2023_a22willi_a21liltr_assignment4/src/game/Game.java @@ -8,32 +8,43 @@ import blocks.Poly; public class Game { private Board board; private Timer timer; - + private final int tickRate = 200; + BlockFactory factory; - + private Poly poly; - - + public Game(Board board) { timer = new Timer(); - timer.scheduleAtFixedRate(gameLoop, (long) 500, (long) 500); + timer.scheduleAtFixedRate(gameLoop, tickRate, tickRate); this.board = board; factory = new BlockFactory(); factory.setSpawn(board.getPrefferedSpawn()); - - poly = factory.generatePoly(); - board.addPoly(poly); } - + private TimerTask gameLoop = new TimerTask() { @Override public void run() { - board.repaint(); - - - poly.move(0, 1); - - board.repaint(); + board.detectFullRow(); + if (!(board.hasLost())) { + board.repaint(); + if (board.isFalling()) { + board.fall(poly); + } else { + board.givePoints(1); + poly = factory.generateRandomPoly(); + board.addPoly(poly); + } + + board.repaint(); + } else { + resetGame(); + } } }; + + private void resetGame() { + System.out.println("Restarting game"); + this.board = new Board(); + } }