2048小游戏

                                                                       2048游戏

 

大家好,这里我给大家介绍一款2048小游戏的思路和具体做法。

 

在这一篇博客里所实现的是2048的做法,具体代码和基本思路。

 

我来具体讲讲这个游戏。

这款游戏里,一共有两个界面。

第一个是外部的主界面:

2048小游戏_第1张图片

 

这个主界面中有四个按钮,功能明确。

下面是帮助按钮和关于按钮的效果图。

2048小游戏_第2张图片

 

 

 

 

2048小游戏_第3张图片

 

 

接下来的面板是游戏内部面板,也就是点击主面板的开始游戏按钮之后出现的面板。

 

2048小游戏_第4张图片

下面这个是项目的主要结构。

 

2048小游戏_第5张图片

 

 

 

我们先从结构入手,可以很快的了解项目。

 

在项目New2048的bao2048里,有7个源文件。

此外,还有两个.jpg图片文件和两个.wav格式的音乐文件。有一个暂不用文件是音乐的备用文件。这两个图片文件是主界面 和游戏界面的背景图。两个音乐 文件是在游戏中添加的音乐。souFeiYa是一开始游戏的音乐,而chunYinYue是游戏界面的音乐。

以下是两幅基本背景图。

 

2048小游戏_第6张图片

 

 

 

2048小游戏_第7张图片

 

看到这两个原图片,大家是不是知道了它们的位置了。哈哈哈哈。

不同的是 , 第二幅是用paint方法画上去的,而第一幅是加到JFrame面板里去的。

 

 

介绍完了游戏所需基本资源,接下来我们一个一个介绍源文件。

 

我们先贴上JieMian.java的源代码。

package bao2048;


import java.awt.Color;
import java.awt.Image;
import java.io.FileNotFoundException;
import java.awt.event.*;


import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


import sun.audio.AudioPlayer;


public class JieMian   implements  ActionListener {


static int  a=9;
static JFrame  jfJieMian;
ImageIcon  g;
JLabel  biaoQian;
JPanel  anNiuMianBan , jp;
MyThread  xianChen; 
    JButton  jtnKaiShi  , jtnWoMen , jtnBangZhu , jtnTuiChu;
public JieMian() throws Exception
{


   xianChen= new MyThread();
   xianChen.start();
jfJieMian = new  JFrame("2048游戏");
g = new ImageIcon("11.jpg");
biaoQian= new JLabel(g);
biaoQian.setBounds(0, 0, g.getIconWidth(), g.getIconHeight());  //设置标签大小是整个图片
jfJieMian.getLayeredPane().add(biaoQian , new Integer(Integer.MIN_VALUE));  //第2层面板
jp = (JPanel)jfJieMian.getContentPane();
jp.setOpaque(false);  //设置透明
anNiuMianBan = new JPanel();
anNiuMianBan.setOpaque(false);
anNiuMianBan.setLayout(null); //设置布局管理器为null


   jtnKaiShi = new JButton("开始游戏");
jtnKaiShi.setSize(100, 50);
jtnKaiShi.setLocation(20, 50);
jtnKaiShi.setBackground(Color.cyan);
jtnKaiShi.addActionListener(this);
anNiuMianBan.add(jtnKaiShi);



jtnWoMen = new JButton("关于我们");  
jtnWoMen.setSize(100 ,50);
jtnWoMen.setLocation(20 ,120);
jtnWoMen.setBackground(Color.orange);
jtnWoMen.addActionListener(this);
anNiuMianBan.add(jtnWoMen);



jtnBangZhu = new  JButton("帮助");
jtnBangZhu.setSize(100 ,50);
jtnBangZhu.setLocation(20 , 190);
jtnBangZhu.setBackground(Color.yellow);
jtnBangZhu.addActionListener(this);
anNiuMianBan.add(jtnBangZhu);


jtnTuiChu = new JButton("退出游戏");
jtnTuiChu.setSize(100 ,50);
jtnTuiChu.setLocation(20, 260);
jtnTuiChu.setBackground(Color.LIGHT_GRAY);
jtnTuiChu.setBorder(BorderFactory.createEtchedBorder());
jtnTuiChu.addActionListener(this);
anNiuMianBan.add(jtnTuiChu);



jp.add(anNiuMianBan);
jfJieMian.setSize(800, 500);
jfJieMian.setLocation(200, 150);
jfJieMian.setVisible(true);
jfJieMian.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub

if(e.getSource() == jtnKaiShi)
{
jfJieMian.setVisible(false);

try {
   My2048 My = new  My2048();
//MyThread.boola=false;
//if(t.isAlive() )  System.out.println("在运行这个线程");
//t.yield();
   AudioPlayer.player.stop(Music.suoFeiYa);
} catch (FileNotFoundException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}

}


if(e.getSource() == jtnWoMen)
{
String  s1 = "团队名\n";
String s2 = "团队人员:***\n";
String s3 = "本游戏由我们团队协作完成,在原有代码基础上增加了部分功能\n本游戏用于发现杯项目作业,可供个人使用,由于代码并非原创\n禁止转出\n编不下去啦。。。。。可以自己改改。。。";
JOptionPane.showMessageDialog(jfJieMian, s1+s2+s3 , "团队介绍" , JOptionPane.INFORMATION_MESSAGE);

}


if(e.getSource() == jtnBangZhu)
{
String s1 = "开始时棋盘内随机出现两个数字,出现的数字仅可能为2或4\n";
String s2 ="玩家可以选择上下左右四个方向,若棋盘内的数字出现位移或合并,视为有效移动\n";
String s3 = "玩家选择的方向上若有相同的数字则合并,每次有效移动可以同时合并,但不可以连续合\n";
String s4="合并所得的所有新生成数字想加即为该步的有效得分\n";
String s5="玩家选择的方向行或列前方有空格则出现位移\n";
String s6="每有效移动一步,棋盘的空位(无数字处)随机出现一个数字(依然可能为2或4)\n";
String s7="棋盘被数字填满,无法进行有效移动,判负,游戏结束\n";
String s8="棋盘上出现2048,判胜,游戏结束\n";
JOptionPane.showMessageDialog(jfJieMian, s1+s2+s3+s4+s5+s6+s7+s8 ,"游戏规则" , JOptionPane.INFORMATION_MESSAGE);
}



if(e.getSource() == jtnTuiChu)
{
System.exit(0);

}
}

}

 

 

在这个源文件里,我们有四个按钮的构造,它们在JieMian的构造 方法里。还加了鼠标监听,用来监听点击按钮之后的操作。

 

帮助按钮和关于 我们按钮点击的结果是new了一个对话框,对话框里以字符串的形式列出了相关信息。退出按钮则调用了System.exit(0)方法来结束 程序,虽然有很多人不太喜欢这个粗暴的方法,但对于我等初学者还是很管用的,主要是播放游戏音乐的功能是放在线程里的,所以用这个方法可以很 直接的结束程序。在开始游戏按钮里,我们看到它new了一个My2048, 这是一个源文件,负责的是游戏的游戏界面。至于背景图片是怎么加上去的,我整了好久,最后才发现,JFrame的控制布局管理器不是只有ContPentpane。它有三层!而我们的图片应该加在它的第二层上面,并且把第一层的布局设置为透明,这样就可以看见图片了。

 

 

这个面板new了My2048,那么,接下来我们贴出它的源码,来看看它实现了什么功能。

 

以下是My2048的源码:

package bao2048;


import java.awt.*;
import java.io.FileNotFoundException;


import javax.swing.*;
public class My2048 extends JFrame 

static Operation  a ;
  public My2048() throws FileNotFoundException//构造函数 
  {

    setTitle("2048");//设置标题
    setSize(500, 670);//设定窗口大小
    setLocation(400, 50);//设定窗口起始位置
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //getContentPane().setLayout(new GridLayout(4, 4, 5, 5));//设定布局方式为GridLayout型
    a =new Operation(this);
    this.setFocusable(true);
    this.requestFocus();
    this.setVisible(true);//设为可视
  }
  
  public static void main(String args[]) throws Exception //程序入口点
  {
   /* try
    {
      UIManager.setLookAndFeel("org.jvnet.substance.skin.SubstanceRavenGraphiteLookAndFeel");//设定UI界面风格
    } //接受抛出的异常
    catch (ClassNotFoundException | InstantiationException| IllegalAccessException | UnsupportedLookAndFeelException e)
    {
      e.printStackTrace();
    }*/
    //JFrame.setDefaultLookAndFeelDecorated(true);//设定Frame的缺省外观
    //new My2048();
 new  JieMian();
  }
}

 

 

这里,出现了主函数,我们把new   JieMian的代码放到了主函数里,程序一执行,就出现主界面。而这里主函数在My2048里。我们来看看My2048的构造函数里都有什么。

除了一些基本的JFrame的设置之外,出现了一个Operation类,这个类实现了2048游戏的主要功能。而其他代码则是构建出一个窗体,也就是内部游戏界面。

 

 

接下来我们看看Operation类。

 

以下是Operation的源代码。

 

package bao2048;


import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public   class Operation   implements   KeyListener   , MouseListener
{
static int  deFenShuJu=0;
   Block[] block;//用于储存16个数据
  static JPanel panel = new JPanel();
  
  public  boolean up;
  public  boolean down;
  public  boolean left;
  public  boolean right;
  static int moveFlag;//用于累计移动的次数
  static boolean numFlag;//用于判断是否还能加入新的数字
  public Operation(JFrame frame ) 
  {
 
 
 
   // this.panel = (JPanel)frame.getContentPane();//构造出panel
SouthMianBan southM = new SouthMianBan(frame,this);




//frame.add( southM);
frame.add(southM, BorderLayout.NORTH);
frame.add(panel , BorderLayout.CENTER);
panel.addMouseListener(this);
panel.addKeyListener(this);
//panel.setFocusable(true);  //设置面板处于激活状态,不然键盘监听用不了
//panel.requestFocus();
panel.setLayout(new GridLayout(4, 4, 5, 5));
    block = new Block[16];//构造出长度为16的数组
    numFlag = true;//初始化
    moveFlag = 0;
    up=true;down=true;left=true;right=true;
    addBlock();
    for (int i = 0; i < 2; i++)
    appearBlock();
    frame.addKeyListener(this);
   
    
  }
  
  private void addBlock() 
  {
    for (int i = 0; i < 16; i++) //往panel里加入block
    {
      block[i] = new Block();
      block[i].setHorizontalAlignment(JLabel.CENTER);// 设置文本对齐方式,CENTER显示居中对齐
      block[i].setOpaque(true);//设置控件是否透明
      panel.add(block[i]);  
    }
  } 
  public void appearBlock() 
  {
    while (numFlag) //当还能加入随机的一个新的值得时候
    {
      int index = (int) (Math.random() * 16);//取一个0到15的随机整数,这个数作为随机加入盘中的2或4的位置
      if (block[index].getValue() == 0)//如果这个数所在的block数组中值为0,即在为空的时候,加入一个2或4的数字
      {
        if (Math.random() < 0.5)
        {
          block[index].setValue(2);
        }
        else
        {
          block[index].setValue(4);
        }
        break;//跳出while
      }
    }
  }
  
  public void judgeAppear() //统计block数组中是否含有值为0的元素,若没有,则numFlag变为false  judge 判断
  {
    int sum = 0;
    for (int i = 0; i < 16; i++) 
    {
      if (block[i].getValue() != 0)
      {
        sum++;
      }
    }
    if (sum == 16)
      numFlag = false;
  
  }
  
  public int Find(int i,int j,int a,int b)
  {// i 0 j4   a 0 b 16 
    while(i=a)
    {
       if(block[i].getValue()!=0)
       {
        return i;
       }
       i=i+j;
    }
    return -1;
  }
  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();
        if(valueI==valueJ&&valueI!=0&&valueJ!=0) // 合并数字
        {
          block[index].setValue(valueI+valueJ);
          block[j].setValue(0);
          numFlag = true;
          deFenShuJu+=10;
          SouthMianBan.getFenShu(deFenShuJu);
          SouthMianBan.deFen.setText("得分: "+deFenShuJu);
        }
        index=j;  //这一句很重要
//index  始终在j的上一行,两个始终相邻
      }
        
    }
  }
  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>i-16 ;j-=4)  //j>i-12
 {
 valueJ=0; valueI=0;
 if(block[index].getValue()==0)
       {
         t=Find(index,-4, 0 , 16);//i-12    
         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;
         deFenShuJu+=10;
         SouthMianBan.getFenShu(deFenShuJu);
         SouthMianBan.deFen.setText("得分: "+deFenShuJu);
       }
       index=j;
     }
 }
 }
  
  
  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--)
      {  
        
        if(block[index].getValue()==0)
        {
          t=Find(index,-1,i-3,index+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,j+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;
          deFenShuJu+=10;
          SouthMianBan.getFenShu(deFenShuJu);
          SouthMianBan.deFen.setText("得分: "+deFenShuJu);
        }
        index=j;
      }
        
    }
  }
  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  {
 if(block[index].getValue()==0)
       {
         t=Find(index,1,index-1,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,j-1,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;
         deFenShuJu+=10;
         SouthMianBan.getFenShu(deFenShuJu);
         SouthMianBan.deFen.setText("得分: "+deFenShuJu);
       }
       index=j;
     } 
 }
 }
  
  public void over() 
  {
    if (numFlag ==false&& up==false&&down==false&&left==false&&right==false) //当不能添加元素,并且不可移动的步数超过36就输了,输了的时候在盘中央显示GAMEOVER
    {
      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"); 
      block[11].addMouseListener(new MouseAdapter() {public void mousePressed(MouseEvent e){reStart();}});
//给标签block[11]添加鼠标监听,单击鼠标,重新启动程序
    }
  }
    
  public void win() //同OVER
  { 
    block[0].setText("Y");
    block[1].setText("O");
    block[2].setText("U");
    block[13].setText("W");
    block[14].setText("I");
    block[15].setText("N");
    block[15].addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        reStart();
      }
    });
  }
  public   void reStart()//重启游戏,和构造函数类似,不在累述
  {
    numFlag=true;
    moveFlag=0;
    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();
  }
  public void keyPressed(KeyEvent e) //判断按的上下左右键,并依次调用移动函数、判断函数、添加函数、判断是否输掉的函数
  {
 
 panel.setFocusable(true);  //设置面板处于激活状态,不然键盘监听用不了
 panel.requestFocus();
    switch (e.getKeyCode()) {
    case KeyEvent.VK_UP:
      if(up)
      {
     upBlock();
      }
      judgeAppear();
      appearBlock();
      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();
      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();
      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();
      over();
        
      if(numFlag==false)
      {
        right=false;
      }
      else
      {
        up=true;down=true;left=true;right=true;
      }
      break;
    }
  
  }
  public void keyTyped(KeyEvent e) {
  
  }
  public void keyReleased(KeyEvent e) {
  
  }


@Override
public void mouseClicked(MouseEvent e) {
// TODO 自动生成的方法存根

}


@Override
public void mousePressed(MouseEvent e) {
// TODO 自动生成的方法存根
panel.setFocusable(true);
panel.requestFocus();
}


@Override
public void mouseReleased(MouseEvent e) {
// TODO 自动生成的方法存根

}


@Override
public void mouseEntered(MouseEvent e) {
// TODO 自动生成的方法存根

}


@Override
public void mouseExited(MouseEvent e) {
// TODO 自动生成的方法存根

}
}

 

这段代码看着有点多,但不要怕,这段代码是最容易理解的。因为这一部分是大佬写的。

 

这段代码 结构非常明确,主要要说的是添加事件监听的那段代码。

也就是上下左右键的功能实现。

重新把它贴出来:(这里以上为例)

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();
        if(valueI==valueJ&&valueI!=0&&valueJ!=0) // 合并数字
        {
          block[index].setValue(valueI+valueJ);
          block[j].setValue(0);
          numFlag = true;
          deFenShuJu+=10;
          SouthMianBan.getFenShu(deFenShuJu);
          SouthMianBan.deFen.setText("得分: "+deFenShuJu);
        }
        index=j;  //这一句很重要
//index  始终在j的上一行,两个始终相邻
      }
        
    }
  }

代码中有两个for循环:外层for循环实现横向转移的功能,内层循环解决按列匹配的功能。也就是说,内层for循环先按列解决一列方块是否为零并且更换位置,而外层循环则是按每列 依次解决四 列的内层循环。

在内层循环 里,有 三个if语句,第一个是 index的匹配,找到index下是否有0的位置,返回,互换,第二个if语句是J从index下找有没有为0的位置互换,最后一个if是查找有没有值 相等的两个,如果 有,值相加,赋给位置居上的一个方块,另一个则 置值为0。

 

接下来贴上block的代码就是很有必要的了。

代码如下:

package bao2048;




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.ORANGE);//设定初始颜色为灰色
  }
  
  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.orange);
      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;
      }
  }
}

 

这里主要是给方块设置显示的值,并且不同的值设置不同的颜色。

 

 

接下来是音乐:Music.java

package bao2048;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;


import sun.audio.AudioPlayer;
import sun.audio.AudioStream;


public  class Music   implements  Runnable{
   static  AudioStream suoFeiYa ,chunYinYue;
public  Music()
{
try {
InputStream  in = new   FileInputStream("suoFeiYa.wav");
suoFeiYa= new  AudioStream(in);
AudioPlayer.player.start(suoFeiYa);
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}



public  Music(int  a)
{
try {
InputStream  in = new   FileInputStream("chunYinYue.wav");
chunYinYue = new  AudioStream(in);
AudioPlayer.player.start(chunYinYue);
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
@Override
public void run() {
new  Music();
}

}

这里是两个音乐,都用构造函数来创建,但以 参数的不同来区分。

 

音乐是放在线程里的,接下来 贴上线程的代码:

 

package bao2048;


public class MyThread extends  Thread{


public  MyThread()
{
super();
}
@SuppressWarnings("deprecation")
public void run()
{
Runnable r =new Music();

}
}

 

在线程里的run方法里跑音乐。

 

最后一个就是游戏界面的位于上部的效果了:

 

package bao2048;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.File;
import java.io.IOException;


import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


import sun.audio.AudioPlayer;
public class SouthMianBan   extends   JPanel     implements  ActionListener{
 Operation op =null;
Image  image = null;
static int def; //用来显示得分数据
static JButton deFen;
JButton  fanHuiJieMian;
JButton  yinYue;
JButton  chonXin;
Font f ,f2 ,f3;
Thread t;
JLabel  one;
JFrame  jiaoDian;
public  SouthMianBan(JFrame frame, Operation op)
{
   this.op=op;
jiaoDian= frame;
Runnable r0 = new Music(0);
t = new Thread(r0);
f =  new  Font("dialog" , Font.CENTER_BASELINE , 12);
this.setLayout(null);
this.setPreferredSize(new Dimension(0 ,170));
this.setVisible(true);



deFen = new JButton("得分: 0 ");
deFen.setSize(120, 40);
deFen.setLocation(350, 15);
deFen.setBackground(Color.magenta);
deFen.setFont(f);
this.add(deFen);



fanHuiJieMian= new JButton("返回主界面 ");
fanHuiJieMian.setSize(120, 40);
fanHuiJieMian.setLocation(200, 15);
fanHuiJieMian.setBackground(Color.green);
fanHuiJieMian.setFont(f);
fanHuiJieMian.addActionListener(this);
this.add(fanHuiJieMian);



chonXin = new JButton("重新游戏");
chonXin.setSize(120, 40);
chonXin.setLocation(350, 110);
chonXin.setBackground(Color.GREEN);
chonXin.setFont(f);
chonXin.addActionListener(this);
this.add(chonXin);




yinYue= new JButton("关闭音乐 ");
yinYue.setSize(120, 40);
yinYue.setLocation(350, 60);
yinYue.setBackground(Color.pink);
yinYue.setFont(f);
yinYue.addActionListener(this);
this.add(yinYue);
yinYue.addFocusListener(new  FocusAdapter()
{
public  void  focusLost(FocusEvent e)
{
Operation.panel.getComponent(0).setFocusable(true);
Operation.panel.getComponent(0).requestFocus();
}
});


}

public static  void getFenShu(int m)
{
def = m;
}


public  void  paint(Graphics  g)
{
try {
f2 =  new  Font("楷体" , Font.CENTER_BASELINE , 32);
f3 =  new  Font("楷体" , Font.CENTER_BASELINE , 18);
image = ImageIO.read(new  File("12.jpg"));
g.drawImage(image , 0 ,0 , 500 ,170 ,null);
g.setColor(Color.red);
g.setFont(f2);
g.drawString("经典2048", 20, 30);
g.setColor(Color.BLUE);
g.setFont(f3);
g.drawString("快来试试你的水平!一起争夺2048", 20, 150);

catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}



boolean  yinYuebool = true;  //决定是否 播放音乐
boolean  huiJieMian = true;  //决定是否 回到界面
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根

if(e.getSource() == fanHuiJieMian)
{
if(huiJieMian)
{
JieMian.jfJieMian.setVisible(true);
AudioPlayer.player.stop(Music.chunYinYue);
fanHuiJieMian.setText("回到游戏");
if(yinYue.getText().equals("关闭音乐")) {}  else  { yinYue.setText("关闭音乐");yinYuebool = true;}
AudioPlayer.player.start(Music.suoFeiYa);
huiJieMian = false;
}
else
{
JieMian.jfJieMian.setVisible(false);
fanHuiJieMian.setText("返回主界面 ");
AudioPlayer.player.start(Music.chunYinYue);
AudioPlayer.player.stop(Music.suoFeiYa);
huiJieMian = true;
}
}


if(e.getSource() ==  chonXin)
{
op.reStart();
deFen.setText("得分:"+0);
Operation.deFenShuJu=0;
}
if(e.getSource() ==  yinYue)
{

if( yinYuebool)
{
AudioPlayer.player.stop(Music.chunYinYue);
yinYue.setText("继续播放");
yinYuebool = false;
}
else
{
AudioPlayer.player.start(Music.chunYinYue);
yinYue.setText("关闭音乐");
yinYuebool = true;
}

jiaoDian.setFocusable(true);
jiaoDian.requestFocus();
}
}



}

这里要注意参数传递,在构造方法里传了一个Operation的对象,用来调用report()方法。

 

说到这里,整个2048就结束 了。

码字不易,留个赞吧

 

2048大家都玩过,说实话,我没完过,自己也不太感兴趣。如果不是这次学校有这样的一个项目落到我手上,可能我不太会去写这个游戏。现在整体写下来,代码风格并不整齐,也有一部分功能上的bug,但自己不怎么打算继续重构和维护下去,因为太耗时间,最近自己精力主要在算法上,而这一个项目确实耗费了我很多时间。由于这是一个团队项目,所以,我先要感谢我的团队,在他们的帮助下,我们成功做出来了。 虽然是团队项目,并有部分代码是已有的,但说原创并不为过。所以先在这里道个歉。
[2048 Dàjiā dōu wánguò, shuō shíhuà, wǒ méiwánguò, zìjǐ yě bù tài gǎn xìngqù. Rúguǒ bùshì zhè cì xuéxiào yǒu zhèyàng de yīgè xiàngmù luò dào wǒ shǒu shàng, kěnéng wǒ bù tài huì qù xiě zhège yóuxì. Xiànzài zhěngtǐ xiě xiàlái, dàimǎ fēnggé bìng bù zhěngqí, yěyǒu yībùfèn gōngnéng shàng de bug, dàn zìjǐ bù zě me dǎsuàn jìxù zhòng gòu hé wéihù xiàqù, yīnwèi tài hào shíjiān, zuìjìn zìjǐ jīnglì zhǔyào zài suànfǎ shàng, ér zhè yīgè xiàngmù quèshí hàofèile wǒ hěnduō shíjiān. Yóuyú zhè shì yīgè tuánduì xiàngmù, suǒyǐ, wǒ xiān yào gǎnxiè wǒ de tuánduì, zài tāmen de bāngzhù xià, wǒmen chénggōng zuò chūláile. Suīrán shì tuánduì xiàngmù, bìng yǒu bùfèn dàimǎ shì yǐ yǒu de, dàn shuō yuánchuàng bìng bù wéiguò. Suǒyǐ xiān zài zhèlǐ dào gè qiàn.]
Everyone has played in 2048. To be honest, I have never finished, and I am not very interested. If it wasn't for this school that had such a project falling into my hands, maybe I wouldn't write this game. Now the whole is written down, the code style is not neat, there are some functional bugs, but I don’t plan to continue to rebuild and maintain it. Because it is too time consuming, my energy is mainly on the algorithm recently, and this project really costs. I have a lot of time. Since this is a team project, I would like to thank my team first, and with their help, we have succeeded in making it.

Although it is a team project, and some of the code is already available, it is not too original. So first apologize here.
 

你可能感兴趣的:(2048小游戏)