我看看怎么个事,是谁还在为大一开学,期末课设而担心?

本文详细介绍了如何使用Java实现2048游戏,包括棋盘初始化、随机位置产生新值、键盘控制(上、下、左、右)以及将棋盘状态映射到真实棋盘上的事件监听。适合Java初学者参考。
摘要由CSDN通过智能技术生成

         这是我的第一篇关于java的博客,所以大多数java细节都会解释,当然大佬可以避开小菜的博客了,对新手还是友好的,来不及解释了,快上车。

不看过程的可以直接拿干净的代码和图片哦~~

package h1;  //这一步要取决于你实际上在哪个包下的名字
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import java.util.Scanner;

public class h1_2 extends JFrame implements KeyListener {
    JFrame screen=this;
    Scanner Scanf=new Scanner(System.in);
    int InPut;
    int[][] arr=new int[4][4];
    Random r=new Random();
    public static void main(String[] args){
        h1_2 obj=new h1_2();
        obj.events();
    }
    public void init(){
        this.addKeyListener(this);
        screen.setSize(890,914);
        screen.setLocationRelativeTo(null);
        screen.setLocation(320,90);

        screen.getContentPane().setLayout(null);
        screen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        screen.setVisible(true);


        for(int i=0;i<4;i++){
            for (int j =0;j<4;j++){
                arr[i][j]=0;}}
        int i=r.nextInt(4);
        int j = r.nextInt(4);
        arr[i][j]=2;
        PainShow();}


    int[] col=new int[16];
    int[] row=new int[16];
    public void RandGener(){
        int lenth=-1;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if (arr[i][j]==0){
                    row[++lenth]=i;
                    col[lenth]=j;
                }
            }
        }
        if (lenth==-1){
            return;}
        int i=r.nextInt(++lenth);
        arr[row[i]][col[i]]=2;
    }

    public void Upper(){
        int point=0;
        for(int j=0;j<4;j++){
            point=0;
            for(int i=1;i<4;i++) {
                if(arr[i][j]==0){
                    continue;
                }
                if(arr[point][j]==0){
                    arr[point][j]=arr[i][j];
                    arr[i][j]=0;
                }
                else{
                    if(arr[i][j]==arr[point][j]){
                        arr[point][j]=arr[point][j]*2;
                        point++;
                        arr[i][j]=0;
                    }
                    else{
                        arr[++point][j]=arr[i][j];
                        if (point!=i){
                            arr[i][j]=0;
                        }}}}}}
    public void Doward(){
        int point;
        for(int j=0;j<4;j++){
            point=3;
            for(int i=2;i>-1;i--) {
                if(arr[i][j]==0){
                    continue;
                }
                if(arr[point][j]==0){
                    arr[point][j]=arr[i][j];
                    arr[i][j]=0;
                }
                else{
                    if(arr[i][j]==arr[point][j]){
                        arr[point][j]=arr[point][j]*2;
                        point--;
                        arr[i][j]=0;
                    }
                    else{
                        arr[--point][j]=arr[i][j];
                        if (point!=i){
                            arr[i][j]=0;
                        }}}}}}

    public void Left(){
        int point;
        for(int i=0;i<4;i++){
            point =0;
            for(int j=1;j<4;j++){
                if(arr[i][j]==0){
                    continue;
                }
                if(arr[i][point]==0){
                    arr[i][point]=arr[i][j];
                    arr[i][j]=0;
                }
                else{
                    if(arr[i][j]==arr[i][point]){
                        arr[i][point]=arr[i][point]*2;
                        point++;
                        arr[i][j]=0;
                    }
                    else{
                        arr[i][++point]=arr[i][j];
                        if(point!=j){
                            arr[i][j]=0;
                        }
                    }
                }

            }
        }
    }
    public void Right(){
        int point;
        for(int i=0;i<4;i++){
            point =3;
            for(int j=2;j>-1;j--){
                if(arr[i][j]==0){
                    continue;
                }
                if(arr[i][point]==0){
                    arr[i][point]=arr[i][j];
                    arr[i][j]=0;
                }
                else{
                    if(arr[i][j]==arr[i][point]){
                        arr[i][point]=arr[i][point]*2;
                        point--;
                        arr[i][j]=0;

                    }
                    else{
                        arr[i][--point]=arr[i][j];
                        if(point!=j){
                            arr[i][j]=0;
                        }
                    }
                }
            }
        }
    }
    public void OutPut(){
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                System.out.print(arr[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println();
    }
    public void events(){
        init();
        OutPut();
    }
    public void PainShow(){
        screen.getContentPane().removeAll();
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if(arr[i][j]!=0){
                    JLabel img=new JLabel(new ImageIcon(arr[i][j]+".png"));
                    System.out.println(arr[i][j]+".png");
                    img.setBounds(56+j*200,61+i*200,160,160);
                    screen.getContentPane().add(img);
                }
            }
        }
        JLabel back=new JLabel(new ImageIcon("棋盘.png"));
        back.setBounds(0,0,890,886);
        screen.getContentPane().add(back);
        repaint();
    }


    @Override
    public void keyTyped(KeyEvent e) {

    }
    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println(e.getKeyCode());
        if(e.getKeyChar()=='w'||e.getKeyCode()==38){
            Upper();
            RandGener();
            PainShow();
            OutPut();
        }
        if(e.getKeyChar()=='a'||e.getKeyCode()==37){
            Left();
            RandGener();
            PainShow();
            OutPut();
        }
        if(e.getKeyChar()=='d'||e.getKeyCode()==39){
            Right();
            RandGener();
            PainShow();
            OutPut();
        }
        if(e.getKeyChar()=='s'||e.getKeyCode()==40){
            Doward();
            RandGener();
            PainShow();
            OutPut();
        }

    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
}

代码开头

package h1;       //package后面跟什么取决于当前在什么包下,我这里包叫h1
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import java.util.Scanner;

public class h1_2 extends JFrame implements KeyListener {      //继承JFrame同时调用KeyListener接口,使该对象具有窗口能力和键盘输入监听能力
//    int isFail=1;  //初始状态默认为输
//    public h1_2(){super();};
//    public h1_2(String e){super(e);};
    JFrame screen=this;    //可以不用这样多次一举,后面的screen其实都可以省略,因为在下面的所有的screen.方法和变量都是这个this环境下的,可以省略变量screen不写

    Scanner Scanf=new Scanner(System.in);      //System.in为控制台的输入流,代表创建一个从控制台读取的读取器对象,后来会学到其他流,比如说InputStream(输入字节流),InputStreamReader(输入字符流).....
    int InPut;    //成员变量,记录每一次你所按下的键是什么,然后再执行对应的操作

    int[][] arr=new int[4][4];    //创建2048棋盘的布局为4*4方格
    Random r=new Random();   //创建Random对象,为了产生随机数,来随机确定下一个2产生的位置

    public static void main(String[] args){
        h1_2 obj=new h1_2();
        obj.events();             //所有的执行操作打包到了events函数里了

    }

棋盘初始化

  public void init(){                   //初始化局内数组变量,以及gui
      this.addKeyListener(this);
      screen.setSize(890,914);     //创建窗口大小,第一个是宽,第二个是高  上面说过,如果没有定义screen在这也是可以省略screen.的。
      screen.setLocationRelativeTo(null);     //  null为空值,在该方法里取消窗口居中显示的默认布局
      screen.setLocation(320,90);      //既然上面取消了1默认布局,就要创建默认布局,第一个参数代表距离屏幕左侧的距离(单位:像素点),第二个参数代表距离屏幕上侧的距离(单位:像素点)

      screen.getContentPane().setLayout(null);  //这段代码的作用是将JFrame的内容面板的布局管理器设置为空(null),即在内容面板上添加的组件将具有绝对定位和尺寸。通常不建议使用此方法,因为在调整应用程序的大小或缩放时,它可能会导致不可预测的行为。建议使用布局管理器来处理组件的位置和大小。
      screen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    //设置当屏幕关闭时,不执行其他操作
      screen.setVisible(true);                          //设置屏幕是可见的


      for(int i=0;i<4;i++){         //对棋盘初始化,把他们的值都变成0
          for (int j =0;j<4;j++){
              arr[i][j]=0;       //由于该方法里也没有放置与this.arr重名的变量,所以默认调用this环境变量下的成员arr,但是如果该方法函数里创建了arr变量,就会默认调用新建的arr,如果想再次调用成员变量arr,就需要this.arr来调用
          }
      }
      //为了定位行和列来随机生成第一个2
      int i=r.nextInt(4);      //r为创建的成员变量Random随机数生成器,i为随机定位的行
      int j = r.nextInt(4);    //j为随机生成的列
      arr[i][j]=2;
      PainShow();                   //该方法为下面定义的方法,其作用是把当前棋盘状态更新到屏幕
  }

  //每当移动一次,创建下一个随机的2的生成位置
  int[] col=new int[16];    //记录空闲位置的横坐标
  int[] row=new int[16];   //记录空闲坐标的列位置

随机位置产生新值方法

    public void RandGener(){   //每移动一次,就生成一个随机位置的2
        int lenth=-1;
        for(int i=0;i<4;i++){   //以下方法是判断哪些位置为0,因为只有0的位置为空闲位置,可以生成2  没什么特别讲的,看看吧
            for(int j=0;j<4;j++){
                if (arr[i][j]==0){
                    row[++lenth]=i;
                    col[lenth]=j;
                }
            }
        }
        if (lenth==-1){
            return;
        }
        int i=r.nextInt(++lenth);
        arr[row[i]][col[i]]=2;

    }

向上,下,左,右方向移动代码方法实现

   //向上移动,改变棋盘布局    这一部分是我自己想的方法,可以参考一下思路,,虽然挺菜的吧,不过感觉普通的两次偏移数字,还是比较优雅的了
   //以下所有i,j分别都按着一个标准,i代表行,j代表列
   public void Upper(){   //向上移动,肯定是一列一列的遍历,所以外层遍历变量是列,内层是行
       int point=0;
       for(int j=0;j<4;j++){
           point=0;   //point代表偏移地址,因为是列合并,所以这里的遍历的行,point代表第二个偏移地址i
           //以下代码有个细节就是,i是从1开始的,不是从0开始的,看完以下代码,过来看看为什么~~~
           for(int i=1;i<4;i++) {   //好吧这里,我真的不想讲了,哈哈~~讲一下基本思路,一定看看这个,再看下面吧 2222-->4022-->4202-->4400,这个展示的是横向左合并,以下代码就是这么实现的
               if(arr[i][j]==0){     //归为两大类,下一个遍历数是0和不是0的,是0的就可以跳过了
                   continue;
               }                       //接下来不是0的情况,又分为两类
               if(arr[point][j]==0){    //point停留的地址为0的话,则执行了4022-->4202 而point指向的地址就是第二个0,所以把2替换过来
                   arr[point][j]=arr[i][j];
                   arr[i][j]=0;
               }
               else{                             //如果point停留的地方不为0,又分为两类,好吧,我承认我有套娃的嫌疑,蛤蛤蛤
                   if(arr[i][j]==arr[point][j]){     //point指向的地方和当前的数值相同,就合并,执行了2222--->4022或者是4202--->4400
                       arr[point][j]=arr[point][j]*2;
                       point++;
                       arr[i][j]=0;
                   }
                   else{                 //point指向的地方和当前的数值不相同,此时point指向的是4,当前遍历的是第三个数值2,就执行4022--->4202。
                       arr[++point][j]=arr[i][j];
                       if (point!=i){       //为什么要有这一步,大佬,请您也想一想,好吧~~
                           arr[i][j]=0;
                       }
                   }
               }
           }
           }

   }

   //向下移动  思路和Upper()函数思路大同小异
   public void Doward(){
       int point;
       for(int j=0;j<4;j++){
           point=3;   //point代表偏移地址,代表第二个偏移地址i
           for(int i=2;i>-1;i--) {
               if(arr[i][j]==0){
                   continue;
               }
               if(arr[point][j]==0){
                   arr[point][j]=arr[i][j];
                   arr[i][j]=0;
               }
               else{
                   if(arr[i][j]==arr[point][j]){
                       arr[point][j]=arr[point][j]*2;
                       point--;
                       arr[i][j]=0;
                   }
                   else{
                       arr[--point][j]=arr[i][j];
                       if (point!=i){
                           arr[i][j]=0;
                       }

                   }
               }
           }
       }

   }

   //向左偏移     思路和Upper()函数思路大同小异
   public void Left(){
       int point; //偏移地址为i
       for(int i=0;i<4;i++){
           point =0;
           for(int j=1;j<4;j++){
               if(arr[i][j]==0){
                   continue;
               }
               if(arr[i][point]==0){
                   arr[i][point]=arr[i][j];
                   arr[i][j]=0;
                   }
                   else{
                   if(arr[i][j]==arr[i][point]){
                       arr[i][point]=arr[i][point]*2;
                       point++;
                       arr[i][j]=0;

                   }
                   else{
                       arr[i][++point]=arr[i][j];
                       if(point!=j){
                           arr[i][j]=0;
                       }
                   }
               }

           }
       }
   }
   //向右偏移       思路和Upper()函数思路大同小异
   public void Right(){
       int point; //偏移地址为i
       for(int i=0;i<4;i++){
           point =3;
           for(int j=2;j>-1;j--){  //从右向左遍历
               if(arr[i][j]==0){  //当前为0跳过
                   continue;
               }                       //当前都不为0的遍历
               if(arr[i][point]==0){     //point为0则替换
                   arr[i][point]=arr[i][j];
                   arr[i][j]=0;
               }
               else{
                   if(arr[i][j]==arr[i][point]){
                       arr[i][point]=arr[i][point]*2;
                       point--;
                       arr[i][j]=0;

                   }
                   else{
                       arr[i][--point]=arr[i][j];
                       if(point!=j){
                           arr[i][j]=0;
                       }
                   }
               }

           }
       }
   }
   public void OutPut(){    //这个函数纯属在调试台测试结果的正确性
       for(int i=0;i<4;i++){
           for(int j=0;j<4;j++){
               System.out.print(arr[i][j]+" ");
           }
           System.out.println();
       }
       System.out.println();
   }
   public void events(){    //运行的总函数
       init();          //初始化棋盘
       OutPut();           //输出棋盘列表,可以忽略这一布
   }

把棋盘状态映射到真实棋盘上

 public void PainShow(){           //一个一个把对应的棋映射到棋盘上面
     screen.getContentPane().removeAll();     //把原来的棋移除,重新更新棋盘
     for(int i=0;i<4;i++){
         for(int j=0;j<4;j++){
             if(arr[i][j]!=0){
                 JLabel img=new JLabel(new ImageIcon(arr[i][j]+".png"));
                 System.out.println(arr[i][j]+".png");
                 img.setBounds(56+j*200,61+i*200,160,160);
                 screen.getContentPane().add(img);
             }
         }
     }
     JLabel back=new JLabel(new ImageIcon("棋盘.png"));
     back.setBounds(0,0,890,886);
     screen.getContentPane().add(back);
     repaint();




 }


 @Override
 public void keyTyped(KeyEvent e) {

 }

事件监听器重构方法

 @Override
 public void keyPressed(KeyEvent e) {       //调用KeyListener重写监听器的方法
     System.out.println(e.getKeyCode());
     if(e.getKeyChar()=='w'||e.getKeyCode()==38){      //按下w或上键执行    上键的代码为38   下面同理
         Upper();
         RandGener();
         PainShow();
         OutPut();
     }
     if(e.getKeyChar()=='a'||e.getKeyCode()==37){
         Left();
         RandGener();
         PainShow();
         OutPut();
     }
     if(e.getKeyChar()=='d'||e.getKeyCode()==39){
         Right();
         RandGener();
         PainShow();
         OutPut();
     }
     if(e.getKeyChar()=='s'||e.getKeyCode()==40){
         Doward();
         RandGener();
         PainShow();
         OutPut();
     }

 }

 @Override
 public void keyReleased(KeyEvent e) {    //上面定义的是键盘按下的反应,也可以把keyPressed的方法放置到这里,代表键盘按下,松开后执行

 }
}

路漫漫兮其修远兮      吾将上下而求索

       在此,我想真诚地表示,虽然我对Java有一定的掌握和了解,但仍然有很多需要学习和探索的地方。 Java是一个复杂而有趣的编程语言,我感到非常荣幸能够在其中学习和成长。我希望能够和其他对Java或python以及虚拟机感兴趣的人共同交流,同时也期待着在未来的学习中不断地拓展自己的知识面。 收尾~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值