这两天写了个Java的2048游戏,找了两天bug,找完bug感觉自己萌萌哒。啥也不说了,来代码,来图吧!
首先,我们得创建一个界面:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;//导包过程,没啥说的
public class UI extends JFrame {
public static void main(String[] args) {
UI ui = new UI();
ui.InUI();
}
// 创建数组,存储数据
private int[][] numbers = new int[4][4];
// 创建界面
public void InUI() {
this.setTitle("2048");
this.setLocation(200, 200);
this.setSize(270, 340);
this.setLayout(null);
// 添加按钮
JButton jb = new JButton();
jb.setText("开始游戏");
jb.setFocusable(false);
jb.setBounds(10, 10, 100, 30);
jb.setForeground(new Color(3, 82, 212));
jb.setFont(new Font("宋体", Font.BOLD, 15));
this.add(jb);
JLabel jl = new JLabel("score:");
jl.setBounds(160, 10, 100, 30);//空布局的大小位置设置要用setBounds………………………………
jl.setForeground(new Color(3, 82, 212));
this.add(jl);
this.setDefaultCloseOperation(3);
this.setResizable(false);//界面大小动一个试试
this.setVisible(true);
// 创建事件处理类
NewListener nl = new NewListener(this, numbers, jl);
jb.addActionListener(nl);// 动作监听器
this.addKeyListener(nl);// 键盘监听器
}
/*
* 重写窗体的方法
*/
public void paint(Graphics g) {
super.paint(g);
g.setColor(new Color(255, 170, 37));
g.fillRoundRect(10, 80, 250, 250, 15, 15);// 绘制大矩形框
g.setColor(new Color(234, 223, 223));
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
g.fillRoundRect(20 + i * 60, 90 + j * 60, 50, 50, 15, 15);
}
}// 绘制小矩形框
// 调整数字的位置,注意横纵坐标~~~~~~是反的哦!!!bug之一!!!
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (numbers[i][j] != 0) {
if (numbers[i][j] == 2 || numbers[i][j] == 4|| numbers[i][j] ==
{
g.setColor(Color.red);
g.fillRoundRect(20 + j * 60, 90 + i * 60, 50, 50, 15,15);
g.setColor(Color.black);
g.setFont(new Font("宋体", Font.BOLD, 30));
g.drawString(numbers[i][j] + "", 20 + j * 60 + 17,90 + i * 60 + 33);
} else if (numbers[i][j] == 16 || numbers[i][j] == 32|| numbers[i][j] == 64) {
g.setColor(Color.CYAN);
g.fillRoundRect(20 + j * 60, 90 + i * 60, 50, 50, 15,15);
g.setColor(Color.BLUE);
g.setFont(new Font("宋体", Font.BOLD, 30));
g.drawString(numbers[i][j] + "", 20 + j * 60 + 8,90 + i * 60 + 33);
} else if (numbers[i][j] == 128 || numbers[i][j] == 256|| numbers[i][j] == 512) {
g.setColor(Color.white);
g.fillRoundRect(20 + j * 60, 90 + i * 60, 50, 50, 15,15);
g.setColor(Color.red);
g.setFont(new Font("宋体", Font.BOLD, 20));
g.drawString(numbers[i][j] + "", 20 + j * 60 + 10,90 + i * 60 + 33);
} else if (numbers[i][j] == 1024 || numbers[i][j] == 2048|| numbers[i][j] == 4096) {
g.setColor(Color.blue);
g.fillRoundRect(20 + j * 60, 90 + i * 60, 50, 50, 15,15);
g.setColor(Color.green);
g.setFont(new Font("宋体", Font.BOLD, 20));
g.drawString(numbers[i][j] + "", 20 + j * 60 + 5,90 + i * 60 + 33);
}
}
}
}
}
}//实现了数字在矩形框上显示的位置(居中),设置了数字所对应的框的颜色
接下来就是各方向算法的分析咯~
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JOptionPane;//又是导包
public class NewListener extends KeyAdapter implements ActionListener {
private UI ui;// 界面类的对象
private int[][] numbers;// 存数数据的数组
private Random rand = new Random();
private JLabel jl;
private int score = 0;
AudioClip audio;
AudioClip audio1;
public NewListener(UI ui, int[][] numbers, JLabel jl) {
this.ui = ui;
this.numbers = numbers;
this.jl = jl;
audio=Applet.newAudioClip(getClass().getResource("click_01.wav"));
audio1=Applet.newAudioClip(getClass().getResource("T-Ara - Number 9.wav"));//2048也是有声音滴~~~~~~这个地方不用new 而是Applet
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
numbers[i][j] = 0;
}
}
score = 0;// 初始化,保证每次按开始后都能重新计分
audio1.loop();//有背景音乐的2048,你玩过么。。。
int r1 = rand.nextInt(4);
int r2 = rand.nextInt(4);
int c1 = rand.nextInt(4);
int c2 = rand.nextInt(4);
while (r1 == r2 && c1 == c2) {
r2 = rand.nextInt(4);
c2 = rand.nextInt(4);
}
// 生成2 或 4
int value1 = rand.nextInt(2) * 2 + 2;
int value2 = rand.nextInt(2) * 2 + 2;
// 把数组存入对应的数组
numbers[r1][c1] = value1;
numbers[r2][c2] = value2;
ui.paint(ui.getGraphics());
}
// 键盘按下的方法
这个地方最好用pressed 不要用released不然后面会有bug。。。如果用release的话,弹出的失败或胜利框,是不能用回车键确定的~pressd则不会出现这种情况
public void keyPressed(KeyEvent e) {
// System.out.println("66666"+e.getKeyCode());
int count = 0;// 计数器
int numberCount = 0;//用来统计整个界面上的格子是否已占满
int numberCount2 = 0;//用来统计相邻格子上的数字是否相同
switch (e.getKeyCode()) {
//37是指键盘上的向左键对应到keyCode上是37;
case 37:// 左
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (numbers[i][j] != 0) {
int temp = numbers[i][j];
int c = j - 1;
while (c >= 0 && numbers[i][c] == 0) {
numbers[i][c] = temp;
numbers[i][c + 1] = 0;
c--;
count++;
}
}
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
/*当相邻两个相等的时候,加一次,并且数组的值不能为零:bug之二!!*/if (j + 1 < 4 && numbers[i][j] == numbers[i][j + 1]&& (numbers[i][j] != 0 || numbers[i][j + 1] != 0)) {
numbers[i][j] = numbers[i][j] + numbers[i][j + 1];
numbers[i][j + 1] = 0;
count++;
score += numbers[i][j];计分~~
if (numbers[i][j] == 2048) {
//向左移动时,当其显示2048时,出现“你赢了!” JOptionPane.showMessageDialog(null, "你赢了!");
}
}
}
}
相加之后如果后面还有空 就再移动一次~
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (numbers[i][j] != 0) {
int temp = numbers[i][j];
int c = j - 1;
while (c >= 0 && numbers[i][c] == 0) {
numbers[i][c] = temp;
numbers[i][c + 1] = 0;
c--;
count++;
}
}
}
}
audio.play();//移动时会发出声音
break;
…………………………//向上、下、右的方法与向左类似,注意数组不能越界,
case38: case39: case40:………………………………
游戏失败的判断~~~当16个格子都有值,且相邻格子上的值不能相等,注意遍历时候越界问题,以及计数器所计的值到底是表示什么,(这个困扰了小编两个下午,真闹心,不过想通了~~~)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (numbers[i][j] == numbers[i][j + 1] && numbers[i][j] != 0) {
numberCount2++;
}
if (numbers[i][j] == numbers[i + 1][j] && numbers[i][j] != 0) {
numberCount2++;
}
if (numbers[3][j] == numbers[3][j + 1] && numbers[3][j] != 0) {
numberCount2++;
}
if (numbers[i][3] == numbers[i + 1][3] && numbers[i][3] != 0) {
numberCount2++;
}
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (numbers[i][j] != 0) {
numberCount++;
}
}
}
进入循环的条件!if (count > 0) {
jl.setText("score:" + score);
int r1 = rand.nextInt(4);
int c1 = rand.nextInt(4);
while (numbers[r1][c1] != 0) {
r1 = rand.nextInt(4);
c1 = rand.nextInt(4);
}
// if(numbers[r1][c1]!=0){
int value1 = rand.nextInt(2) * 2 + 2;
numbers[r1][c1] = value1;
// }
ui.paint(ui.getGraphics());
}
失败的输出语句: if (numberCount == 16 && numberCount2 == 0) {
JOptionPane.showMessageDialog(ui, "思密达,你输了~~~");
}
}
下面是测试结果:
当然,数字可以换成图片,这时就可以用drawimage 或者直接添加Jbutton,然后在jbutton上添加图片,这个小编还没做,不过目前来说简单的2048就算完成咯~~