本章目的
- 使用炮筒来确定坦克目前的方向
- 让坦克发射多发炮弹问题
一、画出炮筒
一般坦克初始位置是不同的,但是我们目前的射击方向是与移动方向一致的
这就导致比较怪异,我们应该是初始时有一个射击方向,比如说:右边
class Tank{
//省略其他关键性代码....
//默认设计方向为右边
private Direction ptdir = Direction.R;
}
而我们的射击方向有了,还需要与移动时方向一致同步并且画出来
这里我们只需要画出一条直线即可,可以使用drawLine方法
我们需要知道两点来确定一条直线,而在坐标中由横(X)、纵坐标(y)确定一个点。
而这drawLine方法的四参数实际就是确定两个点,要画的直线的起始点横纵坐标和终点的横纵坐标
X1,Y1是确定直线的起始点,即横坐标为x1,纵坐标为y1的点。
同理x2,y2确定直线的终点。
例:
A(x1,y1) B(x2,y2) 就可以画出直线AB了。
参数:
x1 - 第一个点的 x 坐标。
y1 - 第一个点的 y 坐标。
x2 - 第二个点的 x 坐标。
y2 - 第二个点的 y 坐标。
而我们的坦克中,想要画出对应方向的直线,则可以使用公式计算相应的坐标
class Tank{
//省略其他关键性代码....
//添加方法完成坦克的绘画
public void draw(Graphics g) {
//省略其他关键性代码....
switch (ptdir) {
case L:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x,y + Tank. HEIGHT/2);
break;
case LU:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x,y);
break;
case U:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH/2,y);
break;
case RU:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH,y);
break;
case R:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH,y + Tank. HEIGHT/2);
break;
case RD:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH,y + Tank. HEIGHT);
break;
case D:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH/2,y + Tank. HEIGHT);
break;
case LD:
g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x,y + Tank. HEIGHT);
break;
}
}
}
这时我们运行起来就发现,我们的坦克炮筒已经出来了
但是为什么它没有随着我们的移动方向而改变射击方向呢?
那么因为我们没有根据移动方向来进行调整,我们现在添加调整一下看看
class Tank{
//省略其他关键性代码....
void move() {
//省略其他关键性代码....
if(this.dir !=Direction.STOP){
this.ptdir = dir;
}
}
}
而之前我们根据坦克的方向进行发射炮弹,会有一个问题不知道大家发现没有
比如说当我们不动的时候,是无法发射炮弹出来的
那么现在我们根据射击方向进行发射,就可以解决这个问题
class Tank{
//省略其他关键性代码....
//坦克发射子弹.....
public Missle fire(){
//省略其他关键性代码....
Missle missle = new Missle(x,y,ptdir);
return missle;
}
}
这时即使我们不动,也可以发射炮弹了
步骤总结
- ✧Tank类增加新的属性ptDir
- ✧每次move后根据Tank新的方向确定炮筒的方向
- ✧将炮简用直线的形式表现出来
二、让坦克发射多发炮弹
目前我们的坦克按下Ctrl键时,就会发射一发炮弹
但是当我们再按下Ctrl键时,就会发现坦克发出的炮弹又从头开始了
这是因为我们目前只维护了一发炮弹的发射状态
那么怎么解决这个问题呢?
我们想想能不能将发出去的炮弹用一个容器将它装起来呢?
public class TankClient extends Frame {
//使用集合容器管理炮弹
List missles = new ArrayList();
@Override
public void paint(Graphics g) {
//画出容器里的子弹
for ( int i = 0; i < missles.size();i++){
Missle m = missles.get(i);
m.draw(g);
}
//画出坦克
mytank.draw(g);
}
//省略其他关键性代码....
}
同时当我们按下Ctrl键时,我们就将炮弹放入集合容器中
class Tank{
//坦克发射子弹.....
public Missle fire(){
//省略其他关键性代码.......
Missle missle =new Missle(x,y,ptdir);
tc.missles.add(missle);
return missle;
}
}
这时我们运行起来就可以发现,我们可以连续打出多发炮弹了
但是有一个小问题:假如一直按住Ctrl键发出的炮弹就会没有间隔
这样的情况我们有两种解决方式:
- 第一种:每一枚炮弹设置间隔时间
- 第二种:将发射炮弹改为按下抬起释放Ctrl键发射炮弹
我们采用Ctrl键按下抬起发射炮弹来解决这个问题
class Tank{
//省略其他关键性代码....
//坦克键盘按下抬起监听器
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_CONTROL:
fire();
break;
}
//省略其他关键性代码.......
}
}
步骤总结
- ✧使用容器装炮弹
- ✧每当抬起Ctr键就往容器中加入新的炮弹
- ✧逐一画出每一发炮弹
三、让炮弹消亡
由于我们目前采用集合容器的方式来管理发射的炮弹
若我们对于这个游戏一直玩个几小时,那么就会造成很多很多的炮弹积累在里面
我们现在在游戏的窗口中将我们当前的炮弹数量显示出来
public class TankClient extends Frame {
//省略其他关键性代码....
@Override
public void paint(Graphics g) {
//省略其他关键性代码....
//展示炮弹容器当前数量
g.drawString("missiles count:" + missles.size()+"",10,50);
}
}
这下我们当前容器里的子弹数量就能显示出来了
刚刚我们说到若我们对于这个游戏一直玩个几小时,那么就会造成很多很多的炮弹积累在里面
那么我们什么时候就要让子弹消亡呢?
- 击中敌方坦克时
- 超出游戏边界时
我们为Missle子弹类添加属性区别存活状态、并且当超出边界时设置为消亡状态
class Missle{
//区分子弹的存活
private boolean live = true;
public boolean isLive() {return live;}
void move() {
//省略其他关键性代码....
//当子弹的x、y坐标小于0 或者大于游戏窗口的宽度与高度则消亡状态
if (x < 0 || y < 0 || x > TankClient.WIDTH || y > TankClient.HEIGHT) {
live = false;
}
}
//省略其他关键性代码....
}
而在我们的游戏界面中的绘画方法,对于消亡的子弹我们从容器中里去除
class Missle{
//引入TankClient管理子弹容器
private TankClient tc;
public Missle(int x, int y, Tank.Direction dir, TankClient tc) {
this.x = x;
this.y = y;
this.dir = dir;
this.tc = tc;
}
void move() {
//省略其他关键性代码....
//当子弹的x、y坐标小于0 或者大于游戏窗口的宽度与高度则消亡状态
if (x < 0 || y < 0 || x > TankClient.GAME_WINDTH || y > TankClient.GAME_HEIGHT) {
this.live = false;
tc.missles.remove(this);
}
//省略其他关键性代码....
}
同时当我们发出炮弹的时候,将tc传给炮弹,让炮弹在消亡的时候自己去除
class Tank{
//省略其他关键性代码....
//坦克发射子弹.....
public Missle fire(){
//省略其他关键性代码.......
Missle missle =new Missle(x,y,ptdir,tc);
tc.missles.add(missle);
return missle;
}
}
步骤总结
- ✧加入控制炮弹生死的量Live ( Missle )
- ✧当炮弹已经死去就不需要对其重画
- ✧当炮弹飞出边界就死亡
- ✧当炮弹死亡就从容器中去除
参考资料
尚学堂:坦克大战(马士兵老师)