package my2048;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class My2048 extends JFrame {
Block[] block;// 用于储存16个数据
JPanel panel;
boolean up, down, left, right;// 判断每个方向上是否还能移动
boolean numFlag;// 用于判断是否还能加入新的数字
boolean iswin; // 用于判断是否win
public My2048() {
setTitle("2048");
setSize(400, 400);
setLocationRelativeTo(null);// 设定窗口起始位置
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(4, 4, 5, 5));// 设定布局方式为GridLayout型
panel = (JPanel) getContentPane();
block = new Block[16];
// 初始化参数
iswin = false;
numFlag = true;
up = true;
down = true;
left = true;
right = true;
// 设置初始化界面
addBlock();
for (int i = 0; i < 2; i++)
appearBlock();
panel.setFocusable(true);
panel.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (iswin) {
return;
}
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
if (up) {
upBlock();
}
judgeAppear();
appearBlock();
win();
over();
if (numFlag == false) {
up = false;
} else {
up = true;
down = true;
left = true;
right = true;
}
break;
case KeyEvent.VK_DOWN:
if (down) {
downBlock();
}
judgeAppear();
appearBlock();
win();
over();
if (numFlag == false) {
down = false;
} else {
up = true;
down = true;
left = true;
right = true;
}
break;
case KeyEvent.VK_LEFT:
if (left) {
leftBlock();
}
judgeAppear();
appearBlock();
win();
over();
if (numFlag == false) {
left = false;
} else {
up = true;
down = true;
left = true;
right = true;
}
break;
case KeyEvent.VK_RIGHT:
if (right) {
rightBlock();
}
judgeAppear();
appearBlock();
win();
over();
if (numFlag == false) {
right = false;
} else {
up = true;
down = true;
left = true;
right = true;
}
break;
}
}
});
setVisible(true);// 设为可视
}
public static void main(String args[]) // 程序入口点
{
JFrame.setDefaultLookAndFeelDecorated(true);// 设定Frame的缺省外观
new My2048();
}
/**
* 往panel里加入block
*/
private void addBlock() {
for (int i = 0; i < 16; i++) {
block[i] = new Block();
block[i].setHorizontalAlignment(JLabel.CENTER);// 设置文本的水平对齐方式
block[i].setOpaque(true);// 设置控件是否透明
panel.add(block[i]);
}
}
/**
* 随机生成一个2或者4
*/
public void appearBlock() {
while (numFlag) {
int index = (int) (Math.random() * 16); // 取一个0到15的随机整数,这个数作为随机加入盘中的2或4的位置
if (block[index].getValue() == 0) // 如果block[index]的值为空时,加入一个2或4
{
if (Math.random() < 0.5) {
block[index].setValue(2);
} else {
block[index].setValue(4);
}
break;// 跳出while
}
}
}
/**
* 统计block数组中是否含有值为0的元素,若没有,则numFlag变为false
*/
public void judgeAppear()
{
int sum = 0;
for (int i = 0; i < 16; i++) {
if (block[i].getValue() != 0) {
sum++;
}
}
if (sum == 16)
numFlag = false;
}
/**
* 返回第一个不为空的block[i]的索引位置
* @param i 起始索引
* @param j 累加数值
* @param a 最小边界
* @param b 最大边界
* @return 没有返回 -1
*/
public int Find(int i, int j, int a, int b) {
while (i < b && i >= a) {
if (block[i].getValue() != 0) {
return i;
}
i = i + j;
}
return -1;
}
/**
* 向上移动
*
* 第一重循环 0 1 2 3
*
* 第二重循环 4 8 12
* 5 9 13
* 6 10 14
* 7 11 15
*/
public void upBlock() {
int i = 0, j = 0;
int t = 0;
int valueJ = 0;
int valueI = 0;
int index = 0;
for (i = 0; i < 4; i++) {
index = i;
for (j = i + 4; j < 16; j += 4) {
valueJ = 0;
valueI = 0;
if (block[index].getValue() == 0) {
//查找竖直方向上第一个不为空的方块索引,并将他置于顶部
t = Find(index, 4, 0, 16);
if (t != -1) {
block[index].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueI = block[index].getValue();
if (block[j].getValue() == 0) {
//查找竖直方向上第二个不为空的方块索引,并将他置于第二层
t = Find(j, 4, 0, 16);
if (t != -1) {
block[j].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueJ = block[j].getValue();
//如果两个方块数值不为0且相等,则合并
if (valueI == valueJ && valueI != 0 && valueJ != 0) {
block[index].setValue(valueI + valueJ);
block[j].setValue(0);
numFlag = true;
}
index = j;
}
}
}
/**
* 向下移动
*
* 第一重循环 12 13 14 15
*
* 第二重循环 8 4 0
* 9 5 1
* 10 6 2
* 11 7 3
*/
public void downBlock() {
int i = 0, j = 0;
int t = 0;
int valueJ = 0;
int valueI = 0;
int index = 0;
for (i = 12; i < 16; i++) {
index = i;
for (j = i - 4; j >= 0; j -= 4) {
valueJ = 0;
valueI = 0;
if (block[index].getValue() == 0) {
t = Find(index, -4, 0, 16);
if (t != -1) {
block[index].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueI = block[index].getValue();
if (block[j].getValue() == 0) {
t = Find(j, -4, 0, 16);
if (t != -1) {
block[j].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueJ = block[j].getValue();
if (valueI == valueJ && valueI != 0 && valueJ != 0) {
block[index].setValue(valueI + valueJ);
block[j].setValue(0);
numFlag = true;
}
index = j;
}
}
}
/**
* 向左移动
*
* 第一重循环 0 4 8 12
*
* 第二重循环 1 2 3
* 5 6 7
* 9 10 11
* 13 14 15
*/
public void leftBlock() {
int i = 0, j = 0;
int t = 0;
int valueJ = 0;
int valueI = 0;
int index = 0;
for (i = 0; i < 16; i += 4) {
index = i;
for (j = i + 1; j < i + 4; j++) {
valueJ = 0;
valueI = 0;
if (block[index].getValue() == 0) {
t = Find(index, 1, i, i + 4);
if (t != -1) {
block[index].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueI = block[index].getValue();
if (block[j].getValue() == 0) {
t = Find(j, 1, i, i + 4);
if (t != -1) {
block[j].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueJ = block[j].getValue();
if (valueI == valueJ && valueI != 0 && valueJ != 0) {
block[index].setValue(valueI + valueJ);
block[j].setValue(0);
numFlag = true;
}
index = j;
}
}
}
/**
* 向右移动
*
* 第一重循环 3 7 11 15
*
* 第二重循环 2 1 0
* 6 5 4
* 10 9 8
* 14 13 12
*/
public void rightBlock() {
int i = 0, j = 0;
int t = 0;
int valueJ = 0;
int valueI = 0;
int index = 0;
for (i = 3; i < 16; i += 4) {
index = i;
for (j = i - 1; j > i - 4; j--) {
valueJ = 0;
valueI = 0;
if (block[index].getValue() == 0) {
t = Find(index, -1, i - 3, i + 1);
if (t != -1) {
block[index].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueI = block[index].getValue();
if (block[j].getValue() == 0) {
t = Find(j, -1, i - 3, i + 1);
if (t != -1) {
block[j].setValue(block[t].getValue());
block[t].setValue(0);
} else {
break;
}
}
valueJ = block[j].getValue();
if (valueI == valueJ && valueI != 0 && valueJ != 0) {
block[index].setValue(valueI + valueJ);
block[j].setValue(0);
numFlag = true;
}
index = j;
}
}
}
public void over() {
if (numFlag == false && up == false && down == false && left == false
&& right == false) // 当不能添加元素,并且不可移动就输了.
{
block[4].setText("G");
block[5].setText("A");
block[6].setText("M");
block[7].setText("E");
block[8].setText("O");
block[9].setText("V");
block[10].setText("E");
block[11].setText("R");
JOptionPane.showMessageDialog(null, "你输了!");
block[15].addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
reStart();
}
});
}
}
public void win() {
for (int i = 0; i < block.length; i++) {
if (block[i].getText().equals("2048")) {
iswin = true;
block[0].setText("Y");
block[1].setText("O");
block[2].setText("U");
block[13].setText("W");
block[14].setText("I");
block[15].setText("N");
JOptionPane.showMessageDialog(null, "你赢了!");
block[15].addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
reStart();
}
});
}
}
}
public void reStart() {
iswin = false;
numFlag = true;
up = true;
down = true;
left = true;
right = true;
for (int i = 0; i < 16; i++)
block[i].setValue(0);
for (int i = 0; i < 2; i++)
appearBlock();
}
}
package my2048;
import javax.swing.*;
import java.awt.*;
public class Block extends JLabel {
private int value;
public Block() {
value = 0;// 初始化值为0
setFont(new Font("font", Font.PLAIN, 40));// 设定字体
setBackground(Color.gray);// 设定初始颜色为灰色
}
public int getValue()// 获取值
{
return value;
}
public void setValue(int value) {
this.value = value;
String text = String.valueOf(value);
if (value != 0)
setText(text);
else
setText("");// 如果值为0则不显示
setColor();
}
public void setColor() // 根据值的不同设定不同的背景颜色、label字体
{
switch (value) {
case 0:
setBackground(Color.gray);
break;
case 2:
setBackground(new Color(238, 228, 218));
break;
case 4:
setBackground(new Color(238, 224, 198));
break;
case 8:
setBackground(new Color(243, 177, 116));
break;
case 16:
setBackground(new Color(243, 177, 116));
break;
case 32:
setBackground(new Color(248, 149, 90));
break;
case 64:
setBackground(new Color(249, 94, 50));
break;
case 128:
setBackground(new Color(239, 207, 108));
break;
case 256:
setBackground(new Color(239, 207, 99));
break;
case 512:
setBackground(new Color(239, 203, 82));
break;
case 1024:
setBackground(new Color(239, 199, 57));
break;
case 2048:
setBackground(new Color(239, 195, 41));
break;
case 4096:
setBackground(new Color(255, 60, 57));
break;
}
}
}
初次学习制作游戏,没有经验,所以借鉴了一位前辈的代码,如有冒犯,请望见谅。而在学习的过程中,由于本人数学不是很好,加之源码中有的地方注释解释的不够清晰,所以对于源码中的移动,合并算法设计着实理解了好久,有感于此,遂决定将此次理解的过程以注释的方式进行了批注,并在自己理解的过程中着手对算法一些难以理解的地方进行了调优,使之更便于理解,并亲测好久,没有发现太大问题,故分享出来,望大家能多多指出一些修改意见!而且对于这个游戏的结束算法,总感觉判断的不够智能,还望各位大神如有更好的建议,能够告知,在下不胜感激!