案例(1)——飞机大战思路和代码实现(Java笔记)

飞机大战的思路 

飞机大战中该有的东西

1、我们控制的飞机(以下简称主机)名为Hero

2、敌机 小蜜蜂(统一称为其他飞行物) 名为Airplane ||  Bee

3、游戏有关的图片(背景图、飞机图、状态图)

 以下是我们控制的飞机的实现代码,需要实现以下的方法:

1、一个无参的Hero方法用来创建Hero飞机

2、我们控制的飞机要有喷射尾焰的效果,用step方法一定的时间里连续切换图片,形成所需效果

3、是否出界outOfBounds方法(离开我们创建的界面),不过我们用鼠标来控制主机,不存在出界问题,故返回值是false

4、 获取移动的方法moveto方法,不过需要进行微调,因为我们一般是控制主机的中心位置,而这默认位置是左上角

5、一些游戏的机制

        5.1、加血 addLife方法

        5.2、扣血 subtraLife方法

        5.3、获取血量值 getLIfe方法

        5.4、增加火力 addFire方法

        5.5、减少火力 clearFire方法

6、子弹,以一个数组来存放

7、是否与其他飞行物碰撞 collide方法,可以有以下两种方式

        7.1、 以主机为中心

        7.2、 以其他飞行物为中心(推荐大家可以去思考下如何实现,可以发在评论中交流)

package com.game;

import java.awt.image.BufferedImage;

/**
 * @auother lungcen
 */

/**
 * 主机的一些属性
 */
public class Hero extends FlyObject//主机的类
{
    private int doubleFire;//火力值
    private int life;//生命值

    private BufferedImage[] images;//图片数组
    private int index;//辅助图片进行切换

    /**
     * 主机的类方法
     */
    public Hero()
    {
        image = ShootGame.hero0;//飞机的图片属性
        width = image.getWidth();
        height = image.getHeight();
        x = 150;//一开始的位置
        y = 310;
        //两张图片存进数组中
        images = new BufferedImage[] {ShootGame.hero0, ShootGame.hero1};
        index = 0;
        life = 3;//初始生命值
    }

    @Override
    public void step()//时间间隔为10ms,让主机动起来
    {
        image = images[index++/10%images.length];
        /*index++;
        int a = index/10;
        int b = a%2;
        image = images[b];
        10ms index = 0	a = 0	b = 0
        20ms index = 1 	a = 0	b = 0
        30ms index = 2	a = 0 	b = 0
        nms	 index = 10 a = 1 	b = 1
         b 最终的结果 取余 不是0 就是1
	    */
    }

    @Override
    public boolean outOfBounds()//判断是否出界,由于主机不会出界,则返回值为false
    {
        return false;
    }

    public void moveTo(int x, int y)//获取鼠标移动的位置
    {//是鼠标的位置在图片的中心
        this.x = x - this.width/2;//调整鼠标的位置
        this.y = y - this.height/2;
    }

    public void addLife()//游戏机制
    {
        life++;
    }

    public void subtractLife()//游戏机制
    {
        life--;
    }

    public int getLife()//游戏机制
    {
        return life;
    }

    public void addFire()//游戏机制
    {
        doubleFire += 20;
    }

    public void clearFire()//游戏机制
    {
        doubleFire = 0;
    }

    public Bullet[] shoot()//子弹数组
    {
        int xStep = this.width/4;//主机中间发射子弹
        int yStep = 20;//从机管中射出,而不是从头射出

        if (doubleFire>0)//双倍
        {
            Bullet[] bullets = new Bullet[2];
            bullets[0] = new Bullet(this.x+1*xStep,this.y-yStep);//两个开火口
            bullets[1] = new Bullet(this.x+3*xStep,this.y-yStep);
            return bullets;
        }
       else//单倍
        {
            Bullet[] bullets = new Bullet[1];
            bullets[0] = new Bullet(this.x+2*xStep,this.y-yStep);//一个开火口
            return bullets;
        }
    }

    public boolean collide(FlyObject flyObject)//判断是否碰撞,以主机为主体
    {
        int x1 = flyObject.x - this.width/2;//确定敌机的碰撞范围
        int x2 = flyObject.x + flyObject.width +this.width/2;
        int y1 = flyObject.y - this.height/2;
        int y2 = flyObject.y + flyObject.height + this.height/2;

        int x = this.x + this.width/2;//确定主机的位置
        int y = this.y + this.height/2;
        return x >= x1 && x <= x2 && y >= y1 && y <= y2;//当主机在碰撞范围,则发生碰撞
    }
}

我们控制的主机写完了,接下来我们控制不了的写其他飞行物,需要有以下基本的方法(当然也可以加点其他的方法):

1、打中可以获得分数,于是就给飞机添加一个接口(获得分数的接口)Enemy接口   注:为啥要用接口勒,因为那时候我们正在学接口,不用接口也是可以的

2、和主机类似,一个无参的Airplane方法来创建敌机

3、敌机的飞行方式step方法

4、敌机出界的方法outOfBounds方法,这个方法还是很重要的,如果越界后不清掉,那就会一直堆在下面,浪费空间

5、打中敌机的分数getScore方法(从Enemy中重写的)

package com.game;

public interface Enemy//得分机制
{
    int getScore();
}
package com.game;

import java.util.Random;

/**
 * @auother lungcen
 */

public class Airplane extends FlyObject implements Enemy//敌机对象
{
    private int step = 2;//移动速度

    public Airplane()//敌机的属性
    {
        image = ShootGame.airplane;//敌机的图片属性
        width = image.getWidth();
        height = image.getHeight();

        Random rand = new Random();//随机数
        x = rand.nextInt(ShootGame.WIDTH-this.width);//随机的范围
        y = -2/4*this.height;//形成一种由外往里的效果
    }

    public void step()//飞机的移动方式
    {
        y= y + 2*step;
    }

    public boolean outOfBounds()//判断是否出界
    {
        return this.y >ShootGame.HEIGHT-1.5*this.height;
    }

    @Override
    public int getScore()//打中敌机的分数
    {
        return 2;
    }
}

 主机有了,敌机也有了,还差点啥勒?有分数机制,还需要奖励机制。奖励机制用蜜蜂来承载:

1、奖励机制提取出来,成为一个接口 Award接口

2、蜜蜂与敌机都是飞行物,都一个对应的无参函数来创建,蜜蜂以Bee方法来创建蜜蜂

3、setp方法来控制蜜蜂的移动

4、outOfBounds方法来判断是否出界

5、获取奖励的方法getType方法,蜜蜂类独有的

package com.game;

public interface Award//奖励机制
{
    int getType();
}
package com.game;

import java.util.Random;

/**
 * @auother lungcen(刘金成)
 */

public class Bee extends FlyObject implements Award{//蜂蜜类
    private int xSpeed = 10;//蜜蜂移动方向的速度
    private int ySpeed = 3;
    private int AwardType;//0表示双倍火力,1表示加生命值

    public Bee()//蜜蜂类的属性和位置
    {
        image = ShootGame.bee;//蜂蜜的图片属性
        width = image.getWidth();
        height = image.getHeight();

        Random rand = new Random();//生成随机数
        AwardType = rand.nextInt(2);//随机数字(0~1)

        x = rand.nextInt(ShootGame.WIDTH-this.width);//随机出现在范围位置中
        y = -this.height;//形成从窗口外到窗口的效果
    }
    @Override
    public void step()//蜜蜂移动
    {
        x+=xSpeed;//移动的速度
        y+=ySpeed;

        if (x>=ShootGame.WIDTH-1.4*this.width)//到右边界就反起来移动
        {
            xSpeed = -10;
        }
        if (x<=0)//到左边界就反起来移动
        {
            xSpeed = 10;
        }
    }
    
    public boolean outOfBounds()//判断出界
    {
        return this.y>ShootGame.HEIGHT - this.height;//出界的范围
    }

    @Override
    public int getType()//获得奖励的效果
    {
        return AwardType;//返回奖励的种类
    }
}

有主机、敌机、蜜蜂,三者都是飞行物,总不能写飞机代码的时候就定义一下那些基本的属性,然后写敌机的时候也再写一遍,写蜜蜂是又写一遍,这就显得冗余了。于是就抽象出一个飞机类Flyobject抽象类

package com.game;

import java.awt.image.BufferedImage;

/**
 * @auother lungcen
 */

/**
 * @aouther lungcen
 */
public abstract class FlyObject//一个抽象类
{
    protected BufferedImage image;//获取图片
    protected int width;//图片的属性
    protected int height;
    protected int x;//坐标的位置
    protected int y;

    public abstract void step(); //移动方式

    public abstract boolean outOfBounds(); //越界的问题

    /**
     *
     * @param bullet 传递子弹是否命中飞行物
     */
   public boolean shootBy(Bullet bullet)
    {
        int x1 = this.x;//获取飞行物的撞击范围
        int y1 = this.y;
        int x2 = this.x + this.width;
        int y2 = this.y + this.height;

        int x = bullet.x;//确定子弹的位置
        int y = bullet.y;

        return (x >= x1 && x <= x2) && (y >= y1 && y <= y2);//当子弹在撞击范围中则发生碰撞
    }
}

 接下的就是飞机发射的子弹Bullet:

1、一个对应的无参函数来创建,子弹以Bullet方法来创建子弹

1、一个有参的方法来创建子弹,需要传入位置

  注 :可能你会好奇,为啥主机和其他飞行物不需要参数,因为主机的移动是由moveTo来传入参数的,蜜蜂是由setp来移动的,而子弹需要根据主机的位置来出现,所以需要传入主机的位置来创建子弹的位置

2、子弹出现后的移动step方法

3、子弹出界问题outOfBounds方法

package com.game;

/**
 * @auother lungcen
 */

public class Bullet extends FlyObject//子弹类
{

    private int speed = 3;//控制子弹的移动速度

    /**
     * 获取子弹的位置
     * @param x 子弹的x坐标
     * @param y 子弹的y坐标
     */
    public Bullet(int x,int y)
    {
        image = ShootGame.bullet;//子弹的图片
        width = image.getWidth();//子弹图片的属性
        height = image.getHeight();
        this.x = x;//位置
        this.y = y;
    }
    
    public void step()
    {
        y-=2*speed;//子弹移动
    }
    
    public boolean outOfBounds()//出界的处理
    {
        return this.y

重头戏来了,我们有了飞机、敌机、蜜蜂、子弹这些,还剩把这些放在一起运行的界面,有以下功能:

1、生成一个界面

2、将图片存储到缓存区

3、游戏状态的值

4、处理异常

5、生成敌机、蜜蜂、子弹

6、使飞行物移动(调用飞行的方法)

7、检测碰撞(子弹与敌机,主机与其他飞行物)

8、消除越界的飞机

9、游戏的三个状态(结束、暂停、运行)

10、action——游戏开始的运行器

11、画飞机、其他飞行物、子弹、背景、状态背景

12、mian主函数入口

package com.game;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @auother lungcen
 */
public class ShootGame extends JPanel//继承JPanel
{
    /*
    public static final int WIDTH = 497;  //游戏背景的宽和高
    public static final int HEIGHT = 899;
    */

    public static final int WIDTH = 420;  //界面的宽和高,后面出界的判断根据这个数值来进行判断
    public static final int HEIGHT = 700;

    public static BufferedImage background;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage start;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage pause;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage gameover;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage bee;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage bullet;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage hero0;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage hero1;//设置图片的容器,将图片加载到内存的缓存区
    public static BufferedImage airplane;//设置图片的容器,将图片加载到内存的缓存区

    //定义游戏的状态,游戏状态中定义的一些值
    public static final int START = 0;//初始值
    public static final int RUNNING = 1;//运行的值
    public static final int PAUSE = 2;//暂停的值
    public static final int GAMEOVER = 3;//结束的值
    private int state = START;//默认的游戏状态,一开始的初值

    static {//这个,,我也不知道是啥
        try {//图片的路径
            background = ImageIO.read(ShootGame.class.getResource("/com/images/background.png"));
            start = ImageIO.read(ShootGame.class.getResource("/com/images/start.png"));
            pause = ImageIO.read(ShootGame.class.getResource("/com/images/pause.png"));
            gameover = ImageIO.read(ShootGame.class.getResource("/com/images/gameover.png"));
            bee = ImageIO.read(ShootGame.class.getResource("/com/images/bee.png"));
            bullet = ImageIO.read(ShootGame.class.getResource("/com/images/bullet.png"));
            hero1 = ImageIO.read(ShootGame.class.getResource("/com/images/hero1.png"));
            hero0 = ImageIO.read(ShootGame.class.getResource("/com/images/hero0.png"));
            airplane = ImageIO.read(ShootGame.class.getResource("/com/images/airplane.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Hero hero = new Hero();//生成主机

    private FlyObject[] flys = {};//存放父类飞行器的数组

    private Bullet[] bullets = {};//存放子弹的数组

    /**
     * 随机生成敌机
     * @return
     */
    public FlyObject nextOne()//随机生成其他飞行物
    {
        Random random = new Random();//生成随机数,按照随机数来生成敌机

        int type = random.nextInt(20);//type的范围是(0~19)
        if (type<3)//随机数小于3是生成蜜蜂
        {
            return new Bee();//出现蜜蜂
        }
        else//反之则是飞机
        {
            return new Airplane();//出现敌机
        }
    }

    /**
     * 令飞行物可以动起来
     */
    public void stepAction()//使飞行物动起来
    {
        hero.step();//运动的频率10ms,让主机的两张图交换出现,形成尾气的效果
        for (int i = 0; i < flys.length; i++)
        {
            flys[i].step();//使每一个飞行物都动起来
        }
        for (Bullet b:bullets)
        {
            b.step();//使子弹也动起来
        }
    }

    /**
     * 生成速度和存放空间
     */
    int flyIndex = 0, x=0, y=40;//计数
    public void enterAction()//在一定的时间内产生一组敌人
    {
        flyIndex++;
        if (flyIndex% y == 0)//产生的频率,每间隔40秒产生一个其他飞行物
        {
            x = x + 2; //使敌机的数量随着时间增加
            if (x%12==0 && y!=6)
                --y; //每过一下,y值减少,飞机的速度也对应变快起来

            FlyObject obj = nextOne();//生成其他飞行物
            flys = Arrays.copyOf(flys,flys.length+1);//给数组扩容,长度加一
            flys[flys.length-1] = obj;//新产生的飞行物放在最后面的位置
        }
    }

    /**
     * 子弹
     */
    int bulletIndex = 0;
    public void enterBullet()//子弹入场
    {
        bulletIndex++;
        if (bulletIndex%15 == 0)//控制子弹发射的频率
        {
            Bullet[] bull = hero.shoot();//一个子弹数组,存放子弹
            bullets = Arrays.copyOf(bullets,bullets.length+bull.length);//扩大数组容量
            System.arraycopy(bull,0,bullets,bullets.length-bull.length,bull.length);//扩容后的数组进行填充内容
        }
    }

    /**
     * 检测主机和敌机的碰撞
     */
    public void CollideBoth()
    {
        for (int i = 0; i < flys.length; i++) //检测敌机与主机是否碰撞
        {
            if (hero.collide(flys[i]))//判断是否碰撞
            {
                hero.subtractLife();//减少生命
                hero.clearFire();//取消双倍火力

                //碰撞后也要消除敌机,不然会一直撞
                FlyObject deFly = flys[i];//临时记录被撞
                flys[i] = flys[flys.length -1];//将最后一个放到现在的位置
                flys[flys.length -1] = deFly;//将被撞的放到最后面
                flys = Arrays.copyOf(flys,flys.length-1);//缩小数组的容量,删去最后一个
            }
        }
    }

    /**
     * 碰撞的方法,主体是子弹,检测子弹是否碰撞敌人
     */
    int score = 0;
    public int beng (Bullet bullet)
    {
        int index = -1;//利用index的值判断
        for (int i = 0; i < flys.length; i++)
        {
            if (flys[i].shootBy(bullet))
            {
                index = i;//将碰撞的子弹的值传给index
                break;
            }
            /**
             * 如何消除击中的子弹
             */
        }
        if (index != -1)//发生了碰撞
        {
            FlyObject one = flys[index];//获取被子弹击中的飞行物
            if (one instanceof Enemy)//判断类型
            {
                score += ((Enemy) one).getScore();//增加分数
            }
            if (one instanceof Award)//判断类型
            {
                int type = ((Award) one).getType();//判断类型
                switch (type)//进一步分析类型
                {
                    case 1:
                        hero.addLife();//增加生命
                        break;
                    case 0:
                        hero.addFire();//增加火力
                        break;
                }
            }
            //消除被击中的飞行物
            FlyObject deFly = flys[index];//临时记录被撞
            flys[index] = flys[flys.length -1];//将最后一个放到现在的位置
            flys[flys.length -1] = deFly;//将被撞的放到最后面
            flys = Arrays.copyOf(flys,flys.length-1);//缩小数组的容量,删去最后一个
            return 1;//如果击中就返回1
        }
        return 0;//如果没有击中就返回0
    }

    /**
     * 判断是否发生了碰撞,同时消除碰撞的子弹
     */
    public void bengAction()//隔一定的时间就检测一遍是否碰撞
    {
        for (int i = 0; i < bullets.length; i++)
            if (beng(bullets[i])==1)//如果子弹发生碰撞,则消除掉
            {
                Bullet deFly = bullets[i];//临时记录被撞
                bullets[i] = bullets[bullets.length -1];//将最后一个放到现在的位置
                bullets[bullets.length -1] = deFly;//将被撞的放到最后面
                bullets = Arrays.copyOf(bullets,bullets.length-1);//缩小数组的容量,删去最后一个
            }
    }

    /**
     * 删除越界的飞机
     * 需要消除的有 向下飞 的 敌机 和 小蜜蜂
     */
    int die = 0;//设置难度1,如越界的飞机大于5,就游戏结束
    private void outOfBoundsAction()//消除越界的飞机
    {
        int index = 0;//不越界的敌人数组的下标,还在屏幕内的敌人
        FlyObject[] flyLive = new FlyObject[flys.length];//存放还未越界的敌人对象

        for (int i =0; i

你可能感兴趣的:(案例,java,jvm)