Shoot射击游戏第八天:
1.英雄机随着鼠标移动:
1)英雄机随着鼠标动为英雄机的行为,所以在Hero中设计moveTo()实现英雄机随着鼠标移动
2)英雄机随着鼠标动为事件触发的,所以在侦听器中重写mouseMoved()鼠标移动事件
在mouseMoved()中:
获取鼠标的x/y坐标,英雄机随着动
(事件、侦听器都是swing相关的内容-------不要求掌握
1)事件:发生了一件事
2)事件处理:发生事之后所做的操作
3)侦听器:
3.1)有一个侦听器对象
3.2)把侦听器装到你家去)
2.删除越界的敌人和子弹:
1)在FlyingObject中设计isOutOfBounds()判断敌人是否越界
在Bullet中重写isOutOfBounds()判断子弹是否越界
2)删除越界的敌人和子弹为定时发生的,所以在run中调用outOfBoundsAction()实现删除越界的敌人和子弹
在outOfBoundsAction()中:
遍历敌人/子弹数组,判断若越界了:
用最后一个敌人/子弹将越界敌人/子弹替换掉,缩容
3.设计EnemyScore得分接口,Airplane和BigAirplane实现接口
设计EnemyAward奖励接口,Bee实现接口
(删除越界的敌人和子弹:
现在的程序运行时间比较长的时候,会特别卡
----原因是: 对象太多了
1秒钟-------2个敌人+3个子弹----共5个
1分钟-------共300个
10分钟------共3000个
10毫秒------遍历30+30-----共60个
1秒钟-------共6000
1分钟-------共360000
10毫秒------遍历3000+3000-----共6000个
1秒钟-------共600000
1分钟-------共36000000)
( 事件 事件处理
鼠标点击 启动状态变为运行状态
鼠标移动 英雄机随着动
鼠标移出 运行状态变为暂停状态
鼠标移入 暂停状态变为运行状态
窗口的状态:
1)启动状态-------------车点着火了,还没有走
2)运行状态-------------车在走着
3)暂停状态-------------碰到红灯,车暂时不走了
4)游戏结束状态---------车熄火了
)
我们昨天看到的飞机飞出了窗口但是并没有在内存中删除,所以我们用数组来删除掉越界的敌人来保证内存的不卡
3.子弹与敌人的碰撞:
1)在FlyingObject中设计isHit()检测碰撞、goDead()飞行物去死 在Hero中设计addLife()增命、addFire()增火力
2)子弹与敌人的碰撞为定时发生的,所以在run中调用bulletBangAction()实现子弹与敌人的碰撞 在bulletBangAction()中: 遍历子弹得子弹,遍历敌人得敌人,判断若都活着并且撞上了: 子弹去死、敌人去死 若被撞敌人能得分,则强转为得分接口, ----玩家增分 若被撞敌人为奖励,则强转为奖励接口, ----获取奖励类型,依据不同的类型来获取不同的奖励
4.画分和画命:
1)在Hero中设计getLife()获取命
2)在World的paint()中: 画分、画命
5.对象的多态:-----被撞的敌人就是多态的
1)作为FlyingObject形态,则能做FlyingObject里面的事
2)作为EnemyScore形态,则能做EnemyScore里面的事
6.为何要强转:
1)若你想访问的东西(getScore())在超类中没有时,就必须强转
2)若你想访问的东西(isLife()、goDead()..)在超类中就有,则不用强转
7.强转之前为何要判断:----不判断有可能会发生类型转换异常
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.isHit(b)) { //若都活着,并且还撞上了
b.goDead(); //子弹去死
f.goDead(); //敌人去死
知识点:
接口:
1)是一种数据类型(引用数据类型)
2)由interface定义
3)只能包含常量和抽象方法
4)接口不能被实例化
5)接口是需在被实现/继承的,实现类/派生类:
必须重写所有抽象方法
6)一个类可以实现多个接口,用逗号分隔
若又继承又实现时,应先继承后实现
7)接口可以继承接口
接口的好处:-----代码复用 2.行为的多态:-----getScore()、getAwardType()都是多态的
1)小敌机、大敌机、大黄蜂getScore()执行的结果不同
2)小蜜蜂、大黄蜂getAwardType()执行的结果不同
多态:
1)意义:
1.1)同一类型的引用指向不同的对象时,有不同的实现 ----行为的多态:cut()、step()、getImage()...
1.2)同一个对象被造型为不同的类型时,有不同的功能 ----对象的多态:我、你、水
2)向上造型/自动类型转换:
2.1)超类型的引用指向派生类的对象
2.2)能造型成为的数据类型: 超类+所实现的接口
2.3)能点出来什么,看引用的类型
3)强制类型转换,成功的条件只有如下两种情况:
3.1)引用所指向的对象,就是该类型
3.2)引用所指向的对象,实现了该接口或继承了该类
4)强转时若不符合如上条件,则发生ClassCastException类型转换异常 建议:在强转之前先通过instanceof来判断引用指向的对象是否是该类型
设计规则:
1.将所有派生类所共有的属性和行为,抽到超类中-------抽共性
2.所有派生类的行为都一样,设计为普通方法
所有派生类的行为都不一样,设计为抽象方法
3.将部分派生类所共有的属性和行为,抽到接口中
接口是对继承的单根性的扩展---------实现多继承
我们上次讲到儿子类只能有一个爸爸类,所以我们要实现继承就要用到了接口(相当于后爸)
我们先建接口
我们这个不是class别看错了是Interface
代码:
package cn.tude;
public interface EnemyAward {
public int FIRE =0;
public int LIFE =1;
public int getAwardType();
}
package cn.tude;
public interface EnemyScore {
public int getScore();
}
package cn.tude;
import java.awt.image.BufferedImage;
import java.util.Random;
public class Airplane extends FlyingObject {
private int speed;
public Airplane() {
super(48, 50);
speed = 2;
}
public void step() {
y+=speed;
}
private int index = 1;
public BufferedImage getImage() {
if (isLife()) {
return Images.airs[0];
} else if (isDead()) {
BufferedImage img = Images.airs[index++];
if (index == Images.airs.length) {
state = REMOVE;
}
return img;
}
return null;
}
}
package cn.tude;
import java.util.Random;
import java.awt.image.BufferedImage;
public class Bee extends FlyingObject{
private int xspeed;//x移动速度
private int yspeed;//y移动速度
private int awardType;//奖励类型
public Bee(){
super(20,50);
Random rand=new Random();
xspeed=1;
yspeed=2;
awardType=rand.nextInt(2);
}
public void step(){
x+=xspeed;
y+=yspeed;
if(x<=0||x>=World.WIDTH-width){
xspeed*=-1;
}
}
private int index=1;
public BufferedImage getImage(){
if(isLife()){
return Images.bees[0];
}else if (isDead()){
BufferedImage img=Images.bees[index++];
if(index==Images.bees.length){
state=REMOVE;
}
return img;
}
return null;
}
}
package cn.tude;
import java.awt.image.BufferedImage;
public class BigAirplane extends FlyingObject {
private int speed;// 移动速度
public BigAirplane() {
super(66, 89);
speed = 2;
}
public void step() {
y += speed;
}
private int index=1;
public BufferedImage getImage(){
if (isLife()){
return Images.bairs[0];
}else if (isDead()){
BufferedImage img =Images.bairs[index++];
if(index==Images.bairs.length){
state=REMOVE;
}
return img;
}
return null;
}
}
package cn.tude;
import java.awt.image.BufferedImage;
public class Bullet extends FlyingObject{
//子弹
private int speed;//移动速度
public Bullet(int x,int y){
super(8,20,x,y);
speed=3;
}
public void step(){
y-=speed;
}
public BufferedImage getImage(){
if (isLife()){
return Images.bullet;
}else if (isDead()){
state=REMOVE;
}
return null;
}
public boolean isOutOfBounds() {
return y<=-height;
}
}
package cn.tude;
import java.util.Random;
import java.awt.image.BufferedImage;
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;
protected int x;
protected int y;
protected int width;
protected int height;
public FlyingObject(int width,int height ){
Random rand =new Random();
// width=rand.nextInt(400-width);
x = rand.nextInt(World.WIDTH - width);
y =-height;
this.width=width;
this.height=height;
}
public FlyingObject(int width,int height ,int x,int y){
this.height=height;
this.width=width;
this.x=x;
this.y=y;
}
public abstract void step();
public abstract BufferedImage getImage();
public boolean isLife(){
return state==LIFE;
}
public boolean isDead(){
return state==DEAD;
}
public boolean isRemove(){
return state==REMOVE;
}
public boolean isOutOfBounds(){
return y>=World.HEIGHT;
}
public boolean isHit(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;
}public void goDead(){
state=DEAD;
}
}
package cn.tude;
import java.awt.image.BufferedImage;
public class Hero extends FlyingObject {
// int width;
// int height;
// int x;
// int y;
private int life;
private int fire;
public Hero() {
super(97, 139, 140, 400);
life = 3;
fire = 0;
}
// 移动
// void step(){//步
// System.out.println("英雄机切换图片了");
// }
public void step() {
}
private int index = 0;
public BufferedImage getImage() {
return Images.heros[index++ % Images.heros.length];
}
public void moveTo(int x,int y){
this.x=x-this.width/2;
this.y=y-this.height/2;
}
public Bullet[] shoot(){
int xspeed =this.width/4;
int yspeed=20;
if(fire>0){
Bullet[] bs=new Bullet[2];
bs[0]=new Bullet(this.x+1*xspeed,this.y-yspeed);
bs[1]=new Bullet(this.x+3*xspeed,this.y-yspeed);
fire -=2;
return bs;
}else {
Bullet[] bs=new Bullet[1];
bs[0]=new Bullet(this.x+2*xspeed-5,this.y-yspeed);
return bs;
}
}
}
package cn.tude;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class Images {
public static BufferedImage sky;
public static BufferedImage bullet;
public static BufferedImage[] heros;
public static BufferedImage[] airs;
public static BufferedImage[] bairs;
public static BufferedImage[] bees;
static {
sky =readImage("background.png");
bullet=readImage("bullet.png");
heros=new BufferedImage[2];
heros[0]=readImage("hero0.png");
heros[1]=readImage("hero1.png");
airs=new BufferedImage[5];
bairs=new BufferedImage[5];
bees=new BufferedImage[5];
airs[0]=readImage("airplane.png");
bairs[0]=readImage("bigairplane.png");
bees[0]=readImage("bee.png");
for (int i=1;i<airs.length;i++){
airs[i]=readImage("bom"+i+".png");
bairs[i]=readImage("bom"+i+".png");
bees[i]=readImage("bom"+i+".png");
}
}
public static BufferedImage readImage(String fileName) {
try {
BufferedImage img = ImageIO.read(FlyingObject.class.getResource(fileName));
return img;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
package cn.tude;
import java.awt.image.BufferedImage;
public class Sky extends FlyingObject{
private int speed;//移动速度
private int y1;//第2张图的y坐标
/**构造方法*/
public Sky(){
super(World.WIDTH,World.HEIGHT,0,0);
speed=1;
y1=-World.HEIGHT;
// System.out.println(y+","+y1);
//测试代码
}
public void step(){
y+=speed;
y1+=speed;
if(y>=World.HEIGHT){
y=-World.HEIGHT;
}
if(y1>=World.HEIGHT){
y1=-World.HEIGHT;
}
}
public BufferedImage getImage(){
return Images.sky;
}public int getY1(){
return y1;
}
}
package cn.tude;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.omg.Messaging.SyncScopeHelper;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.TimerTask;
import java.util.Timer;
import java.util.Random;
import java.util.Arrays;
public class World extends JPanel {
public static final int WIDTH = 400;
public static final int HEIGHT = 700;
private Hero hero = new Hero();
private Sky sky = new Sky();
private FlyingObject[] enemies = {};// 0
private Bullet[] bullets = {};
public FlyingObject nextOne() {
Random rand = new Random();
int type = rand.nextInt(20);
if (type < 5) {
return new Bee();
} else if (type < 14) {
return new Airplane();
} else {
return new BigAirplane();
}
}
private int enterIndex=0;
public void enterAction(){
enterIndex++;
if(enterIndex%40==0){
FlyingObject obj =nextOne();
enemies=Arrays.copyOf(enemies,enemies.length+1);
enemies[enemies.length-1]=obj;
}
}
private int shootIndex=0;
public void shootAction(){
shootIndex++;
if(shootIndex%30==0){
Bullet[] bs=hero.shoot();
bullets=Arrays.copyOf(bullets,bullets.length+bs.length);
System.arraycopy(bs,0,bullets,bullets.length-bs.length,bs.length);
//System.arraycopy(bs,0,bullets,bullets.length-bs.length,bs.length);
//bullets=Arrays.copyOf(bullets,bullets.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(){
for(int i=0;i<enemies.length;i++){
if(enemies[i].isOutOfBounds()){
enemies[i]=enemies[enemies.length-1];
enemies=Arrays.copyOf(enemies, enemies.length-1);
}
for(int d=0;d<bullets.length;d++){
if(bullets[d].isOutOfBounds()){
bullets[d]=bullets[bullets.length-1];
bullets=Arrays.copyOf(bullets, bullets.length-1);
}
}
}
}
public void bulletBangAction(){
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
for(int j=0;j<enemies.length;j++){
FlyingObject p=enemies[j];
if(b.isLife()&&p.isLife()&&p.isHit(b)){
b.goDead();
p.goDead();
}
}
}
}
public void action() {
MouseAdapter m=new MouseAdapter(){
public void mouseMoved(MouseEvent e){
int x=e.getX();//获取鼠标x坐标
int y=e.getY();
hero.moveTo(x, y);
}
};
this.addMouseListener(m);//处理鼠标操作事件
this.addMouseMotionListener(m);//处理鼠标滑动事件
Timer timer = new Timer();
int intervel = 10;// 定时间隔等于(10毫秒走一次)
timer.schedule(new TimerTask() {
public void run() {// 定时干的事
bulletBangAction();
enterAction();
shootAction();
outOfBoundsAction();
System.out.println(enemies.length+","+bullets.length);
//我们用这句话来输出敌人和子弹的内存情况
stepAction();
repaint();
}
}, intervel, intervel);
BufferedImage img = Images.sky;
}
public void paint(Graphics g) {
g.drawImage(sky.getImage(), sky.x, sky.y, null);
g.drawImage(sky.getImage(), sky.x, sky.getY1(), null);
g.drawImage(hero.getImage(),hero.x,hero.y,null);
for(int i=0;i<enemies.length;i++){
FlyingObject f= enemies[i];
g.drawImage(f.getImage(), f.x,f.y,null);
}for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
g.drawImage(b.getImage(),b.x,b.y,null);
}
}
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);
world.action();
}
}
测试结果:
https://download.csdn.net/download/Theshy08/12740617