【Java】推箱子小游戏(带背景音乐)完整代码

简介: 【Java】推箱子小游戏(带背景音乐)完整代码

Java实现推箱子小游戏

一、整体框架

二、游戏效果图

三、推箱子四大类

1. GameFrame类

2. Map类

3. MapFactory类

4. Sound类

四、游戏分析

1.游戏操作

2.数组解读

五、单独窗体播放音乐(wav格式)

1.GameFrame类

2. Sound类



文章比较长,请耐心看完。


一、整体框架


该程序由四个类组成,GameFrame类(程序主体)、Map类(地图基础设置)、MapFactory类(地图构图)、Sound类(添加音乐),下面是程序结构图。

注意音乐格式要转MIDI序列(直接改文件后缀名不可行,如果想更换背景音乐,建议下载widi进行格式转换)


二、游戏效果图


游戏画面没有设置的很炫酷,因为绿色比较护眼。

正在看这篇博客的你,让眼睛休息一下吧!

图片音乐素材及游戏源码链接:

https://pan.baidu.com/wap/init?surl=PvUnMYBukB7A_2K-uNhzxw

提取码:5k71

言归正传,我们来看游戏代码

代码直接复制粘贴就能运行(素材包放在项目src目录下)


三、推箱子四大类


1. GameFrame类


package 推箱子;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class GameFrame extends JFrame implements ActionListener ,MouseListener,KeyListener{
  /**
   * 序列化ID,相当于身份认证,
   * 主要用于程序的版本控制,保持不同版本的兼容性,
   * 在程序版本升级时避免程序报出版本不一致的错误。
   */
  private static final long serialVersionUID = 1L;  
  private int grade = 0;//定义关卡数
  private int row = 7,column = 7,leftX = 0,leftY = 0;
  //row,column表示人物坐标;leftX,leftY记载左上角图片位置
  private int mapRow = 0,mapColumn = 0;//地图的行列数
  private int width = 0,height = 0;//屏幕大小
  private boolean acceptKey = true;
  private Image pic[] = null;//图片数组
  private byte[][] map = null;//地图数组
  private ArrayList list = new ArrayList();//用于撤回操作
  Sound sound;
  final byte WALL = 1,BOX = 2,BOXONEND = 3,END = 4,MANDOWN = 5,
      MANLEFT = 6,MANRIGHT = 7,MANUP = 8,GRASS = 9,MANDOWNONEND = 10,
      MANLEFTONEND = 11,MANRIGHTONEND = 12,MANUPONEND = 13;
  /**
   * 构造方法
   */
  public GameFrame(){
    super("推箱子游戏带音乐版");
    //1.窗体设置
    setSize(600,600);//窗体大小
    setVisible(true);//窗体可见
    setResizable(false);//窗体大小不可被用户改变
    setLocation(680,200);//窗体位置
    setBackground(Color.green);//窗体背景颜色
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体结束程序
    //2.cont容器设置
    Container cont = getContentPane();
    /**
     * 因为JFrame是一个框架,所以JFrame不能通过add方法直接添加组件,
     * 创建一个content pane容器,方便向框架内添加组件
     */
    cont.setLayout(null);//清空默认的流式布局管理器
    cont.setBackground(Color.green);//容器背景颜色
    getPic();//获取图片
    width = this.getWidth();
    height = this.getHeight();
    this.setFocusable(true);//设置组件可以被选中
    initMap();
    this.addKeyListener(this);
    this.addMouseListener(this);
    //播放音乐
    Sound sound = new Sound();
    sound.loadSound();//加载音乐
  }
  //初始化地图
  public void initMap(){
    map = getMap(grade);//获取每个地图的关卡数
    list.clear();//清除列表
    byte[][] temp = map;
    //创建地图
    for(int i=0;i<temp.length;i++)
    {
      for(int j=0;j<temp[0].length;j++){
        System.out.print(temp[i][j]+" ");   
        }
      System.out.println();
    } 
    getMapSizeAndPosition();
    getManPosition();
  }
  //获取人物当前位置
  public void getManPosition(){
    for(int i=0;i<map.length;i++){
      for(int j=0;j<map[0].length;j++){
        if(map[i][j]==MANDOWN||map[i][j]==MANUP||map[i][j]==MANLEFT||map[i][j]==MANRIGHT){
          row = i;
          column = j;
          break;
        }     
      }
    }
  }
  //获取游戏区域大小及显示游戏的左上角位置
  public void getMapSizeAndPosition(){
    mapRow = map.length;
    mapColumn = map[0].length;
    leftX = (width - map[0].length * 30)/2;
    leftY = (height - map.length * 30)/2;
    System.out.println(leftX);
    System.out.println(leftY);
    System.out.println(mapRow);
    System.out.println(mapColumn);
  }
  //获取图片
  public void getPic(){
    pic = new Image[14];
    for(int i=0;i<=13;i++){
      pic[i] = Toolkit.getDefaultToolkit().getImage
          ("E:\\kkkkk\\\\推箱子\\\\src\\\\img/pic"+i+".png");
    }
  }
  //人走过变草地
  public byte grassOrEnd(byte man){
    byte result = GRASS;
    if(man == MANLEFTONEND || man == MANRIGHTONEND || man == MANUPONEND || man == MANDOWNONEND){
      result = END;
    }
    return result;
  }
  private void moveUp(){
    if(map[row-1][column]==WALL)
      return;
    byte tempBox;
    byte tempMan;
    if(map[row-1][column]==BOX||map[row-1][column]==BOXONEND){    //如果向上一格是箱子
      if(map[row-2][column]==GRASS||map[row-2][column]==END){     //如果向上第二格是过道或者终点
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row-2][column]==END?BOXONEND:BOX;
        tempMan = map[row-1][column]==BOXONEND?MANUPONEND:MANUP;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row-2][column] = tempBox;
        map[row-1][column] = tempMan;
        row--;
      }
    }else{//如果向上一格是过道或者终点
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row-1][column]==GRASS?MANUP:MANUPONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row-1][column] = tempMan;
      row--;
    }   
  }
  private void moveDown(){
    if(map[row+1][column]==WALL)
      return ;
    byte tempBox;
    byte tempMan;
    if(map[row+1][column]==BOX||map[row+1][column]==BOXONEND){
      if(map[row+2][column]==END||map[row+2][column]==GRASS){
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row+2][column] == END?BOXONEND:BOX;
        tempMan = map[row+1][column] == BOXONEND?MANDOWNONEND:MANDOWN;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row+2][column] = tempBox;
        map[row+1][column] = tempMan;
        row++;
      }
    }else{
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row+1][column]==GRASS?MANDOWN:MANDOWNONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row+1][column] = tempMan;
      row++;
    }   
  }
  private void moveLeft(){
    if(map[row][column-1]==WALL)
      return ;
    byte tempBox;
    byte tempMan;
    if(map[row][column-1]==BOX||map[row][column-1]==BOXONEND){
      if(map[row][column-2]==END||map[row][column-2]==GRASS){
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row][column-2] == END?BOXONEND:BOX;
        tempMan = map[row][column-1] == BOXONEND?MANLEFTONEND:MANLEFT;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row][column-2] = tempBox;
        map[row][column-1] = tempMan;
        column--;
      }
    }else{
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row][column-1]==GRASS?MANLEFT:MANLEFTONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row][column-1] = tempMan;
      column--;
    }
  }
  private void moveRight(){
    if(map[row][column+1]==WALL)
      return ;
    byte tempBox;
    byte tempMan;
    if(map[row][column+1]==BOX||map[row][column+1]==BOXONEND){
      if(map[row][column+2]==END||map[row][column+2]==GRASS){
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row][column+2] == END?BOXONEND:BOX;
        tempMan = map[row][column+1] == BOXONEND?MANRIGHTONEND:MANRIGHT;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row][column+2] = tempBox;
        map[row][column+1] = tempMan;
        column++;
      }
    }else{
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row][column+1]==GRASS?MANRIGHT:MANRIGHTONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row][column+1] = tempMan;
      column++;
    }   
  }
  //判断游戏是否结束
  public boolean isFinished(){
    for(int i=0;i<mapRow;i++) {
      for(int j=0;j<mapColumn;j++){
  //    System.out.println("值是"+map[i][j]+",END 的值是"+END+",他们相等吗?:"+(map[i][j]==END));
        if(map[i][j]==END||map[i][j]==MANDOWNONEND||map[i][j]==MANUPONEND||map[i][j]==MANLEFTONEND||map[i][j]==MANRIGHTONEND){
          return false;
        }
      }
    }
    return true;
  }
  @Override
  public void keyTyped(KeyEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_UP){
      moveUp();
    }
    if(e.getKeyCode() == KeyEvent.VK_DOWN){
      moveDown();
    }
    if(e.getKeyCode() == KeyEvent.VK_LEFT){
      moveLeft();
    }
    if(e.getKeyCode() == KeyEvent.VK_RIGHT){
      moveRight();
    }
    if(e.getKeyCode() == KeyEvent.VK_A){//上一关
      acceptKey = true;
      priorGrade();
      return ;
    }
    if(e.getKeyCode() == KeyEvent.VK_D){//下一关
      acceptKey = true;
      nextGrade();
      return ;
    }
    if(e.getKeyCode() == KeyEvent.VK_B){//撤回
      undo();
    }
    repaint();
    if(isFinished()){
      //禁用按键
      acceptKey = false;
      if(grade==10){JOptionPane.showMessageDialog(this, "恭喜通过最后一关");}
      else{
        String msg = "恭喜你通过第"+(grade+1)+"关!!!\n是否要进入下一关?";
        int type = JOptionPane.YES_NO_OPTION;
        String title = "过关";
        int choice = 0;
        choice = JOptionPane.showConfirmDialog(null, msg,title,type);
        if(choice==1){
          System.exit(0);
        }else if(choice == 0){
          acceptKey = true;
          nextGrade();
        }
      }
    }
  }
  //画图
  public void paint(Graphics g){
    //System.out.println("我被调用了");
    for(int i=0;i<mapRow;i++) {
      for(int j=0;j<mapColumn;j++){
        if(map[i][j]!=0){
//          System.out.println("这个位置 不是0,它的值是"+map[i][j]);
//          g.drawRect(10, 30, getWidth()/2-50, getHeight()/2-50);
          g.drawImage(pic[map[i][j]],leftX+j*30,leftY+i*30,30,30,this);
      }
    }
  }
    g.setColor(Color.black);
    g.setFont(new Font("楷体_2312",Font.BOLD,30));
    g.drawString("现在是第", 150, 140);
    g.drawString(String.valueOf(grade+1),310,140);
    g.drawString("关", 360, 140);
  }
  public int getManX(){
    return row;
  }
  public int getManY(){
    return column;
  }
  public int getGrade(){
    return grade;
  }
  public byte[][] getMap(int grade){    
    return MapFactory.getMap(grade);
  }
  public void DisplayToast(String str){
    JOptionPane.showMessageDialog(null, str,"提示",JOptionPane.ERROR_MESSAGE);
  }
  //过关后不可撤销
  public void undo(){
    if(acceptKey){
      if(list.size()>0){
        Map priorMap = (Map)list.get(list.size()-1);
        map = priorMap.getMap();
        row = priorMap.getManX();
        column = priorMap.getManY();
        repaint();
        list.remove(list.size()-1);
      }else{
        DisplayToast("不能再撤销");
      }
    }else{
      DisplayToast("此关已完成,不能撤销");
    }
  }
  public void priorGrade(){
    grade--;
    acceptKey = true;
    if(grade<0)
      grade = 0;
    initMap();
    clearPaint(this.getGraphics());
    repaint();
  }
  public void nextGrade(){
    if(grade>=MapFactory.getCount()-1){
      DisplayToast("恭喜你完成所有关卡");
      acceptKey = false;
    }else{
      grade++;
      initMap();
      clearPaint(this.getGraphics());
      repaint();
      acceptKey = true;
    }
  }
  private void clearPaint(Graphics g) {
   g.clearRect(0, 0, width+leftX, height+leftY);
  }
  @Override
  public void keyReleased(KeyEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseClicked(MouseEvent e) {
    // TODO Auto-generated method stub
    if(e.getButton() == MouseEvent.BUTTON3)
    {
      undo();
    }
  }
  @Override
  public void mousePressed(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
  }
  public static void main(String[] args){
    GameFrame a = new GameFrame();
  } 
}

2. Map类


package 推箱子;
public class Map {
  int manX = 0;
  int manY = 0;
  byte map[][];
  int grade;
  public Map(int manX,int manY,byte[][] map){
    this.manX = manX;
    this.manY = manY;
    int row = map.length;
    int column = map[0].length;
    byte temp[][] = new byte[row][column];
    for(int i=0;i<row;i++){
      for(int j=0;j<column;j++){
        temp[i][j] = map[i][j];
      }
    }
    this.map = temp;//避免直接引用
  }
  public Map(int manX,int manY,byte[][] map,int grade){
    this(manX,manY,map);
    this.grade = grade;
  }
  //人物X坐标
  public int getManX(){
    return manX;
  }
  //人物Y坐标
  public int getManY(){
    return manY;
  }
  //地图数组
  public byte[][] getMap(){
    return map;
  }
  //关卡
  public int getGrade(){
    return grade;
  } 
}

3. MapFactory类


package 推箱子;
public class MapFactory {//地图数据类
  static byte map[][][] = {
    {
      {0,0,1,1,1,0,0,0},
      {0,0,1,4,1,0,0,0},
      {0,0,1,9,1,1,1,1},
      {1,1,1,2,9,2,4,1},
      {1,4,9,2,5,1,1,1},
      {1,1,1,1,2,1,0,0},
      {0,0,0,1,4,1,0,0},
      {0,0,0,1,1,1,0,0}
    },
    {
      {1,1,1,1,1,0,0,0,0},
      {1,9,9,5,1,0,0,0,0},
      {1,9,2,2,1,0,1,1,1},
      {1,9,2,9,1,0,1,4,1},
      {1,1,1,9,1,1,1,4,1},
      {0,1,1,9,9,9,9,4,1},
      {0,1,9,9,9,1,9,9,1},
      {0,1,9,9,9,1,1,1,1},
      {0,1,1,1,1,1,0,0,0}
    },
    {
      {1,1,1,1,1,0,0,0,0},
      {1,9,9,9,1,1,0,0,0},
      {1,9,2,9,9,1,0,0,0},
      {1,1,9,2,9,1,1,1,1},
      {0,1,1,1,5,4,9,9,1},
      {0,0,1,9,9,4,1,9,1},
      {0,0,1,9,9,9,9,9,1},
      {0,0,1,1,1,1,1,1,1}     
    },
    {
      {0,0,1,1,1,1},
      {0,1,1,9,9,1},
      {1,1,9,2,9,1},
      {1,4,2,9,5,1},
      {1,2,4,9,1,1},
      {1,4,9,1,1,0},
      {1,1,1,1,0,0}
    },
    {
      {1,1,1,1,1,1},
      {1,9,5,9,9,1},
      {1,9,2,9,9,1},
      {1,2,9,1,1,1},
      {1,4,9,4,1,0},
      {1,1,1,1,1,0}
    },
    {
      {0,0,0,1,1,1,1,0,0},
      {0,0,1,1,9,9,1,1,0},
      {1,1,1,9,5,2,4,1,1},
      {1,9,9,9,9,2,4,9,1},
      {1,9,9,9,1,2,4,9,1},
      {1,1,1,1,1,9,1,9,1},
      {0,0,0,0,1,9,9,9,1},
      {0,0,0,0,1,1,1,1,1}
    },
    {
      {0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},//19行
      {0,0,0,0,1,9,9,9,1,0,0,0,0,0,0,0,0,0,0},
      {0,0,0,0,1,2,9,9,1,0,0,0,0,0,0,0,0,0,0},
      {0,0,1,1,1,9,9,2,1,1,0,0,0,0,0,0,0,0,0},
      {0,0,1,9,9,2,9,2,9,1,0,0,0,0,0,0,0,0,0},
      {1,1,1,9,1,9,1,1,9,1,0,0,0,1,1,1,1,1,1},
      {1,9,9,9,1,9,1,1,9,1,1,1,1,1,9,9,4,4,1},
      {1,9,2,9,9,2,9,9,9,9,9,9,9,9,9,9,4,4,1},
      {1,1,1,1,1,9,1,1,1,9,1,5,1,1,9,9,4,4,1},
      {0,0,0,0,1,9,9,9,9,9,1,1,1,1,1,1,1,1,1},
      {0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0}
    },
    {
      {1,1,1,1,1,1,1,1,1,1,1,1,0,0},//14行
      {1,4,4,9,9,1,9,9,9,9,9,1,1,1},
      {1,4,4,9,9,1,9,2,9,9,2,9,9,1},
      {1,4,4,9,9,1,2,1,1,1,1,9,9,1},
      {1,4,4,9,9,9,9,5,9,1,1,9,9,1},
      {1,4,4,9,9,1,9,1,9,9,2,9,1,1},
      {1,1,1,1,1,1,9,1,1,2,9,2,9,1},
      {0,0,1,9,2,9,9,2,9,2,9,2,9,1},
      {0,0,1,9,9,9,9,1,9,9,9,9,9,1},
      {0,0,1,1,1,1,1,1,1,1,1,1,1,1}
    },
    {
      {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0},//17行
      {0,0,0,0,0,0,0,0,1,9,9,9,9,9,5,1,0},
      {0,0,0,0,0,0,0,0,1,9,2,1,2,9,1,1,0},
      {0,0,0,0,0,0,0,0,1,9,2,9,9,2,1,0,0},
      {0,0,0,0,0,0,0,0,1,1,2,9,2,9,1,0,0},
      {1,1,1,1,1,1,1,1,1,9,2,9,1,9,1,1,1},
      {1,4,4,4,4,9,9,1,1,9,2,9,9,2,9,9,1},
      {1,1,4,4,4,9,9,9,9,2,9,9,2,9,9,9,1},
      {1,4,4,4,4,9,9,1,1,1,1,1,1,1,1,1,1},
      {1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0} 
    },
    {
      {0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0},//19行
      {0,0,0,0,0,1,1,1,1,0,1,9,9,1,0,0,0,0,0},
      {0,0,0,1,1,1,9,5,1,1,1,2,9,1,0,0,0,0,0},
      {0,0,1,1,9,9,9,9,9,9,2,9,9,1,0,0,0,0,0},
      {0,1,1,9,9,2,9,2,2,1,1,9,1,1,0,0,0,0,0},
      {0,1,9,9,1,2,1,1,9,9,9,9,9,1,0,0,0,0,0},
      {0,1,9,1,9,2,9,2,2,9,1,9,1,1,1,0,0,0,0},
      {0,1,9,9,9,2,9,1,9,9,1,9,2,9,1,1,1,1,1},
      {1,1,1,1,9,9,9,9,1,9,9,2,2,9,1,9,9,9,1},
      {1,1,1,1,9,1,1,9,2,9,9,9,9,9,9,9,9,9,1},
      {1,4,9,9,9,9,1,1,1,9,9,1,1,1,1,1,1,1,1},
      {1,4,4,9,4,4,1,0,1,1,1,1,0,0,0,0,0,0,0},
      {1,4,4,4,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0},
      {1,4,4,4,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0},
      {1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}
    }
  };
  static int count = map.length;
  public static byte[][] getMap(int grade){
    byte[][] temp;
    if(grade>=0&&grade<count) {
      temp = map[grade];
    }else {
      temp = map[0];
    }
    int row = temp.length;
    int column = temp[0].length;
    byte[][] result = new byte[row][column];//备份关卡版本
    for(int i=0;i<row;i++){
      for(int j=0;j<column;j++){
        result[i][j] = temp[i][j];
      }
    }   
    return result;
  }
  public static int getCount(){
    return count;
  }
}

4. Sound类


package 推箱子;
import javax.sound.midi.*;
import java.io.File;
import java.io.IOException;
public class Sound {
  String path = new String("E:/kkkkk/推箱子/src/img/");
  String file = new String("nor.mid");
  Sequence seq;
  Sequencer midi;
  boolean sign;
  //加载音乐
  public void loadSound(){
    try {
      seq = MidiSystem.getSequence(new File(path+file));
      midi = MidiSystem.getSequencer();
      midi.open();
      midi.setSequence(seq);
      midi.start();
      midi.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
    } catch (InvalidMidiDataException | IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (MidiUnavailableException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }   
    sign = true;
  } 
  void mystop(){
    midi.stop();
    midi.close();
    sign=false;
  }
  boolean isplay(){
    return sign;
  }
  void setMusic(String e){
    file=e;
  }
}

四、游戏分析


1.游戏操作


键盘上下左右键控制人物的移动,按A回到上一关,按D直接进入下一关。


2.数组解读


很多人对这个庞大的数组很好奇,其实呢,它们非常简单,下面我来解读一下。

0(墙外的空余区域);1(墙);2(箱子);3(箱子位于目标点上);

4(目标点);5(人物向下);9(空地);

五、单独窗体播放音乐(wav格式)


由于mid格式比较少见,一般的软件无法实现该格式的转换,所以我们使用javax.sound实现简单的音频播放(只支持AU,RA,WAV格式),相比而言比较大众化。可以自己挑选喜欢的音乐作为背景音乐。

更新后代码如下(只修改GameFrame类和Sound类)


1.GameFrame类


package 推箱子;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class GameFrame extends JFrame implements ActionListener ,MouseListener,KeyListener{
  private static final long serialVersionUID = 1L;  
  private int grade = 0;//定义关卡数
  private int row = 7,column = 7,leftX = 0,leftY = 0;
  //row,column表示人物坐标;leftX,leftY记载左上角图片位置
  private int mapRow = 0,mapColumn = 0;//地图的行列数
  private int width = 0,height = 0;//屏幕大小
  private boolean acceptKey = true;
  private Image pic[] = null;//图片数组
  private byte[][] map = null;//地图数组
  private ArrayList list = new ArrayList();//用于撤回操作
  Sound sound;
  final byte WALL = 1,BOX = 2,BOXONEND = 3,END = 4,MANDOWN = 5,
      MANLEFT = 6,MANRIGHT = 7,MANUP = 8,GRASS = 9,MANDOWNONEND = 10,
      MANLEFTONEND = 11,MANRIGHTONEND = 12,MANUPONEND = 13;
  /**
   * 构造方法
   */
  public GameFrame(){
    super("推箱子游戏带音乐版");
    //1.窗体设置
    setSize(600,600);//窗体大小
    setVisible(true);//窗体可见
    setResizable(false);//窗体大小不可被用户改变
    setLocation(680,200);//窗体位置
    setBackground(Color.green);//窗体背景颜色
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体结束程序
    //2.cont容器设置
    Container cont = getContentPane();
    /**
     * 因为JFrame是一个框架,所以JFrame不能通过add方法直接添加组件,
     * 创建一个content pane容器,方便向框架内添加组件
     */
    cont.setLayout(null);//清空默认的流式布局管理器
    cont.setBackground(Color.green);//容器背景颜色
    getPic();//获取图片
    width = this.getWidth();
    height = this.getHeight();
    this.setFocusable(true);//设置组件可以被选中
    initMap();
    this.addKeyListener(this);
    this.addMouseListener(this);
  }
  //初始化地图
  public void initMap(){
    map = getMap(grade);//获取每个地图的关卡数
    list.clear();//清除列表
    byte[][] temp = map;
    //创建地图
    for(int i=0;i<temp.length;i++)
    {
      for(int j=0;j<temp[0].length;j++){
        System.out.print(temp[i][j]+" ");   
        }
      System.out.println();
    }     
    getMapSizeAndPosition();
    getManPosition();
  }
  //获取人物当前位置
  public void getManPosition(){
    for(int i=0;i<map.length;i++){
      for(int j=0;j<map[0].length;j++){
        if(map[i][j]==MANDOWN||map[i][j]==MANUP||map[i][j]==MANLEFT||map[i][j]==MANRIGHT){
          row = i;
          column = j;
          break;
        }     
      }
    }
  }
  //获取游戏区域大小及显示游戏的左上角位置
  public void getMapSizeAndPosition(){
    mapRow = map.length;
    mapColumn = map[0].length;
    leftX = (width - map[0].length * 30)/2;
    leftY = (height - map.length * 30)/2;
    System.out.println(leftX);
    System.out.println(leftY);
    System.out.println(mapRow);
    System.out.println(mapColumn);
  }
  //获取图片
  public void getPic(){
    pic = new Image[14];
    for(int i=0;i<=13;i++){
      pic[i] = Toolkit.getDefaultToolkit().getImage
          ("E:\\kkkkk\\\\推箱子\\\\src\\\\img/pic"+i+".png");
    }
  }
  //人走过变草地
  public byte grassOrEnd(byte man){
    byte result = GRASS;
    if(man == MANLEFTONEND || man == MANRIGHTONEND || man == MANUPONEND || man == MANDOWNONEND){
      result = END;
    }
    return result;
  }
  private void moveUp(){
    if(map[row-1][column]==WALL)
      return;
    byte tempBox;
    byte tempMan;
    if(map[row-1][column]==BOX||map[row-1][column]==BOXONEND){    //如果向上一格是箱子
      if(map[row-2][column]==GRASS||map[row-2][column]==END){     //如果向上第二格是过道或者终点
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row-2][column]==END?BOXONEND:BOX;
        tempMan = map[row-1][column]==BOXONEND?MANUPONEND:MANUP;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row-2][column] = tempBox;
        map[row-1][column] = tempMan;
        row--;
      }
    }else{//如果向上一格是过道或者终点
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row-1][column]==GRASS?MANUP:MANUPONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row-1][column] = tempMan;
      row--;
    } 
  }
  private void moveDown(){
    if(map[row+1][column]==WALL)
      return ;
    byte tempBox;
    byte tempMan;
    if(map[row+1][column]==BOX||map[row+1][column]==BOXONEND){
      if(map[row+2][column]==END||map[row+2][column]==GRASS){
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row+2][column] == END?BOXONEND:BOX;
        tempMan = map[row+1][column] == BOXONEND?MANDOWNONEND:MANDOWN;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row+2][column] = tempBox;
        map[row+1][column] = tempMan;
        row++;
      }
    }else{
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row+1][column]==GRASS?MANDOWN:MANDOWNONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row+1][column] = tempMan;
      row++;
    }   
  }
  private void moveLeft(){
    if(map[row][column-1]==WALL)
      return ;
    byte tempBox;
    byte tempMan;
    if(map[row][column-1]==BOX||map[row][column-1]==BOXONEND){
      if(map[row][column-2]==END||map[row][column-2]==GRASS){
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row][column-2] == END?BOXONEND:BOX;
        tempMan = map[row][column-1] == BOXONEND?MANLEFTONEND:MANLEFT;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row][column-2] = tempBox;
        map[row][column-1] = tempMan;
        column--;
      }
    }else{
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row][column-1]==GRASS?MANLEFT:MANLEFTONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row][column-1] = tempMan;
      column--;
    }   
  }
  private void moveRight(){
    if(map[row][column+1]==WALL)
      return ;
    byte tempBox;
    byte tempMan;
    if(map[row][column+1]==BOX||map[row][column+1]==BOXONEND){
      if(map[row][column+2]==END||map[row][column+2]==GRASS){
        Map currentMap = new Map(row,column,map);
        list.add(currentMap);//用于撤回操作
        tempBox = map[row][column+2] == END?BOXONEND:BOX;
        tempMan = map[row][column+1] == BOXONEND?MANRIGHTONEND:MANRIGHT;
        map[row][column] = grassOrEnd(map[row][column]);
        map[row][column+2] = tempBox;
        map[row][column+1] = tempMan;
        column++;
      }
    }else{
      Map currentMap = new Map(row,column,map);
      list.add(currentMap);//用于撤回操作
      tempMan = map[row][column+1]==GRASS?MANRIGHT:MANRIGHTONEND;
      map[row][column] = grassOrEnd(map[row][column]);
      map[row][column+1] = tempMan;
      column++;
    }   
  }
  //判断游戏是否结束
  public boolean isFinished(){
    for(int i=0;i<mapRow;i++) {
      for(int j=0;j<mapColumn;j++){
  //    System.out.println("值是"+map[i][j]+",END 的值是"+END+",他们相等吗?:"+(map[i][j]==END));
        if(map[i][j]==END||map[i][j]==MANDOWNONEND||map[i][j]==MANUPONEND||map[i][j]==MANLEFTONEND||map[i][j]==MANRIGHTONEND){
          return false;
        }
      }
    }
    return true;
  } 
  @Override
  public void keyTyped(KeyEvent e) {
    // TODO Auto-generated method stub    
  }
  @Override
  public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_UP){
      moveUp();
    }
    if(e.getKeyCode() == KeyEvent.VK_DOWN){
      moveDown();
    }
    if(e.getKeyCode() == KeyEvent.VK_LEFT){
      moveLeft();
    }
    if(e.getKeyCode() == KeyEvent.VK_RIGHT){
      moveRight();
    }
    if(e.getKeyCode() == KeyEvent.VK_A){//上一关
      acceptKey = true;
      priorGrade();
      return ;
    }
    if(e.getKeyCode() == KeyEvent.VK_D){//下一关
      acceptKey = true;
      nextGrade();
      return ;
    }
    if(e.getKeyCode() == KeyEvent.VK_B){//撤回
      undo();
    }
    repaint();
    if(isFinished()){
      //禁用按键
      acceptKey = false;
      if(grade==10){JOptionPane.showMessageDialog(this, "恭喜通过最后一关");}
      else{
        String msg = "恭喜你通过第"+(grade+1)+"关!!!\n是否要进入下一关?";
        int type = JOptionPane.YES_NO_OPTION;
        String title = "过关";
        int choice = 0;
        choice = JOptionPane.showConfirmDialog(null, msg,title,type);
        if(choice==1){
          System.exit(0);
        }else if(choice == 0){
          acceptKey = true;
          nextGrade();
        }
      }
    }
  }
  //画图
  public void paint(Graphics g){
    //System.out.println("我被调用了");
    for(int i=0;i<mapRow;i++) {
      for(int j=0;j<mapColumn;j++){
        if(map[i][j]!=0){
//          System.out.println("这个位置 不是0,它的值是"+map[i][j]);
//          g.drawRect(10, 30, getWidth()/2-50, getHeight()/2-50);
          g.drawImage(pic[map[i][j]],leftX+j*30,leftY+i*30,30,30,this);
      }
    }
  }
    g.setColor(Color.black);
    g.setFont(new Font("楷体_2312",Font.BOLD,30));
    g.drawString("现在是第", 150, 140);
    g.drawString(String.valueOf(grade+1),310,140);
    g.drawString("关", 360, 140);
  }
  public int getManX(){
    return row;
  }
  public int getManY(){
    return column;
  }
  public int getGrade(){
    return grade;
  }
  public byte[][] getMap(int grade){    
    return MapFactory.getMap(grade);
  }
  public void DisplayToast(String str){
    JOptionPane.showMessageDialog(null, str,"提示",JOptionPane.ERROR_MESSAGE);
  }
  //过关后不可撤销
  public void undo(){
    if(acceptKey){
      if(list.size()>0){
        Map priorMap = (Map)list.get(list.size()-1);
        map = priorMap.getMap();
        row = priorMap.getManX();
        column = priorMap.getManY();
        repaint();
        list.remove(list.size()-1);
      }else{
        DisplayToast("不能再撤销");
      }
    }else{
      DisplayToast("此关已完成,不能撤销");
    }
  }
  public void priorGrade(){
    grade--;
    acceptKey = true;
    if(grade<0)
      grade = 0;
    initMap();
    clearPaint(this.getGraphics());
    repaint();
  }
  public void nextGrade(){
    if(grade>=MapFactory.getCount()-1){
      DisplayToast("恭喜你完成所有关卡");
      acceptKey = false;
    }else{
      grade++;
      initMap();
      clearPaint(this.getGraphics());
      repaint();
      acceptKey = true;
    }
  }
  private void clearPaint(Graphics g) {
   g.clearRect(0, 0, width+leftX, height+leftY);
  }
  @Override
  public void keyReleased(KeyEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseClicked(MouseEvent e) {
    // TODO Auto-generated method stub
    if(e.getButton() == MouseEvent.BUTTON3)
    {
      undo();
    }
  }
  @Override
  public void mousePressed(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub
  }
  @Override
  public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
  }
  //主方法
  public static void main(String[] args) throws InterruptedException{
    GameFrame a = new GameFrame();
    Sound player = new Sound("E:/kkkkk/推箱子/src/img/XiongDi.wav");   //创建音乐播放器
        player.start(true);//以开始以循环的形式播放,player(false)为不循环播放
        TimeUnit.SECONDS.sleep(5);
        player.stop();                        //暂停播放音频
        TimeUnit.SECONDS.sleep(4);
        player.continues();                //继续开始播放音频
  } 
}

2. Sound类


package 推箱子;
/**
*
* Description: 简易音频播放器(只支持AU,RA,WAV)
*          在不使用JMF的情况下快速实现音频播放
* 
*/
import javax.sound.sampled.*;
import java.io.*;
import java.util.concurrent.TimeUnit;
public class Sound {
  private String musicPath; //音频文件
  private volatile boolean run = true;  //记录音频是否播放
  private Thread mainThread;   //播放音频的任务线程  
  private AudioInputStream audioStream;
  private AudioFormat audioFormat;
  private SourceDataLine sourceDataLine;
  public Sound(String musicPath) {
    this.musicPath = musicPath;
    prefetch();
  }
  //数据准备
  private void prefetch(){
    try{
    //获取音频输入流
      audioStream = AudioSystem.getAudioInputStream(new File(musicPath));
    //获取音频的编码对象
    audioFormat = audioStream.getFormat();
    //包装音频信息
    DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class,
        audioFormat,AudioSystem.NOT_SPECIFIED);
    //使用包装音频信息后的Info类创建源数据行,充当混频器的源
    sourceDataLine = (SourceDataLine)AudioSystem.getLine(dataLineInfo);   
    sourceDataLine.open(audioFormat);
    sourceDataLine.start();   
    }catch(UnsupportedAudioFileException ex){
      ex.printStackTrace();
    }catch(LineUnavailableException ex){
      ex.printStackTrace();
    }catch(IOException ex){
      ex.printStackTrace();
    }   
  }
  //析构函数:关闭音频读取流和数据行
  protected void finalize() throws Throwable{
    super.finalize();
    sourceDataLine.drain();
    sourceDataLine.close();
    audioStream.close();
  }
  //播放音频:通过loop参数设置是否循环播放
  private void playMusic(boolean loop)throws InterruptedException {
    try{
        if(loop){
          while(true){
            playMusic();
          }
        }else{
          playMusic();
          //清空数据行并关闭
          sourceDataLine.drain();
          sourceDataLine.close();
          audioStream.close();
        }     
    }catch(IOException ex){
      ex.printStackTrace();
    }       
  }
  private void playMusic(){
    try{
      synchronized(this){
        run = true;
      }
      //通过数据行读取音频数据流,发送到混音器;
      //数据流传输过程:AudioInputStream -> SourceDataLine;
      audioStream = AudioSystem.getAudioInputStream(new File(musicPath));
      int count;
      byte tempBuff[] = new byte[1024];     
        while((count = audioStream.read(tempBuff,0,tempBuff.length)) != -1){
          synchronized(this){
          while(!run)
            wait();
          }
          sourceDataLine.write(tempBuff,0,count);             
      } 
    }catch(UnsupportedAudioFileException ex){
      ex.printStackTrace();
    }catch(IOException ex){
      ex.printStackTrace();
    }catch(InterruptedException ex){
      ex.printStackTrace();
    }   
  } 
  //暂停播放音频
  private void stopMusic(){
    synchronized(this){
      run = false;
      notifyAll();
    }
  }
  //继续播放音乐
  private void continueMusic(){
    synchronized(this){
       run = true;
       notifyAll();
    }
  } 
  //外部调用控制方法:生成音频主线程;
  public void start(boolean loop){
    mainThread = new Thread(new Runnable(){
      public void run(){
        try {
          playMusic(loop);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    });
    mainThread.start();
  }
  //外部调用控制方法:暂停音频线程
  public void stop(){
    new Thread(new Runnable(){
      public void run(){
        stopMusic();      
      }
    }).start();
  }
  //外部调用控制方法:继续音频线程
  public void continues(){
    new Thread(new Runnable(){
      public void run(){
        continueMusic();
      }
    }).start();
  } 
 }

修改后就可以自己修改喜欢的背景音乐了

目录
相关文章
|
6天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
21天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
34 5
Java反射机制:解锁代码的无限可能
|
17天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
48 3
|
22天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
61 10
|
18天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
16天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
24天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
30 6
java编写背景音乐
import java.applet.AudioClip; import java.net.MalformedURLException; import java.net.URL; import javax.swing.JApplet; public class PlayMusic { public static AudioClip loadSound(String filen
1414 0
|
10天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
7天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
27 9