Java 面向对象战舰小游戏

2024-03-22 12:40

本文主要是介绍Java 面向对象战舰小游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java面向对象战舰小游戏

    • 前言
    • 思路:
    • 战舰项目代码
      • 1. 战舰特征和行为
        • 水雷艇特征和行为
        • 侦查艇特征和行为
        • 鱼雷艇特征和行为
        • 水雷特征和行为
        • 深水炸弹特征和行为
      • 2. 归纳共有特征
      • 3.初始化
      • 4. 画图
      • 5. 重写方法
        • 定时器
        • 新建潜水艇对象
        • 新建水雷
        • 新建深水炸弹
        • 重写所有类的move方法
      • 6. 把超过窗口和相互碰撞的物体删掉
        • 删除超过窗口的对象
        • 删除相互碰撞的物体
      • 7.最终代码
        • Battleship
        • Bomb
        • Images
        • Mine
        • MineSubmarine
        • ObserveSubmarine
        • SeaObject
        • TorpedoSubmarine
        • World

代码和图片下载 https://download.csdn.net/download/gydennis/78761288

前言

这是面向对象的小游戏,运用的的知识点有:父子类,继承,构造方法,重载,重写,静态块,修饰词

在这里插入图片描述

思路:

1.首先写出项目中会运运用到的物体,在这个项目中,我们会用到:
敌人:三种潜艇:水雷潜艇(Mine Submarine),侦查潜艇(Observe Submarine),鱼雷艇(Torpedo Submarine)
玩家:战舰(Battleship)
道具:水雷(Mine),深水炸弹(Bomb)。
2.每个物体写出它们的特征,并把它们共有的特征归纳,放到超类(父类)里面,再把它们共有的行为写出普通方法写到超类里面,如果是行为一样但是每个行为发生的过程不一样,就写成抽象类(abstract)放到超类.
3.进行初始化,定义每个物体的初始坐标,高度等等特征的初始值。注意这时候图片初始值写成静态块,因为静态块初始化会声明类的时候自动执行,调用的时候直接类.变量就直接出来了,复用性较好。其他的例如窗口高,宽等不变的可以直接定义为常量,其他的特征为实例变量。然后添加访问权限
4. 开始画窗口,然后把物体画到窗口里面
5. 重写方法,让物体移动起来,并发射水雷或者炸弹。
6. 把超过窗口,或者爆炸的物体删掉

战舰项目代码

项目名称我建的叫SubmarineDemo,package的名字叫submarine
6个物体的特征和行为

1. 战舰特征和行为

战舰有宽, 高, x坐标, y坐标, 生命数量, 移动速度
方法是左右移动,发射深水炸弹,爆炸

class Battleship {// 战舰类//战舰有宽 高 x坐标 y坐标 生命数量 移动速度int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int life;   //生命数量int speed;  //移动速度//左右移动void move(){}//发射深水炸弹void shootBombs(){}
}

我们设计几个敌方战舰:水雷艇,鱼雷艇,潜水艇
它们的攻击方式是发射: 水雷和深水炸弹
这些的初始代码其实都跟战舰相同,只是没有生命值,因为他只有一条命

下面是它们初始化代码

水雷艇特征和行为
public class MineSubmarine {//水雷艇有宽 高 x坐标 y坐标 移动速度int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度//向右移动void move(){}//发射水雷void newMine(){}
}
侦查艇特征和行为
public class ObserveSubmarine {//侦查艇//侦查艇有宽 高 x坐标 y坐标 生命数量 移动速度int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度//向右移动void move(){}
}
鱼雷艇特征和行为
public class TorpedoSubmarine {//鱼雷艇//鱼雷艇有宽 高 x坐标 y坐标 移动速度int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度//向右移动void move(){}
}
水雷特征和行为
public class Mine {//水雷有宽 高 x坐标 y坐标 移动速度int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度//向上移动void move(){}
}
深水炸弹特征和行为
public class Bomb {//深水炸弹有宽 高 x坐标 y坐标 移动速度int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度//向下移动void move(){}
}

2. 归纳共有特征

它们的共有特征有宽,高,x坐标,y坐标,移动速度
所以我们新建一个父类,把共有特征和方法放进去,父类叫SeaObject。因为它们都是在海里运行的所以叫Sea Object(海洋物体)

共有的特征有: 宽, 高, x坐标, y 坐标,移动速度
共有的方法:
1.移动,因为每个类的移动行为都不一样,所以写成抽象模式,强制重写

abstract public class SeaObject {int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度abstract void move();
}

因为我们把move,每个类的移动行为都不一样,所以写成抽象模式,让派生类强制重写

代码:

Battleship

package submarine;public class Battleship extends SeaObject{int life;   //生命数量//左右移动void move(){}//发射深水炸弹void shootBombs(){}
}

Bomb

package submarine;public class Bomb extends SeaObject{//向下移动void move(){}
}

Mine

package submarine;public class Mine extends SeaObject {//向上移动void move(){}
}

Minesubmarine

package submarine;public class MineSubmarine extends SeaObject{//向右移动void move(){}//发射水雷void shoot(){}
}

ObserveSubmarine

package submarine;public class ObserveSubmarine extends SeaObject{//向右移动void move(){}
}

SeaObject

package submarine;abstract public class SeaObject {int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度abstract void move();
}

TorpedoSubmarine 鱼雷艇

package submarine;public class TorpedoSubmarine extends SeaObject{//向右移动void move(){}
}

3.初始化

常量:

  1. 6个类的长,宽高都是固定的
  2. 窗口的长宽高都是固定的

变量

  1. 6个类的一开始坐标(x和y),注意左上角的坐标是(0,0)
  2. 速度

下面是各个数据

类名初始坐标(x,y)
Battleship6626(270.142)
Bomb912按空格键出来,这里不定义
mine1111生成水雷艇后定时器自动生成
MineSubmarine6319在窗口左边自动生成
TorpedoSubmarine6420在窗口左边自动生成
ObserveSubmarine6319在窗口左边自动生成
窗口641479

6个类的除了我们设bomb和mine我们设成3,其他类速度是随机数从1-3不等

这里我们新建一个World类专门写main,在加上一个窗口的初始化

这里给类初始值得方法叫做构造方法。注意这里bomb和mine之间的xy的值不是固定的,所以要把它们在超类里重新定义(重载一个构造方法,相同方法名 不同参数列表)
然后给他们加修饰符(访问权限),注意泛生类的访问权限大于或等于超类,一般加public即可

代码
Battleship战舰

package submarine;public class Battleship extends SeaObject{//战舰的宽public static final int WIDTH = 66;//战舰的高public static final int HEIGHT = 26;//生命数量private int life;//初始化Battleship(){//把船放到海平面上的任意位置,x,y是左上角//初始位置是(200,150-Battleship.HEIGHT),速度是3super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);//初始命是5life = 5;}//左右移动public void move(){}//发射深水炸弹public void shootBombs(){}
}

Bomb炸弹

package submarine;public class Bomb extends SeaObject{//炸弹的宽public static final int WIDTH = 9;//炸弹的高public static final int HEIGHT = 12;//深水炸弹初始化Bomb(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向下移动public void move(){}}

水雷Mine

package submarine;public class Mine extends SeaObject {//水雷的宽public static final int WIDTH = 11;//水雷的高public static final int HEIGHT = 11;//水雷初始化Mine(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向上移动public void move(){}
}

MineSubmarine 水雷艇

package submarine;public class MineSubmarine extends SeaObject{//水雷艇的宽public static final int WIDTH = 63;//水雷艇的高public static final int HEIGHT = 19;//向右移动public void move(){}//水雷潜艇初始化MineSubmarine(){super(MineSubmarine.WIDTH,MineSubmarine.HEIGHT);}//发射水雷public void newMine(){}}

ObserveSubmarine 侦查艇

package submarine;public class ObserveSubmarine extends SeaObject{//侦查艇的宽public static final int WIDTH = 63;//侦查艇的高public static final int HEIGHT = 19;//侦查潜艇初始化ObserveSubmarine(){super(ObserveSubmarine.WIDTH,ObserveSubmarine.HEIGHT);}//向右移动public void move(){}
}

Seaobject超类

package submarine;import java.util.Random;public abstract class SeaObject {int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度public abstract void move();SeaObject(int width,int height,int x,int y,int speed ){//bomb还有minethis.width = width;this.height = height;this.x = x;this.y = y;this.speed = speed;}SeaObject(int width,int height){this.width = width;this.height = height;x = -width;//潜艇进场是在窗口最左边进场//海平面以下随机生成,随机高度在150到(最低减去一个潜艇的高度)Random rand = new Random();y = rand.nextInt(World.HEIGHT-World.SEA_LEVEL_HEIGHT-MineSubmarine.HEIGHT+1)+150;speed = rand.nextInt(3);}}

TorpedoSubmarine 鱼雷艇

package submarine;public class TorpedoSubmarine extends SeaObject{//鱼雷艇的宽public static final int WIDTH = 64;//鱼雷艇的高public static final int HEIGHT = 20;//水雷潜艇的初始化TorpedoSubmarine(){super(TorpedoSubmarine.WIDTH,TorpedoSubmarine.HEIGHT);}//向右移动public void move(){}
}

World主方法

package submarine;public class World {//海平面public static final int SEA_LEVEL_HEIGHT = 150;//窗口宽public static final int WIDTH = 641;//窗口长public static final int HEIGHT = 479;//主方法public static void main(String[] args) {}
}

4. 画图

这里我们用了现在不怎么用的方法,这里就不说了,直接是赋值黏贴过来的

  • 这里需要import Graphics,Jframe和JPanel三个类
  • main还要继承JFrame
  • 直接在main里面添加代码,复制黏贴就行
JFrame frame = new JPanel ();
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);//1)设置窗口可见  2)尽快调用paint()方法

我们需要写一个paint方法来画

  • 最主要把图片画出来的方法是paintIcon,有兴趣的自己了解即可,但现在没什么人用了。写了一个Image
  • 画的动作是一样的,就是对象图片调用paintIcon方法,所以把他们写在超类SeaObject里面
  • 把每个类都画一个在画布上
    Battleship
package submarine;import javax.swing.*;public class Battleship extends SeaObject{//战舰的宽public static final int WIDTH = 66;//战舰的高public static final int HEIGHT = 26;//生命数量private int life;//初始化Battleship(){//把船放到海平面上的任意位置,x,y是左上角//初始位置是(200,150-Battleship.HEIGHT),速度是3super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);//初始命是5life = 5;}//左右移动public void move(){}//发射深水炸弹public void shootBombs(){}//画布上画battleship对象public ImageIcon getObject(){return Images.battleship;}
}

Bomb

package submarine;import javax.swing.*;public class Bomb extends SeaObject{//炸弹的宽public static final int WIDTH = 9;//炸弹的高public static final int HEIGHT = 12;//深水炸弹初始化Bomb(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向下移动public void move(){}//画布上画bomb对象public ImageIcon getObject(){return Images.bomb;}}

Images

package submarine;
import javax.swing.ImageIcon;
/** 图片类 */
public class Images {//  公开的  静态的  图片数据类型   变量名public static ImageIcon  battleship; //战舰图片public static ImageIcon  obsersubm;  //侦察潜艇图片public static ImageIcon  torpesubm;  //鱼雷潜艇图片public static ImageIcon  minesubm;   //水雷潜艇图片public static ImageIcon  mine;       //水雷图片public static ImageIcon  bomb;       //深水炸弹图片public static ImageIcon  sea;        //海洋图public static ImageIcon  gameover;   //游戏结束图static{ //给静态图片赋值battleship = new ImageIcon("img/battleship.png");obsersubm = new ImageIcon("img/obsersubm.png");torpesubm = new ImageIcon("img/torpesubm.png");minesubm = new ImageIcon("img/minesubm.png");mine = new ImageIcon("img/mine.png");bomb = new ImageIcon("img/bomb.png");sea = new ImageIcon("img/sea.png");gameover = new ImageIcon("img/gameover.png");}public static void main(String[] args) {//写完上面对象之后,测试,返回8表示读取成功System.out.println(battleship.getImageLoadStatus()); //返回8表示读取成功System.out.println(obsersubm.getImageLoadStatus());System.out.println(torpesubm.getImageLoadStatus());System.out.println(minesubm.getImageLoadStatus());System.out.println(mine.getImageLoadStatus());System.out.println(bomb.getImageLoadStatus());System.out.println(sea.getImageLoadStatus());System.out.println(gameover.getImageLoadStatus());}}

Mine

package submarine;import javax.swing.*;public class Mine extends SeaObject {//水雷的宽public static final int WIDTH = 11;//水雷的高public static final int HEIGHT = 11;//水雷初始化Mine(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向上移动public void move(){}//画布上画mine对象public ImageIcon getObject(){return Images.mine;}
}

MineSubmarine

package submarine;import javax.swing.*;public class MineSubmarine extends SeaObject{//水雷艇的宽public static final int WIDTH = 63;//水雷艇的高public static final int HEIGHT = 19;//向右移动public void move(){}//水雷潜艇初始化MineSubmarine(){super(MineSubmarine.WIDTH,MineSubmarine.HEIGHT);}//发射水雷public void newMine(){}//画布上画MineSubmarine对象public ImageIcon getObject(){return Images.minesubm;}
}

ObserveSubmarine

package submarine;import javax.swing.*;public class ObserveSubmarine extends SeaObject{//侦查艇的宽public static final int WIDTH = 63;//侦查艇的高public static final int HEIGHT = 19;//侦查潜艇初始化ObserveSubmarine(){super(ObserveSubmarine.WIDTH,ObserveSubmarine.HEIGHT);}//向右移动public void move(){}//画布上画ObserveSubmarine对象public ImageIcon getObject(){return Images.obsersubm;}
}

SeaObject

package submarine;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.ImageIcon;
public abstract class SeaObject {int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度public abstract void move();SeaObject(int width,int height,int x,int y,int speed ){//bomb还有minethis.width = width;this.height = height;this.x = x;this.y = y;this.speed = speed;}SeaObject(int width,int height){this.width = width;this.height = height;x = width;//潜艇进场是在窗口最左边进场//海平面以下随机生成,随机高度在150到(最低减去一个潜艇的高度)Random rand = new Random();y = rand.nextInt(World.HEIGHT-World.SEA_LEVEL_HEIGHT-MineSubmarine.HEIGHT+1)+150;speed = rand.nextInt(3);}//画布上画子类的对象,行为一样,所以定义为抽象public abstract ImageIcon getObject();//画对象 g:画笔public void paintImage(Graphics g){this.getObject().paintIcon(null,g,this.x,this.y);}}

TorpedoSubmarine

package submarine;import javax.swing.*;public class TorpedoSubmarine extends SeaObject{//鱼雷艇的宽public static final int WIDTH = 64;//鱼雷艇的高public static final int HEIGHT = 20;//水雷潜艇的初始化TorpedoSubmarine(){super(TorpedoSubmarine.WIDTH,TorpedoSubmarine.HEIGHT);}//向右移动public void move(){}//画布上画TorpedoSubmarine对象public ImageIcon getObject(){return Images.torpesubm;}
}

World

package submarine;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
public class World extends JPanel {//海平面public static final int SEA_LEVEL_HEIGHT = 150;//窗口宽public static final int WIDTH = 641;//窗口长public static final int HEIGHT = 479;//定义一个战舰对象Battleship ship = new Battleship();SeaObject[] submarines = {new MineSubmarine(),new ObserveSubmarine(),new TorpedoSubmarine()};Bomb[] bombs = {new Bomb(200,200)};Mine[] mines = {new Mine(200,150)};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<bombs.length;i++){bombs[i].paintImage(g);}//画水雷数组for(int i = 0;i<mines.length;i++){mines[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);//1)设置窗口可见  2)尽快调用paint()方法}
}

代码呈现出来的是这样的
在这里插入图片描述
如果你跟我一样再画布上呈现了6个类说明你已经成功一半了,剩下的就是让这些类移动起来

5. 重写方法

这里使用定时器每10毫秒重写画一次对象(导入Timer和TimerTask两个类)

重写move方法

移动方向
战舰移动战舰由键盘左右控制移动
深水炸弹移动由战舰发出,只能向下移动
潜水艇移动潜水艇只能向右移动
水雷移动水雷由水雷艇发射,向上移动
定时器

需要导入两个类一个是Timer,一个是TimerTask

import java.util.Timer;
import java.util.TimerTask;
public void action(){int period = 10;//delay和period都设置为10毫秒Timer timer = new Timer();//新建一个Timer对象timer.schedule(new TimerTask() {/*** 每10毫秒调用schedule* 并重写TimerTask里面的run方法* 这里用到的知识是匿名内部类*/@Overridepublic void run() {/*** 这里面需要写的是新建潜艇,深水炸弹,水雷对象* 移动* 撞击爆炸消失等方法*/repaint();//重写调用paint方法}}, period, period);
}
新建潜水艇对象

这里用随机数的方法来生成潜艇

public SeaObject newSubmarine(){Random rand = new Random();//生成一个Random对象int number = rand.nextInt(3);//随机数是0到2if(number<1){//如果number等于0,输出水雷艇return new MineSubmarine();}else if(number<2){//如果number等于1,输出侦查艇return new ObserveSubmarine();}else{//如果number等于2,输出鱼雷艇return new TorpedoSubmarine();}
}
private int submarineIndex = 0;
public void addSubmarine(){submarineIndex++;if(submarineIndex%40 == 25){//每40*10=400毫秒=0.4秒生成潜艇//给submarines数组扩容submarines = Arrays.copyOf(submarines,submarines.length+1);SeaObject new_Submarine = newSubmarine();//新建潜水艇对象//扩容之后,把新的潜水艇对象保存在submarines数组里面submarines[submarines.length-1] = new_Submarine;}
}
新建水雷

在Worls中添加方法

private int mineIndex = 0;
public  void addMine(){/*** 水雷,因为是水雷潜水艇发射的,需要知道水雷潜水艇x和y的坐标* 所以写在MineSubmarine类里面* 我们先要分辨数组里面哪一个是MineSubmarine* 再给他添加水雷*/mineIndex++;if(mineIndex%80==79){for(int i = 0; i <submarines.length;i++){if(submarines[i] instanceof MineSubmarine){/*** 水雷是写在MineSubmarine类里面* 为了调用MineSubmarine* 我们需要强制转换submarines[i]成MineSubmarine类型*///给水雷数组扩容mines = Arrays.copyOf(mines,mines.length+1);//强转的目的是现在潜水艇的数据类型是父类SeaObjext类型//但是我们要调用子类的方法,所以要强转//调用newMine生成新的水雷mines[mines.length-1] = ((MineSubmarine) submarines[i]).newMine();}}}
}
新建深水炸弹
  • 因为深水炸弹是在有人控制键盘,并在战舰中发射出去
  • 要先得到战舰的坐标,所以在战舰类里面写一个shootBombs方法,里面生成一个新的深水炸弹对象。
  • 最后在World类里面写一个addBomb方法调shootBombs方法,里面是按键盘触发相应的动作

战舰类里面的shootBombs方法

public  Bomb shootBombs(){return new Bomb(this.x-10,this.y);
}

World类里面的addBomb方法

public void addBomb(){KeyAdapter k = new KeyAdapter() { //不要求掌握/** 重写keyReleased()按键抬起事件 */public void keyReleased(KeyEvent e) { //当按键抬起时会自动触发--不要求掌握if(e.getKeyCode()==KeyEvent.VK_SPACE){ //若抬起的是空格键--不要求掌握Bomb obj = ship.shootBombs(); //获取深水炸弹对象bombs = Arrays.copyOf(bombs,bombs.length+1); //扩容bombs[bombs.length-1] = obj; //将obj添加到bombs的最后一个元素上}if(e.getKeyCode()==KeyEvent.VK_LEFT){ //若抬起的是左键头--不要求掌握ship.moveLeft(); //战舰左移}if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //若抬起的是右键头--不要求掌握ship.moveRight(); //战舰右移}}};this.addKeyListener(k); //不要求掌握
}
重写所有类的move方法

Battleship

public void moveLeft(){//键盘控制向左移动x-=7;
}
public void moveRight(){//键盘控制向右移动x+=7;
}

Bomb

//向下移动
public void move(){y+=speed;
}

Mine

//向上移动
public void move(){y-=speed;
}

MineSubmarine

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

ObserveSubmarine

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

TorpedoSubmarine

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

代码
记得数组初始化的时候清空里面的元素,之前是测试版

Battleship

package submarine;import javax.swing.*;public class Battleship extends SeaObject{//战舰的宽public static final int WIDTH = 66;//战舰的高public static final int HEIGHT = 26;//生命数量private int life;//初始化Battleship(){//把船放到海平面上的任意位置,x,y是左上角//初始位置是(200,150-Battleship.HEIGHT),速度是3super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);//初始命是5life = 5;}//左右移动public void move(){}//发射深水炸弹public  Bomb shootBombs(){return new Bomb(this.x-10,this.y);}//画布上画battleship对象public ImageIcon getObject(){return Images.battleship;}public void moveLeft(){//键盘控制向左移动this.x-=7;}public void moveRight(){//键盘控制向右移动this.x+=7;}}

Bomb

package submarine;import javax.swing.*;public class Bomb extends SeaObject{//炸弹的宽public static final int WIDTH = 9;//炸弹的高public static final int HEIGHT = 12;//深水炸弹初始化Bomb(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向下移动public void move(){y+=speed;}//画布上画bomb对象public ImageIcon getObject(){return Images.bomb;}}

Images

package submarine;import javax.swing.*;public class Bomb extends SeaObject{//炸弹的宽public static final int WIDTH = 9;//炸弹的高public static final int HEIGHT = 12;//深水炸弹初始化Bomb(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向下移动public void move(){y+=speed;}//画布上画bomb对象public ImageIcon getObject(){return Images.bomb;}}

Mine

package submarine;import javax.swing.*;public class Mine extends SeaObject {//水雷的宽public static final int WIDTH = 11;//水雷的高public static final int HEIGHT = 11;//水雷初始化Mine(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,2);}//向上移动public void move(){y-=speed;}//画布上画mine对象public ImageIcon getObject(){return Images.mine;}
}

MineSubmarine

package submarine;import javax.swing.*;public class MineSubmarine extends SeaObject{//水雷艇的宽public static final int WIDTH = 63;//水雷艇的高public static final int HEIGHT = 19;//向右移动public void move(){x+=speed;}//水雷潜艇初始化MineSubmarine(){super(MineSubmarine.WIDTH,MineSubmarine.HEIGHT);}//发射水雷public Mine newMine(){//生成鱼雷//可以控制水雷出现在水雷潜艇的哪一边//这里用的是出现在水雷潜艇中间偏上return new Mine(this.x+30,this.y-5);}//画布上画MineSubmarine对象public ImageIcon getObject(){return Images.minesubm;}
}

ObserveSubmarine

package submarine;import javax.swing.*;public class ObserveSubmarine extends SeaObject{//侦查艇的宽public static final int WIDTH = 63;//侦查艇的高public static final int HEIGHT = 19;//侦查潜艇初始化ObserveSubmarine(){super(ObserveSubmarine.WIDTH,ObserveSubmarine.HEIGHT);}//向右移动public void move(){x+=speed;}//画布上画ObserveSubmarine 对象public ImageIcon getObject(){return Images.obsersubm;}
}

SeaObject

package submarine;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.ImageIcon;
public abstract class SeaObject {int width;  //宽int height; //高int x;      //x坐标int y;      //y坐标int speed;  //移动速度public abstract void move();SeaObject(int width,int height,int x,int y,int speed ){//bomb还有minethis.width = width;this.height = height;this.x = x;this.y = y;this.speed = speed;}SeaObject(int width,int height){this.width = width;this.height = height;x = -width;//潜艇进场是在窗口最左边进场//海平面以下随机生成,随机高度在150到(最低减去一个潜艇的高度)Random rand = new Random();y = rand.nextInt(World.HEIGHT-World.SEA_LEVEL_HEIGHT-MineSubmarine.HEIGHT+1)+150;speed = rand.nextInt(3);}//画布上画子类的对象,行为一样,所以定义为抽象public abstract ImageIcon getObject();//画对象 g:画笔public void paintImage(Graphics g){this.getObject().paintIcon(null,g,this.x,this.y);}
}

TorpedoSubmarine

package submarine;import javax.swing.*;public class TorpedoSubmarine extends SeaObject{//鱼雷艇的宽public static final int WIDTH = 64;//鱼雷艇的高public static final int HEIGHT = 20;//水雷潜艇的初始化TorpedoSubmarine(){super(TorpedoSubmarine.WIDTH,TorpedoSubmarine.HEIGHT);}//向右移动public void move(){x+=speed;}//画布上画TorpedoSubmarine对象public ImageIcon getObject(){return Images.torpesubm;}
}

World

package submarine;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class World extends JPanel {//海平面public static final int SEA_LEVEL_HEIGHT = 150;//窗口宽public static final int WIDTH = 641;//窗口长public static final int HEIGHT = 479;//定义一个战舰对象Battleship ship = new Battleship();SeaObject[] submarines = {new MineSubmarine(),new ObserveSubmarine(),new TorpedoSubmarine()};Bomb[] bombs = {};Mine[] mines = {};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<bombs.length;i++){bombs[i].paintImage(g);}//画水雷数组for(int i = 0;i<mines.length;i++){mines[i].paintImage(g);}}public SeaObject newSubmarine(){Random rand = new Random();//生成一个Random对象int number = rand.nextInt(3);//随机数是0到2if(number<1){//如果number等于0,输出水雷艇return new MineSubmarine();}else if(number<2){//如果number等于1,输出侦查艇return new ObserveSubmarine();}else{//如果number等于2,输出鱼雷艇return new TorpedoSubmarine();}}private int submarineIndex = 0;public void addSubmarine(){submarineIndex++;if(submarineIndex%40 == 25){//每40*10=400毫秒=0.4秒生成潜艇//给submarines数组扩容submarines = Arrays.copyOf(submarines,submarines.length+1);SeaObject new_Submarine = newSubmarine();//新建潜水艇对象//扩容之后,把新的潜水艇对象保存在submarines数组里面submarines[submarines.length-1] = new_Submarine;}}private int mineIndex = 0;public  void addMine(){/*** 水雷,因为是水雷潜水艇发射的,需要知道水雷潜水艇x和y的坐标* 所以写在MineSubmarine类里面* 我们先要分辨数组里面哪一个是MineSubmarine* 再给他添加水雷*/mineIndex++;if(mineIndex%80==79){for(int i = 0; i <submarines.length;i++){if(submarines[i] instanceof MineSubmarine){/*** 水雷是写在MineSubmarine类里面* 为了调用MineSubmarine* 我们需要强制转换submarines[i]成MineSubmarine类型*///给水雷数组扩容mines = Arrays.copyOf(mines,mines.length+1);//强转的目的是现在潜水艇的数据类型是父类SeaObjext类型//但是我们要调用子类的方法,所以要强转//调用newMine生成新的水雷mines[mines.length-1] = ((MineSubmarine) submarines[i]).newMine();}}}}public void addBomb(){KeyAdapter k = new KeyAdapter() { //不要求掌握/** 重写keyReleased()按键抬起事件 */public void keyReleased(KeyEvent e) { //当按键抬起时会自动触发--不要求掌握if(e.getKeyCode()==KeyEvent.VK_SPACE){ //若抬起的是空格键--不要求掌握Bomb obj = ship.shootBombs(); //获取深水炸弹对象bombs = Arrays.copyOf(bombs,bombs.length+1); //扩容bombs[bombs.length-1] = obj; //将obj添加到bombs的最后一个元素上}if(e.getKeyCode()==KeyEvent.VK_LEFT){ //若抬起的是左键头ship.moveLeft(); //战舰左移}if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //若抬起的是右键头ship.moveRight(); //战舰右移}}};this.addKeyListener(k); //不要求掌握}public void objectMove(){/*** 遍历潜水艇,水雷,深水炸弹让它们移动* Battleship是由键盘控制的*/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();}}public void action(){addBomb();int period = 10;//delay和period都设置为10毫秒Timer timer = new Timer();//新建一个Timer对象timer.schedule(new TimerTask() {/*** 每10毫秒调用schedule* 并重写TimerTask里面的run方法* 这里用到的知识是匿名内部类*/@Overridepublic void run() {/*** 这里面需要写的是新建潜艇,深水炸弹,鱼雷对象* 移动* 撞击爆炸消失等方法*/addSubmarine();//生成新的潜水艇对象addMine();//生成新的深水炸弹对象objectMove();repaint();//重写调用paint方法}}, period, period);}//主方法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);//1)设置窗口可见  2)尽快调用paint()方法world.action();}
}

6. 把超过窗口和相互碰撞的物体删掉

删除超过窗口的对象
public void deleteOutOfBounds(){//删除超过边界的对象//潜水艇超过边界会被删除for(int i = 0;i<submarines.length;i++){//潜水艇只有向右的动作,所以当有潜水艇超过右边边界,就会被删除if(submarines[i].x>=World.WIDTH){//思路是让要删除的这个数组元素下标等于,最后一个数组元素,再缩容submarines[i] = submarines[submarines.length-1];submarines = Arrays.copyOf(submarines,submarines.length-1);}}//水雷超过边界会被删除for(int i = 0;i<mines.length;i++){//水雷只有向上的动作,所以当有水雷超过海平面,就会被删除if(mines[i].y<World.SEA_LEVEL_HEIGHT){//思路是让要删除的这个数组元素下标等于,最后一个数组元素,再缩容mines[i] = mines[mines.length-1];mines = Arrays.copyOf(mines,mines.length-1);}}//深水炸弹超过边界会被删除for(int i = 0;i<bombs.length;i++){//深水炸弹只有向下的动作,所以当有深水炸弹超过最下面边界,就会被删除if(bombs[i].y>World.HEIGHT){//思路是让要删除的这个数组元素下标等于,最后一个数组元素,再缩容bombs[i] = bombs[bombs.length-1];bombs = Arrays.copyOf(bombs,bombs.length-1);}}
}
删除相互碰撞的物体
  • 这里要判断两个物体是否碰撞就可以定义一个为参照物,其他对象在哪个范围就代表着碰撞
  • 战舰和水雷碰撞,深水炸弹和潜水艇碰撞
  • 碰撞的结果:战舰和水雷碰撞,水雷消失,战舰命减一,如果命为零,游戏结束
  • 深水炸弹和潜水艇碰撞两个都消失,战舰命加一
  • 方法是写在SeaObject里面,返回值是boolean类型
    在这里插入图片描述

因为坐标出现在每个物体的左上角,所以以other作为参照物,只需要计算黄色部分范围即可

public boolean isHit(SeaObject other){return other.x>=this.x-other.width && other.x<=this.x+this.width &&other.y>=this.y-other.height && other.y<=this.y+this.height;
}

在Battleship类里面写一个得到生命和失去生命的方法,因为在Battleship中life是私有的,所以用方法输出

public int getLife(){return life;
}
public void subtractLife(){life--;
}

在paint里面加两行,分别对应的是在画布上画出score和life来

g.drawString("SCORE: "+score,200,50); //画分
g.drawString("LIFE: "+ship.getLife(),400,50); //画命
  • 我们设定只有水雷潜艇是得命,其他潜艇得分
  • 为了区分它们,我们写两个接口让它们继承,这样如果判断潜艇和深水炸弹是碰撞的,那我们就判断是不是属于命或者得分接口
  • 最后写了判断有没有碰撞的方法在World里面
public void judgeIsHit(){//判断潜水艇和深水炸弹碰撞for(int i = 0;i<submarines.length;i++){for(int j = 0;j<bombs.length;j++){if(submarines[i].isHit(bombs[j])){//把潜水艇和深水炸弹的状态设为DEADsubmarines[i].status = SeaObject.DEAD;bombs[j].status = SeaObject.DEAD;//得分 先判断这个潜艇对象是否继承EnemyScore接口if(submarines[i] instanceof EnemyScore){score += ((EnemyScore) submarines[i]).getScore();}//得命 先判断这个潜艇对象是否继承EnemyLife接口if(submarines[i] instanceof EnemyLife){ship.addLife();//加命}}}}//判断战舰和水雷碰撞for(int i = 0;i<mines.length;i++){System.out.println("ship"+(ship.y+ship.height));System.out.println("mines"+i+"   "+mines[i].y);if(mines[i].isHit(ship)){//把水雷的状态设为DEADmines[i].status = SeaObject.DEAD;ship.subtractLife();}}
}

最后判断当命为0的时候 ,游戏结束

  • 定义两个常量
  • 写一个判断游戏状态的方法在World里面
public void checkGameOverAction(){if(ship.getLife()==0){gameStatus = GAMEOVER;}
}

最后改paint方法,当gameStatus = GAMEOVER;游戏就结束,当gameStatus = RUNNING;的时候,游戏没结束

7.最终代码

Battleship
package submarine;import javax.swing.*;public class Battleship extends SeaObject{//战舰的宽public static final int WIDTH = 66;//战舰的高public static final int HEIGHT = 26;//生命数量private int life;//初始化Battleship(){//把船放到海平面上的任意位置,x,y是左上角//初始位置是(200,150-Battleship.HEIGHT),速度是3super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);//初始命是5life = 5;}//左右移动public void move(){}//发射深水炸弹public  Bomb shootBombs(){return new Bomb(this.x-10,this.y);}//画布上画battleship对象public ImageIcon getObject(){return Images.battleship;}public void moveLeft(){//键盘控制向左移动this.x-=7;}public void moveRight(){//键盘控制向右移动this.x+=7;}public int getLife(){return life;}public void addLife(){life++;}public void subtractLife(){life--;}
}
Bomb
package submarine;import javax.swing.*;public class Bomb extends SeaObject{//炸弹的宽public static final int WIDTH = 9;//炸弹的高public static final int HEIGHT = 12;//深水炸弹初始化Bomb(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,3);}//向下移动public void move(){y+=speed;}//画布上画bomb对象public ImageIcon getObject(){return Images.bomb;}}

EnemyLife

package submarine;public interface EnemyLife {public int getLife();
}

EnemyScore

package submarine;public interface EnemyScore {public int getScore();
}
Images
package submarine;import javax.swing.ImageIcon;
/** 图片类 */
public class Images {//  公开的  静态的  图片数据类型   变量名public static ImageIcon  battleship; //战舰图片public static ImageIcon  obsersubm;  //侦察潜艇图片public static ImageIcon  torpesubm;  //鱼雷潜艇图片public static ImageIcon  minesubm;   //水雷潜艇图片public static ImageIcon  mine;       //水雷图片public static ImageIcon  bomb;       //深水炸弹图片public static ImageIcon  sea;        //海洋图public static ImageIcon  gameover;   //游戏结束图static{ //给静态图片赋值battleship = new ImageIcon("img/battleship.png");obsersubm = new ImageIcon("img/obsersubm.png");torpesubm = new ImageIcon("img/torpesubm.png");minesubm = new ImageIcon("img/minesubm.png");mine = new ImageIcon("img/mine.png");bomb = new ImageIcon("img/bomb.png");sea = new ImageIcon("img/sea.png");gameover = new ImageIcon("img/gameover.png");}public static void main(String[] args) {//写完上面对象之后,测试,返回8表示读取成功System.out.println(battleship.getImageLoadStatus()); //返回8表示读取成功System.out.println(obsersubm.getImageLoadStatus());System.out.println(torpesubm.getImageLoadStatus());System.out.println(minesubm.getImageLoadStatus());System.out.println(mine.getImageLoadStatus());System.out.println(bomb.getImageLoadStatus());System.out.println(sea.getImageLoadStatus());System.out.println(gameover.getImageLoadStatus());}}
Mine
package submarine;import javax.swing.*;public class Mine extends SeaObject {//水雷的宽public static final int WIDTH = 11;//水雷的高public static final int HEIGHT = 11;//水雷初始化Mine(int x,int y){super(Bomb.WIDTH,Bomb.HEIGHT,x,y,1);}//向上移动public void move(){y-=speed;}//画布上画mine对象public ImageIcon getObject(){return Images.mine;}
}
MineSubmarine
package submarine;import javax.swing.*;public class MineSubmarine extends SeaObject implements EnemyLife{//水雷艇的宽public static final int WIDTH = 63;//水雷艇的高public static final int HEIGHT = 19;//向右移动public void move(){x+=speed;}//水雷潜艇初始化MineSubmarine(){super(MineSubmarine.WIDTH,MineSubmarine.HEIGHT);}//发射水雷public Mine newMine(){//生成鱼雷//可以控制水雷出现在水雷潜艇的哪一边//这里用的是出现在水雷潜艇中间偏上return new Mine(this.x+30,this.y-5);}//画布上画MineSubmarine对象public ImageIcon getObject(){return Images.minesubm;}public int getLife(){return 1; //打掉水雷潜艇,战舰得1条命}
}
ObserveSubmarine
package submarine;import javax.swing.*;public class ObserveSubmarine extends SeaObject  implements EnemyScore{//侦查艇的宽public static final int WIDTH = 63;//侦查艇的高public static final int HEIGHT = 19;//侦查潜艇初始化ObserveSubmarine(){super(ObserveSubmarine.WIDTH,ObserveSubmarine.HEIGHT);}//向右移动public void move(){x+=speed;}//画布上画ObserveSubmarine 对象public ImageIcon getObject(){return Images.obsersubm;}public int getScore(){return 20;}
}
SeaObject
package submarine;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.ImageIcon;
public abstract class SeaObject{public static final int DEAD = 0;public static final int LIVE = 1;public int status = LIVE;protected int width;  //宽protected int height; //高public int x;      //x坐标public int y;      //y坐标public int speed;  //移动速度public abstract void move();SeaObject(int width,int height,int x,int y,int speed ){//bomb还有minethis.width = width;this.height = height;this.x = x;this.y = y;this.speed = speed;}SeaObject(int width,int height){this.width = width;this.height = height;x = -width;//潜艇进场是在窗口最左边进场//海平面以下随机生成,随机高度在150到(最低减去一个潜艇的高度)Random rand = new Random();y = rand.nextInt(World.HEIGHT-World.SEA_LEVEL_HEIGHT-MineSubmarine.HEIGHT+1)+150;speed = rand.nextInt(3);}//画布上画子类的对象,行为一样,所以定义为抽象public abstract ImageIcon getObject();//画对象 g:画笔public void paintImage(Graphics g){this.getObject().paintIcon(null,g,this.x,this.y);}public boolean isHit(SeaObject other){return other.x>=this.x-other.width && other.x<=this.x+this.width &&other.y>=this.y-other.height && other.y<=this.y+this.height;}}
TorpedoSubmarine
package submarine;import javax.swing.*;public class TorpedoSubmarine extends SeaObject implements EnemyScore{//鱼雷艇的宽public static final int WIDTH = 64;//鱼雷艇的高public static final int HEIGHT = 20;//水雷潜艇的初始化TorpedoSubmarine(){super(TorpedoSubmarine.WIDTH,TorpedoSubmarine.HEIGHT);}//向右移动public void move(){x+=speed;}//画布上画TorpedoSubmarine对象public ImageIcon getObject(){return Images.torpesubm;}public int getScore(){return 20;}
}
World
package submarine;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class World extends JPanel {//游戏运行public static final int RUNNING = 1;//海平面public static final int GAMEOVER = 0;//窗口宽public static final int WIDTH = 641;//窗口长public static final int HEIGHT = 479;//海平面public static final int SEA_LEVEL_HEIGHT = 150;//分数public int score = 0;//定义一个战舰对象Battleship ship = new Battleship();SeaObject[] submarines = {};Bomb[] bombs = {};Mine[] mines = {};//游戏状态,RUNNING就是游戏没有结束,GAMEOVER就是游戏结束public int gameStatus = RUNNING;public int numberLife = 0;public void paint(Graphics g){if(gameStatus==GAMEOVER){if(numberLife==0){//让画布上的life变成0g.drawString("LIFE: "+ship.getLife(),400,50); //画命numberLife=1;}Images.gameover.paintIcon(null,g,0,0);}else if(gameStatus==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<bombs.length;i++){bombs[i].paintImage(g);}//画水雷数组for(int i = 0;i<mines.length;i++){mines[i].paintImage(g);}g.drawString("SCORE: "+score,200,50); //画分g.drawString("LIFE: "+ship.getLife(),400,50); //画命}}public SeaObject newSubmarine(){Random rand = new Random();//生成一个Random对象int number = rand.nextInt(3);//随机数是0到2if(number<1){//如果number等于0,输出水雷艇return new MineSubmarine();}else if(number<2){//如果number等于1,输出侦查艇return new ObserveSubmarine();}else{//如果number等于2,输出鱼雷艇return new TorpedoSubmarine();}}private int submarineIndex = 0;public void addSubmarine(){submarineIndex++;if(submarineIndex%40 == 25){//每40*10=400毫秒=0.4秒生成潜艇//给submarines数组扩容submarines = Arrays.copyOf(submarines,submarines.length+1);SeaObject new_Submarine = newSubmarine();//新建潜水艇对象//扩容之后,把新的潜水艇对象保存在submarines数组里面submarines[submarines.length-1] = new_Submarine;}}private int mineIndex = 0;public  void addMine(){/*** 水雷,因为是水雷潜水艇发射的,需要知道水雷潜水艇x和y的坐标* 所以写在MineSubmarine类里面* 我们先要分辨数组里面哪一个是MineSubmarine* 再给他添加水雷*/mineIndex++;if(mineIndex%80==79){for(int i = 0; i <submarines.length;i++){if(submarines[i] instanceof MineSubmarine){/*** 水雷是写在MineSubmarine类里面* 为了调用MineSubmarine* 我们需要强制转换submarines[i]成MineSubmarine类型*///给水雷数组扩容mines = Arrays.copyOf(mines,mines.length+1);//强转的目的是现在潜水艇的数据类型是父类SeaObjext类型//但是我们要调用子类的方法,所以要强转//调用newMine生成新的水雷mines[mines.length-1] = ((MineSubmarine) submarines[i]).newMine();}}}}public void addBomb(){KeyAdapter k = new KeyAdapter() { //不要求掌握/** 重写keyReleased()按键抬起事件 */public void keyReleased(KeyEvent e) { //当按键抬起时会自动触发if(e.getKeyCode()==KeyEvent.VK_SPACE){ //若抬起的是空格键Bomb obj = ship.shootBombs(); //获取深水炸弹对象bombs = Arrays.copyOf(bombs,bombs.length+1); //扩容bombs[bombs.length-1] = obj; //将obj添加到bombs的最后一个元素上}if(e.getKeyCode()==KeyEvent.VK_LEFT){ //若抬起的是左键头--不要求掌握ship.moveLeft(); //战舰左移}if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //若抬起的是右键头--不要求掌握ship.moveRight(); //战舰右移}}};this.addKeyListener(k); //不要求掌握}public void objectMove(){/*** 遍历潜水艇,水雷,深水炸弹让它们移动* Battleship是由键盘控制的*/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();}}public void deleteOutOfBounds(){//删除超过边界的对象//潜水艇超过边界会被删除for(int i = 0;i<submarines.length;i++){//潜水艇只有向右的动作,所以当有潜水艇超过右边边界,就会被删除if(submarines[i].x>=World.WIDTH||submarines[i].status==SeaObject.DEAD){//思路是让要删除的这个数组元素下标等于,最后一个数组元素,再缩容submarines[i] = submarines[submarines.length-1];submarines = Arrays.copyOf(submarines,submarines.length-1);}}//水雷超过边界会被删除for(int i = 0;i<mines.length;i++){//水雷只有向上的动作,所以当有水雷超过海平面,就会被删除if(mines[i].y<World.SEA_LEVEL_HEIGHT||mines[i].status==SeaObject.DEAD){//思路是让要删除的这个数组元素下标等于,最后一个数组元素,再缩容mines[i] = mines[mines.length-1];mines = Arrays.copyOf(mines,mines.length-1);}}//深水炸弹超过边界会被删除for(int i = 0;i<bombs.length;i++){//深水炸弹只有向下的动作,所以当有深水炸弹超过最下面边界,就会被删除if(bombs[i].y>World.HEIGHT||bombs[i].status==SeaObject.DEAD){//思路是让要删除的这个数组元素下标等于,最后一个数组元素,再缩容bombs[i] = bombs[bombs.length-1];bombs = Arrays.copyOf(bombs,bombs.length-1);}}}public void judgeIsHit(){//判断潜水艇和深水炸弹碰撞for(int i = 0;i<submarines.length;i++){for(int j = 0;j<bombs.length;j++){if(submarines[i].isHit(bombs[j])){//把潜水艇和深水炸弹的状态设为DEADsubmarines[i].status = SeaObject.DEAD;bombs[j].status = SeaObject.DEAD;//得分 先判断这个潜艇对象是否继承EnemyScore接口if(submarines[i] instanceof EnemyScore){score += ((EnemyScore) submarines[i]).getScore();}//得命 先判断这个潜艇对象是否继承EnemyLife接口if(submarines[i] instanceof EnemyLife){ship.addLife();//加命}}}}//判断战舰和水雷碰撞for(int i = 0;i<mines.length;i++){if(mines[i].isHit(ship)){//把水雷的状态设为DEADmines[i].status = SeaObject.DEAD;ship.subtractLife();}}}public void checkGameOverAction(){if(ship.getLife()==0){gameStatus = GAMEOVER;}}public void action(){addBomb();int period = 10;//delay和period都设置为10毫秒Timer timer = new Timer();//新建一个Timer对象timer.schedule(new TimerTask() {/*** 每10毫秒调用schedule* 并重写TimerTask里面的run方法* 这里用到的知识是匿名内部类*/@Overridepublic void run() {/*** 这里面需要写的是新建潜艇,深水炸弹,鱼雷对象* 移动* 撞击爆炸消失等方法*/addSubmarine();//生成新的潜水艇对象addMine();//生成新的深水炸弹对象objectMove();//除了战舰所有对象移动deleteOutOfBounds();//删除超过边界的对象judgeIsHit();//判断两个对象是否碰撞checkGameOverAction();//检查游戏是不是结束repaint();//重写调用paint方法}}, period, period);}//主方法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);//1)设置窗口可见  2)尽快调用paint()方法world.action();}
}

这篇关于Java 面向对象战舰小游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/835305

相关文章

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis