728x90
저번 글 : https://stickode.tistory.com/822
안녕하세요. 저번 시간에 이어서, 오늘은 테트리스를 게임답게 만들어보겠습니다. 우선 모든 코드를 올려두고, 모듈화한 코드들을 설명하겠습니다. 총 5부에 걸쳐서 업로드 할 예정입니다. 각 모듈들(Configuration, Figure, Game, SquareBoard, ,,,)에 대한 설명은 각 게시물로 따로 올리도록 하겠습니다. 오늘 업로드된 코드들에는 모듈에 주석이 없습니다.
우선 디렉토리 구조는 다음과 같습니다.
Tetris.java
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* 테트리스 게임의 메인 클래스입니다. 이 클래스에는 독립적으로 실행되는 애플리케이션 또는 웹 페이지 내의 애플릿으로 게임을 실행하기 위한 필요한 메서드가 포함되어 있습니다.
*/
public class Tetris {
/**
* 애플릿에서 실행되는 테트리스 게임입니다.
*/
private Game game = null;
/**
* 독립 실행형 메인 루틴입니다.
*
* @param args 명령 줄 인수
*/
public static void main(String[] args) {
System.out.println("starting");
Frame frame = new Frame("Tetris");
final Game game = new Game();
game.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("PCE " + evt.getPropertyName() + " " + evt.getNewValue());
}
});
final TextArea taHiScores = new TextArea("", 10, 10, TextArea.SCROLLBARS_NONE);
taHiScores.setBackground(Color.black);
taHiScores.setForeground(Color.white);
taHiScores.setFont(new Font("monospaced", 0, 11));
taHiScores.setText(" 득점자 점수판 \n" +
" -----------------------------\n\n" +
" PLAYER LEVEL SCORE \n\n" +
" 김씨 12 1 50280 \n" +
" 양씨 12 1 50280 \n"
);
taHiScores.setEditable(false);
final TextField txt = new TextField();
txt.setEnabled(false);
game.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
int state = ((Integer) evt.getNewValue()).intValue();
if (state == Game.STATE_GAMEOVER) {
txt.setEnabled(true);
txt.requestFocus();
txt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
txt.setEnabled(false);
game.init();
}
});
// 점수 표시...
}
}
}
});
Button btnStart = new Button("Start");
btnStart.setFocusable(false);
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
game.start();
}
});
final Container c = new Container();
c.setLayout(new BorderLayout());
c.add(txt, BorderLayout.NORTH);
c.add(game.getSquareBoardComponent(), BorderLayout.CENTER);
c.add(btnStart, BorderLayout.SOUTH);
final Container c2 = new Container();
c2.setLayout(new GridLayout(1, 2));
c2.add(c);
c2.add(taHiScores);
frame.add(c2);
System.out.println("packing");
frame.pack();
// 프레임 창 리스너 추가
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// 프레임 보이기 (게임 시작)
frame.show();
}
}
Configuration.java
import java.awt.*;
import java.util.Hashtable;
public class Configuration extends Object {
private static Hashtable config = new Hashtable();
public static String getValue(String key) {
if (config.containsKey(key)) {
return config.get(key).toString();
} else {
try {
return System.getProperty(key);
} catch (SecurityException ignore) {
return null;
}
}
}
public static String getValue(String key, String def) {
String value = getValue(key);
return (value == null) ? def : value;
}
public static void setValue(String key, String value) {
config.put(key, value);
}
public static Color getColor(String key, String def) {
String value = getValue("tetris.color." + key, def);
Color color;
color = parseColor(value);
if (color != null) {
return color;
}
color = parseColor(def);
if (color != null) {
return color;
} else {
return Color.white;
}
}
private static Color parseColor(String value) {
if (!value.startsWith("#")) {
return null;
}
try {
return new Color(Integer.parseInt(value.substring(1), 16));
} catch (NumberFormatException ignore) {
return null;
}
}
}
Figure.java
import java.awt.*;
public class Figure extends Object {
public static final int SQUARE_FIGURE = 1;
public static final int LINE_FIGURE = 2;
public static final int S_FIGURE = 3;
public static final int Z_FIGURE = 4;
public static final int RIGHT_ANGLE_FIGURE = 5;
public static final int LEFT_ANGLE_FIGURE = 6;
public static final int TRIANGLE_FIGURE = 7;
private SquareBoard board = null;
private int xPos = 0;
private int yPos = 0;
private int orientation = 0;
private int maxOrientation = 4;
private int[] shapeX = new int[4];
private int[] shapeY = new int[4];
private Color color = Color.white;
public Figure(int type) throws IllegalArgumentException {
initialize(type);
}
private void initialize(int type) throws IllegalArgumentException {
// 기본 변수 초기화
board = null;
xPos = 0;
yPos = 0;
orientation = 0;
// 도형 유형 변수 초기화
switch (type) {
case SQUARE_FIGURE:
maxOrientation = 1;
color = Configuration.getColor("figure.square", "#ffd8b1");
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = -1;
shapeY[2] = 1;
shapeX[3] = 0;
shapeY[3] = 1;
break;
case LINE_FIGURE:
maxOrientation = 2;
color = Configuration.getColor("figure.line", "#ffb4b4");
shapeX[0] = -2;
shapeY[0] = 0;
shapeX[1] = -1;
shapeY[1] = 0;
shapeX[2] = 0;
shapeY[2] = 0;
shapeX[3] = 1;
shapeY[3] = 0;
break;
case S_FIGURE:
maxOrientation = 2;
color = Configuration.getColor("figure.s", "#a3d5ee");
shapeX[0] = 0;
shapeY[0] = 0;
shapeX[1] = 1;
shapeY[1] = 0;
shapeX[2] = -1;
shapeY[2] = 1;
shapeX[3] = 0;
shapeY[3] = 1;
break;
case Z_FIGURE:
maxOrientation = 2;
color = Configuration.getColor("figure.z", "#f4adff");
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 0;
shapeY[2] = 1;
shapeX[3] = 1;
shapeY[3] = 1;
break;
case RIGHT_ANGLE_FIGURE:
maxOrientation = 4;
color = Configuration.getColor("figure.right", "#c0b6fa");
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = 1;
shapeY[3] = 1;
break;
case LEFT_ANGLE_FIGURE:
maxOrientation = 4;
color = Configuration.getColor("figure.left", "#f5f4a7");
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = -1;
shapeY[3] = 1;
break;
case TRIANGLE_FIGURE:
maxOrientation = 4;
color = Configuration.getColor("figure.triangle", "#a4d9b6");
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = 0;
shapeY[3] = 1;
break;
default:
throw new IllegalArgumentException("No figure constant: " +
type);
}
}
public boolean isAttached() {
return board != null;
}
public boolean attach(SquareBoard board, boolean center) {
int newX;
int newY;
int i;
// 이전 연결 여부 확인
if (isAttached()) {
detach();
}
// 위치 초기화 (올바른 조작을 위해)
xPos = 0;
yPos = 0;
// 위치 계산
newX = board.getBoardWidth() / 2;
if (center) {
newY = board.getBoardHeight() / 2;
} else {
newY = 0;
for (i = 0; i < shapeX.length; i++) {
if (getRelativeY(i, orientation) - newY > 0) {
newY = -getRelativeY(i, orientation);
}
}
}
// 위치 확인
this.board = board;
if (!canMoveTo(newX, newY, orientation)) {
this.board = null;
return false;
}
// 도형 그리기
xPos = newX;
yPos = newY;
paint(color);
board.update();
return true;
}
public void detach() {
board = null;
}
public boolean isAllVisible() {
if (!isAttached()) {
return false;
}
for (int i = 0; i < shapeX.length; i++) {
if (yPos + getRelativeY(i, orientation) < 0) {
return false;
}
}
return true;
}
public boolean hasLanded() {
return !isAttached() || !canMoveTo(xPos, yPos + 1, orientation);
}
public void moveLeft() {
if (isAttached() && canMoveTo(xPos - 1, yPos, orientation)) {
paint(null);
xPos--;
paint(color);
board.update();
}
}
public void moveRight() {
if (isAttached() && canMoveTo(xPos + 1, yPos, orientation)) {
paint(null);
xPos++;
paint(color);
board.update();
}
}
public void moveDown() {
if (isAttached() && canMoveTo(xPos, yPos + 1, orientation)) {
paint(null);
yPos++;
paint(color);
board.update();
}
}
public void moveAllWayDown() {
int y = yPos;
// 보드 확인
if (!isAttached()) {
return;
}
// 가장 낮은 위치 찾기
while (canMoveTo(xPos, y + 1, orientation)) {
y++;
}
// 업데이트
if (y != yPos) {
paint(null);
yPos = y;
paint(color);
board.update();
}
}
public int getRotation() {
return orientation;
}
public void setRotation(int rotation) {
int newOrientation;
// 새로운 방향 설정
newOrientation = rotation % maxOrientation;
// 새 위치 확인
if (!isAttached()) {
orientation = newOrientation;
} else if (canMoveTo(xPos, yPos, newOrientation)) {
paint(null);
orientation = newOrientation;
paint(color);
board.update();
}
}
public void rotateRandom() {
setRotation((int) (Math.random() * 4.0) % maxOrientation);
}
public void rotateClockwise() {
if (maxOrientation == 1) {
return;
} else {
setRotation((orientation + 1) % maxOrientation);
}
}
public void rotateCounterClockwise() {
if (maxOrientation == 1) {
return;
} else {
setRotation((orientation + 3) % 4);
}
}
private boolean isInside(int x, int y) {
for (int i = 0; i < shapeX.length; i++) {
if (x == xPos + getRelativeX(i, orientation)
&& y == yPos + getRelativeY(i, orientation)) {
return true;
}
}
return false;
}
private boolean canMoveTo(int newX, int newY, int newOrientation) {
int x;
int y;
for (int i = 0; i < 4; i++) {
x = newX + getRelativeX(i, newOrientation);
y = newY + getRelativeY(i, newOrientation);
if (!isInside(x, y) && !board.isSquareEmpty(x, y)) {
return false;
}
}
return true;
}
private int getRelativeX(int square, int orientation) {
switch (orientation % 4) {
case 0:
return shapeX[square];
case 1:
return -shapeY[square];
case 2:
return -shapeX[square];
case 3:
return shapeY[square];
default:
return 0; // 발생하지 않아야 함
}
}
private int getRelativeY(int square, int orientation) {
switch (orientation % 4) {
case 0:
return shapeY[square];
case 1:
return shapeX[square];
case 2:
return -shapeY[square];
case 3:
return -shapeX[square];
default:
return 0; // 발생하지 않아야 함
}
}
private void paint(Color color) {
int x, y;
for (int i = 0; i < shapeX.length; i++) {
x = xPos + getRelativeX(i, orientation);
y = yPos + getRelativeY(i, orientation);
board.setSquareColor(x, y, color);
}
}
}
Game.java
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Game extends Object {
public static final int STATE_GETREADY = 1;
public static final int STATE_PLAYING = 2;
public static final int STATE_PAUSED = 3;
public static final int STATE_GAMEOVER = 4;
private final PropertyChangeSupport PCS = new PropertyChangeSupport(this);
private final SquareBoard board;
private final SquareBoard previewBoard = new SquareBoard(5, 5);
private Figure[] figures = {
new Figure(Figure.SQUARE_FIGURE),
new Figure(Figure.LINE_FIGURE),
new Figure(Figure.S_FIGURE),
new Figure(Figure.Z_FIGURE),
new Figure(Figure.RIGHT_ANGLE_FIGURE),
new Figure(Figure.LEFT_ANGLE_FIGURE),
new Figure(Figure.TRIANGLE_FIGURE)
};
private final GameThread thread;
private int level = 1;
private int score = 0;
private Figure figure = null;
private Figure nextFigure = null;
private int nextRotation = 0;
private boolean preview = true;
private boolean moveLock = false;
private int state;
public Game() {
this(10, 20);
}
public Game(int width, int height) {
board = new SquareBoard(width, height);
thread = new GameThread();
handleGetReady();
board.getComponent().setFocusable(true);
board.getComponent().addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
handleKeyEvent(e);
}
});
}
public void addPropertyChangeListener(PropertyChangeListener l) {
PCS.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
PCS.removePropertyChangeListener(l);
}
public int getState() {
return state;
}
public int getLevel() {
return level;
}
public int getScore() {
return score;
}
public int getRemovedLines() {
return board.getRemovedLines();
}
public Component getSquareBoardComponent() {
return board.getComponent();
}
public Component getPreviewBoardComponent() {
return previewBoard.getComponent();
}
public void init() {
if (state == STATE_GAMEOVER) {
handleGetReady();
}
}
public void start() {
handleStart();
}
public void pause() {
if (state == STATE_PLAYING) {
handlePause();
}
}
public void resume() {
if (state == STATE_PAUSED) {
handleResume();
}
}
public void terminate() {
handleGameOver();
}
private void handleStart() {
level = 1;
score = 0;
figure = null;
nextFigure = randomFigure();
nextFigure.rotateRandom();
nextRotation = nextFigure.getRotation();
state = STATE_PLAYING;
board.setMessage(null);
board.clear();
previewBoard.clear();
handleLevelModification();
handleScoreModification();
PCS.firePropertyChange("state", -1, STATE_PLAYING);
thread.reset();
}
private void handleGameOver() {
thread.setPaused(true);
if (figure != null) {
figure.detach();
}
figure = null;
if (nextFigure != null) {
nextFigure.detach();
}
nextFigure = null;
state = STATE_GAMEOVER;
board.setMessage("Game Over");
PCS.firePropertyChange("state", -1, STATE_GAMEOVER);
}
private void handleGetReady() {
board.setMessage("Get Ready");
board.clear();
previewBoard.clear();
state = STATE_GETREADY;
PCS.firePropertyChange("state", -1, STATE_GETREADY);
}
private void handlePause() {
thread.setPaused(true);
state = STATE_PAUSED;
board.setMessage("Paused");
PCS.firePropertyChange("state", -1, STATE_PAUSED);
}
private void handleResume() {
state = STATE_PLAYING;
board.setMessage(null);
thread.setPaused(false);
PCS.firePropertyChange("state", -1, STATE_PLAYING);
}
private void handleLevelModification() {
PCS.firePropertyChange("level", -1, level);
thread.adjustSpeed();
}
private void handleScoreModification() {
PCS.firePropertyChange("score", -1, score);
}
private void handleFigureStart() {
int rotation;
figure = nextFigure;
moveLock = false;
rotation = nextRotation;
nextFigure = randomFigure();
nextFigure.rotateRandom();
nextRotation = nextFigure.getRotation();
if (preview) {
previewBoard.clear();
nextFigure.attach(previewBoard, true);
nextFigure.detach();
}
figure.setRotation(rotation);
if (!figure.attach(board, false)) {
previewBoard.clear();
figure.attach(previewBoard, true);
figure.detach();
handleGameOver();
}
}
private void handleFigureLanded() {
if (figure.isAllVisible()) {
score += 10;
handleScoreModification();
} else {
handleGameOver();
return;
}
figure.detach();
figure = null;
if (board.hasFullLines()) {
board.removeFullLines();
PCS.firePropertyChange("lines", -1, board.getRemovedLines());
if (level < 9 && board.getRemovedLines() / 20 > level) {
level = board.getRemovedLines() / 20;
handleLevelModification();
}
} else {
handleFigureStart();
}
}
private synchronized void handleTimer() {
if (figure == null) {
handleFigureStart();
} else if (figure.hasLanded()) {
handleFigureLanded();
} else {
figure.moveDown();
}
}
private synchronized void handlePauseOnOff() {
if (nextFigure == null) {
handleStart();
} else if (thread.isPaused()) {
handleResume();
} else {
handlePause();
}
}
private synchronized void handleKeyEvent(KeyEvent e) {
if (state == STATE_GETREADY) {
handleStart();
return;
}
if (e.getKeyCode() == KeyEvent.VK_P) {
handlePauseOnOff();
return;
}
if (figure == null || moveLock || thread.isPaused()) {
return;
}
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
figure.moveLeft();
break;
case KeyEvent.VK_RIGHT:
figure.moveRight();
break;
case KeyEvent.VK_DOWN:
figure.moveAllWayDown();
moveLock = true;
break;
case KeyEvent.VK_UP:
case KeyEvent.VK_SPACE:
if (e.isControlDown()) {
figure.rotateRandom();
} else if (e.isShiftDown()) {
figure.rotateClockwise();
} else {
figure.rotateCounterClockwise();
}
break;
case KeyEvent.VK_S:
if (level < 9) {
level++;
handleLevelModification();
}
break;
case KeyEvent.VK_N:
preview = !preview;
if (preview && figure != nextFigure) {
nextFigure.attach(previewBoard, true);
nextFigure.detach();
} else {
previewBoard.clear();
}
break;
}
}
private Figure randomFigure() {
return figures[(int) (Math.random() * figures.length)];
}
private class GameThread extends Thread {
private boolean paused = true;
private int sleepTime = 500;
public GameThread() {
}
public void reset() {
adjustSpeed();
setPaused(false);
if (!isAlive()) {
this.start();
}
}
public boolean isPaused() {
return paused;
}
public void setPaused(boolean paused) {
this.paused = paused;
}
public void adjustSpeed() {
sleepTime = 4500 / (level + 5) - 250;
if (sleepTime < 50) {
sleepTime = 50;
}
}
public void run() {
while (thread == this) {
handleTimer();
try {
Thread.sleep(sleepTime);
} catch (InterruptedException ignore) {
}
while (paused && thread == this) {
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {
}
}
}
}
}
}
SquareBoard.java
import javax.swing.*;
import java.awt.*;
import java.util.Hashtable;
public class SquareBoard extends Object {
private final int width;
private final int height;
private Color[][] matrix = null;
private String message = null;
private int removedLines = 0;
private final SquareBoardComponent component;
public SquareBoard(int width, int height) {
this.width = width;
this.height = height;
this.matrix = new Color[height][width];
this.component = new SquareBoardComponent();
clear();
}
public boolean isSquareEmpty(int x, int y) {
if (x < 0 || x >= width || y < 0 || y >= height) {
return x >= 0 && x < width && y < 0;
} else {
return matrix[y][x] == null;
}
}
public boolean isLineEmpty(int y) {
if (y < 0 || y >= height) {
return false;
}
for (int x = 0; x < width; x++) {
if (matrix[y][x] != null) {
return false;
}
}
return true;
}
public boolean isLineFull(int y) {
if (y < 0 || y >= height) {
return true;
}
for (int x = 0; x < width; x++) {
if (matrix[y][x] == null) {
return false;
}
}
return true;
}
public boolean hasFullLines() {
for (int y = height - 1; y >= 0; y--) {
if (isLineFull(y)) {
return true;
}
}
return false;
}
public Component getComponent() {
return component;
}
public int getBoardHeight() {
return height;
}
public int getBoardWidth() {
return width;
}
public int getRemovedLines() {
return removedLines;
}
public Color getSquareColor(int x, int y) {
if (x < 0 || x >= width || y < 0 || y >= height) {
return null;
} else {
return matrix[y][x];
}
}
public void setSquareColor(int x, int y, Color color) {
if (x < 0 || x >= width || y < 0 || y >= height) {
return;
}
matrix[y][x] = color;
if (component != null) {
component.invalidateSquare(x, y);
}
}
public void setMessage(String message) {
this.message = message;
if (component != null) {
component.redrawAll();
}
}
public void clear() {
removedLines = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
this.matrix[y][x] = null;
}
}
if (component != null) {
component.redrawAll();
}
}
public void removeFullLines() {
boolean repaint = false;
for (int y = height - 1; y >= 0; y--) {
if (isLineFull(y)) {
removeLine(y);
removedLines++;
repaint = true;
y++;
}
}
if (repaint && component != null) {
component.redrawAll();
}
}
private void removeLine(int y) {
if (y < 0 || y >= height) {
return;
}
for (; y > 0; y--) {
for (int x = 0; x < width; x++) {
matrix[y][x] = matrix[y - 1][x];
}
}
for (int x = 0; x < width; x++) {
matrix[0][x] = null;
}
}
public void update() {
component.redraw();
}
private class SquareBoardComponent extends JComponent {
/**
* The component size. If the component has been resized, that
* will be detected when the paint method executes. If this
* value is set to null, the component dimensions are unknown.
*/
private Dimension size = null;
private Insets insets = new Insets(0, 0, 0, 0);
private Dimension squareSize = new Dimension(0, 0);
private Image bufferImage = null;
private Rectangle bufferRect = new Rectangle();
private Color messageColor = Color.white;
private Hashtable lighterColors = new Hashtable();
private Hashtable darkerColors = new Hashtable();
private boolean updated = true;
private Rectangle updateRect = new Rectangle();
public SquareBoardComponent() {
setBackground(Configuration.getColor("board.background",
"#000000"));
messageColor = Configuration.getColor("board.message",
"#ffffff");
}
public void invalidateSquare(int x, int y) {
if (updated) {
updated = false;
updateRect.x = x;
updateRect.y = y;
updateRect.width = 0;
updateRect.height = 0;
} else {
if (x < updateRect.x) {
updateRect.width += updateRect.x - x;
updateRect.x = x;
} else if (x > updateRect.x + updateRect.width) {
updateRect.width = x - updateRect.x;
}
if (y < updateRect.y) {
updateRect.height += updateRect.y - y;
updateRect.y = y;
} else if (y > updateRect.y + updateRect.height) {
updateRect.height = y - updateRect.y;
}
}
}
public void redraw() {
Graphics g;
if (!updated) {
updated = true;
g = getGraphics();
if (g == null) return;
g.setClip(insets.left + updateRect.x * squareSize.width,
insets.top + updateRect.y * squareSize.height,
(updateRect.width + 1) * squareSize.width,
(updateRect.height + 1) * squareSize.height);
paint(g);
}
}
public void redrawAll() {
Graphics g;
updated = true;
g = getGraphics();
if (g == null) return;
g.setClip(insets.left,
insets.top,
width * squareSize.width,
height * squareSize.height);
paint(g);
}
public boolean isDoubleBuffered() {
return true;
}
public Dimension getPreferredSize() {
return new Dimension(width * 20, height * 20);
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
public Dimension getMaximumSize() {
return getPreferredSize();
}
private Color getLighterColor(Color c) {
Color lighter;
lighter = (Color) lighterColors.get(c);
if (lighter == null) {
lighter = c.brighter().brighter();
lighterColors.put(c, lighter);
}
return lighter;
}
private Color getDarkerColor(Color c) {
Color darker;
darker = (Color) darkerColors.get(c);
if (darker == null) {
darker = c.darker().darker();
darkerColors.put(c, darker);
}
return darker;
}
public synchronized void paint(Graphics g) {
Graphics bufferGraphics;
Rectangle rect;
if (size == null || !size.equals(getSize())) {
size = getSize();
squareSize.width = size.width / width;
squareSize.height = size.height / height;
//if (squareSize.width <= squareSize.height) {
//} else {
//}
insets.left = (size.width - width * squareSize.width) / 2;
insets.right = insets.left;
insets.top = 0;
insets.bottom = size.height - height * squareSize.height;
bufferImage = createImage(width * squareSize.width,
height * squareSize.height);
}
rect = g.getClipBounds();
bufferGraphics = bufferImage.getGraphics();
bufferGraphics.setClip(rect.x - insets.left,
rect.y - insets.top,
rect.width,
rect.height);
doPaintComponent(bufferGraphics);
g.drawImage(bufferImage,
insets.left,
insets.top,
getBackground(),
null);
}
private void doPaintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0,
0,
width * squareSize.width,
height * squareSize.height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (matrix[y][x] != null) {
paintSquare(g, x, y);
}
}
}
if (message != null) {
paintMessage(g, message);
}
}
private void paintSquare(Graphics g, int x, int y) {
Color color = matrix[y][x];
int xMin = x * squareSize.width;
int yMin = y * squareSize.height;
int xMax = xMin + squareSize.width - 1;
int yMax = yMin + squareSize.height - 1;
int i;
bufferRect.x = xMin;
bufferRect.y = yMin;
bufferRect.width = squareSize.width;
bufferRect.height = squareSize.height;
if (!bufferRect.intersects(g.getClipBounds())) {
return;
}
g.setColor(color);
g.fillRect(xMin, yMin, squareSize.width, squareSize.height);
g.setColor(getLighterColor(color));
for (i = 0; i < squareSize.width / 10; i++) {
g.drawLine(xMin + i, yMin + i, xMax - i, yMin + i);
g.drawLine(xMin + i, yMin + i, xMin + i, yMax - i);
}
g.setColor(getDarkerColor(color));
for (i = 0; i < squareSize.width / 10; i++) {
g.drawLine(xMax - i, yMin + i, xMax - i, yMax - i);
g.drawLine(xMin + i, yMax - i, xMax - i, yMax - i);
}
}
private void paintMessage(Graphics g, String msg) {
int fontWidth;
int offset;
int x;
int y;
g.setFont(new Font("SansSerif", Font.BOLD, squareSize.width + 4));
fontWidth = g.getFontMetrics().stringWidth(msg);
x = (width * squareSize.width - fontWidth) / 2;
y = height * squareSize.height / 2;
offset = squareSize.width / 10;
g.setColor(Color.black);
g.drawString(msg, x - offset, y - offset);
g.drawString(msg, x - offset, y);
g.drawString(msg, x - offset, y - offset);
g.drawString(msg, x, y - offset);
g.drawString(msg, x, y + offset);
g.drawString(msg, x + offset, y - offset);
g.drawString(msg, x + offset, y);
g.drawString(msg, x + offset, y + offset);
g.setColor(messageColor);
g.drawString(msg, x, y);
}
}
}
'Java' 카테고리의 다른 글
[Java] Thread와 Swing으로 디지털 시계 만들기 (0) | 2023.07.16 |
---|---|
[Java] awt 테트리스 모듈화 - Configuration (0) | 2023.07.02 |
[Java] 스케줄링 라이브러리, Quartz 사용해 Hello world 출력해보기 (0) | 2023.06.16 |
[JAVA]SHA-256 를 사용한 문자열 암호화(비밀번호 생성) (0) | 2023.06.05 |
[Java] awt 테트리스 - 기본편 (0) | 2023.06.03 |