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(); } }
修改后就可以自己修改喜欢的背景音乐了