From 489a043441fdbdee902a74ac30fe479948ed80ea Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Sun, 16 Aug 2020 09:24:46 +0900 Subject: [PATCH] Finish implementation of Tetris! Download the jar if you want to play it. --- Tetris/Tetris.jar | Bin 0 -> 48356 bytes Tetris/src/sig/game/Color.java | 26 +- Tetris/src/sig/game/Frame.java | 1 + Tetris/src/sig/game/Game.java | 420 ++++++++++++++++----------- Tetris/src/sig/game/GameCanvas.java | 132 +++++++++ Tetris/src/sig/game/Grid.java | 2 +- Tetris/src/sig/game/Key.java | 18 ++ Tetris/src/sig/game/Player.java | 28 +- Tetris/src/sig/game/PlayerBlock.java | 5 + Tetris/src/sig/game/Shape.java | 2 + Tetris/src/sig/utils/DrawUtils.java | 21 +- Tetris/src/sig/utils/TextUtils.java | 7 +- 12 files changed, 462 insertions(+), 200 deletions(-) create mode 100644 Tetris/Tetris.jar create mode 100644 Tetris/src/sig/game/GameCanvas.java create mode 100644 Tetris/src/sig/game/Key.java create mode 100644 Tetris/src/sig/game/PlayerBlock.java diff --git a/Tetris/Tetris.jar b/Tetris/Tetris.jar new file mode 100644 index 0000000000000000000000000000000000000000..a8ef4b62308fcff251656ecf789ec426ea2b419a GIT binary patch literal 48356 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 keyMap = new HashMap<>(); + + final public static Frame LPiece = new Frame( + new Shape( + "XOXX" + + "XOXX" + + "XOOX" + + "XXXX"), + new Shape( + "XXXX" + + "XOOO" + + "XOXX" + + "XXXX"), + new Shape( + "XOOX" + + "XXOX" + + "XXOX" + + "XXXX"), + new Shape( + "XXXX" + + "XXOX" + + "OOOX" + + "XXXX") + ,Color.ORANGE); + final public static Frame JPiece = new Frame( + new Shape( + "XXOX" + + "XXOX" + + "XOOX" + + "XXXX"), + new Shape( + "XOXX" + + "XOOO" + + "XXXX" + + "XXXX"), + new Shape( + "XOOX" + + "XOXX" + + "XOXX" + + "XXXX"), + new Shape( + "OOOX" + + "XXOX" + + "XXXX" + + "XXXX") + ,Color.BLUE); + final public static Frame SPiece = new Frame( + new Shape( + "XOXX" + + "XOOX" + + "XXOX" + + "XXXX"), + new Shape( + "XOOX" + + "OOXX" + + "XXXX" + + "XXXX"), + new Shape( + "XOXX" + + "XOOX" + + "XXOX" + + "XXXX"), + new Shape( + "XOOX" + + "OOXX" + + "XXXX" + + "XXXX") + ,Color.RED); + final public static Frame ZPiece = new Frame( + new Shape( + "XXOX" + + "XOOX" + + "XOXX" + + "XXXX"), + new Shape( + "OOXX" + + "XOOX" + + "XXXX" + + "XXXX"), + new Shape( + "XXOX" + + "XOOX" + + "XOXX" + + "XXXX"), + new Shape( + "OOXX" + + "XOOX" + + "XXXX" + + "XXXX") + ,Color.GREEN); + final public static Frame TPiece = new Frame( + new Shape( + "OOOX" + + "XOXX" + + "XXXX" + + "XXXX"), + new Shape( + "XOXX" + + "OOXX" + + "XOXX" + + "XXXX"), + new Shape( + "XOXX" + + "OOOX" + + "XXXX" + + "XXXX"), + new Shape( + "XOXX" + + "XOOX" + + "XOXX" + + "XXXX") + ,Color.PURPLE); + final public static Frame OPiece = new Frame( + new Shape( + "XOOX" + + "XOOX" + + "XXXX" + + "XXXX"), + new Shape( + "XOOX" + + "XOOX" + + "XXXX" + + "XXXX"), + new Shape( + "XOOX" + + "XOOX" + + "XXXX" + + "XXXX"), + new Shape( + "XOOX" + + "XOOX" + + "XXXX" + + "XXXX") + ,Color.YELLOW); + final public static Frame IPiece = new Frame( + new Shape( + "XXOX" + + "XXOX" + + "XXOX" + + "XXOX"), + new Shape( + "OOOO" + + "XXXX" + + "XXXX" + + "XXXX"), + new Shape( + "XXOX" + + "XXOX" + + "XXOX" + + "XXOX"), + new Shape( + "OOOO" + + "XXXX" + + "XXXX" + + "XXXX") + ,Color.AQUA); + public static void main(String[] args) { - final Frame LPiece = new Frame( - new Shape( - "XOXX" - + "XOXX" - + "XOOX" - + "XXXX"), - new Shape( - "XXXX" - + "XOOO" - + "XOXX" - + "XXXX"), - new Shape( - "XOOX" - + "XXOX" - + "XXOX" - + "XXXX"), - new Shape( - "XXXX" - + "XXOX" - + "OOOX" - + "XXXX") - ,Color.ORANGE); - final Frame JPiece = new Frame( - new Shape( - "XXOX" - + "XXOX" - + "XOOX" - + "XXXX"), - new Shape( - "XOXX" - + "XOOO" - + "XXXX" - + "XXXX"), - new Shape( - "XXOX" - + "XXOX" - + "XOOX" - + "XXXX"), - new Shape( - "OOOX" - + "XXOX" - + "XXXX" - + "XXXX") - ,Color.BLUE); - final Frame SPiece = new Frame( - new Shape( - "XOXX" - + "XOOX" - + "XXOX" - + "XXXX"), - new Shape( - "XOOX" - + "OOXX" - + "XXXX" - + "XXXX"), - new Shape( - "XOXX" - + "XOOX" - + "XXOX" - + "XXXX"), - new Shape( - "XOOX" - + "OOXX" - + "XXXX" - + "XXXX") - ,Color.RED); - final Frame ZPiece = new Frame( - new Shape( - "XXOX" - + "XOOX" - + "XOXX" - + "XXXX"), - new Shape( - "OOXX" - + "XOOX" - + "XXXX" - + "XXXX"), - new Shape( - "XXOX" - + "XOOX" - + "XOXX" - + "XXXX"), - new Shape( - "OOXX" - + "XOOX" - + "XXXX" - + "XXXX") - ,Color.GREEN); - final Frame TPiece = new Frame( - new Shape( - "OOOX" - + "XOXX" - + "XXXX" - + "XXXX"), - new Shape( - "XOXX" - + "OOXX" - + "XOXX" - + "XXXX"), - new Shape( - "XOXX" - + "OOOX" - + "XXXX" - + "XXXX"), - new Shape( - "XOXX" - + "XOOX" - + "XOXX" - + "XXXX") - ,Color.PURPLE); - final Frame OPiece = new Frame( - new Shape( - "XOOX" - + "XOOX" - + "XXXX" - + "XXXX"), - new Shape( - "XOOX" - + "XOOX" - + "XXXX" - + "XXXX"), - new Shape( - "XOOX" - + "XOOX" - + "XXXX" - + "XXXX"), - new Shape( - "XOOX" - + "XOOX" - + "XXXX" - + "XXXX") - ,Color.YELLOW); - final Frame IPiece = new Frame( - new Shape( - "XXOX" - + "XXOX" - + "XXOX" - + "XXOX"), - new Shape( - "OOOO" - + "XXXX" - + "XXXX" - + "XXXX"), - new Shape( - "XXOX" - + "XXOX" - + "XXOX" - + "XXOX"), - new Shape( - "OOOO" - + "XXXX" - + "XXXX" - + "XXXX") - ,Color.AQUA); - piecePool = new Frame[] {LPiece,JPiece,SPiece,ZPiece,TPiece,OPiece,IPiece}; p = new Player(); + frame = new JFrame(); + canvas = new GameCanvas(); + frame.addKeyListener(canvas); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setSize(1024, 576); + frame.setTitle("My Tetris Game"); + frame.add(canvas); + frame.setResizable(false); + frame.setVisible(true); + TimerTask stepTask = new TimerTask() { @Override @@ -194,27 +222,71 @@ public class Game { Timer t = new Timer(); t.schedule(stepTask, 0, (long)Math.floor(1000/60f)); - } static void step() { tickDelay--; - rotateTimer--; - if (tickDelay<=0) { - moveBlock(); - tickDelay=levelDelay[level]; - } - if (rotateTimer<=0) { - //p.rotateCounterClockwise(); - p.moveBlockLeft(); - rotateTimer=rotateDelay; + //rotateTimer--; + if (state!=GameState.LOSE) { + if (tickDelay<=0) { + moveBlock(); + tickDelay=levelDelay[level]; + } + /*if (rotateTimer<=0) { + //p.rotateCounterClockwise(); + p.moveBlockLeft(); + rotateTimer=rotateDelay; + }*/ + HandleKeys(); } DrawBoard(); } + private static void HandleKeys() { + if (AreKeysHeldDown(KeyEvent.VK_LEFT,KeyEvent.VK_A)) { + Game.p.moveBlockLeft(); + UpdateKeyDelay(KeyEvent.VK_LEFT,KeyEvent.VK_A); + } + if (AreKeysHeldDown(KeyEvent.VK_RIGHT,KeyEvent.VK_D)) { + Game.p.moveBlockRight(); + UpdateKeyDelay(KeyEvent.VK_RIGHT,KeyEvent.VK_D); + } + if (AreKeysHeldDown(KeyEvent.VK_S,KeyEvent.VK_DOWN)) { + Game.tickDelay=1; + UpdateKeyDelay(KeyEvent.VK_S,KeyEvent.VK_DOWN); + } + } + + private static void UpdateKeyDelay(int...keys) { + for (int i=0;i=0;y--) { for (int x=0;x<10;x++) { boolean plotted=false; @@ -252,7 +324,7 @@ public class Game { } }*/ - Point[] checkPoints = p.GetPlayerBlocksInGrid(p.getCurrentShape()); + Point[] checkPoints = p.GetPlayerBlocksInGrid(p.getCurrentShape(),p.pos); boolean isOccupied = isOccupied(checkPoints,new Point(0,-1)); @@ -270,6 +342,10 @@ public class Game { //System.out.println("Called: "+y); deletionRows = CheckAndClearFullRows(deletionRows, y); } + linesCleared+=deletionRows; + if (linesCleared/10>level && level<19) { + level=linesCleared/10; + } } private static int CheckAndClearFullRows(int deletionRows, int y) { @@ -298,7 +374,9 @@ public class Game { private static void ShiftBlockDownByNumberOfDeletionRows(int deletionRows, int y, int x) { if (deletionRows>0) { gameGrid.grid[x][y-deletionRows].active=gameGrid.grid[x][y].active; + gameGrid.grid[x][y-deletionRows].color=gameGrid.grid[x][y].color; gameGrid.grid[x][y].active=false; + gameGrid.grid[x][y].color=Color.BLACK; } } @@ -309,10 +387,12 @@ public class Game { private static void SnapPieceThatCollided(Point[] checkPoints) { for (Point point : checkPoints) { //If any point in the grid is outside, this is our lose condition. - if (point.y>=gameGrid.grid[0].length) { + if (point.y>=20) { state = GameState.LOSE; + } else { + gameGrid.grid[point.x][point.y].active=true; + gameGrid.grid[point.x][point.y].color=p.getCurrentShape().col; } - gameGrid.grid[point.x][point.y].active=true; } p.ShuffleNextPiece(); } @@ -325,6 +405,7 @@ public class Game { for (int i=0;i=gameGrid.grid[0].length|| point.x+offset.x>=gameGrid.grid.length|| @@ -333,6 +414,7 @@ public class Game { isOccupied=true; break; } + //System.out.println("Pass"); } return isOccupied; } diff --git a/Tetris/src/sig/game/GameCanvas.java b/Tetris/src/sig/game/GameCanvas.java new file mode 100644 index 0000000..821a6e1 --- /dev/null +++ b/Tetris/src/sig/game/GameCanvas.java @@ -0,0 +1,132 @@ +package sig.game; + +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JPanel; + +import sig.utils.DrawUtils; + +public class GameCanvas extends JPanel implements KeyListener{ + public final static Font displayText = new Font("Consolas",Font.BOLD,24); + + public final static int WINDOW_WIDTH = 1024; + public final static int WINDOW_HEIGHT = 576; + + public final static int BLOCK_SIZE = 24; + public final static int FIELD_WIDTH = BLOCK_SIZE*10; + public final static int FIELD_HEIGHT = BLOCK_SIZE*20; + + public final static int FIELD_STARTX = WINDOW_WIDTH/2-FIELD_WIDTH/2; + public final static int FIELD_STARTY = WINDOW_HEIGHT/2+FIELD_HEIGHT/2; + + public final static int LINES_CLEARED_DISPLAYX = WINDOW_WIDTH/2+180; + public final static int LINES_CLEARED_DISPLAYY = WINDOW_HEIGHT/2; + + public final static int LEVEL_DISPLAYX = WINDOW_WIDTH/2+180; + public final static int LEVEL_DISPLAYY = LINES_CLEARED_DISPLAYY-64; + + public final static int NEXTPIECE_DISPLAYX = WINDOW_WIDTH/2+180; + public final static int NEXTPIECE_DISPLAYY = LEVEL_DISPLAYY-128; + + public void paintComponent(Graphics g) { + g.setColor(java.awt.Color.DARK_GRAY); + g.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + //System.out.println("Redrawn"); + Point[] checkPoints = Game.p.GetPlayerBlocksInGrid(Game.p.getCurrentShape(),Game.p.pos); + for (int y=0;y<20;y++) { + for (int x=0;x<10;x++) { + boolean plotted=false; + for (Point point : checkPoints) { + if (point.x==x && point.y==y) { + plotted=true; + //System.out.print('P'); + g.setColor((Game.state==GameState.LOSE) + ?java.awt.Color.LIGHT_GRAY: + Game.p.getCurrentShape().col.getColor()); + Point blockCoord=getBlockCoordinateToPixelCoordinate(point); + g.fill3DRect(blockCoord.x, blockCoord.y, BLOCK_SIZE, BLOCK_SIZE, false); + break; + } + } + if (!plotted) { + g.setColor((Game.state==GameState.LOSE&&Game.gameGrid.grid[x][y].active) + ?java.awt.Color.LIGHT_GRAY:Game.gameGrid.grid[x][y].color.getColor()); + Point blockCoord=getBlockCoordinateToPixelCoordinate(new Point(x,y)); + g.fill3DRect(blockCoord.x, blockCoord.y, BLOCK_SIZE, BLOCK_SIZE, false); + } + } + } + Point[] nextPoints = Game.p.GetPlayerBlocksInGrid(Game.p.getNextShape(),new Point(0,0)); + + g.setColor(java.awt.Color.BLACK); + g.fill3DRect(NEXTPIECE_DISPLAYX, NEXTPIECE_DISPLAYY, 104, 104, true); + for (Point p : nextPoints) { + g.setColor(Game.p.getNextShape().col.getColor()); + g.fill3DRect(p.x*BLOCK_SIZE+NEXTPIECE_DISPLAYX+52, p.y*BLOCK_SIZE+NEXTPIECE_DISPLAYY+52, BLOCK_SIZE, BLOCK_SIZE, false); + } + g.setColor(java.awt.Color.WHITE); + g.setFont(displayText); + g.drawString("NEXT",NEXTPIECE_DISPLAYX,NEXTPIECE_DISPLAYY); + g.setColor(java.awt.Color.WHITE); + g.setFont(displayText); + g.drawString("LINES",LINES_CLEARED_DISPLAYX,LINES_CLEARED_DISPLAYY); + g.drawString(Integer.toString(Game.linesCleared),LINES_CLEARED_DISPLAYX+6,LINES_CLEARED_DISPLAYY+24); + g.drawString("LEVEL",LEVEL_DISPLAYX,LEVEL_DISPLAYY); + g.drawString(Integer.toString(Game.level+1),LEVEL_DISPLAYX+6,LEVEL_DISPLAYY+24); + if (Game.state==GameState.LOSE) { + DrawUtils.drawCenteredText(g, g.getFont(),this, WINDOW_WIDTH/2, WINDOW_HEIGHT/2, java.awt.Color.WHITE, "Press R to Restart!"); + } + } + + public Point getBlockCoordinateToPixelCoordinate(Point blockLoc) { + return new Point(FIELD_STARTX+BLOCK_SIZE*blockLoc.x,FIELD_STARTY-BLOCK_SIZE*blockLoc.y); + } + + @Override + public void keyPressed(KeyEvent e) { + List keys = Arrays.asList( + KeyEvent.VK_LEFT,KeyEvent.VK_A, + KeyEvent.VK_RIGHT,KeyEvent.VK_D, + KeyEvent.VK_S,KeyEvent.VK_DOWN + ); + Game.lastKey=e.getKeyCode(); + /*if ((Game.keyMap.containsKey(e.getKeyCode())&&!Game.keyMap.get(e.getKeyCode())&&keys.contains(e.getKeyCode()) + )||!Game.keyMap.containsKey(e.getKeyCode())) { + System.out.println("Executing"); + Game.keyDelay=20; + }*/ + if (Game.keyMap.containsKey(e.getKeyCode())) { + Game.keyMap.put(e.getKeyCode(),Game.keyMap.get(e.getKeyCode()).updatePress(true)); + } else { + Game.keyMap.put(e.getKeyCode(),new Key(true)); + } + if (e.getKeyCode()==KeyEvent.VK_Z||e.getKeyCode()==KeyEvent.VK_COMMA) { + Game.p.rotateClockwise(); + } + if (e.getKeyCode()==KeyEvent.VK_X||e.getKeyCode()==KeyEvent.VK_PERIOD) { + Game.p.rotateCounterClockwise(); + } + if (e.getKeyCode()==KeyEvent.VK_R && Game.state==GameState.LOSE) { + Game.p = new Player(); + Game.gameGrid = new Grid(); + Game.level=0; + Game.linesCleared=0; + Game.state=GameState.PLAYING; + } + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + Game.keyMap.put(e.getKeyCode(),Game.keyMap.get(e.getKeyCode()).updatePress(false)); + } +} diff --git a/Tetris/src/sig/game/Grid.java b/Tetris/src/sig/game/Grid.java index 12b9716..6c4b4d2 100644 --- a/Tetris/src/sig/game/Grid.java +++ b/Tetris/src/sig/game/Grid.java @@ -5,7 +5,7 @@ import java.util.Arrays; public class Grid { final int GRID_WIDTH = 10; - final int GRID_HEIGHT = 20; + final int GRID_HEIGHT = 24; Block[][] grid = new Block[GRID_WIDTH][GRID_HEIGHT]; diff --git a/Tetris/src/sig/game/Key.java b/Tetris/src/sig/game/Key.java new file mode 100644 index 0000000..2ec96f7 --- /dev/null +++ b/Tetris/src/sig/game/Key.java @@ -0,0 +1,18 @@ +package sig.game; + +public class Key { + boolean pressed; + int timer; + public Key(boolean pressed) { + this.pressed=pressed; + this.timer=0; + } + public Key updatePress(boolean pressed) { + this.pressed=pressed; + return this; + } + public Key setTimer(int timer) { + this.timer=timer; + return this; + } +} diff --git a/Tetris/src/sig/game/Player.java b/Tetris/src/sig/game/Player.java index 24d3e9c..51c9d8f 100644 --- a/Tetris/src/sig/game/Player.java +++ b/Tetris/src/sig/game/Player.java @@ -20,10 +20,10 @@ public class Player { public void ShuffleNextPiece() { piece = nextPiece.clone(); nextPiece = SelectRandomTetrimino(); - pos = new Point(5,20); + pos = new Point(5,21); } - public Point[] GetPlayerBlocksInGrid(Shape s) { + public Point[] GetPlayerBlocksInGrid(Shape s,Point offset) { Point[] checkPoints = new Point[4]; Shape tetShape = s; int pointsInserted=0; @@ -31,7 +31,7 @@ public class Player { for (int y=0;y=0) { + //System.out.println(p.x+","+p.y); isFree=false; break; } @@ -92,14 +93,19 @@ public class Player { private void RotateIfSpaceIsFree(Point[] checkPoints,RotationDirection dir) { int[] offset = new int[]{0,-1,1}; - int freeOffset = -1; + if (Game.p.getCurrentShape().equals(Game.IPiece.shape[Game.rotation])) { + //System.out.println("Is I Piece."); + offset = new int[] {0,-1,1,-2,2,-3}; + } + int freeOffset = -99999; for (int i=0;i0) { - AttributedString as = new AttributedString(message); - as.addAttribute(TextAttribute.FONT, MyPanel.programFont); + /*AttributedString as = new AttributedString(message); + as.addAttribute(TextAttribute.FONT, MyPanel.programFont);*/ g.setColor(color); - g.drawString(as.getIterator(),(int)x,(int)y); + g.drawString(message,(int)x,(int)y); } } public static void drawTextFont(Graphics g, Font font, double x, double y, Color color, String message) { @@ -90,11 +91,11 @@ public class DrawUtils { /** * Centers the text along the X Axis. */ - public static void drawCenteredText(Graphics g, Font font, int x, int y, Color color, String text) { + public static void drawCenteredText(Graphics g, Font font,JPanel panel, int x, int y, Color color, String text) { AttributedString as = new AttributedString(text); as.addAttribute(TextAttribute.FONT, font); g.setColor(color); - Rectangle2D textBounds = TextUtils.calculateStringBoundsFont(text, font); + Rectangle2D textBounds = TextUtils.calculateStringBoundsFont(panel,text, font); g.drawString(as.getIterator(),(int)(x-textBounds.getWidth()/2),(int)(y+textBounds.getHeight())); } diff --git a/Tetris/src/sig/utils/TextUtils.java b/Tetris/src/sig/utils/TextUtils.java index 693f45f..4e0002d 100644 --- a/Tetris/src/sig/utils/TextUtils.java +++ b/Tetris/src/sig/utils/TextUtils.java @@ -6,12 +6,13 @@ import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.List; -import sig.MyRobot; + +import javax.swing.JPanel; public class TextUtils { - public static Rectangle2D calculateStringBoundsFont(String msg, Font font) { - FontRenderContext frc = MyRobot.p.getFontMetrics(font).getFontRenderContext(); + public static Rectangle2D calculateStringBoundsFont(JPanel panel,String msg, Font font) { + FontRenderContext frc = panel.getFontMetrics(font).getFontRenderContext(); return font.getStringBounds(msg, frc); }