Tetris/Java: Difference between revisions
Content added Content deleted
m (turn previewOffsets into EnumMap) |
(→{{header|Java}}: cleaned up code a bit, calculate preview offsets) |
||
Line 1: | Line 1: | ||
==Code== |
==Code== |
||
{{works with|java|8}} |
{{works with|java|8}} |
||
<lang java> |
<lang java>package tetris; |
||
⚫ | |||
import java.awt.event.*; |
import java.awt.event.*; |
||
⚫ | |||
import static java.lang.String.format; |
import static java.lang.String.format; |
||
import java.util. |
import java.util.*; |
||
⚫ | |||
⚫ | |||
import javax.swing.*; |
import javax.swing.*; |
||
import static tetris.Config.*; |
|||
public class Tetris extends JPanel implements Runnable { |
public class Tetris extends JPanel implements Runnable { |
||
⚫ | |||
right(1, 0), down(0, 1), left(-1, 0); |
|||
Dir(int x, int y) { |
|||
this.x = x; |
|||
this.y = y; |
|||
⚫ | |||
⚫ | |||
}; |
|||
public static final int EMPTY = -1; |
public static final int EMPTY = -1; |
||
public static final int BORDER = -2; |
public static final int BORDER = -2; |
||
Shape fallingShape; |
Shape fallingShape; |
||
Shape |
Shape nextShape; |
||
// position of falling shape |
// position of falling shape |
||
int fallingShapeRow; |
int fallingShapeRow; |
||
int fallingShapeCol; |
int fallingShapeCol; |
||
final int blockSize = Config.blockSize; |
|||
⚫ | |||
final int nCols = Config.nCols; |
|||
final int topMargin = Config.topMargin; |
|||
final int leftMargin = Config.leftMargin; |
|||
final int[][] grid = new int[nRows][nCols]; |
final int[][] grid = new int[nRows][nCols]; |
||
Line 33: | Line 39: | ||
public Tetris() { |
public Tetris() { |
||
setPreferredSize( |
setPreferredSize(dim); |
||
setBackground( |
setBackground(bgColor); |
||
setFocusable(true); |
setFocusable(true); |
||
Line 67: | Line 73: | ||
case KeyEvent.VK_LEFT: |
case KeyEvent.VK_LEFT: |
||
if (canMove(fallingShape, |
if (canMove(fallingShape, Dir.left)) |
||
move(fallingShape, |
move(fallingShape, Dir.left); |
||
break; |
break; |
||
case KeyEvent.VK_RIGHT: |
case KeyEvent.VK_RIGHT: |
||
if (canMove(fallingShape, |
if (canMove(fallingShape, Dir.right)) |
||
move(fallingShape, |
move(fallingShape, Dir.right); |
||
break; |
break; |
||
Line 79: | Line 85: | ||
if (!fastDown) { |
if (!fastDown) { |
||
fastDown = true; |
fastDown = true; |
||
while (canMove(fallingShape, |
while (canMove(fallingShape, Dir.down)) { |
||
move(fallingShape, |
move(fallingShape, Dir.down); |
||
repaint(); |
repaint(); |
||
} |
} |
||
Line 99: | Line 105: | ||
fallingShapeRow = 1; |
fallingShapeRow = 1; |
||
fallingShapeCol = 5; |
fallingShapeCol = 5; |
||
fallingShape = |
fallingShape = nextShape; |
||
Shape[] shapes = Shape.values(); |
Shape[] shapes = Shape.values(); |
||
nextShape = shapes[rand.nextInt(shapes.length)]; |
|||
if (fallingShape != null) |
if (fallingShape != null) |
||
fallingShape.reset(); |
fallingShape.reset(); |
||
Line 139: | Line 145: | ||
try { |
try { |
||
Thread.sleep(scoreboard.getSpeed()); |
Thread.sleep(scoreboard.getSpeed()); |
||
} catch (InterruptedException |
} catch (InterruptedException e) { |
||
return; |
|||
} |
} |
||
if (!scoreboard.isGameOver()) { |
if (!scoreboard.isGameOver()) { |
||
if (canMove(fallingShape, |
if (canMove(fallingShape, Dir.down)) { |
||
move(fallingShape, |
move(fallingShape, Dir.down); |
||
} else { |
} else { |
||
shapeHasLanded(); |
shapeHasLanded(); |
||
Line 154: | Line 161: | ||
void drawStartScreen(Graphics2D g) { |
void drawStartScreen(Graphics2D g) { |
||
g.setFont( |
g.setFont(mainFont); |
||
g.setColor( |
g.setColor(titlebgColor); |
||
g.fill( |
g.fill(titleRect); |
||
g.fill( |
g.fill(clickRect); |
||
g.setColor( |
g.setColor(textColor); |
||
g.drawString("Tetris", |
g.drawString("Tetris", titleX, titleY); |
||
g.setFont( |
g.setFont(smallFont); |
||
g.drawString("click to start", |
g.drawString("click to start", clickX, clickY); |
||
} |
} |
||
void drawSquare(Graphics2D g, int colorIndex, int r, int c) { |
void drawSquare(Graphics2D g, int colorIndex, int r, int c) { |
||
g.setColor( |
g.setColor(colors[colorIndex]); |
||
g.fillRect(leftMargin + c * blockSize, topMargin + r * blockSize, |
g.fillRect(leftMargin + c * blockSize, topMargin + r * blockSize, |
||
blockSize, blockSize); |
blockSize, blockSize); |
||
g.setStroke( |
g.setStroke(smallStroke); |
||
g.setColor( |
g.setColor(squareBorder); |
||
g.drawRect(leftMargin + c * blockSize, topMargin + r * blockSize, |
g.drawRect(leftMargin + c * blockSize, topMargin + r * blockSize, |
||
blockSize, blockSize); |
blockSize, blockSize); |
||
Line 180: | Line 187: | ||
void drawUI(Graphics2D g) { |
void drawUI(Graphics2D g) { |
||
// grid background |
// grid background |
||
g.setColor( |
g.setColor(gridColor); |
||
g.fill( |
g.fill(gridRect); |
||
// the blocks dropped in the grid |
// the blocks dropped in the grid |
||
Line 193: | Line 200: | ||
// the borders of grid and preview panel |
// the borders of grid and preview panel |
||
g.setStroke( |
g.setStroke(largeStroke); |
||
g.setColor( |
g.setColor(gridBorderColor); |
||
g.draw( |
g.draw(gridRect); |
||
g.draw( |
g.draw(previewRect); |
||
// scoreboard |
// scoreboard |
||
int x = |
int x = scoreX; |
||
int y = |
int y = scoreY; |
||
g.setColor( |
g.setColor(textColor); |
||
g.setFont( |
g.setFont(smallFont); |
||
g.drawString(format("hiscore %6d", scoreboard.getTopscore()), x, y); |
g.drawString(format("hiscore %6d", scoreboard.getTopscore()), x, y); |
||
g.drawString(format("level %6d", scoreboard.getLevel()), x, y + 30); |
g.drawString(format("level %6d", scoreboard.getLevel()), x, y + 30); |
||
Line 209: | Line 216: | ||
// preview |
// preview |
||
int |
int minX = 5, minY = 5, maxX = 0, maxY = 0; |
||
⚫ | |||
int offsetX = Config.previewOffsets.get(preSelectedShape)[0] + 15 * blockSize; |
|||
minX = min(minX, p[0]); |
|||
int offsetY = Config.previewOffsets.get(preSelectedShape)[1] + 2 * blockSize; |
|||
minY = min(minY, p[1]); |
|||
maxX = max(maxX, p[0]); |
|||
maxY = max(maxY, p[1]); |
|||
} |
|||
⚫ | |||
double cx = previewCenterX - ((minX + maxX + 1) / 2.0 * blockSize); |
|||
double cy = previewCenterY - ((minY + maxY + 1) / 2.0 * blockSize); |
|||
g.translate( |
g.translate(cx, cy); |
||
for (int[] p : nextShape.shape) |
|||
drawSquare(g, nextShape.ordinal(), p[1], p[0]); |
|||
g.translate(-cx, -cy); |
|||
} |
} |
||
Line 279: | Line 290: | ||
} |
} |
||
void move(Shape s, |
void move(Shape s, Dir dir) { |
||
fallingShapeRow += |
fallingShapeRow += dir.y; |
||
fallingShapeCol += |
fallingShapeCol += dir.x; |
||
} |
} |
||
boolean canMove(Shape s, |
boolean canMove(Shape s, Dir dir) { |
||
for (int[] p : s.pos) { |
for (int[] p : s.pos) { |
||
int newCol = fallingShapeCol + |
int newCol = fallingShapeCol + dir.x + p[0]; |
||
int newRow = fallingShapeRow + |
int newRow = fallingShapeRow + dir.y + p[1]; |
||
if (grid[newRow][newCol] != EMPTY) |
if (grid[newRow][newCol] != EMPTY) |
||
return false; |
return false; |
||
Line 348: | Line 359: | ||
}); |
}); |
||
} |
} |
||
}</lang> |
|||
} |
|||
<lang java>package tetris; |
|||
class Scoreboard { |
class Scoreboard { |
||
Line 455: | Line 468: | ||
return score; |
return score; |
||
} |
} |
||
}</lang> |
|||
} |
|||
<lang java>package tetris; |
|||
enum Shape { |
enum Shape { |
||
ZShape(new int[][]{{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}), |
ZShape(new int[][]{{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}), |
||
SShape(new int[][]{{0, -1}, {0, 0}, {1, 0}, {1, 1}}), |
SShape(new int[][]{{0, -1}, {0, 0}, {1, 0}, {1, 1}}), |
||
IShape(new int[][]{{0, -1}, {0, 0}, {0, 1}, {0, 2}}), |
|||
TShape(new int[][]{{-1, 0}, {0, 0}, {1, 0}, {0, 1}}), |
TShape(new int[][]{{-1, 0}, {0, 0}, {1, 0}, {0, 1}}), |
||
Square(new int[][]{{0, 0}, {1, 0}, {0, 1}, {1, 1}}), |
Square(new int[][]{{0, 0}, {1, 0}, {0, 1}, {1, 1}}), |
||
Line 479: | Line 494: | ||
final int[][] pos, shape; |
final int[][] pos, shape; |
||
}</lang> |
|||
} |
|||
<lang java>package tetris; |
|||
import java.awt.*; |
|||
final class Config { |
final class Config { |
||
final static Color[] colors = {Color.green, Color.red, Color.blue, |
final static Color[] colors = {Color.green, Color.red, Color.blue, |
||
Color.pink, Color.orange, Color.cyan, Color.magenta}; |
Color.pink, Color.orange, Color.cyan, Color.magenta}; |
||
// used for centering shapes in the preview pane |
|||
final static EnumMap<Shape, int[]> previewOffsets = new EnumMap<>(Shape.class); |
|||
⚫ | |||
previewOffsets.put(Shape.ZShape, new int[]{16, 15}); |
|||
previewOffsets.put(Shape.SShape, new int[]{-15, 15}); |
|||
previewOffsets.put(Shape.Straight, new int[]{0, 0}); |
|||
previewOffsets.put(Shape.TShape, new int[]{0, 0}); |
|||
previewOffsets.put(Shape.Square, new int[]{-15, 5}); |
|||
previewOffsets.put(Shape.LShape, new int[]{16, 15}); |
|||
previewOffsets.put(Shape.JShape, new int[]{-15, 15}); |
|||
⚫ | |||
final static Font mainFont = new Font("Monospaced", Font.BOLD, 48); |
final static Font mainFont = new Font("Monospaced", Font.BOLD, 48); |
||
Line 501: | Line 508: | ||
final static Dimension dim = new Dimension(640, 640); |
final static Dimension dim = new Dimension(640, 640); |
||
⚫ | |||
⚫ | |||
⚫ | |||
final static Rectangle clickRect = new Rectangle(50, 375, 252, 40); |
|||
final static int blockSize = 30; |
final static int blockSize = 30; |
||
Line 513: | Line 525: | ||
final static int clickX = 120; |
final static int clickX = 120; |
||
final static int clickY = 400; |
final static int clickY = 400; |
||
final static int previewCenterX = 467; |
|||
final static |
final static int previewCenterY = 97; |
||
⚫ | |||
⚫ | |||
⚫ | |||
final static Stroke largeStroke = new BasicStroke(5); |
final static Stroke largeStroke = new BasicStroke(5); |