一,游戏的底层逻辑
游戏规则:
每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方随机生成一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。
思路:
游戏的逻辑特别简单,只有接收随机生成方块,用户输入,方块向一个方向靠拢,方块相撞4个主要功能,我们可以先在控制台把逻辑实现。
1,新建项目
private static int[][] maps=new int[4][4];//储存游戏信息
public static void main(String[] args) throws InterruptedException {
}
//将游戏信息输出到控制台
public static void creatMap() {
for (int i = 0; i < maps.length; i++) {
for (int j = 0; j < maps.length; j++) {
System.out.print("[" + String.format("%3d ", maps[i][j]) + "]");
}
System.out.println();
}
System.out.println();
}
2,随机生成方块
public static void newNum() throws InterruptedException {
Random ran = new Random();
int x, y;
boolean flag = false;
//用来检测能不能生成方块
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (maps[i][j] == 0)
flag = true;//遍历数组,如果有元素为0,说明还有空位
}
}
if (!flag){//如果flag没有改变,说明没有空位,输出游戏结束提示语
System.out.println("游戏结束!");
sleep(2000);
System.exit(0);
}
do {
int a = ran.nextInt(16);//随机生成一个数用来确定位置
x = a / 4;
y = a % 4;
} while (maps[x][y] != 0);//如果位置上没有元素则选中这个位置
maps[x][y] = (ran.nextInt(2) + 1) * 2;//在选中的位置上随机生成一个新数,新数为2或者4
}
3,方块靠拢
这里只写了一个方向的方法,其他方向的方法以此类推,这里使用了三个循环,但是因为数组的大小是确定的,所以实际循环次数并不高,不用担心时间复杂度。
private static void moveUp() {
for (int i = 0; i < 4; i++) {//向上移动最外层循环是列号
for (int j = 3; j > 0; j--) {
for (int k = 0; k < j; k++) {
//通过冒泡排序的逻辑把0全放到下面去
if (maps[k][i] == 0 && maps[k + 1][i] != 0) {
int temp = maps[k][i];
maps[k][i] = maps[k + 1][i];
maps[k + 1][i] = temp;
}
}
}
}
}
4,方块相撞
private static void mergeUp() {
moveUp();//进来前先把元素靠拢到上面
for (int i = 0; i < 4; i++) {//向上合并最外层循环为列号
for (int j = 0; j < 3; j++) {
//检测相邻元素是否相等,相等则合并
if (maps[j][i] == maps[j + 1][i] && maps[j][i] != 0) {
maps[j][i] *= 2;
maps[j + 1][i] = 0;
}
}
}
moveUp();//把合并出来的空位填满
}
5,用户输入
这里我们暂时先用直接在控制台输入wasd的方式来控制游戏。
public static void mergeNum(char c) throws InterruptedException {
switch (c) {
case 'w':
mergeUp();
break;
case 's':
mergeDown();
break;
case 'a':
mergeLeft();
break;
case 'd':
mergeRight();
break;
default:
}
newNum();//每次用户操作完之后生成新数字
creatMap();//重新生成游戏信息
}
测试:
游戏的底层逻辑写好了,测试一下没有发现问题。
二,JFrame窗口和JPanel画板
1,JFrame的基本设置
让当前类继承JFrame类,设置一下初始属性,不用全部都设置
public class Frame extends JFrame {//继承JFrame
int[][] maps=new int[4][4];
public Frame() throws InterruptedException {
this.setTitle("genshin");//标题
this.setSize(494,517);//大小
this.setResizable(false);//能否改变大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//退出方式
//左上角和应用栏的图标
this.setIconImage(new ImageIcon("C:\\dev\\work\\JavaStudy\\game\\src\\com\\lzy\\resources\\icon1.png").getImage());
this.setVisible(true);//能否显示
this.setLocation(500,200);//初始在屏幕上的位置
// this.setAlwaysOnTop(true);//总是在最上面
// this.setEnabled(false);//能不能操作
}
}
2,JPanel面板
public class Panel extends JPanel {
private int maps[][];
public int[][] getMaps() {
return maps;
}
public void setMaps(int[][] maps) {
this.maps = maps;
}
public void paint(Graphics g){//重写JPanel的paint方法
super.paint(g);//调用
//drawImage方法可以生成图片
g.drawImage(new ImageIcon("C:\\dev\\work\\JavaStudy\\game\\src\\com\\lzy\\resources\\bg.jpg").getImage(),0,0,480,480,null);
}
}
在Frame类中add一下Panel就可以生成图片了
3,绘制游戏画面
需要写在Panel类里面,通过重写的paint方法调用这个方法。
public void creatGame(Graphics g){
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
//每隔120像素画一个100*100像素的颜色块,颜色根据maps中的数字自动生成
g.drawImage(image,i*120,j*120,100,100,newColor(maps[j][i]),null);
if (maps[j][i]!=0)//如果元素不为0的话也输出出来
g.drawString(String.valueOf(maps[j][i]),i*120+40,j*120+55);
}
}
}
public Color newColor(int a) {
switch (a) {
case 0:
return null;
case 2:
return new Color(200,255,200, 255);
case 4:
return new Color(150,150,255, 255);
case 8:
return new Color(255,150,150, 255);
case 16:
return new Color(255, 251, 0, 255);
case 32:
return new Color(250, 118, 43, 255);
case 64:
return new Color(255, 36, 36, 255);
case 128:
return new Color(31, 255, 12);
case 256:
return new Color(0, 31, 255);
case 512:
return new Color(255, 42, 218);
case 1024:
return new Color(255, 15, 81);
case 2048:
return new Color(255, 106, 0);
case 4096:
return new Color(255, 255, 255);
case 8192:
return new Color(200,200,255, 0);
default:
return null;
}
}
这一步完成之后我们调用一下前面写的新生成一个数字,就能得到这种效果了
4,键盘监听
接下来我们写一个方法调用addKeyLinstener方法,添加一个键盘监听
public void keyboard(){
this.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {//键盘操作时
}
@Override
public void keyPressed(KeyEvent e) {//键盘按下时
}
@Override
public void keyReleased(KeyEvent e) {//键盘松开时
if (KeyEvent.VK_W == e.getKeyCode()) {
mergeUp();
newNum();
}
if (KeyEvent.VK_A == e.getKeyCode()) {
mergeLeft();
newNum();
}
if (KeyEvent.VK_S == e.getKeyCode()) {
mergeDown();
newNum();
}
if (KeyEvent.VK_D == e.getKeyCode()) {
mergeRight();
newNum();
}
}
});
}
在Frame中调用一下键盘监听功能,游戏就可以玩啦!
其他:
把这些弄懂之后可以自己深入摸索一下,比如把数字变成其他的图片就能做出《合成涩图》之类的,或者是写一些其他游戏的底层逻辑比如《扫雷》,《数独》等等。