水果忍者游戏
此篇文章是在时间较为紧的情况之下写;不足之处、日后定当丰富之。。。。望见谅。
做软件开发的同学应该知道:水果忍者游戏本身其实是个大随机:随机产生抛出水果、每个水果随机运动、、、而这一切使用最重要的就是线程的运用了。
按照自己小组做出的水果忍者游戏的步骤:大至分为游戏选择界面--游戏界面--结束游戏的选择框界面。
1、游戏选择界面:主要添加按钮及其动作命令;背景音乐,以及添加背景图片。
例如:
// 主界面的方法 public void init() { this.setTitle("切水果"); this.setSize(300, 250); this.setDefaultCloseOperation(3); this.setLocationRelativeTo(null); this.setResizable(false); // 增加一个容器,添加选择按钮 JPanel jp = new JPanel(); // 添加按钮 JButton jb_start = new JButton("计时模式"); jp.add(jb_start); // 设置一个间隔 JLabel jl = new JLabel(" "); JButton jb1_close = new JButton(); // 添加经典模式按钮 JButton jb1_start = new JButton("经典模式"); jp.add(jb1_start); // 设置动作命令 jb1_close.setActionCommand("退出游戏"); //设置开始按钮图片 ImageIcon icon1=new ImageIcon("src/image/start.png"); //获取图片大小 int height1 = icon1.getIconHeight(); int weight1 = icon1.getIconHeight(); // 将按钮的大小设置成图片的大小 jb_start.setPreferredSize(new Dimension(height1, weight1)); // 设置退出游戏界面的图片 ImageIcon icon = new ImageIcon("src/image/back.png"); // 获取图片大小 int height = icon.getIconHeight(); int weight = icon.getIconHeight(); // 将关闭按钮的大小设置成图片的大小 jb1_close.setPreferredSize(new Dimension(height, weight)); // 添加图片 jb1_close.setIcon(icon); // 将开始按钮的大小设置成图片的大小 jb_start.setPreferredSize(new Dimension(height1, weight1)); // 添加图片 jb_start.setIcon(icon1); // 将按钮添加到画板上 jp.add(jb_start); jp.add(jb1_start); jp.add(jl); jp.add(jb1_close); // 添加容器到界面上 this.add(jp, BorderLayout.SOUTH); this.setVisible(true); //实例化第一界面音乐对象 MusicPlay2 mp=new MusicPlay2(); //启动音乐线程 mp.start(); // 实例化监听器对象 GoActionListener gal=new GoActionListener(this,mp); //添加监听器 jb_start.addActionListener(gal); jb1_close.addActionListener(gal);
接着是实现按钮的动作命令:如果命令是游戏模式时、其相应的执行命令中就会将第一界面关闭、调用游戏界面的方法
其代码如下:
/** * 构造方法 * * @param m * 游戏主界面 * @param ef * 游戏结束界面 */ public GoActionLis(MainLogin m, EndingFrame ef, String gameModel) { this.m = m; this.ef = ef; this.gameModel = gameModel; } public void actionPerformed(ActionEvent e) { // 如果点击的是开始游戏 if (e.getActionCommand().equals("计时模式")) { // 实例化一个游戏主界面的对象 MainLogin ml = new MainLogin(lo, count, ef, "计时模式"); ml.LoginSh(); // 关闭登陆界面的音乐 lm.CloseMusic(); // 播放背景音乐 Music_Thread mt = new Music_Thread(); mt.start(); } else if (e.getActionCommand().equals("退出游戏")) {// 退出游戏判断 System.exit(0); } else if (e.getActionCommand().equals("经典模式")) {// 判断是否进入经典模式 // 实例化一个游戏主界面的对象 MainLogin ml = new MainLogin(lo, count, ef, "经典模式"); ml.LoginSh(); // 关闭登陆界面的音乐 lm.CloseMusic(); // 播放背景音乐 Music_Thread mt = new Music_Thread(); mt.start(); } else if (e.getActionCommand().equals("重新开始")) { // 关掉上一次游戏的界面 m.dispose(); // 表示进行过一次游戏 count = 1; // 实例化一个游戏主界面的对象 MainLogin ml = new MainLogin(lo, count, ef, gameModel); ml.LoginSh(); // 播放背景音乐 Music_Thread mt = new Music_Thread(); mt.start(); } }
接着进入游戏界面后,实例化抛出水果的线程、添加背景音乐、最复杂是就是在重绘画布中的水果运动线程添加、判断水果是否切到、切到水果后画出的水果图形、、、
需要提醒的一点:线程游戏一般会持续的闪烁、、所以,要想解决这种情况、我们需要使用 双缓冲:声明第二块画布,将所有画图都在次画布上实现。
例:
// 设置属性 this.setTitle("水果忍者"); System.out.println(width + " " + height); this.setSize(new Dimension(width + 149, height)); this.setDefaultCloseOperation(3); this.setLocationRelativeTo(null); this.setCursor(HAND_CURSOR); this.setResizable(false); this.setLayout(new BorderLayout()); // 添加一个计数面板 jp1 = new JPanel(); jp1.setPreferredSize(new Dimension(149, height)); jp1.setBackground(Color.PINK); // 添加分数 label = new JLabel(); // 设置窗体可见 this.setVisible(true); // 获取画布 g = this.getGraphics(); //实例化一个鼠标监听器对象 fruitListenr = new Fruit_MouseListener(); this.addMouseMotionListener(fruitListenr); this.addMouseListener(fruitListenr); // 创建一个线程,用来持续抛出水果 throw_thread = new FruitThrow_Thread(this, g, fruitListenr, gameModel); throw_thread.start(); // 创建双缓冲 image = this.createImage(width + 149, height); // 获取次画布 gra = image.getGraphics(); // 倒计时标签 time_label = new JLabel(); // 实例化倒计时线程 TimeThread time_thread = new TimeThread(time_label, gameModel); time_thread.start(); //实例化一个连切的线程 Pummel_Thread pummel_thread = new Pummel_Thread(); pummel_thread.start(); } // 获取图片的Image的画布 /** * 重绘方法,水果和背景图片 */ public void paint(Graphics g) { super.paint(gra); // 绘制背景图片 gra.drawImage(icon_1.getImage(), 0, 0, this); // 获得数组 fruitArray = throw_thread.getArray(); // 实例化一个随即类对象 Random rand = new Random(); // 随机获取图片 drawfruit = throw_thread.getDrawfruit(); int ran = rand.nextInt(180); // 获得球的半径 size = throw_thread.getSize(); if (fruitArray != null) { // 获取球心坐标 if (null != fruitArray && fruitArray.length != 0) { // 画出水果 for (int i = 0; i < fruitArray.length; i++) { FruitThread fruit_thread = fruitArray[i]; // 判断是否进行过一次游戏 if (count == 1) { fruit_thread.score = 0; count = 2; } if (fruit_thread != null) { // 判断水果是否被切到 boolean cut = fruit_thread.getCut(); // 如果水果被切到,则画出两个被裁减成两半的图形 if (cut) { // 判断是否切到弹 if (icon2[drawfruit[i]][1] == icon2[9][1] || icon2[drawfruit[i]][1] == icon2[8][1]) { // 绘制爆炸后的图片 gra.drawImage( icon2[drawfruit[i]][1].getImage(), fruit_thread.getX(), fruit_thread.getY(), null); } else { gra.drawImage( icon2[drawfruit[i]][1].getImage(), fruit_thread.getX() + 30, fruit_thread.getY() + 40, null); gra.drawImage( icon2[drawfruit[i]][0].getImage(), fruit_thread.getX() - 30, fruit_thread.getY() - 40, null); gra.drawImage(blood_icon.getImage(), fruit_thread.a, fruit_thread.b, null); } score = fruit_thread.getScore(); } else {// 没有切到,则画出完整的图形 gra.drawImage(icon[drawfruit[i]].getImage(), fruit_thread.getX(), fruit_thread.getY(), null); } } } } }
游戏需要判断是否结束;这就需要添加判断:时间判断和切到炸个数的判断以及掉下水果数目的判断。。。这些方法可以在球运动过程中调用。
最后的游戏结束框界面中,添加两个选择按钮:继续游戏和结束游戏。
每个界面都有其相应的音乐线程、
然而,值得注意的是,每个水果线程掉下后,都应该将其break掉;不然会使游戏运行越来越卡。。。。。
对于此游戏的介绍确实过于简单、、、为此,提供了自己所写的游戏代码。需要者可以下载查看。。。。你会有想不到的收获。。但较为可惜的是没能上传音乐。。。