Java面向对象战舰小游戏
- 前言
- 思路:
- 战舰项目代码
- 1. 战舰特征和行为
- 水雷艇特征和行为
- 侦查艇特征和行为
- 鱼雷艇特征和行为
- 水雷特征和行为
- 深水炸弹特征和行为
- 2. 归纳共有特征
- 3.初始化
- 4. 画图
- 5. 重写方法
- 定时器
- 新建潜水艇对象
- 新建水雷
- 新建深水炸弹
- 重写所有类的move方法
- 6. 把超过窗口和相互碰撞的物体删掉
- 删除超过窗口的对象
- 删除相互碰撞的物体
- 7.最终代码
- Battleship
- Bomb
- Images
- Mine
- MineSubmarine
- ObserveSubmarine
- SeaObject
- TorpedoSubmarine
- World
前言
这是面向对象的小游戏,运用的的知识点有:父子类,继承,构造方法,重载,重写,静态块,修饰词
思路:
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.初始化
常量:
- 6个类的长,宽高都是固定的
- 窗口的长宽高都是固定的
变量
- 6个类的一开始坐标(x和y),注意左上角的坐标是(0,0)
- 速度
下面是各个数据
类名 | 长 | 宽 | 初始坐标(x,y) |
Battleship | 66 | 26 | (270.142) |
Bomb | 9 | 12 | 按空格键出来,这里不定义 |
mine | 11 | 11 | 生成水雷艇后定时器自动生成 |
MineSubmarine | 63 | 19 | 在窗口左边自动生成 |
TorpedoSubmarine | 64 | 20 | 在窗口左边自动生成 |
ObserveSubmarine | 63 | 19 | 在窗口左边自动生成 |
窗口 | 641 | 479 | 无 |
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),速度是3
super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);
//初始命是5
life = 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还有mine
this.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),速度是3
super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);
//初始命是5
life = 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还有mine
this.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方法
* 这里用到的知识是匿名内部类
*/
@Override
public void run() {
/**
* 这里面需要写的是新建潜艇,深水炸弹,水雷对象
* 移动
* 撞击爆炸消失等方法
*/
repaint();//重写调用paint方法
}
}, period, period);
}
新建潜水艇对象
这里用随机数的方法来生成潜艇
public SeaObject newSubmarine(){
Random rand = new Random();//生成一个Random对象
int number = rand.nextInt(3);//随机数是0到2
if(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),速度是3
super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);
//初始命是5
life = 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还有mine
this.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到2
if(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方法
* 这里用到的知识是匿名内部类
*/
@Override
public 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])){
//把潜水艇和深水炸弹的状态设为DEAD
submarines[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)){
//把水雷的状态设为DEAD
mines[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),速度是3
super(Battleship.WIDTH,Battleship.HEIGHT,200,150-Battleship.HEIGHT,3);
//初始命是5
life = 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还有mine
this.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变成0
g.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到2
if(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])){
//把潜水艇和深水炸弹的状态设为DEAD
submarines[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)){
//把水雷的状态设为DEAD
mines[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方法
* 这里用到的知识是匿名内部类
*/
@Override
public 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();
}
}