1.需求分析:
运行项目,看结果:
A:小敌机,大敌机,蜜蜂,--------敌人
英雄机发射子弹
B:
子弹击中小敌机----玩家得分 1分
子弹击中大敌机----玩家得分 5分
子弹击中小蜜蜂-----玩家得 1生命或者火力值30
C:
英雄机的火力值变为0 的时候,就变成单倍火力
火力值变为0 的时候,变为双倍火力;依此减少2
D:碰撞
敌人与英雄机发发生碰撞,碰撞之后,英雄机的生命值减少,变位0的时候,游戏结束
2.计数分析
设计类:
A:找对象:6个对象
英雄机,小敌机,大敌机,蜜蜂,子弹,天空
B:抽类
Hero/Airplane/BIgAirplane/Bee/Bullet/Sky
C:设计成员变量和方法
1.需求分析:
A:设计一个父类、超类:并且让6个对象继承超类,测试
B:给超累添加构造方法;让六个对像分别调用超类
C: 设置对象数组,进行测试
D:在六各子类,派生类中重写
E:画窗体
2.技术分析:
重写和重载:
重写:(Override)
重载:(Overload)
A:给类中添加修饰符
B:给6个派生类中添加图片属性
1):6个类种添加Static
2)在父类中添加静态方法Loadlmage()添加图片
3):六个派生类中static代码块调用Loadlmage()方法
2:技术实现:
修饰符
y/n public protected default private
同一个类 y y y y
同一个包中不同类 y y y
不同包类 y y
不同胞中的类 y
1.需求分析
A:将窗体大小设置成常量
B:画对象:
想画对象先获取图片,针对每个对象能够获取到图片,
获取到图片的行为事共有的,设计到父类中;
每个对象得到图片的行为是不一样的,设计了抽象的方法----getImage();
在不同状态下,得到不同的图片;
状态:设计到父类中,设计常量:Life DEAD; REMOVE
默认状态:state=LIFE
获取图片的同时,需不需要判断当前的装态???? y
每个对象都需要判断。设计到超类,父类中;
而每个对象判断行为都是不一样的,设计普通方法即可;
-----FlyObject:isLife()/isDead()/isRemove()
C:在6个子类中重写getImage()方法
D:得到不同状态下的图片,进行开始画出来;
画对象的行为是共有的,所以涉及到超类中;
每个对象画的方式都是一样的,所以设计为【普通方法】
E:测试,调用即可
设计规则:
1.需求分析
A:敌人入场
产生敌人:在ShootMain类中nextOne()
需要定时加载敌人----enterAction()实现敌人入场;
每400毫秒,获取到敌人,扩容,将敌人添加到数组最后一位
英雄机中发射子弹,hero类设计有一个方法来实现子弹的发射----shoot()
run()方法中,子弹发射shootAction()
每400毫秒。获取到子弹数组,扩容,将子弹数组添加到
C:飞行物移动
D:英雄机随鼠标移动
E:删除越界飞行物
F:设计接口
子弹与敌人碰撞:
子弹:
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
/**
* 子弹
* @author Administrator
*
*/
public class Bullet extends FlyingObject{
private static BufferedImage images;
//静态代码块
static {
images = loadImage("bullet.png");
}
private int speed;//速度
/**构造方法*/
public Bullet(int x, int y){
super(8, 14, x, y);
speed = 2;
}
/**子弹的移动*/
public void step(){
this.y -= speed;
}
/**重写getImage()方法获取到图片*/
@Override
public BufferedImage getImage() {
if (isLife()) {
return images;
}else if(isDead()){
state = REMOVE;//修改状态为删除状态
}
return null;
}
/**检测是否越界*/
@Override
public boolean outOfBounds() {
return this.y <= -this.height;
}
}
大敌机:
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 大敌机:
*
* @author Administrator
*
*/
public class BigAirplane extends FlyingObject implements Enemy{
private static BufferedImage[] images;
// 静态代码块
static {
images = new BufferedImage[5];
for (int i = 0; i < images.length; i++) {
images[i] = loadImage("bigplane" + i + ".png");
}
}
int speed;// 速度
/** 构造方法 */
public BigAirplane() {
super(99, 89);
this.speed = 2;
}
public void step(){
this.y += speed;
}
// 得到图片
int index = 1;
@Override
public BufferedImage getImage() {// 10M
if (isLife()) {
return images[0];
} else if (isDead()) {// 图片的切换
BufferedImage img = images[index++];
if (index == images.length) {
state = REMOVE;
}
return img;
}
/*
* images[index++]; index = 1; 10M images[1] index = 2 返回images[1] 20M
* images[2] index = 3 返回images[2] 30M images[3] index = 4 返回images[3]
* 40M images[4] index = 5 返回images[4]
*/
return null;
}
/**重写得分接口*/
@Override
public int getScore() {
return 3;
}
}
小敌机:
package cn.tedu.shoot;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 小敌机:
* @author Administrator
*
*/
public class Airplane extends FlyingObject implements Enemy{
private static BufferedImage[] images;
//静态代码块
static {
images = new BufferedImage[5];
for (int i = 0; i < images.length; i++) {
images[i] = loadImage("airplane" + i + ".png");
}
}
private int speed;//速度
/**构造方法*/
public Airplane(){
super(49, 36);
this.speed = 5;
}
/**移动*/
public void step(){
this.y += speed;
}
//得到图片
int index = 1;
@Override
public BufferedImage getImage() {//10M
if (isLife()) {
return images[0];
}else if(isDead()){//图片的切换
BufferedImage img = images[index++];
if (index == images.length) {
state = REMOVE;
}
return img;
}
/*images[index++];
* index = 1;
* 10M images[1] index = 2 返回images[1]
* 20M images[2] index = 3 返回images[2]
* 30M images[3] index = 4 返回images[3]
* 40M images[4] index = 5 返回images[4]
*
*/
return null;
}
@Override
public int getScore() {
return 1;
}
}
英雄机
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
/**
* 英雄机:
*
* @author Administrator
*
*/
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 = 6;
doubleFire = 0;//单倍火力
}
/**英雄机的移动:随着鼠标的移动而动*/
public void movedTo(int x, int y){
this.x = x - this.width/2;
this.y = y - this.height/2;
}
/**英雄机的移动*/
public void step(){
System.out.println("图片的切换");
}
int index = 0;
@Override
public BufferedImage getImage() {
// return images[0];
return images[index++/10%images.length];
}
/**英雄机产生子弹*/
public Bullet[] shoot(){
int xStep = this.width/4;
int yStep = 15;
if (doubleFire > 0) {//双倍火力
Bullet[] bs = new Bullet[2];
bs[0] = new Bullet(this.x + xStep * 1, this.y - yStep);
bs[1] = new Bullet(this.x + xStep * 3, this.y - yStep);
doubleFire -= 2;
return bs;
}else{
Bullet[] bs = new Bullet[1];
bs[0] = new Bullet(this.x + xStep * 2, this.y - yStep);
return bs;
}
}
public void addDoubleFire(){
doubleFire += 10;
}
public void addLife(){
life++;
}
/**获得生命*/
public int getLife(){
return life;
}
/**减少生命*/
public void substractLife(){
life--;
}
/**清空火力*/
public void clearDoubleFire(){
doubleFire = 0;
}
}
蜜蜂:
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 蜜蜂:
*
* @author 小二郎
*
*/
public class Bee extends FlyingObject implements Award{
private static BufferedImage[] images;
// 静态代码块
static {
images = new BufferedImage[5];
for (int i = 0; i < images.length; i++) {
images[i] = loadImage("bee" + i + ".png");
}
}
private int xSpeed;// x坐标的速度
private int ySpeed;// y坐标的速度
private int awardType;// 获取奖励的类型
public Bee() {
super(29, 39);
xSpeed = 1;
ySpeed = 2;
Random rand = new Random();
awardType = rand.nextInt(2);// 0 1
}
public void step() {
x += xSpeed;
y += ySpeed;
if (x < 0 || x >= ShootMain.SCREEN_WIDTH - this.width) {
xSpeed *= -1;
}
}
// 得到图片
int index = 1;
@Override
public BufferedImage getImage() {// 10M
if (isLife()) {
return images[0];
} else if (isDead()) {// 图片的切换
BufferedImage img = images[index++];
if (index == images.length) {
state = REMOVE;
}
return img;
}
return null;
}
@Override
public int getAwardType() {
// TODO Auto-generated method stub
return awardType;
}
}
天空:
package cn.tedu.shoot;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
/**
* 天空:
*
* @author Administrator
*
*/
public class Sky extends FlyingObject {
private static BufferedImage images;
// 静态代码块
static {
images = loadImage("background.png");
}
private int speed;// 速度
public int y1;// 第二张图片的坐标
/** 构造方法 */
public Sky() {
super(ShootMain.SCREEN_WIDTH, ShootMain.SCREEN_HEIGHT, 0, 0);
speed = 1;
y1 = -ShootMain.SCREEN_HEIGHT;
}
/** 天空移动 */
public void step() {
y += speed;
y1 += speed;
if (y >= ShootMain.SCREEN_HEIGHT) {
y = -ShootMain.SCREEN_HEIGHT;
}
if (y1 >= ShootMain.SCREEN_HEIGHT) {
y1 = -ShootMain.SCREEN_HEIGHT;
}
}
@Override
public BufferedImage getImage() {
return images;
}
/** 重写父类中的方法 */
@Override
public void paintObject(Graphics g) {
g.drawImage(getImage(), x, y, null);
g.drawImage(getImage(), x, y1, null);
}
}
飞行物得父类
package cn.tedu.shoot;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* 父类:飞行物
*
* @author 小二郎
*
*/
public abstract class FlyingObject {
// 成员变量
protected int width;// 宽
protected int height;// 高
protected int x;// x坐标
protected int y;// y坐标
// 设计三种状态
public static final int LIFE = 0;// 存活
public static final int DEAD = 1;// over
public static final int REMOVE = 2;// 删除
public int state = LIFE;// 当前状态为存活
/** 提供敌人(小敌机+大敌机+蜜蜂) */
public FlyingObject(int width, int height) {
this.width = width;
this.height = height;
Random rand = new Random();
// 小敌机出现的位置
this.x = rand.nextInt(ShootMain.SCREEN_WIDTH - this.width);
this.y = -this.height;
}
/** 提供英雄机+子弹+天空的构造方法 */
public FlyingObject(int width, int height, int x, int y) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
/** 移动的方法 */
public void step() {
}
/** 读取图片 */
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 abstract BufferedImage getImage();
/** 画图片 g:画笔 */
public void paintObject(Graphics g) {
g.drawImage(this.getImage(), this.x, this.y, null);
}
/** 判断当前状态是不是存活的 */
public boolean isLife() {
return state == LIFE;
}
/** 判断当前状态是不是over的 */
public boolean isDead() {
return state == DEAD;
}
/** 判断当前状态是不是删除的 */
public boolean isRemove() {
return state == REMOVE;
}
/** 检测越界的方法 */
public boolean outOfBounds() {
return this.y >= ShootMain.SCREEN_HEIGHT;
}
/* 实现子弹与敌人发生碰撞 other:子弹敌人 */
public boolean hit(FlyingObject other) {
int x1 = this.x - other.width;
int y1 = this.y - other.height;
int x2 = this.x + this.width;
int y2 = this.y + this.height;
int x = other.x;
int y = other.y;
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
}
/** 飞行物over */
public void goDead() {
state = DEAD;// 将对象状态修改为DAED
}
public int getScore() {
// TODO Auto-generated method stub
return 0;
}
}
得分接口
package cn.tedu.shoot;
/**
* 得分接口
* @author 小二郎
*
*/
public interface Enemy {
/*得分*/
public int getScore();
}
奖励接口
package cn.tedu.shoot;
/**
* 得分接口
* @author 小二郎
*
*/
public interface Enemy {
/*得分*/
public int getScore();
}
主函数得类:
package cn.tedu.shoot;
import java.awt.AWTError;
import java.awt.Graphics;
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;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 主函数的类:
*
* @author Administrator
*
*/
public class ShootMain extends JPanel {
public static final int SCREEN_WIDTH = 400;
public static final int SCREEN_HEIGHT = 700;
//起始状态START/RUNNING/PAUSE/GAME_OVER
//默认起始状态
/*
* 鼠标点击事件:
* 开始--运行 结束---开始
* 鼠标移动事件:
* 启动状态:结束----启动
* 暂停状态:鼠标从屏幕里划到外
* 运行状态:从外到内的时候
* 结束状态:英雄机的生命为0
*/
public static final int START = 0;
public static final int RUNNING = 1;
public static final int PAUSE = 2;
public static final int GAME_OVER = 3;
public int state = START;//默认状态
public static BufferedImage start;
public static BufferedImage pause;
public static BufferedImage gameover;
//静态代码块
static{
start = FlyingObject.loadImage("start.png");
pause = FlyingObject.loadImage("pause.png");
gameover = FlyingObject.loadImage("gameover"
+ ".png");
}
private Sky sky = new Sky();
private Hero hero = new Hero();
private FlyingObject[] flys = {};
private Bullet[] bullets = {};
/** 产生敌人对象 */
public FlyingObject nextOne() {
Random rand = new Random();
int type = rand.nextInt(20);
if (type < 5) {
return new Airplane();
} else if (type < 12) {
return new Bee();
} else {
return new BigAirplane();
}
}
/** 实现敌人入场 */
int enterIndex = 0;
public void enterAction() {
enterIndex++;
if (enterIndex % 40 == 0) {
// 获取到敌人
FlyingObject f = nextOne();
// 敌人添加到数组的最后一位上
flys = Arrays.copyOf(flys, flys.length + 1);
flys[flys.length - 1] = f;
}
}
/** 子弹入场 */
int shootIndex = 0;
public void shootAction() {
shootIndex++;
if (shootIndex % 40 == 0) {
Bullet[] bs = hero.shoot();// 获取子弹数组
bullets = Arrays.copyOf(bullets, bullets.length + bs.length);
// 将产生的子弹数组放到源数组中的最后一个元素
System.arraycopy(bs, 0, bullets, bullets.length - bs.length,
bs.length);
}
}
/** 飞行物移动 */
public void stepAction() {
sky.step();
for (int i = 0; i < flys.length; i++) {
flys[i].step();
}
for (int i = 0; i < bullets.length; i++) {
bullets[i].step();
}
}
/**删除越界的飞行物*/
public void outOfBoundsAction(){
int index = 0;//存放不越界数组的下标,个数
//新建不越界的敌人数组
FlyingObject[] flysLive = new FlyingObject[flys.length];
for (int i = 0; i < flys.length; i++) {
//获取到每一个敌人
FlyingObject f = flys[i];
//判断敌人是否不越界
if (!f.outOfBounds()) {//如果不越界,
flysLive[index] = f;
index++;
}
//将不越界的敌人存放到不越界的数组中
}
flys = Arrays.copyOf(flysLive, index);
//System.out.println("index == " + index);
index = 0;
Bullet[] bulletLive = new Bullet[bullets.length];
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];
if (!b.outOfBounds()) {
bulletLive[index] = b;
index++;
}
}
bullets = Arrays.copyOf(bulletLive, index);
}
/**子弹与敌人的碰撞*/
int score = 0;//玩家的得分记录
public void bulletBangAction(){
//遍历所有的子弹
for (int i = 0; i < bullets.length; i++) {
//获取每一个子弹
Bullet b = bullets[i];
//遍历所有的敌人
for (int j = 0; j < flys.length; j++) {
//获取每一个敌人
FlyingObject f = flys[j];
//判断碰撞
if (f.isLife() && b.isLife() && f.hit(b)) {
f.goDead();//敌人over
b.goDead();//子弹over
if (f instanceof Enemy) {//如果撞上的是敌人能得分
Enemy e = (Enemy)f;
score += e.getScore();
}
//如果撞上的是奖励
if (f instanceof Award) {
Award a = (Award)f;
int type = a.getAwardType();
switch (type) {
case Award.DOUBLE_FIRE://火力
hero.addDoubleFire();
break;
case Award.LIFE://生命
hero.addLife();
break;
}
}
}
}
}
}
/**英雄机与敌人发生碰撞*/
public void heroBangAction(){
/*
* 思路:
* 1)借助FlyingObject中的hit()方法检测碰撞
* 2)借助FlyingObject中的goDead()方法over
* 3)在Hero类中设计一个方法实现碰撞之后
* substractLife()减少生命, clearDoubleFire()火力清0
* 4) 在run()方法中实现英雄机与敌人发生碰撞
* heroBangAction();
* 遍历敌人获取到每一个敌人:
* 判断撞上了:
* 敌人over,英雄机减少生命,清空火力
*/
//遍历所有的敌人
for (int i = 0; i < flys.length; i++) {
//获取每一个敌人
FlyingObject f = flys[i];
if (hero.isLife() && f.isLife() && f.hit(hero)) {
f.goDead();
hero.substractLife();//减少生命
hero.clearDoubleFire();//清空火力
}
}
}
/**检测游戏是否结束*/
public void checkGameOverAction(){
//判断英雄机的生命值,
//如果小于0的话,游戏结束,修改状态
if(hero.getLife() <= 0){
state = GAME_OVER;
}
}
/** 测试方法 */
public void action() {// 数组越界、数组空指针异常
//鼠标适配器
MouseAdapter ma = new MouseAdapter() {
/**重写鼠标的移动事件*/
public void mouseMoved(MouseEvent e){
int x = e.getX();
int y = e.getY();
hero.movedTo(x, y);
}
/**重写鼠标的点击事件*/
@Override
public void mouseClicked(MouseEvent e) {
//根据当前状态的不同,进行相应的处理
switch (state) {
case START:
state = RUNNING;
break;
case GAME_OVER:
score = 0;
sky = new Sky();
hero = new Hero();
flys = new FlyingObject[0];
bullets = new Bullet[0];
state = START;//修改状态为开始状态
break;
}
}
/**重写鼠标的移入事件*/
@Override
public void mouseEntered(MouseEvent e) {
if (state == PAUSE) {
state = RUNNING;
}
}
/**重写鼠标的移出事件*/
@Override
public void mouseExited(MouseEvent e) {
if (state == RUNNING) {
state = PAUSE;
}
}
};
this.addMouseListener(ma);//处理鼠标的操作事件
this.addMouseMotionListener(ma);//处理鼠标的移动事件
// 定时器对象
Timer timer = new Timer();
int inters = 10;
timer.schedule(new TimerTask() {
@Override
public void run() {
if (state == RUNNING) {
enterAction();// 敌人入场
shootAction();// 子弹入场
stepAction();// 飞行物移动
outOfBoundsAction();//删除越界的飞行物
bulletBangAction();//子弹与敌人的碰撞
heroBangAction();//英雄机与敌人发生碰撞
checkGameOverAction();//检测游戏是都结束
}
repaint();// 重绘,调用paint方法
}
}, inters, inters);// 计划任务
/*
* 7.30 20 第一次 10 第一次---第二次
*/
}
/** 画对象 */
@Override
public void paint(Graphics g) {
super.paint(g);
sky.paintObject(g);
hero.paintObject(g);
// 画敌人
for (int i = 0; i < flys.length; i++) {
flys[i].paintObject(g);
}
for (int i = 0; i < bullets.length; i++) {
bullets[i].paintObject(g);
}
g.drawString("分数:" + score, 30, 60);
g.drawString("生命:" + hero.getLife(), 30, 80);
switch (state) {//根据不同状态画不同的状态图
case START://开始状态的启动图
g.drawImage(start, 0, 0, null);
break;
case PAUSE://暂停状态的图
g.drawImage(pause, 0, 0, null);
break;
case GAME_OVER://游戏结束的时候状态图
g.drawImage(gameover, 0, 0, null);
break;
}
}
/** 主函数:程序的入口 */
public static void main(String[] args) {
ShootMain sm = new ShootMain();
JFrame jf = new JFrame();
jf.add(sm);// 将画布装在窗体上
jf.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);// 窗体的大小
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);// 居中显示
jf.setVisible(true);
sm.action();
}
}