学习笔记——java潜艇游戏项目

第一天任务

创建了6个类,创建World类并测试

第二天任务

给六个类添加构造方法,并测试

第三天任务

1.设计深水炸弹、侦查潜艇、鱼雷潜艇、水雷潜艇、水雷和炸弹的数组,并测试
2.设计SeaObject超类,设计六个类继承超类
3.给SeaObject设计两个构造方法,六个派生类分别调用

第四天任务

1.将侦查潜艇、鱼雷潜艇、水雷潜艇数组
2.在六个类中重写move()移动,并测试
3.画窗口

第五天任务

1.给类中成员添加访问控制修饰符
2.创建Images图片类

第六天任务

1.画海洋图,画对象:

1.在SeaObject中设计抽象方法getImage()获取图片
2.在子类中重写getImage()获取图片
3.在SeaObject中设计状态常量LIVE、DEAD、state变量表示当前状态并设计isLIVE()、isDEAD()判断对象状态
4.在SeaObject中设计paintImage()画图片
5.在world中调用方法画窗口和对象
> 准备对象,重写paint() 方法,调用paintImage()方法

2.设计窗口的宽和高为常量

第七天任务

1.潜艇入场:

1潜艇在窗口中产生,即在World窗口类中设计nextSubmarine()生成潜艇对象
2.设置定时器实现潜艇对象自动生成:在run中调用submarineEnterAction()实现潜艇入场,在submarineEnterAction()中:每400毫秒获取潜艇对象,submarines数组扩容,将新生成的对象添加到submarines的最后一个元素上。在run()中调用submarineEnterAction()后需再调用repaint()方法重画

2.水雷入场:

1在MineSubmarine中设计shootMine()生成水雷对象
2.水雷对象定时出现,在run中调用MineEnterAction()实现水雷入场
在MineEnterAction()中:(见第九天)

3.海洋对象移动(不包括战舰)

1.移动为所有对象共有行为,在父类SeaObject中设计抽象move(),并在6个派生类中重写
2.海洋对象移动定时发生,在run中调用moveAction()实现海洋对象移动
在moveAction()中:遍历所有潜艇让潜艇移动,同理,遍历水雷,遍历炸弹

第八天任务

1.深水炸弹:

1在Battleship中设计shootBomb()发射炸弹
2.发出炸弹为事件触发,在侦听器中重写keyReleased()按键抬起事件:判断若按键是空格,则获取炸弹对象,bombs数组扩容,并将新对象加到数组最后一位上

2.战舰移动:

1.在Battleship中设计moveLeft()左移、moveRight()右移
2.战舰移动为事件触发,在侦听器的keyReleased()按键抬起事件中:判断按键,若是左方向键,则左移,右方向键,则右移

3.删除越界对象(潜艇、水雷、炸弹)

1.在SeaObject中设计isOutBounds()检测潜艇是否越界
在Bomb/Mine中重写isOutOfBounds()检测炸弹鱼雷是否越界
2.删除越界的对象时定时器中生成的,所以在run中调outBoundsAction()删除越界对象,在BoundsAction()中:遍历所有海洋对象,判断是否越界,若越界则将越界元素替换为最后一个元素,并缩容(缩容后该元素被删除)

4.设计接口:

1设计EnemyScore得分接口,侦查潜艇与鱼雷潜艇实现得分
2.设计EnemyLife得命接口,水雷潜艇实现得命接口

第九天任务

1.水雷入场:

1在MineSubmarine中设计shootMine()生成水雷对象
2.水雷对象定时出现,在run中调用MineEnterAction()实现水雷入场
在MineEnterAction()中:每1000毫秒,遍历所有潜艇,判断是水雷潜艇则强转为水雷潜艇类型,获取水雷对象,mines扩容,将对象添加到数组末尾

2.深水炸弹与潜艇的碰撞:

1.在SeaObject中设计isHit()检测碰撞,goDead()判定死亡;在Battleship中设计addLife()增命
2.炸弹与潜艇的碰撞是定时其中的对象发生的,所以在run中调用bombBangAction()实现炸弹与潜艇碰撞
在bombBangAction()中:
遍历所有炸弹和潜艇,判断两者是否相撞:
若撞上:潜艇消失、炸弹消失
并判断,若为分,则强转为得分接口,玩家得分,
若为命,则强转为得命接口,战舰增命

3.画分和画命:

1在Battleship中设计getLife()获取命数
2.在paint()中:画分、画命

第十天任务

1.水雷与战舰的碰撞:

1.在Battleship中设计subtractLife()减命
2.在run中调用mineBangAction()实现水雷与战舰碰撞
		在mineBangAction()中:遍历所有水雷,并判断是否相撞,撞上则水雷消失,潜艇减命

2.检测游戏结束:

1.调用Battleship中的getLife()获取命数
2.在run中调用checkGameOverAction()检测游戏结束
	在checkGameOverAction()中:判断若战舰的命数<=0,游戏结束了,将state设置为GAME_OVER

3.画状态:

1.在World中设计RUNNING、GAME_OVER状态常量,同时设计state变量表示窗口当前状态,
2.在paint()中:
	1.游戏结束时,显示游戏结束图
	2.运行时,显示海洋图、对象、分数和命数

潜艇游戏需求

1.所参与的角色:
战舰、深水炸弹、侦查潜艇、鱼雷潜艇、水雷潜艇、水雷
2.角色间的关系:

  • 战舰发射深水炸弹
  • 深水炸弹可以打潜艇(侦查潜艇、鱼雷潜艇、水雷潜艇)
    • 若打中:
      • 潜艇消失、
      • 深水炸弹消失
    • 得东西:
      • 打掉侦查潜艇,玩家得10分
      • 打掉鱼雷潜艇,玩家得40分
      • 打掉水雷潜艇,战舰得1条命
  • 水雷潜艇可以发射水雷
  • 水雷可以击打战舰,
    • 若打中:
      • 水雷消失,
      • 战舰减一条命(当命数为0时游戏结束)

    画窗口

    swing组件------已被淘汰
    如下代码实现窗口建立
      import javax.swing.JFrame;
      import javax.swing.JPanel;//1.
      public class World extends JPanel{//2.
      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(641+16,479+39);
         frame.setLocationRelativeTo(null);
         frame.setVisible(true);
        }
      }
    

下面是具体代码:

各个对象类

战舰类

import javax.swing.ImageIcon;
//战舰
public class Battleship extends SeaObject{
    private int life;//命数
    public Battleship(){
        super(66,26,270,124,20);
        life = 5;
    }
    /*战舰移动*/
    public void move(){
    }
    /*重写getImage()获取图片*/
    public ImageIcon getImage(){
        return Images.battleship;
    }
    /*战舰放出炸弹*/
    public Bomb shoot(){
        return new Bomb(this.x,this.y);//将战舰坐标定为炸弹初始位置
    }
    /*左移*/
    public void moveLeft(){//左移
        x -= speed;
    }
    /*右移*/
    public void moveRight(){//右移
        x += speed;
    }
    /*战舰增命*/
    public void addLife(int num){
        life += num;
    }
    /*获取战舰的命数*/
    public int getLife(){
        return life;  //返回命数
    }
    /*战舰减命*/
    public void subtractLive(){
        life--;
    }
}

侦查潜艇类

import javax.swing.ImageIcon;
//侦查潜艇
public class ObserveSubmarine extends SeaObject implements EnemyScore{
    //构造方法
    public ObserveSubmarine(){
        super(63,19);
    }

    /*重写移动move()*/
    public void move(){
        x += speed;//x+(向右)
    }

    /*重写getImage()获取图片*/
    public ImageIcon getImage(){
        return Images.obsersubm;
    }

    /*重写getScore()得分*/
    public int getScore(){
        return 10;
    }
}

水雷潜艇类

import javax.swing.ImageIcon;
//水雷潜艇
public class MineSubmarine extends SeaObject implements EnemyLife{
    //构造方法
    public MineSubmarine(){
        super(63,19);
    }

    /*重写移动move()*/
    public void move(){
        x += speed;//x+(向右)
    }

    /*重写getImage()获取图片*/
    public ImageIcon getImage(){
        return Images.minesubm;
    }

    /**潜艇发射水雷*/
    public Mine shootMine(){
        int x = this.x+this.width;
        int y = this.y-5;
        return new Mine(x,y);
    }

    /*重写getLife()得命*/
    public int getLife(){
        return 1;
    }
}

鱼雷潜艇类

import javax.swing.ImageIcon;

//鱼雷潜艇
public class TorpedoSubmarine extends SeaObject implements EnemyScore{
    //构造方法
    public TorpedoSubmarine(){
        super(64,20);
    }
    /*重写移动move()*/
    public void move(){
        x += speed;//x+(向右)
    }
    /*重写getImage获取图片*/
    public ImageIcon getImage(){
        return Images.torpesubm;
    }

    /*重写getScore()得分*/
    public int getScore(){
        return 40;
    }
}

深水炸弹类

import javax.swing.ImageIcon;
//深水炸弹
public class Bomb extends SeaObject{
    //构造方法
    public Bomb(int x,int y){
        super(9,12,x,y,3);
    }
    public void move(){
        y += speed;//向下
    }
    public ImageIcon getImage(){
        return Images.bomb;
    }

    /*重写检测炸弹越界*/
    public boolean isOutOfBounds(){
        return this.y>=World.HEIGHT;
    }


}

水雷类

import javax.swing.ImageIcon;
//水雷
public class Mine extends SeaObject{
    //构造方法
    public Mine(int x,int y){//每个水雷的x/y初始坐标都是不一样的
        super(11,11,x,y,1);//
    }
    /*重构移动方法*/
    public void move(){
        y -= speed;//向上
    }
    /*重写getImage()获取图片*/
    public ImageIcon getImage(){
        return Images.mine;
    }

    /*检测潜艇越界*/
    public boolean isOutOfBounds(){
        return this.y<=150-height;
    }
}

海洋对象类

//海洋对象
import java.util.Random;
import java.awt.Graphics;
import javax.swing.ImageIcon;

public abstract class SeaObject {
    public static final int LIVE = 0;//活着的
    public static final int DEAD = 1;//死了的
    protected int state = LIVE;//当前状态(默认为活着的)

    protected int width;
    protected int height;
    protected int x;
    protected int y;
    protected int speed;

    /**
     * 专门给侦查潜艇,水雷潜艇,鱼雷潜艇提供
     */
    //因为三种潜艇的宽高不一样,所以数据不能写死,需传参写活
    //因为三种潜艇的x/y/speed是一样的,所以数据可以写死,不需要传参
    public SeaObject(int width, int height) {
        this.width = width;
        this.height = height;
        x = -width;
        Random rand = new Random();
        y = rand.nextInt(World.HEIGHT - height - 150 + 1) + 150;//生成
        speed = rand.nextInt(3) + 1;//生成1~300的随机数
    }

    /**
     * 专门给水雷,深水炸弹,战舰提供
     */
    //因为战舰/炸弹/水雷的宽/高/x/y/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 abstract void move();

    /**
     * 获取对象的图片
     */
    public abstract ImageIcon getImage();

    /**
     * 判断对象是否活着
     */
    public boolean isLive() {
        return state == LIVE;//若当前状态为LIVE,则返回true表示活着的,否者返回false
    }

    /**
     * 判断对象是否死亡
     */
    public boolean isDead() {
        return state == DEAD;//若当前状态为DEAD,则返回true表示死亡,否者返回false
    }

    /**
     * 画对象 g:画笔
     */
    public void paintImage(Graphics g) {
        if (this.isLive()) {//若活着
            this.getImage().paintIcon(null, g, this.x, this.y);
        }
    }

    /*检测潜艇越界*/
    public boolean isOutOfBounds(){
        return this.x>=World.WIDTH;
    }

    /*检测碰撞  this指一个对象 other另一个对象*/
    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 = DEAD;
    }
}

图片类

import javax.swing.ImageIcon;

public class Images {
    //公开的  静态的  图片数据类型    变量名
    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 sea;//海洋图
    public static ImageIcon torpesubm;//游戏结束图

    /*导入图片对象*/
    static { //初始化静态图片
        battleship = new ImageIcon("img/battleship.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");
        sea = new ImageIcon("img/sea.png");
        torpesubm = new ImageIcon("img/torpesubm.png");
    }

}

接口

public interface EnemyLife {
    /*得命*/
    public int getLife();
}

public interface EnemyScore {
    /*得分*/
    public int getScore();
}

测试类

package cn.tedu.submarine;
//整个游戏世界
import javax.swing.JFrame;
import javax.swing.JPanel;//1.
import java.awt.Graphics;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class World extends JPanel{//2.
    public static final int WIDTH = 641;//窗口的宽
    public static final int HEIGHT = 479;//窗口的高

    public static final int RUNNING = 0;
    public static final int GAME_OVER = 1;
    private int state = RUNNING;

    private Battleship ship = new Battleship();//战舰
    private SeaObject[] submarines = {
            new ObserveSubmarine(),//侦查
            new TorpedoSubmarine(),//鱼雷
            new MineSubmarine()//水雷
    };//潜艇(侦查潜艇、鱼雷潜艇、水雷潜艇)
    private Mine[] mines = {
    };//水雷
    private Bomb[] bombs = {
    };//深水炸弹

    /**生成潜艇(侦查潜艇、鱼雷潜艇、水雷潜艇)对象*/
    public SeaObject nextSubmarine(){
        Random rand =new Random();
        int type = rand.nextInt(20);
        if (type<10){//0-9返回侦查潜艇
            return new ObserveSubmarine();
        }else if (type<15){//10-14返回侦查潜艇
            return new TorpedoSubmarine();
        }else {//15-19返回水雷潜艇
            return new MineSubmarine();
        }
    }

    private int suEnterIndex = 0;
    /**潜艇入场*/
    public void submarineEnterAction(){//每10毫秒走一次
        suEnterIndex++;
        if (suEnterIndex%40==0){//控制多长时间走一次
            SeaObject obj = nextSubmarine();
            submarines = Arrays.copyOf(submarines,submarines.length+1);
            submarines[submarines.length-1] = obj;
        }
    }

    private int mineEnterIndex = 0;
    /**雷入场*/
    private void mineEnterAction(){
        mineEnterIndex++;
        if (mineEnterIndex%100==0){
            for (int i = 0; i < submarines.length; i++) {
                if (submarines[i] instanceof MineSubmarine){
                    MineSubmarine ms = (MineSubmarine) submarines[i];
                    Mine obj = ms.shootMine();
                    mines = Arrays.copyOf(mines,mines.length+1);
                    mines[mines.length-1] = obj;
                }
            }
        }
    }

    /**海洋对象移动*/
    public void moveAction(){
        for (int i = 0; i < submarines.length; i++) {//潜艇
            submarines[i].move();
        }
        for (int i = 0; i < mines.length; i++) {//水雷
            mines[i].move();
        }
        for (int i = 0; i < bombs.length; i++) {//深水炸弹
            bombs[i].move();
        }
    }

    /**重写paint()画 g:画笔*/
    public void paint(Graphics g){
        switch (state){
            case GAME_OVER:
                Images.gameover.paintIcon(null,g,0,0);//画海洋
                break;
            case RUNNING:
                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,200,50);
                g.drawString("LIFE:"+ship.getLife(),400,50);
        }
    }

    /*删除越界对象*/
    public void outOfBoundsAction(){
        for (int i = 0; i < submarines.length; i++) {
            if (submarines[i].isOutOfBounds() || submarines[i].isDead()){//出界的或者死了的
                submarines[i]=submarines[submarines.length-1];
                submarines = Arrays.copyOf(submarines,submarines.length-1);
            }
        }

        for (int i = 0; i < mines.length; i++) {
            if (mines[i].isOutOfBounds()|| mines[i].isDead()){
                mines[i]=mines[mines.length-1];
                mines = Arrays.copyOf(mines,mines.length-1);
            }
        }

        for (int i = 0; i < bombs.length; i++) {
            if (bombs[i].isOutOfBounds()|| bombs[i].isDead()){
                bombs[i]=bombs[bombs.length-1];
                bombs = Arrays.copyOf(bombs,bombs.length-1);
            }
        }
    }

    private int score = 0;//玩家得分
    /*深水炸弹与潜艇的碰撞*/
    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)){
                    b.goDEAD();//炸弹死
                    s.goDEAD();//潜艇死
                    if (s instanceof EnemyScore){//
                        EnemyScore es = (EnemyScore) s;//将被撞潜艇强转为得分接口
                        score += es.getScore();//玩家得分
                    }
                    if (s instanceof EnemyLife){//
                        EnemyLife el = (EnemyLife) s;//被撞潜艇强转为得命接口
                        int num = el.getLife();//获取命数
                        ship.addLife(num);//战舰增命
                    }
                }
            }
        }
    }
    /*水雷与炸弹碰撞*/
    public void mineBangAction(){
        for (int i = 0; i < mines.length; i++) {
            Mine m = mines[i];
            if (m.isLive()&& ship.isLive()&&m.isHit(ship)){
                m.goDEAD();
                System.out.println("1");
                ship.subtractLive();
            }
        }
    }
    /*检测结束*/
    private void checkGameOverAction(){
        if (ship.getLife()<=0){
            state = GAME_OVER;
        }
    }

    /**启动程序的执行*/
    public void action(){
        KeyAdapter k = new KeyAdapter() {/*重写键盘弹起*/
            public void keyReleased(KeyEvent e) {//当按键抬起时会自动执行
            if (e.getExtendedKeyCode()==KeyEvent.VK_SPACE){//若按键是空格键
                Bomb obj = ship.shoot();
                bombs = Arrays.copyOf(bombs,bombs.length+1);
                bombs[bombs.length-1] = obj;
            }
            if (e.getKeyCode()==KeyEvent.VK_LEFT){
                ship.moveLeft();
            }
            if (e.getKeyCode()==KeyEvent.VK_RIGHT){
                ship.moveRight();
            }
            }
        };//键盘侦听器
        this.addKeyListener(k);//添加侦听

        Timer timer = new Timer();//
        int interval = 10;//
        timer.schedule(new TimerTask() {
            public void run(){
                if(state==RUNNING){
                    submarineEnterAction();//潜艇入场
                    moveAction();//海洋对象移动
                    mineEnterAction();//水雷入场
                    outOfBoundsAction();//删除越界对象
                    bombBangAction();
                    mineBangAction();
                    checkGameOverAction();
                }

                repaint();
            }
        },interval,interval);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();//3.
        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);//设置窗口可见 2)尽快调paint()方法

        world.action();//启动程序执行
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值