本文共 12281 字,大约阅读时间需要 40 分钟。
【Java】Java小游戏之Shoot游戏源码及详解
Shoot游戏是模仿微信中打飞机小游戏,这个游戏虽然简单,但通过这个游戏小项目,可以练习很多小的知识点,提高对面向对象的理解,还能提高逻辑思维能力。总之,好处多多,下面我将对游戏的结构及代码进行详细说明:
游戏运行状态界面:
2)游戏步骤01:
1.class FlyingObject{ image,width,height,x,y }2.interface Enemy{ int getScore(); }3.interface Award{ DOUBLE_FILE,LIFE int getType(); }4.class Airplane extends 1 implements 2{ speed Airplane(){} 重写getScore() }5.class Bee extends 1 implements 3{ xSpeed,ySpeed,awardType Bee(){} 重写getType() }6.class Bullet extends 1{ speed Bullet(int x,int y){} }7.class Hero extends 1{ life,doubleFire,images,index Hero(){} }8.class ShootGame extends JPanel{ WIDTH,HEIGHT background,start,pause,gameover airplane,bee,bullet,hero0,hero1 hero(Hero) flyings(FlyingObject[]) bullets(Bullet[]) ShootGame(){初始化对象} static{} 重写paint(g){ 画背景图 paintHero(g); paintFlyingObjects(g); paintBullets(g); } paintHero(g){} //画英雄机 paintFlyingObjects(g){} //画敌人 paintBullets(g){} //画子弹 main(){ ... frame.setVisible(true); } }3)游戏步骤02:
1.敌人入场的实现步骤: 1)main(){ game.action(); } 2)action(){ ... run(){ //10毫秒定时执行 enteredAction(); //敌人入场 repaint(); } } 3)int index = 0; enteredAction(){ //10毫秒 index++; if(index%40==0){ //40*10毫秒 FlyingObject one = nextOne(); //创建一个敌人对象 flyings = Arrays.copyOf(flyings,flyings.length+1); //扩容 flyings[flyings.length-1] = one; //将敌人对象添加到敌人数组中 } } 4)nextOne(){ 生成0到19间的随机数 为0时return new Bee(); 否则return new Airplane(); }2.飞行物走一步的实现步骤: 1)FlyingObject----抽象方法step(); 2)Airplane,Bee,Bullet,Hero---重写step() 3)action(){ run(){ enterAction(); stepAction(); repaint(); //重画 } } 4)stepAction(){ 遍历所有敌人,调用step() 遍历所有子弹,调用step() hero.step(); }3.子弹入场的实现步骤: 1)Hero---shoot()英雄机发射子弹 2)action(){ run(){ ... shootAction(); //发射子弹 repaint(); } } 3)int shootIndex = 0; shootAction(){ //10毫秒走一次 shootIndex++; if(shootIndex%30==0){ //300毫秒 调用Hero的shoot()得到发射出的子弹数组bs 将bullets扩容 将bs追加到bullets数组中--System.arraycopy() } }4.英雄机随着鼠标移动的实现步骤: 1)Hero---moveTo(int x,int y) 2)action(){ MouseAdapter l = new MouseAdapter(){ 重写MouseMoved(){ 获取鼠标的x和y hero.moveTo(x,y); //移动 } }; this.addMouseMotionListener(l); this.addMouseListener(l); run(){ ... } }5.子弹和敌人碰撞的实现步骤: 1)FlyingObject---shootBy(Bullet b) 2)Hero----addDoubleFire(),addLife() 3)action(){ run(){ ... bangAction(); //检查碰撞 repaint(); } } 4)bangAction(){ 遍历所有子弹,将子弹传给bang()方法 } 5)bang(Bullet b){ //1发子弹与所有敌人撞 遍历所有敌人,获取每一个敌人f 判断f是否与b撞上了 若撞上了: 5.1)得分或得奖励 5.1.1)得到被撞敌人对象 5.1.2)判断是敌人还是奖励 若是敌人则增分 若是奖励则得奖励类型 判断不同的奖励类型: 增命或增火力值 5.2)将被撞对象从flyings中删除 5.2.1)将被撞敌人与最后一个元素交换(追尾并绕圈) 5.2.2)缩容---删除最后一个元素(被撞的对象) }
1.画分和画命的实现步骤: 1)hero---getLife()获取命 2)paint(g){ ...... paintScore(g); //画分和命 } 3)paintScore(g){ 设置颜色g.setColor(...) 设置字体g.setFont(...) 画分g.drawString(...); 画命g.drawString(...); }2.删除越界的敌人和子弹的实现步骤: 1)FlyingObject----abstract outOfBounds(); 2)Airplane,bee,bullet,Hero--重写outOfBounds() 3)action(){ run(){ ... outOfBoundsAction(); //删除越界的 repaint(); } } 4)outOfBoundsAction(){ 1)声明活着的数组 2)遍历flyings/bullets数组 判断对象是否不越界: 若true: 将对象添加到活着的数组中 3)将活着的数组复制到flyings/bullets数组中 }3.英雄机与敌人碰撞、游戏结束检查的实现步骤: 1)Hero---boolean hit(FlyingObject other); 2)Hero---substractLife() setDoubleFire(int doubleFire) 3)action(){ 重写run(){ ... checkGameOverAction(); //检测英雄机与敌人撞 repaint(); } } 4)checkGameOverAction(){ if(isGameOver()){ } } 5)isGameOver(){ //检测游戏是否结束 遍历所有敌人,获取每一个敌人f 判断hero.hit(f){ 减命 火力值清零 删除被撞的敌人(交换,缩容) } return hero.getLife()<=0; }4.画状态的实现步骤: 1)START,RUNNING,PAUSE,GAME_OVER state=0(存储当前状态) 2)paint(){ ... paintState(g); } 3)paintState(g){ START状态--贴start图 PAUSE状态--贴pause图 GAME_OVER状态--贴gameover图 } 4)run(){ if(state==RUNNING){ 一堆action(); } repaint(); } 5)mouseMoved(){ if(state== RUNNING){ 获取x,y,调英雄机移动方法 } } 6)重写mouseClicked(){ 若为启动状态,则改为运行状态 若为游戏结束状态,则: 清理现场(hero,flyings,bullets,score) 改为启动状态 } 7)checkGameOverAction(){ if(isGameOver()){ state = GAME_OVER; } } 8)重写mouseExited(){ if(state == RUNNING){ state = PAUSE; } } 9)重写mouseEntered(){ if(state == PAUSE){ state = RUNNING; } }
package shootgame;import java.awt.image.BufferedImage;/** * 飞行物类 * @author long * */public abstract class FlyingObject { protected BufferedImage image; //图片 protected int x; //x坐标 protected int y; //y坐标 protected int width; //图片宽度 protected int height; //图片高度 public abstract void step(); //走步方法 public abstract boolean outOfBounds(); public boolean shootBy(Bullet b){ int x1 = this.x - b.width; int x2 = this.x + this.width; int y1 = this.y; int y2 = this.y + this.height; int x = b.x; int y = b.y; return (x>x1&&xy1&&y
package shootgame;/** * 奖励接口 * @author long * */public interface Award { public int LIFE = 0; //命 public int DOUBLE_FIRE = 1; //双倍火力 public int getType(); //获取奖励类型}
package shootgame;/** * 敌机接口 * @author long * */public interface Enemy { public int getScore(); //得分}
package shootgame;import java.awt.image.BufferedImage;import java.io.IOException;import javax.imageio.ImageIO;/** * 常量类 * @author long * */public class Constant { public static final int WIDTH = 400; public static final int HEIGHT = 650; public static BufferedImage background; public static BufferedImage start; public static BufferedImage pause; public static BufferedImage gameover; public static BufferedImage airplane; public static BufferedImage bee; public static BufferedImage bullet; public static BufferedImage hero0; public static BufferedImage hero1; public static final int START = 0; public static final int PAUSE = 1; public static final int RUNNING = 2; public static final int GAME_OVER = 3; static { try { background=ImageIO.read(Constant.class.getResource("background.png")); start=ImageIO.read(Constant.class.getResource("start.png")); pause=ImageIO.read(Constant.class.getResource("pause.png")); gameover=ImageIO.read(Constant.class.getResource("gameover.png")); airplane=ImageIO.read(Constant.class.getResource("airplane.png")); bee=ImageIO.read(Constant.class.getResource("bee.png")); bullet=ImageIO.read(Constant.class.getResource("bullet.png")); hero0=ImageIO.read(Constant.class.getResource("hero0.png")); hero1=ImageIO.read(Constant.class.getResource("hero1.png")); } catch (IOException e) { System.out.println("图片加载异常"); e.printStackTrace(); } } }
package shootgame;import java.util.Random;/** * 敌机类 * @author long * */public class Airplane extends FlyingObject implements Enemy{ private int speed = 3; //飞行速度 public Airplane(){ this.image = Constant.airplane; this.width = image.getWidth(); this.height = image.getHeight(); this.y = -height; Random rand = new Random(); this.x = rand.nextInt(Constant.WIDTH-this.width); rand = null; } /** * 打掉一个敌机获得的分数 */ public int getScore(){ return 5; } /** * 重写走步方法 * 向下走一步 */ public void step(){ y += speed; } /** * 重写边界检测方法 * 当敌机到最小面的时候越界 */ public boolean outOfBounds(){ return y>Constant.HEIGHT; }}
package shootgame;import java.util.Random;/** * 小蜜蜂类 * @author long * */public class Bee extends FlyingObject implements Award{ private int xSpeed = 2; //水平方向移动速度 private int ySpeed = 3; //垂直方向移动速度 private int awardType; //奖励类型 public Bee(){ this.image = Constant.bee; this.width = image.getWidth(); this.height = image.getHeight(); this.y = -height; Random rand = new Random(); this.x = rand.nextInt(Constant.WIDTH-this.width); this.awardType = rand.nextInt(2); rand = null; } /** * 打死一只小蜜蜂可以获取的奖励类型 * 生命或值双倍子弹 */ public int getType(){ return awardType; } /** * 重写走步方法 * 小蜜蜂可以左右走 * 到最左边或者最右边的时候转向 */ public void step(){ x += xSpeed; y += ySpeed; if(x>Constant.WIDTH-this.width){ xSpeed = -1; } if(x<0){ xSpeed = 1; } } /** * 小蜜蜂边界检测 */ public boolean outOfBounds(){ return y>Constant.HEIGHT; } }
package shootgame;import java.util.Random;/** * 子弹类 * @author long * */public class Bullet extends FlyingObject{ private int speed = 5; //子弹的速度 public Bullet(int x,int y){ this.image = Constant.bullet; this.width = image.getWidth(); this.height = image.getHeight(); this.x = x; this.y = y; } /** * 重写step方法 * 子弹向上走步 */ public void step(){ y -= speed; } /** * 子弹边界检测 * 当子弹到最上边的时候越界 */ public boolean outOfBounds(){ return y<-this.width; }}
package shootgame;import java.awt.image.BufferedImage;/** * 英雄机类 * @author long * */public class Hero extends FlyingObject{ BufferedImage[] images; //图片数组 private int index; //图片数组索引 private int life; //命 private int doubleFire; //双倍火力 public Hero(){ this.image = Constant.hero0; this.width = image.getWidth(); this.height = image.getHeight(); this.x = 150; this.y = 400; this.life = 3; this.doubleFire = 20; this.index = 0; this.images = new BufferedImage[]{Constant.hero0,Constant.hero1}; } /** * 获取生命值 * @return */ public int getLife() { return life; } /** * 增加一条命 */ public void addLife(){ life++; } /** * 减一条命 */ public void substractLife(){ life--; } /** * 设置双倍火力 * @param doubleFire */ public void setDoubleFire(int doubleFire) { this.doubleFire = doubleFire; } public void addDoubleFire(){ doubleFire += 40; } /** * 重写走步方法 * 英雄机走步即切换图片,实现动画效果 */ public void step(){ image = images[index++/10%images.length]; } /** * 英雄机射出子弹 * @return */ public Bullet[] shoot(){ Bullet[] b; int temp = this.width/4; if(doubleFire>0){ b = new Bullet[2]; b[0] = new Bullet(this.x+1*temp-1,this.y-10); b[1] = new Bullet(this.x+3*temp-1,this.y-10); doubleFire -= 2; }else{ b = new Bullet[1]; b[0] = new Bullet(this.x+2*temp-1,this.y-10); } return b; } /** * 英雄机随鼠标移动方法 * @param x * @param y */ public void move(int x,int y){ this.x = x-this.width/2; this.y = y-this.height/2; } /** * 英雄机永不越界 */ public boolean outOfBounds(){ return false; } public boolean hit(FlyingObject f){ int x1 = f.x-this.width/2; int x2 = f.x+f.width+this.width/2; int y1 = f.y-this.height/2; int y2 = f.y+f.height+this.height/2; int x = this.x+this.width/2; int y = this.y+this.height/2; return (x>x1&&xy1&&y
package shootgame;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.util.Arrays;import java.util.Random;import java.util.Timer;import java.util.TimerTask;import javax.swing.JFrame;import javax.swing.JPanel;/** * 游戏主界面类 * @author long * */public class ShootGame extends JPanel{ private FlyingObject[] flyings = {}; //飞行物数组 private Bullet[] bullets = {}; //子弹数组 private Hero hero = new Hero(); //英雄机 private int score = 0; //得分 private int state = 0; //游戏状态 /** * 重写paint方法 */ @Override public void paint(Graphics g) { g.drawImage(Constant.background,0,0,null); paintHero(g); paintFlyings(g); paintBullets(g); paintScore(g); paintState(g); } /** * 画游戏的开始、运行、暂停、结束四中状态 * @param g */ public void paintState(Graphics g){ switch (state) { case Constant.START: g.drawImage(Constant.start,0,0,null); break; case Constant.PAUSE: g.drawImage(Constant.pause,0,0,null); break; case Constant.GAME_OVER: g.drawImage(Constant.gameover,0,0,null); break; default: break; } } /** * 画分数和命 * @param g */ public void paintScore(Graphics g){ Color c = g.getColor(); g.setColor(new Color(0x8A2BE2)); g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,20)); g.drawString("SCORE:"+score,10,25); g.drawString("LIFE:"+hero.getLife(),10,50); g.setColor(c); } /** * 画英雄机 * @param g */ private void paintHero(Graphics g) { g.drawImage(hero.image,hero.x,hero.y,null); } /** * 画飞行物 * @param g */ private void paintFlyings(Graphics g) { for(int i=0;i注:每个类的作用及每个方法的作用都已在注释中详细说明。