第一天任务
创建了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();//启动程序执行
}
}