您的位置:首页 > 其它

2048小游戏

2017-11-25 22:38 441 查看

                                                                       2048游戏

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

在这一篇博客里所实现的是2048的做法,具体代码和基本思路。
2048大家都玩过,说实话,我没完过,自己也不太感兴趣。如果不是这次学校有这样的一个项目落到我手上,可能我不太会去写这个游戏。现在整体写下来,代码风格并不整齐,也有一部分功能上的bug,但自己不怎么打算继续重构和维护下去,因为太耗时间,最近自己精力主要 在算法上,而这一个项目确实耗费了我很多时间。由于这是一个团队项目,所以,我先要感谢我的团队,在他们的帮助下,我们成功做出来了。
虽然是团队项目,并有部分代码是已有的,但说原创并不为过。所以先在这里道个歉。
我来具体讲讲这个游戏。
这款游戏里,一共有两个界面。
第一个是外部的主界面:



这个主界面中有四个按钮,功能明确。
下面是帮助按钮和关于按钮的效果图。





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



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



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

在项目New2048的bao2048里,有7个源文件。
此外,还有两个.jpg图片文件和两个.wav格式的音乐文件。有一个暂不用文件是音乐的备用文件。这两个图片文件是主界面 和游戏界面的背景图。两个音乐 文件是在游戏中添加的音乐。souFeiYa是一开始游戏的音
4000
乐,而chunYinYue是游戏界面的音乐。
以下是两幅基本背景图。





看到这两个原图片,大家是不是知道了它们的位置了。哈哈哈哈。
不同的是 , 第二幅是用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();//
126ed
构造出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<b&&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<i+4 ; 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就结束 了。
码字不易,留个赞吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: