1.多态
- 意义:
- 同一个对象被造型为不同的类型时,有不同的功能
----对象的多态:我、你、水......-------------所有对象都是多态的(明天总结时详细讨论)
- 同一类型的引用在指向不同的对象时,有不同的实现
----行为的多态:cut()、getImage()、move()......-----所有抽象方法都是多态的
- 向上造型/自动类型转换:
- 超类型的引用指向派生类的对象
- 能点出来什么,看引用的类型
- 能造型成为的类型有:超类+所实现的接口
- 强制类型转换,成功的条件只有如下两种:
- 引用所指向的对象,就是该类型
- 引用所指向的对象,实现了该接口或继承了该类
- 强转时若不符合如上两个条件,则发生ClassCastException类型转换异常
建议:在强转之前先通过instanceof判断引用的对象是否是该类型
> 何时强转:当你想访问的东西超类中没有,就需要强转(哪个类中有就转成哪个类型)
public class MultiTypeDemo {
public static void main(String[] args) {
Aoo o = new Boo();
Boo o1 = (Boo)o; //引用o所指向的对象就是Boo类型
Inter o2 = (Inter)o; //引用o所指向的对象实现了Inter接口
//Coo o3 = (Coo)o; //运行时发生ClassCastException类型转换异常
if(o instanceof Coo){ //false
Coo o4 = (Coo)o;
}else{
System.out.println("o不是Coo类型");
}
}
}
interface Inter{
}
class Aoo{
}
class Boo extends Aoo implements Inter{
}
class Coo extends Aoo{
}
2. 潜艇游戏第九天:
1. 水雷入场:-------后半段
- 水雷对象是由水雷潜艇发射出来的,所以在MineSubmarine中设计shootMine()生成水雷对象
- 水雷入场为定时发生的,所以在run中调用mineEnterAction()实现水雷入场
在mineEnterAction()中:
每1000毫秒,遍历潜艇数组,判断若是水雷潜艇,则强转为水雷潜艇类型,
获取水雷对象obj,mines扩容,将obj添加到mines最后一个元素上
2. 炸弹与潜艇的碰撞:
- 在SeaObject中设计isHit()检测碰撞、goDead()去死
在Battleship中设计addLife()增命
- 炸弹与潜艇的碰撞为定时发生的,所以在run中调用bombBangAction()实现炸弹与潜艇的碰撞
在bombBangAction()中:
遍历所有炸弹得炸弹,遍历所有潜艇得潜艇,判断若都活着并且还撞上了:
潜艇去死、炸弹去死
判断若潜艇能得分,则强转为得分接口,增分
若潜艇能得命,则强转为得命接口,获取命数,战舰增命
3. 画分和画命:
- 在Battleship中设计getLife()获取命数
- 在World类的paint中: 画分和画命
2.1目录
2.1.1Battleship类
package cn.tedu.submarine;
import javax.swing.*;
import java.awt.Graphics;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/**
* 整个游戏世界
*/
public class World extends JPanel {
public static final int WIDTH = 641;//窗口的宽
public static final int HEIGHT = 479;//窗口的高
private Battleship ship = new Battleship();//战舰
private SeaObject[] submarines = {};//潜艇数组(侦察潜艇,鱼雷潜艇,水雷潜艇)
private Mine[] mines = {};//水雷数组
private Bomb[] bombs = {};//炸弹数组
//玩家得分
private int score = 0;
public void action() {
KeyAdapter k = new KeyAdapter() {
/**
* 按键按下事件
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
//判断按的是不是空格键
if (e.getKeyCode() == KeyEvent.VK_LEFT){
ship.moveLeft();
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
ship.moveRight();
}
}
/**
* 重写keyReleased()按键抬起事件
* @param e
*/
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_SPACE){
Bomb bomb = ship.shootBomb();
bombs = Arrays.copyOf(bombs,bombs.length+1);
bombs[bombs.length-1] = bomb;
}
}
};
this.addKeyListener(k);//添加键盘的侦听器
Timer timer = new Timer();
int interval = 10;
timer.schedule(new TimerTask() {
@Override
public void run() {
submarineEnterAction();//敌人入场
minesEnterAction();//水雷入场
submarineMove();//潜艇移动
imageChuJie();//判断图片出界删除
bombBangAction();//炸弹碰撞潜艇
mineBangAction();//
repaint();//重新画一下
}
}, interval, interval);
}
public void mineBangAction() {
for (int i = 0; i < mines.length; i++) {
Mine m = mines[i];
if (m.isLive() && ship.isLive() && m.isHit(ship)){
int life = ship.getLife();
life--;
ship.setLife(life);
}
}
}
/**
* 物块碰撞
*/
public void bombBangAction() {
//遍历所有炸弹
for (int i = 0; i < bombs.length; i++) {
Bomb b = bombs[i];
for (int j = 0; j < submarines.length; j++) {
SeaObject s = submarines[j];
//若都或者并且还撞上了
if(b.isLive() && s.isLive() && s.isHit(b)){
s.goDead();//潜艇去死
b.goDead();//炸弹去死
//判断是不是加分的
if (s instanceof EnemyScore){
score+=((EnemyScore) s).getScore();
}
//判断是不是加命的
if (s instanceof EnemyLife){
int num = ((EnemyLife) s).getLife();
ship.addLife(num);
}
}
}
}
}
/**
* 图片出界删除方法
*/
public void imageChuJie() {
for (int i = 0; i < submarines.length; i++) {
if (submarines[i].x>WIDTH||submarines[i].isDeal()){
submarines[i] = submarines[submarines.length-1];
submarines = Arrays.copyOf(submarines,submarines.length-1);
}
}
for (int i = 0; i < bombs.length; i++) {
if (bombs[i].y>HEIGHT||bombs[i].isDeal()){
bombs[i] = bombs[bombs.length-1];
bombs = Arrays.copyOf(bombs,bombs.length-1);
}
}
for (int i = 0; i < mines.length; i++) {
if (mines[i].y<150||mines[i].isDeal()){
mines[i] = mines[mines.length-1];
mines = Arrays.copyOf(mines,mines.length-1);
}
}
}
/**
* 潜艇移动
*/
public void submarineMove() {
for (int i = 0; i < submarines.length; i++) {
submarines[i].move();
}
for (int i = 0; i < bombs.length; i++) {
bombs[i].move();
}
for (int i = 0; i < mines.length; i++) {
mines[i].move();
}
}
private int mineEnterIndex = 0;//水雷入场计数
/**
* 水雷入场
*/
public void minesEnterAction() {//没10个毫秒走一次
mineEnterIndex++;//没10毫秒增1
if (mineEnterIndex % 100 == 0){
for (int i = 0; i < submarines.length; i++) {
if (submarines[i] instanceof MineSubmarine){
MineSubmarine ms = (MineSubmarine)submarines[i];
Mine mine = ms.shootMine();
mines = Arrays.copyOf(mines,mines.length+1);
mines[mines.length-1] = mine;
}
}
}
}
private int subEnterIndex = 0;
/**
* 敌人入场
*/
public void submarineEnterAction() {
subEnterIndex++;
if (subEnterIndex%40 == 0){
SeaObject obj = nextSubmarine();
submarines = Arrays.copyOf(submarines,submarines.length+1);
submarines[submarines.length-1]=obj;
}
}
/**
* 生成潜艇对象
*/
public SeaObject nextSubmarine() {
Random random = new Random();
int type = random.nextInt(20);
if (type < 10) {
return new ObserverSubmarine();
} else if (type < 15) {
return new TorpedoSubmarine();
} else {
return new MineSubmarine();
}
}
/**
* 重写JPanel中的paint()画 g 画笔
*
* @param g
*/
@Override
public void paint(Graphics g) {
Images.sea.paintIcon(null, g, 0, 0);//海洋图片
ship.paintImage(g);
//画敌人
for (int i = 0; i < submarines.length; i++) {
submarines[i].paintImage(g);
}
//画水雷
for (int i = 0; i < mines.length; i++) {
mines[i].paintImage(g);
}
//画炸弹
for (int i = 0; i < bombs.length; i++) {
bombs[i].paintImage(g);
}
g.drawString("SCORE:"+score,10,25);
g.drawString("LIFE:"+ship.getLife(),10,45);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
World world = new World();
world.setFocusable(true);
frame.add(world);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(WIDTH + 16, HEIGHT + 39);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
world.action();
}
}
2.1.2Bomb类
package cn.tedu.submarine;
import javax.swing.*;
import java.util.Objects;
/**
* 炸弹
*/
public class Bomb extends SeaObject{
public Bomb(int x , int y) {
super(9,12,x,y,3);
}
/**
* 炸弹移动的方法
*/
@Override
public void move() {
y += speed;
}
@Override
public ImageIcon getImage() {
return Images.bomb;
}
}
2.1.3EnemyLife接口
package cn.tedu.submarine;
public interface EnemyLife {
/**
* 得命
*/
int getLife();
}
2.1.4EnemyScore接口
package cn.tedu.submarine;
public interface EnemyScore {
int getScore();
}
2.1.5Images类
package cn.tedu.submarine;
import javax.swing.ImageIcon;
public class Images {
/**
* 背景图
*/
public static ImageIcon sea;
/**
* 战舰图
*/
public static ImageIcon battleship;
/**
* 炸弹图片
*/
public static ImageIcon bomb;
/**
* 游戏结束
*/
public static ImageIcon gameover;
/**
* 水雷图片
*/
public static ImageIcon mine;
/**
* 水雷潜艇
*/
public static ImageIcon minesubm;
/**
* 侦察潜艇
*/
public static ImageIcon obsersubm;
/**
* 鱼类潜艇
*/
public static ImageIcon torpesubm;
/**
* 初始化图片
*/
static {
battleship = new ImageIcon("img/battleship.png");
sea = new ImageIcon("img/sea.png");
bomb = new ImageIcon("img/bomb.png");
gameover = new ImageIcon("img/gameover.png");
mine = new ImageIcon("img/mine.png");
minesubm = new ImageIcon("img/minesubm.png");
obsersubm = new ImageIcon("img/obsersubm.png");
torpesubm = new ImageIcon("img/torpesubm.png");
}
// /**
// * 测试图片
// * @param args
// */
// public static void main(String[] args) {
// //返回8表示成功了
// System.out.println(battleship.getImageLoadStatus());
// }
}
2.1.6Mine类
package cn.tedu.submarine;
import javax.swing.*;
import java.util.Objects;
/**
* 水雷
*/
public class Mine extends SeaObject{
public Mine(int x , int y) {
super(11,11,x,y,1);
}
/**
* 水雷移动的方法
*/
@Override
public void move() {
y-=speed;
}
@Override
public ImageIcon getImage() {
return Images.mine;
}
}
2.1.7MineSubMarine类
package cn.tedu.submarine;
import javax.swing.*;
import java.util.Objects;
import java.util.Random;
/**
* 水雷潜艇
*/
public class MineSubmarine extends SeaObject implements EnemyLife{
public MineSubmarine() {
super(63,19);
}
/**
* 水雷潜艇移动
*/
@Override
public void move() {
x+=speed;
}
@Override
public ImageIcon getImage() {
return Images.minesubm;
}
/**
* 发射水雷---生成水雷对象
* @return
*/
public Mine shootMine(){
return new Mine(this.x+this.width,this.y-11);
}
@Override
public int getLife() {
return 1;
}
}
2.1.8ObserverSubMarine类
package cn.tedu.submarine;
import javax.swing.*;
import java.util.Objects;
import java.util.Random;
/**
* 侦察潜艇
*/
public class ObserverSubmarine extends SeaObject implements EnemyScore{
public ObserverSubmarine() {
super(63,19);
}
/**
* 侦察潜艇移动
*/
@Override
public void move() {
x+=speed;
}
@Override
public ImageIcon getImage() {
return Images.obsersubm;
}
@Override
public int getScore() {
return 10;
}
}
2.1.9SeaObject类
package cn.tedu.submarine;
import javax.swing.*;
import java.awt.*;
import java.util.Random;
/**
* 海洋对象
*/
public abstract class SeaObject {
public static final int LIVE = 0;//或者的
public static final int DEAL = 1;//死了的
protected int state = LIVE;//当前状态(默认是活着的)
/**
* 成员变量一般都要private的
* 此处设计为protected
* 因为还没有讲到getter/setter
*/
/**
* 宽
*/
protected int width;
/**
* 高
*/
protected int height;
/**
* x轴
*/
protected int x;
/**
* y轴
*/
protected int y;
/**
* 速度
*/
protected int speed;
public SeaObject(int width,int height,int x , int y,int speed){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speed = speed;
}
public SeaObject(int width,int height){
this.width = width;
this.height = height;
Random rand = new Random();
x = -width;
y = rand.nextInt(World.HEIGHT-height-150+1 ) +150;
this.speed = rand.nextInt(3)+1;
}
/**
* 移动的方法
*/
public abstract void move();
/**
* 获取对象的图片
*/
public abstract ImageIcon getImage();
/**
* 判断是活着的
* @return
*/
public boolean isLive(){
return state == LIVE;
}
/**
* 判断是死的吗
* @return
*/
public boolean isDeal(){
return state == DEAL;
}
/**
* 画图片
* @param g
*/
public void paintImage(Graphics g){
if (isLive()){//若或者的
//不要求掌握
this.getImage().paintIcon(null,g,this.x,this.y);
}
}
/**
* 检测碰撞的算法
* @param other
* @return
*/
public boolean isHit(SeaObject 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 =DEAL;//将当前装填修改为DEAD死了的
}
}
2.1.10TorpedoSubmarine类
package cn.tedu.submarine;
import javax.swing.*;
import java.util.Objects;
import java.util.Random;
/**
* 鱼类潜艇
*/
public class TorpedoSubmarine extends SeaObject implements EnemyScore{
public TorpedoSubmarine() {
super(64,20);
}
/**
* 鱼类潜艇移动的方法
*/
@Override
public void move() {
x+=speed;
}
@Override
public ImageIcon getImage() {
return Images.torpesubm;
}
@Override
public int getScore() {
return 40;
}
}
2.1.11World(测试类)
package cn.tedu.submarine;
import javax.swing.*;
import java.util.Objects;
import java.util.Random;
/**
* 侦察潜艇
*/
public class ObserverSubmarine extends SeaObject implements EnemyScore{
public ObserverSubmarine() {
super(63,19);
}
/**
* 侦察潜艇移动
*/
@Override
public void move() {
x+=speed;
}
@Override
public ImageIcon getImage() {
return Images.obsersubm;
}
@Override
public int getScore() {
return 10;
}
}
3.补充
3.1体会接口的好处:
//复用性好、扩展性好、维护性好------------------高质量代码
//被撞的是ObserveSubmarine-----调用ObserveSubmarine的getScore()-----10分
//被撞的是TorpedoSubmarine-----调用TorpedoSubmarine的getScore()-----40分
//被撞的是NuclearSubmarine-----调用NuclearSubmarine的getScore()-----80分
if(s instanceof EnemyScore){ //------适用于所有实现EnemyScore接口的
EnemyScore es = (EnemyScore)s;
score += es.getScore();
}
//被撞的是MineSubmarine--------调用MineSubmarine的getLife()---------1
//被撞的是NuclearSubmarine-----调用NuclearSubmarine的getLife()------3
if(s instanceof EnemyLife){ //-------适用于所有实现EnemyLife接口的
EnemyLife el = (EnemyLife)s;
int num = el.getLife();
ship.addLife(num);
}
//复用性差、扩展性差、维护性差------------------垃圾代码
if(s instanceof ObserveSubmarine){ //---------只能适用于ObserveSubmarine的
ObserveSubmarine os = (ObserveSubmarine)s;
score += os.getScore();
}
if(s instanceof TorpedoSubmarine){ //---------只能适用于TorpedoSubmarine的
TorpedoSubmarine ts = (TorpedoSubmarine)s;
score += ts.getScore();
}
if(s instanceof MineSubmarine){ //---------只能适用于MineSubmarine的
MineSubmarine ms = (MineSubmarine)s;
int num = ms.getLife();
ship.addLife(num);
}
if(s instanceof NuclearSubmarine){ //---------只能适用于NuclearSubmarine
NuclearSubmarine ns = (NuclearSubmarine)s;
score += ns.getScore();
int num = ns.getLife();
ship.addLife(num);
}
3.2碰撞检测图:
3.3明日单词:
1)subtract:减
2)gameover:结束
3)running:运行