day09
1.子弹与敌人的碰撞
1)在超类中FlyingObject设计hit()实现敌人与子弹/英雄机得碰撞
/** 成员方法:检测敌人与子弹/英雄机的碰撞
* this:敌人 other:子弹 */
public boolean hit(FlyingObject other) {
int x1 = this.x - other.width;
int x2 = this.x + this.width;
int y1 = this.y - other.height;
int y2 = this.y + this.height;
int x = other.x;
int y = other.y;
return x>=x1 && x<=x2 && y>=y1 && y<=y2;
}
在超类中FlyingObject设计goDead()实现飞行物去死的
/** 成员方法:飞行物去死 */
public void goDead() {
state = DEAD; //将当前状态修改为DEAD
}
import java.util.Random;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.awt.Graphics;
/**
* 飞行物--超类
* @author soft01
*/
public abstract class FlyingObject {
/** 常量: 三种状态(活着的、死了的、删除的) */
public static final int LIFE = 0;
public static final int DEAD = 1;
public static final int REMOVE = 2;
/** 成员变量:当前状态(默认为活着的) */
protected int state = LIFE;
/** 成员变量:宽、高、x轴、y轴 */
protected int width;
protected int height;
protected int x;
protected int y;
/** 构造方法:专门给英雄机、天空、子弹用 */
public FlyingObject(int width,int height,int x,int y) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
/** 构造方法:专门给小敌机、大敌机、小蜜蜂用 */
public FlyingObject(int width,int height) {
this.width = width;
this.height = height;
Random rand = new Random();
x = rand.nextInt(World.WIDTH-width);
y = -height;
}
/** 抽象方法:飞行物移动 */
public abstract void step();
/** 抽象方法:获取图片 */
public abstract BufferedImage getImage();
/** 抽象方法:检查飞行物是否越界 */
public abstract boolean outOfBounds();
/** 静态方法:读取图片 */
public static BufferedImage loadImage(String fileName) {
try {
BufferedImage img = ImageIO.read(FlyingObject.class.getResource(fileName)); //同包中读图片
return img;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
/** 成员方法:判断状态(活着的、死了的、删除的) */
public boolean isLife() {
return state == LIFE;
}
public boolean isDead() {
return state == DEAD;
}
public boolean isRemove() {
return state == REMOVE;
}
/** 成员方法:画对象的 g:画笔 */
public void paintObject(Graphics g) {
g.drawImage(getImage(),x,y,null);
}
/** 成员方法:检测敌人与子弹/英雄机的碰撞
* this:敌人 other:子弹 */
public boolean hit(FlyingObject other) {
int x1 = this.x - other.width; //敌人的x - 子弹/英雄机的宽
int x2 = this.x + this.width; //敌人的x + 敌人的宽
int y1 = this.y - other.height; //敌人的y - 子弹/英雄机的高
int y2 = this.y + this.height; //敌人的y + 敌人的高
int x = other.x; //子弹/英雄机的x
int y = other.y; //子弹/英雄机的y
return x>=x1 && x<=x2 && y>=y1 && y<=y2; //x在x1和x2之间,y在y1和y2之间
}
/** 成员方法:飞行物去死 */
public void goDead() {
state = DEAD; //将当前状态修改为DEAD
}
}
在Hero类中设计addLife()增命、addDoubleFire()增火力
/** 成员方法:命数增加 */
public void addLife() {
life++; //命数增1
}
/** 成员方法:火力值增加 */
public void addDoubleFire() {
doubleFire += 40; //火力值增40
}
import java.awt.image.BufferedImage;
/**
* 英雄机
* @author soft01
*/
public class Hero extends FlyingObject{
/** 静态变量:英雄机图片 */
private static BufferedImage[] images;
static {
images = new BufferedImage[2];
for (int i = 0; i < images.length; i++) {
images[i] = loadImage("hero" + i + ".png");
}
}
/** 成员变量:生命、火力值 */
private int life; //生命
private int doubleFire; //火力值
/** 构造方法 */
public Hero(){
super(97,124,140,400);
life = 3;
doubleFire = 0;
}
/** 成员方法:命数增加 */
public void addLife() {
life++; //命数增1
}
/** 成员方法:获取命数 */
public int getLife() {
return life; //返回命
}
/** 成员方法:火力值增加 */
public void addDoubleFire() {
doubleFire += 40; //火力值增40
}
/** 成员方法:英雄机移动 */
public void step() {}
/** 成员方法:英雄机随鼠标移动x,y */
public void moveTo(int x,int y) {
this.x = x - this.width/2; //英雄机的x=鼠标的x-1/2英雄机的宽
this.y = y - this.height/2; //英雄机的y=鼠标的y-1/2英雄机的高
}
/** 成员方法:获取图片 */
int index = 0;
@Override
public BufferedImage getImage() {
if(isLife()) {
return images[index++%2]; //(index++%2)余数为0或1
}
return null;
}
/** 成员方法:英雄机发射子弹(创建子弹对象) */
public Bullet[] shoot() {
int xStep = this.width/4; //xStep:1/4英雄机的宽
int yStep = 20; //yStep:固定的20
if (doubleFire > 0) { //双
Bullet[] bs = new Bullet[2]; //2发子弹
//英雄机的x坐标加1/4英雄机的宽
bs[0] = new Bullet(this.x + 1 * xStep,y-yStep);
//英雄机的x坐标加3/4英雄机的宽
bs[1] = new Bullet(this.x + 3 * xStep, y-yStep);
doubleFire -= 2; //发射一次双倍火力,火力值减2
return bs;
} else { //单
Bullet[] bs = new Bullet[1]; //1发子弹
//英雄机的x坐标加2/4英雄机的宽
bs[0] = new Bullet(this.x + 2 * xStep, y-yStep);
return bs;
}
}
/** 成员方法:英雄机永不越界 */
@Override
public boolean outOfBounds() {
return false;
}
}
2)子弹与敌人的碰撞为定时发生的,所以在run()中调用BulletBangAction()方法
在BulletBangAction()中:
遍历所有子弹,获取每一个子弹,遍历所有敌人,获取每个敌人
判断是否撞上了,若撞上了:
1)子弹去死,敌人去死
2)小敌机和大敌机 ----------得分
小蜜蜂 ----------------英雄机得命或双倍火力
/** 成员方法:子弹与敌人的碰撞 */
int score = 0;
public void bulletBangAction() { //每10个毫秒走一次
//遍历子弹数组
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];//得到每一个子弹
//遍历敌人数组
for (int j = 0; j < enemies.length; j++) {
FlyingObject f = enemies[j]; //得到每一个敌人
//如果活着的子弹和活着的敌人撞上了
if(b.isLife() && f.isLife() && f.hit(b)) {
b.goDead(); //子弹去死
f.goDead(); //敌人去死
if (f instanceof Enemy) {//若被撞对象是敌人
Enemy e = (Enemy)f;//强转为得分接口
score += e.getScore();//玩家得分
}
if (f instanceof Award) {//若被撞对象是奖励
Award a = (Award)f;// 强转为奖励接口
int type = a.getType();//获取奖励类型 //基于不同的类型来得到不同的奖励
switch (type) {
//若奖励为火力值
case Award.DOUBLE_FIRE:
hero.addDoubleFire(); //则增加火力值
break;
case Award.LIFE: //若奖励为命
hero.addLife(); //则增加命
break; }
}
}
}
}
}
2.画分和画命
1)在Hero类中设计getLife()获取命
/** 成员方法:获取命数 */
public int getLife() {
return life; //返回命
}
2)在paint()方法中,画分和画命
g.drawString("SCORE:" + score,10,25);
g.drawString("LIFE:" + hero.getLife(), 10, 45);
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.util.Arrays;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;;
/**
* 整个世界
* @author soft01
*/
public class World extends JPanel{
/** 常量:窗口宽、窗口高 */
public static final int WIDTH = 400;
public static final int HEIGHT = 700;
/** 成员变量:天空、英雄机、飞行物敌人数组、子弹数组 */
private Sky sky = new Sky();
private Hero hero = new Hero();
private FlyingObject[] enemies = {};
private Bullet[] bullets = {};
/** 启动程序的执行 */
public void action() {
Timer timer = new Timer(); //创建定时器对象
int interval = 10; //定时间隔(以毫秒为单位)
timer.schedule(new TimerTask() { //匿名内部类
@Override
public void run() { //定时干的事(每10个毫秒走一次)
enterAction(); //敌人入场,子弹入场,飞行物移动
shootAction(); //子弹入场,英雄机发射子弹
stepAction(); //飞行物入场
outOfBoundsAction(); //删除越界
bulletBangAction(); //子弹与敌人的碰撞
repaint(); //重画(重新调用paint()方法)
}
},interval,interval); //定时计划
/** 鼠标侦听器 */
MouseAdapter l = new MouseAdapter() {
/** 重写mouseMoved()鼠标移动 */
public void mouseMoved(MouseEvent e) {
int x = e.getX(); //获取鼠标的x坐标
int y = e.getY(); //获取鼠标的y坐标
hero.moveTo(x, y); //英雄机随着鼠标移动
}
};
this.addMouseListener(l); //处理鼠标操作事件
this.addMouseMotionListener(l); //处理鼠标滑动事件
}
/** 成员方法:生成敌人(小敌机、大敌机、小蜜蜂)对象 */
public FlyingObject nextOne() {
Random rand = new Random(); //随机数对象
int type = rand.nextInt(20); //0~19之间的数
if (type < 11) { //0~7返回小敌机
return new Airplane();
} else if(type < 17){ //8~15返回小敌机
return new BigAirplane();
} else { //16~19返回小敌机
return new Bee();
}
}
/** 成员方法:敌人(小敌机、大敌机、小蜜蜂)入场 */
int enterIndex = 0; //敌人入场计数
public void enterAction() { //每10个毫秒走一次
enterIndex++; //每10毫秒增1
if(enterIndex%40 == 0) { //每400(10*40)毫秒走一次
FlyingObject obj = nextOne();
enemies = Arrays.copyOf(enemies, enemies.length+1); //数组扩容
enemies[enemies.length-1] = obj; //将敌人对象填充到enemies数组的最后一个元素上
}
}
/** 成员方法:子弹入场,英雄机发射子弹 */
int shootIndex = 0; //子弹入场计数
public void shootAction() { //每10个毫秒走一次
shootIndex++; //每10毫秒增1
if(shootIndex%20 == 0) { //每300(10*30)毫秒走一次
Bullet[] bs = hero.shoot(); //获取英雄机发射出来的子弹对象
bullets = Arrays.copyOf(bullets, bullets.length+bs.length); //扩容(bs有几个元素就扩大几个)
System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length); //数组的追加
}
}
/** 成员方法:飞行物入场 */
public void stepAction() {
sky.step(); //天空移动
for (int i = 0; i < enemies.length; i++) {
enemies[i].step(); //飞行物移动
}
for (int i = 0; i < bullets.length; i++) {
bullets[i].step(); //子弹移动
}
}
/** 成员方法:删除越界 */
public void outOfBoundsAction() { //每10个毫秒走一次
int index = 0; //1)不越界敌人下标 2)不越界敌人个数
FlyingObject[] enemyLives = new FlyingObject[enemies.length]; //不越界敌人数组
for (int i = 0; i < enemies.length; i++) { //获取敌人数组
FlyingObject f = enemies[i]; //获取每一个敌人
if(!f.outOfBounds()) { //不越界
enemyLives[index] = f; //将不越界敌人放到不越界数组中
index++; //1)不越界敌人数组下标增一 2)不越界敌人个数增1
}
}
enemies = Arrays.copyOf(enemyLives, index); //将不越界数组中的元素复制到敌人数组之中,数组的长度为index
index = 0;
Bullet[] bulletLives = new Bullet[bullets.length];
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];
if(!b.outOfBounds()) {
bulletLives[index] = b;
index++;
}
}
bullets = Arrays.copyOf(bulletLives, index);
}
/** 成员方法:子弹与敌人的碰撞 */
int score = 0;
public void bulletBangAction() { //每10个毫秒走一次
for (int i = 0; i < bullets.length; i++) { //遍历子弹数组
Bullet b = bullets[i]; //得到每一个子弹
for (int j = 0; j < enemies.length; j++) { //遍历敌人数组
FlyingObject f = enemies[j]; //得到每一个敌人
if(b.isLife() && f.isLife() && f.hit(b)) { //如果活着的子弹和活着的敌人撞上了
b.goDead(); //子弹去死
f.goDead(); //敌人去死
if (f instanceof Enemy) { //若被撞对象是敌人
Enemy e = (Enemy)f; //强转为得分接口
score += e.getScore(); //玩家得分
}
if (f instanceof Award) { // 若被撞对象是奖励
Award a = (Award)f; // 强转为奖励接口
int type = a.getType(); //获取奖励类型
switch (type) { //基于不同的类型来得到不同的奖励
case Award.DOUBLE_FIRE: //若奖励为火力值
hero.addDoubleFire(); //则增加火力值
break;
case Award.LIFE: //若奖励为命
hero.addLife(); //则增加命
break;
}
}
}
}
}
}
/** 成员方法:paint()方法 */
@Override
public void paint(Graphics g) {
sky.paintObject(g); //画天空
hero.paintObject(g); //画英雄机
for (int i = 0; i < enemies.length; i++) { //遍历所有敌人
enemies[i].paintObject(g); //画敌对飞行物
}
for (int i = 0; i < bullets.length; i++) { //遍历子弹
bullets[i].paintObject(g); //画子弹
}
g.drawString("SCORE:" + score,10,25);
g.drawString("LIFE:" + hero.getLife(), 10, 45);
}
/** main主方法 */
public static void main(String[] args) {
JFrame frame = new JFrame(); //创建窗口
World world = new World(); //创建面板
frame.add(world); //将面板添加到窗口
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭窗口即停止运行程序
frame.setSize(WIDTH,HEIGHT); //设置窗口大小
frame.setLocationRelativeTo(null); //设置窗口居中显示
frame.setVisible(true); //1)设置窗口可见 2)尽快调用paint()方法
world.action(); //启动程序
}
}