JSD-2204-面向对象-接口-潜艇游戏--Day14

这篇博客介绍了Java中接口的概念及其在潜艇游戏中如何使用。主要内容包括接口的定义、潜艇游戏的更新,如炸弹入场、战舰移动以及删除越界对象的逻辑。同时,讲解了新添加的EnemyLife和EnemyScore接口,以及各对象之间的类型关系和设计原则。

1.接口

   - 是一种数据类型(引用数据类型) 
   - 由interface定义
   - 只能包含常量和抽象方法
   - 接口不能被实例化
   - 接口是需要被实现/继承的,实现类/派生类:必须重写所有抽象方法
   - 一个类可以实现多个接口,用逗号分隔,若又继承又实现时,应先继承后实现
   - 接口可以继承接口

   /*
     演示接口的语法:
     1)接口中的数据,默认都是常量。接口中的方法,默认都是抽象的。
     2)接口中的所有内容的访问权限都一定是public的
    */
   interface Inter{
       public static final int NUM = 5;
       public abstract void show();
       int COUNT = 5; //默认public static final
       void test();   //默认public abstract
       //int number; //编译错误,常量必须声明同时初始化
       //void show(){} //编译错误,抽象方法不能有方法体
   }
   
   //演示接口的实现:
   interface Inter1{
       void show();
       void test();
   }
   class Aoo implements Inter1{
       public void show(){} //重写接口中的抽象方法时,权限必须是public的
       public void test(){}
   }
   
   //演示接口的多实现:
   interface Inter2{
       void show();
   }
   interface Inter3{
       void test();
   }
   abstract class Boo{
       abstract void say();
   }
   class Coo extends Boo implements Inter2,Inter3{
       public void show(){}
       public void test(){}
       void say(){}
   }
   
   //演示接口继承接口:
   interface Inter4{
       void test();
   }
   interface Inter5 extends Inter4{ //自己的show()+继承过来的test()
       void show();
   }
   class Doo implements Inter5{
       public void show(){}
       public void test(){}
   }
   
   public class InterfaceDemo {
       public static void main(String[] args) {
           //Inter5 o1 = new Inter5(); //编译错误,接口不能被实例化
           Inter5 o2 = new Doo(); //向上造型
           Inter4 o3 = new Doo(); //向上造型
       }
   }

2.潜艇游戏第八天:

1. 炸弹入场:

   - 炸弹是由战舰发射出来的,所以在Battleship中设计shootBomb()生成炸弹对象

   - 炸弹入场为事件触发的,所以在侦听器中重写keyReleased()按键抬起事件/keyPressed()按键按下事件,判断若按下的是空格键:

     ​    获取炸弹对象obj,bombs扩容,将obj添加到bombs最后一个元素上

2. 战舰移动:

   - 战舰移动为战舰的行为,所以在Battleship中设计moveLeft()左移、moveRight()右移

   - 战舰移动为事件触发的,所以在侦听器的重写keyReleased()中:

     ​    判断若抬起的是左键头,则战舰左移

     ​    判断若抬起的是右键头,则战舰右移

3. 删除越界的海洋对象:

   - 在SeaObject中设计isOutOfBounds()检测潜艇是否越界,在Bomb和Mine中重写isOutOfBounds()检测炸弹和水雷是否越界

   - 删除越界的海洋对象为定时发生的,所以在run()中调用outOfBoundsAction()实现删除越界的海洋对象

     在outOfBoundsAction()中:

     ​    遍历潜艇数组,判断若越界了则:将越界的替换为最后一个元素,缩容

     ​    遍历水雷数组,判断若越界了则:将越界的替换为最后一个元素,缩容

     ​    遍历炸弹数组,判断若越界了则:将越界的替换为最后一个元素,缩容

4. 设计EnemyScore得分接口,ObserveSubmarine和TorpedoSubmarine实现得分接口

   设计EnemyLife得分接口,MineSubmarine实现得命接口

2.1目录展示

2.1.1Battleship类

package cn.tedu.submarine;

import javax.swing.*;
import java.util.Objects;

/**
 * 战舰
 */
public class Battleship extends SeaObject{
    /**
     * 命
     */
    private int life;


    public Battleship() {
        super(66,26,270,124,5);
        this.life = 5;
    }


    /**
     * 战舰移动
     */
    @Override
    public void move() {

    }
    /**
     * 战舰想左边移动
     */
    public  void moveLeft(){
        if (this.x>0){
            this.x-=speed;
        }
    }

    /**
     * 战舰想右边移动
     */
    public  void moveRight(){
        if (this.x<World.WIDTH-this.width){
            this.x+=speed;
        }
    }
    @Override
    public ImageIcon getImage() {
        return Images.battleship;
    }


    /**
     * 发射炸弹的方法
     */
    public Bomb shootBomb(){
        return new Bomb(this.x,this.y);
    }


}


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.3Images类

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.4Mine类

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.5MineSubMarine类

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.6ObserverSubMarine类

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.7SeaObject类

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);
        }
    }
}


2.1.8TorpedoSubmarine类

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.9World

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 = {
            new Mine(200, 300)
    };//水雷数组
    private Bomb[] bombs = {
            new Bomb(180, 130)
    };//炸弹数组

    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();//判断图片出界删除
                repaint();//重新画一下
            }
        }, interval, interval);
    }

    /**
     * 图片出界删除方法
     */
    public void imageChuJie() {
        for (int i = 0; i < submarines.length; i++) {
            if (submarines[i].x>WIDTH){
                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] = 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] = 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){

        }
    }


    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);
        }
    }

    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();


    }


}

3.补充

3.1类型间的关系:

   - 类和类----------------------------继承extends
   - 接口和接口----------------------继承extends
   - 类和接口-------------------------实现implements

3.2对象可以向上造型为:

超类+所实现的接口

3.3设计规则:

   - 将所有派生类所共有的属性和行为,抽到超类中------------------抽共性

   - 若对象的行为都一样,设计为普通方法

     若对象的行为都不一样,设计为抽象方法

   - 将部分派生类所共有的属性和行为,抽到接口中

     接口是对继承单根性的扩展------------------实现多继承

     接口相当于制定了一个标准、规范---------随着后面课程的深入才能理解得更好

3.4如何调错:

   - 快速锁定问题方法:
     - 将所有方法的调用代码都注释掉
     - 然后一个一个的放开,放开哪个出错了,说明问题就在哪个方法中
   - 打桩:System.out.println(数据);-----------需要慢慢来,调得多了就有经验了

3.5明日单词:

   1)hit:撞
   2)other:另一个
   3)instanceof:实例
   4)cut:剪
   5)cast:类型
   6)go:去
   7)draw:画

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值