一、先看一下游戏运行什么样
如图所示:
运行环境:
使用软件:eclipse2021-12版
JDK版本:JDK15.0.1
二、代码部分详解:
1.项目结构及下载路径:
链接:https://pan.baidu.com/s/1NVWaklg9K2wRmBOLew6iMQ
提取码:ts08文章来源:https://www.toymoban.com/news/detail-495776.html
2.所有代码部分
1. Client.java:
package com.it.client;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
import com.it.constant.Constant;
import com.it.core.BlockLoader;
import com.it.core.MyFrame;
public class Client extends MyFrame{
public BlockLoader loader = new BlockLoader();
@Override
public void loadFrame() {
super.loadFrame();
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
loader.keyPressed(e);
}
});
}
@Override
public void paint(Graphics g) {
drawBasic(g);
drawScore(g);
if(gameStart){
try {
loader.draw(g);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}else{
if(!gameStart&flag)
gameReset();
}
}
public static boolean gameStart =true;
public static boolean flag=true;
public void gameReset(){
flag=false;
int m = JOptionPane.showOptionDialog(null, "对不起 , 游戏结束 ! 点击确定重新开始","游戏结束",JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,null,new String[]{"确定","关闭游戏"},"确定");
if(m==JOptionPane.YES_OPTION){
gameStart=true;
flag=true;
loader=new BlockLoader();
}else{
System.exit(0);
}
}
/**
* 画分数
*/
private void drawScore(Graphics g) {
g.setColor(Color.RED);
g.fillRoundRect(Constant.BACK_X, Constant.BACK_Y-100, 220, 80, 10, 10);
g.setColor(Color.WHITE);
g.setFont(new Font("幼圆", Font.BOLD, 30));
g.drawString("分数:"+BlockLoader.score+"",Constant.BACK_X, Constant.BACK_Y-50);
g.setColor(Color.GREEN);
g.fillRoundRect(Constant.BACK_RIGHT_IN_X+Constant.BLOCK_SPACE-250, Constant.BACK_Y-100, 250, 80, 10, 10);
g.setColor(Color.WHITE);
g.setFont(new Font("幼圆", Font.BOLD, 30));
g.drawString("最高分:"+BlockLoader.bestScore+"",Constant.BACK_RIGHT_IN_X+Constant.BLOCK_SPACE-250, Constant.BACK_Y-50);
}
/**
* 画背景
* @param g
*/
private void drawBasic(Graphics g) {
g.setColor(Constant.COLOR_BACK);
g.fillRoundRect(Constant.BACK_X, Constant.BACK_Y, Constant.BACK_WIDTH, Constant.BACK_HEIGHT, 20, 20);
g.setColor(Constant.COLOR_BLOCK_BACK);
for(int i=1;i<=4;i++){
for(int j=1;j<=4;j++){
int xStart =Constant.BACK_X+Constant.BLOCK_SPACE*j+Constant.BLOCK_WIDTH*(j-1);
int yStart = Constant.BACK_Y+Constant.BLOCK_SPACE*i+Constant.BLOCK_WIDTH*(i-1);
g.fillRoundRect(xStart, yStart,
Constant.BLOCK_WIDTH, Constant.BLOCK_WIDTH, 10, 10);
}
}
}
public static void main(String[] args) {
new Client().loadFrame();
}
}
2.Constant.java
package com.it.constant;
import java.awt.Color;
public class Constant {
public static final int GAME_WIDTH = 900;
public static final int GAME_HEIGHT = 850;
public static final int BACK_X = 150;
public static final int BACK_Y = 150;
public static final int BACK_WIDTH = 600;
public static final int BACK_HEIGHT = 600;
public static final int BLOCK_SPACE = 20;
public static final int BLOCK_WIDTH = (BACK_WIDTH - 5 * BLOCK_SPACE) / 4;
public static final int BLOCK_HEIGHT = (BACK_HEIGHT - 5 * BLOCK_SPACE) / 4;
public static final int BACK_UP_IN_Y = BACK_Y+BLOCK_SPACE;
public static final int BACK_DOWN_IN_Y = BACK_Y + BACK_HEIGHT-BLOCK_SPACE;
public static final int BACK_LEFT_IN_X = BACK_X +BLOCK_SPACE;
public static final int BACK_RIGHT_IN_X = BACK_X + BACK_WIDTH-BLOCK_SPACE;
public static final String IMG_PRE = "com/zzk/Game_2048/img/";
public static final Color COLOR_BACK = new Color(187, 173, 160);
public static final Color COLOR_BLOCK_BACK = new Color(205, 192, 180);
public static final Color COLOR_BLOCKS_ACTIVE[] = new Color[] {
new Color(238, 228, 218), //2
new Color(237, 224, 200),//4
new Color(242, 177, 121), //8
new Color(245, 149, 99), //16
new Color(255, 204, 0),//32
new Color(153, 255, 153) ,//64
new Color(204, 204, 0),//128
new Color(255, 204, 102),//256
new Color(255, 80, 80),//512
new Color(102, 102, 255),//1024
new Color(204, 0, 102),//2048
new Color(153, 102, 0),//4096
new Color(153, 0, 153)//8192
};
}
3.Block.java
package com.it.core;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Rectangle;
import com.it.constant.Constant;
public class Block implements Drawable, Moveable {
public static final int DIRECTION_NONE = 0;
public static final int DIRECTION_UP = 1;
public static final int DIRECTION_DOWN = -1;
public static final int DIRECTION_LEFT = 2;
public static final int DIRECTION_RIGHT = -2;
public int direction = DIRECTION_NONE;// 默认静止
private String value;
public int xOrder;// 方块坐标(非像素坐标)
public int yOrder;// 方块坐标
public int x;// 像素坐标
public int y;//
public static final int SPEED = 5;
int level;
boolean live;
public int directionX = 0;
public int directionY = 0;
public BlockLoader loader =null;
public Block(int xOrder, int yOrder, int level,BlockLoader loader) {
super();
this.xOrder = xOrder;
this.yOrder = yOrder;
this.level = level;
this.value = (int) Math.pow(2, level) + "";
if (level == 0)
this.live = false;
else
this.live = true;
this.x = Constant.BACK_Y + Constant.BLOCK_SPACE * xOrder + Constant.BLOCK_WIDTH * (xOrder - 1);
this.y = Constant.BACK_X + Constant.BLOCK_SPACE * yOrder + Constant.BLOCK_WIDTH * (yOrder - 1);
this.loader=loader;
}
public void keyPressed(int newDirection) {
this.direction = newDirection;
switch (direction) {
case DIRECTION_UP:
directionX = 0;
directionY = -1;
break;
case DIRECTION_DOWN:
directionX = 0;
directionY = 1;
break;
case DIRECTION_LEFT:
directionX = -1;
directionY = 0;
break;
case DIRECTION_RIGHT:
directionX = 1;
directionY = 0;
break;
}
updateOrder();
}
@Override
public void draw(Graphics g) throws CloneNotSupportedException {
updateOrder();
updateState();
switch (state) {
case STATE_UNKOWN:
case STATE_MERGE:
break;
case STATE_MOVING:
case STATE_FREE:
move();// 移动
break;
}
// 画内容
drawContent(g);
}
/**
* 画内容
*
* @param g
*/
public void drawContent(Graphics g) {
this.value = (int) Math.pow(2, level) + "";
g.setColor(Constant.COLOR_BLOCKS_ACTIVE[level - 1]);
Font f = new Font("微软雅黑", Font.BOLD, 60 - 5 * value.length());
g.setFont(f);
FontMetrics fm = new Label().getFontMetrics(f);
int xValueStart = x + (Constant.BLOCK_WIDTH - fm.stringWidth(value)) / 2;
int yValueStart = y+Constant.BLOCK_HEIGHT- (Constant.BLOCK_HEIGHT - fm.getHeight()) / 2-fm.getDescent();
// 画背景
g.fillRoundRect(x, y, Constant.BLOCK_WIDTH, Constant.BLOCK_WIDTH, 10, 10);
g.setColor(Color.BLACK);
// 画数字
g.drawString(value, xValueStart, yValueStart);
// //测试记录
// f = new Font("微软雅黑", Font.BOLD, 20);
// g.setFont(f);
// String s = "(" + x + "," + y + ")" + moveCount;
// g.drawString(s, x, y + 20);
}
/**
* 移动
*/
int moveCount = 0;
// 移动次数最大值
public static final int MOVE_COUNT_MAX = (Constant.BLOCK_WIDTH + Constant.BLOCK_SPACE) / SPEED;
/**
* 移动
*/
@Override
public void move() {
// 0到MOVE_COUNT_MAX
switch (direction) {
case DIRECTION_UP:
y -= SPEED;
break;
case DIRECTION_DOWN:
y += SPEED;
break;
case DIRECTION_LEFT:
x -= SPEED;
break;
case DIRECTION_RIGHT:
x += SPEED;
break;
}
moveCount++;
if (moveCount >= MOVE_COUNT_MAX) {
moveCount = 0;
}
// 1到MOVE_COUNT_MAX
}
public int state=STATE_UNKOWN;
public static final int STATE_UNKOWN = 0;// 未知态(判断态)
public static final int STATE_MOVING = 1;// 移动态
public static final int STATE_FREE = 2;// 自由态
public static final int STATE_MERGE = 3;// 合并态
/**
* 获得状态
* @return
*/
public int updateState() {
if (moveCount != 0) {
state = STATE_MOVING;
} else if (moveCount == 0) {
state = STATE_UNKOWN;
}
if (direction != DIRECTION_NONE && getNextBlock() == null) {
state = STATE_FREE;
}
Block b = (Block) getNextBlock();
//合并态判断
if (direction != DIRECTION_NONE && b != null && b.level == level && (b.state != STATE_FREE)) {
this.live = false;
b.level++;
b.state=STATE_MERGE;
setThisBlock(null);
BlockLoader.score += b.level * 10;
if(BlockLoader.score>=BlockLoader.bestScore){
BlockLoader.bestScore=BlockLoader.score;
}
if(b.getNextBlock()!=null&&b.getNextBlock().live&&b.getNextBlock().state==STATE_FREE){
}else{
b.direction=DIRECTION_NONE;
b.directionX=0;
b.directionY=0;
}
}
return state;
}
/**
* 更新order
*
* @throws CloneNotSupportedException
*/
public void updateOrder() {
if (moveCount == 0) {// 判断态
xOrder = (x - Constant.BACK_LEFT_IN_X) / (Constant.BLOCK_WIDTH + Constant.BLOCK_SPACE) + 1;
yOrder = (y - Constant.BACK_UP_IN_Y) / (Constant.BLOCK_HEIGHT + Constant.BLOCK_SPACE) + 1;
loader.blocks[xOrder][yOrder] = this;
if (direction != 0 && getLastBlock() != null && getLastBlock().live && (getLastBlock() == this))
setLastBlock(null);// 设置历史轨迹为空
}
}
public void setLastBlock(Block block) {
loader.blocks[xOrder - directionX][yOrder - directionY] = block;
}
public Block getLastBlock() {
return loader.blocks[xOrder - directionX][yOrder - directionY];
}
public Block getNextBlock() {
return loader.blocks[xOrder + directionX][yOrder + directionY];
}
public void setThisBlock(Block block){
loader.blocks[xOrder][yOrder]=block;
}
/**
* 返回block对应的矩形
*
* @return
*/
public Rectangle getRectangle() {
return new Rectangle(x, y, Constant.BLOCK_WIDTH, Constant.BLOCK_HEIGHT);
}
/**
* 判断是否在边界
*
* @return
*/
boolean xIsBounds = (x == (Constant.BACK_RIGHT_IN_X - Constant.BLOCK_WIDTH)) || (x == Constant.BACK_LEFT_IN_X);
boolean yIsBounds = (y == (Constant.BACK_DOWN_IN_Y - Constant.BLOCK_HEIGHT)) || (y == Constant.BACK_UP_IN_Y);
public boolean isAtBounds() {
if ((xIsBounds || yIsBounds)) {
return true;
}
return false;
}
/**
* 判断是否在角落
*
* @return
*/
public boolean isAtCorner() {
if ((xIsBounds && yIsBounds)) {
return true;
}
return false;
}
/**
* 处理出界问题
*/
public void outOfBounds() {
if (x > (Constant.BACK_RIGHT_IN_X - Constant.BLOCK_WIDTH)) {
x = Constant.BACK_RIGHT_IN_X - Constant.BLOCK_WIDTH;
}
if (x < Constant.BACK_LEFT_IN_X) {
x = Constant.BACK_LEFT_IN_X;
}
if (y == (Constant.BACK_DOWN_IN_Y - Constant.BLOCK_HEIGHT)) {
y = Constant.BACK_DOWN_IN_Y - Constant.BLOCK_HEIGHT;
}
if (y == Constant.BACK_UP_IN_Y) {
y = Constant.BACK_UP_IN_Y;
}
}
@Override
public String toString() {
String s = "value=" + value + " (" + xOrder + "," + yOrder + "),Direction=";
switch (direction) {
case DIRECTION_UP:
s += "↑";
break;
case DIRECTION_DOWN:
s += "↓";
break;
case DIRECTION_LEFT:
s += "←";
break;
case DIRECTION_RIGHT:
s += "→";
break;
case DIRECTION_NONE:
s += "0";
break;
default:
s += "方向异常";
break;
}
if (getNextBlock() == null)
s += ",block=null(" + (xOrder + directionX) + "," + (yOrder + directionY) + ")";
else
s += ",block=(" + getNextBlock().xOrder + "," + getNextBlock().yOrder + ")";
return s + "(state=" + state + ")";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + direction;
result = prime * result + directionX;
result = prime * result + directionY;
result = prime * result + level;
result = prime * result + (live ? 1231 : 1237);
result = prime * result + moveCount;
result = prime * result + ((value == null) ? 0 : value.hashCode());
result = prime * result + x;
result = prime * result + xOrder;
result = prime * result + y;
result = prime * result + yOrder;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Block other = (Block) obj;
if (direction != other.direction)
return false;
if (directionX != other.directionX)
return false;
if (directionY != other.directionY)
return false;
if (level != other.level)
return false;
if (live != other.live)
return false;
if (moveCount != other.moveCount)
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
if (x != other.x)
return false;
if (xOrder != other.xOrder)
return false;
if (y != other.y)
return false;
if (yOrder != other.yOrder)
return false;
return true;
}
}
4.BlockLoader.java
package com.it.core;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import com.it.client.Client;
import com.it.constant.Constant;
public class BlockLoader implements Drawable {
public static Random random = new Random();
public Block[][] blocks = new Block[6][6];
public List<Block> blockList = new CopyOnWriteArrayList<Block>();
public BlockLoader() {
super();
init();
}
public void init() {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
if (i == 5 || j == 5 || i == 0 || j == 0) {
blocks[i][j] = new Block(i, j, 0, this);
}
}
}
int x1 = randomBlockPoint().x;// 1-4
int y1 = randomBlockPoint().y;
blocks[x1][y1] = new Block(x1, y1, 1,this);
blockList.add(blocks[x1][y1]);
int x2 = randomBlockPoint().x;
int y2 = randomBlockPoint().y;
while (x1 == x2 && y1 == y2) {
x2 = randomBlockPoint().x;
y2 = randomBlockPoint().y;
}
blocks[x2][y2] = new Block(x2, y2, 1,this);
blockList.add(blocks[x2][y2]);
score=0;
}
public static Point randomBlockPoint() {
return new Point(random.nextInt(4) + 1, random.nextInt(4) + 1);
}
public void newBlock() {
int x = randomBlockPoint().x;// 1-4
int y = randomBlockPoint().y;
int i = 0;
while (blocks[x][y] != null && i < 100) {
x = randomBlockPoint().x;
y = randomBlockPoint().y;
i++;
}
if (blocks[x][y] == null) {
newBlock = blocks[x][y] = new Block(x, y, 1, this);
blockList.add(newBlock);
System.out.println("newBlock:" + newBlock);
} else {
Client.gameStart = false;// 游戏结束
}
}
public static boolean isPressed = false;
public static Block newBlock = null;
public void keyPressed(KeyEvent e) {
if (!isPressed) {
int direction = e.getKeyCode();
switch (direction) {
case KeyEvent.VK_UP:
case KeyEvent.VK_W:
direction = Block.DIRECTION_UP;
isPressed = true;
break;
case KeyEvent.VK_DOWN:
case KeyEvent.VK_S:
direction = Block.DIRECTION_DOWN;
isPressed = true;
break;
case KeyEvent.VK_LEFT:
case KeyEvent.VK_A:
direction = Block.DIRECTION_LEFT;
isPressed = true;
break;
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_D:
direction = Block.DIRECTION_RIGHT;
isPressed = true;
break;
default:
direction = -1;
break;
}
if (isPressed) {
for (Block block : blockList) {
block.keyPressed(direction);
}
}
}
// newBlock();
}
public static int score = 0;
public static int bestScore = 0;
@Override
public void draw(Graphics g) throws CloneNotSupportedException {
boolean newFlag = true;
for (Block block : blockList) {
if (block.live) {
block.draw(g);
g.setFont(new Font("微软夜黑", Font.BOLD, 20));
if (block.state != Block.STATE_UNKOWN) {
newFlag = false;
}
} else {
blockList.remove(block);
}
}
if (newFlag && isPressed) {
newBlock();
isPressed = false;
}
// drawTestInfo(g);//测试信息
}
public void drawTestInfo(Graphics g) {
// 测试
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
int x = Constant.BACK_Y + Constant.BLOCK_SPACE * i + Constant.BLOCK_WIDTH * (i - 1);
int y = Constant.BACK_X + Constant.BLOCK_SPACE * j + Constant.BLOCK_WIDTH * (j - 1);
if (blocks[i][j] == null) {
g.drawString("null", x, y);
} else {
g.drawString("(" + x + "," + y + ")" + blocks[i][j].state, x, y);
}
}
}
}
}
5.Drawable.java
package com.it.core;
import java.awt.Graphics;
public interface Drawable {
void draw(Graphics g) throws CloneNotSupportedException;
}
6.Moveable.java
package com.it.core;
public interface Moveable {
void move();
}
7.MyFrame.java
package com.it.core;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import com.it.constant.Constant;
public class MyFrame extends Frame{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 加载窗体
*/
public void loadFrame(){
this.setTitle("2048");
this.setSize(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
this.setBackground(Color.WHITE);
this.setLocationRelativeTo(null);//居中
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setVisible(true);
new MyThread().start();
}
/**
* 防止图片闪烁
*
* @param g
*/
Image backImg = null;
@Override
public void update(Graphics g) {
if (backImg == null) {
backImg = createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
}
Graphics backg = backImg.getGraphics();
Color c = backg.getColor();
backg.setColor(Color.WHITE);
backg.fillRect(0, 0, Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
backg.setColor(c);
paint(backg);
g.drawImage(backImg, 0, 0, null);
}
/**
* 这种 创建一个重新画的线程内部类
*
* @param args
*/
class MyThread extends Thread{
@Override
public void run() {
while(true){
repaint();
try {
sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
总结
提示:代码写的有些臃肿,其中也有一些BUG,理解源码以后可以修正。
链接:https://pan.baidu.com/s/1NVWaklg9K2wRmBOLew6iMQ
提取码:ts08文章来源地址https://www.toymoban.com/news/detail-495776.html
到了这里,关于用JAVA写一个2048的小游戏。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!