第四个版本:
从这一个版本开始,一个游戏的简单雏形已经有了,这一个版本实现了让敌人移动的同时发射子弹的功能,同时我方的坦克射击敌人的时候,可以让敌人消失
怎么样让敌人可以边移动边发射子弹:
我们需要在敌人的多线程run
代码里面,然敌人进行间歇性的走动:
@Override //我们发现坦克在原地抽搐,我们要实现坦克的平稳运行 //实现坦克运动不会越界 public void run() { do { switch (this.direct) { case 0: for (int i = 0; i < 30; i++) { if (y > 0) y -= sreed; try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 1: for (int i = 0; i < 30; i++) { if (x < 500) x += sreed; try { // 短暂的停顿 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 2: for (int i = 0; i < 30; i++) { if (y < 400) y += sreed; try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 3: for (int i = 0; i < 30; i++) { if (x > 0) x -= sreed; try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; } //不同的方向移动的方向不同 this.direct = (int) (Math.random() * 4); } while (this.isLive); } 复制代码
至于生成子弹,需要定时去轮询所有的坦克,检查坦克中组合的子弹集合是否存在子弹,如果小于一定的数量,需要生成对应的子弹对象同时加入到敌人的坦克当中。由于子弹创建就会开始执行线程进行
@Override public void run() { //限定一段时间重新绘制 while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //判断是否击中 for (int x = 0; x < mytank.vecs.size(); x++) { //每一颗子弹和每一个坦克匹配 //取出一颗子弹之前判断是否有子弹 buts = mytank.vecs.get(x); //判断子弹是否有效 if (buts.isOut()) { continue; } //取出每一个坦克与它判断 for (int y = 0; y < vec.size(); y++) { //判断敌方坦克是否死亡 if (vec.get(y).isLive) { en = vec.get(y); //记性判断是否击中操作 hitTank(en, buts); } } } //如果子弹数小于一定数目 for (int x = 0; x < vec.size(); x++) { EnemyTank et = vec.get(x); //遍历每一辆坦克的子弹集合 if (!et.isLive()) { continue; } if (et.vecs.size() < 1) { //对于不同的坦克方向生成子弹的方向也不同 Bullet enybut = null; switch (et.getDirect()) { case 0: enybut = new Bullet(et.getX() + 10, et.getY(), 0); //将创建的子弹加入到集合当中 et.vecs.addElement(enybut); break; case 1: enybut = new Bullet(et.getX() + 30, et.getY() + 10, 1); et.vecs.addElement(enybut); break; case 2: enybut = new Bullet(et.getX() + 10, et.getY() + 30, 2); et.vecs.addElement(enybut); break; case 3: enybut = new Bullet(et.getX(), et.getY() + 10, 3); et.vecs.addElement(enybut); break; } new Thread(enybut).start(); } } //重绘 this.repaint(); } } 复制代码
在子弹类当中进行不断的数值改变:
下面的内容表示子弹的类
public class Bullet implements Runnable { //隐藏一大段代码: public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } switch (this.direct) { case 0: this.y -= screed; break; case 1: this.x += screed; break; case 2: this.y += screed; break; case 3: this.x -= screed; break; } //碰到边缘消失 if (x < 0 || x > outx || y < 0 || y > outy) { isOut = true; break; } } } } 复制代码
第五个版本:
在第五个版本当中,我们实现了开始菜单的界面,同时视线菜单的不断显示:
界面会不断的闪烁
接着,敌人增加了子弹可以摧毁我们的方法
网络异常,图片无法展示
|
网络异常,图片无法展示
|
接着,我们可以实现爆炸的效果:
由于爆炸的效果不好截图,请看源代码
网络异常,图片无法展示
|
/** * 实现闪烁功能 * 重构坦克 - 第五版 * @author zxd * @version 1.0 * @date 2021/1/29 23:54 */ class SelectIsSallup extends JPanel implements Runnable { /** * 时间属性 */ int times = 0; public void paint(Graphics g) { super.paint(g); g.fillRect(0, 0, 600, 400); if (times % 2 == 0) { //画出文字 Font font1 = new Font("华文新魏", Font.BOLD, 20); //设置字体的颜色 g.setColor(Color.yellow); g.setFont(font1); g.drawString("stage 1", 200, 150); } } @Override public void run() { while (true) { try { Thread.sleep(750); } catch (InterruptedException e) { e.printStackTrace(); } if (times > 500) times = 0; times++; this.repaint(); } } } 复制代码
如何让敌人的子弹对我们造成伤害:
/** * 建立一个方法,判断是否产生碰撞 * 是否攻击了其他的坦克 * @return */ private boolean isTouchOther() { // 根据自己的方向进行选择判断 switch (this.direct) { // 坦克向上走的时候 case 0: // 取出所有的坦克对象 for (int x = 0; x < enevec.size(); x++) { EnemyTank et = enevec.get(x); //如果不是自己的坦克 if (et != this) { //如果敌人的坦克朝上或者朝下的时候 if (et.direct == 0 || et.direct == 2) { //判断边界 //对于第一个点进行判断 if (this.x >= et.x && this.x <= et.x + 20 && this.y >= et.y && this.y <= et.y + 30) { return true; } //对于第二个点进行判断 if (this.x + 20 >= et.x && this.x + 20 <= et.x + 20 && this.y >= et.y && this.y <= et.y + 30) { return true; } } //如果敌人是朝左边或者右边的时候 if (et.direct == 1 || et.direct == 3) { //判断边界 //对于第一个点进行判断 if (this.x >= et.x && this.x <= et.x + 30 && this.y >= et.y && this.y <= et.y + 20) { return true; } //对于第二个点进行判断 if (this.x + 20 >= et.x && this.x + 20 <= et.x + 30 && this.y >= et.y && this.y <= et.y + 20) { return true; } } } } break; // 坦克想右边走的时候 case 1: // 取出所有的坦克对象 for (int x = 0; x < enevec.size(); x++) { EnemyTank et = enevec.get(x); //如果不是自己的坦克 if (et != this) { //如果敌人的坦克朝上或者朝下的时候 if (et.direct == 0 || et.direct == 2) { //判断边界 //对于第一个点进行判断 if (this.x + 30 >= et.x && this.x + 30 <= et.x + 20 && this.y >= et.y && this.y <= et.y + 30) { return true; } //对于第二个点进行判断 if (this.x + 30 >= et.x && this.x + 30 <= et.x + 20 && this.y >= et.y && this.y <= et.y + 30) { return true; } } //如果敌人是朝左边或者右边的时候 if (et.direct == 1 || et.direct == 3) { //判断边界 //对于第一个点进行判断 if (this.x + 30 >= et.x && this.x + 30 <= et.x + 30 && this.y + 20 >= et.y && this.y <= et.y + 20) { return true; } //对于第二个点进行判断 if (this.x + 30 >= et.x && this.x + 30 <= et.x + 30 && this.y + 20 >= et.y && this.y <= et.y + 20) { return true; } } } } // 坦克想下的时候 case 2: // 取出所有的坦克对象 for (int x = 0; x < enevec.size(); x++) { EnemyTank et = enevec.get(x); //如果不是自己的坦克 if (et != this) { //如果敌人的坦克朝上或者朝下的时候 if (et.direct == 0 || et.direct == 2) { //判断边界 //对于第一个点进行判断 if (this.x >= et.x && this.x <= et.x + 20 && this.y + 30 >= et.y && this.y + 30 <= et.y + 30) { return true; } //对于第二个点进行判断 if (this.x + 20 >= et.x && this.x + 20 <= et.x + 20 && this.y + 30 >= et.y && this.y + 30 <= et.y + 30) { return true; } } //如果敌人是朝左边或者右边的时候 if (et.direct == 1 || et.direct == 3) { //判断边界 //对于第一个点进行判断 if (this.x >= et.x && this.x <= et.x + 30 && this.y + 30 >= et.y && this.y + 30 <= et.y + 20) { return true; } //对于第二个点进行判断 if (this.x + 20 >= et.x && this.x + 20 <= et.x + 30 && this.y + 30 >= et.y && this.y + 30 <= et.y + 20) { return true; } } } } break; // 坦克向左移动的时候 case 3: // 取出所有的坦克对象 for (int x = 0; x < enevec.size(); x++) { EnemyTank et = enevec.get(x); //如果不是自己的坦克 if (et != this) { //如果敌人的坦克朝上或者朝下的时候 if (et.direct == 0 || et.direct == 2) { //判断边界 //对于第一个点进行判断 if (this.x >= et.x && this.x <= et.x + 20 && this.y >= et.y && this.y <= et.y + 30) { return true; } //对于第二个点进行判断 if (this.x >= et.x && this.x <= et.x + 20 && this.y + 20 >= et.y && this.y + 20 <= et.y + 30) { return true; } } //如果敌人是朝左边或者右边的时候 if (et.direct == 1 || et.direct == 3) { //判断边界 //对于第一个点进行判断 if (this.x >= et.x && this.x <= et.x + 30 && this.y >= et.y && this.y <= et.y + 20) { return true; } //对于第二个点进行判断 if (this.x >= et.x && this.x <= et.x + 30 && this.y + 20 >= et.y && this.y + 20 <= et.y + 20) { return true; } } } } } return false; } 复制代码
最终版本:
在最终的版本当中,一个坦克大战的基本游戏算是完成
了,当然还有很多需要完成点。这里主要提示一下暂停这一个功能点:
暂停的主要思想是为坦克加一个状态去控制坦克的所有行为。让暂停的flag为false的时候,线程不在执行,绘画每次都是绘制在同一个位置。这样就造成了“暂停”的假象。
//暂停功能 if(e.getKeyCode()==KeyEvent.VK_P) { if(this.clickcount%2 == 0) mytank.setSuspend(false); else mytank.setSuspend(true); //利用循环将坦克类中的子弹速度变成0 for(int x=0; x<vec.size(); x++) { en = vec.get(x); //敌方坦克移动速度归于0 //坦克不允许移动 if(this.clickcount%2 == 0) en.setSuspend(false); else en.setSuspend(true); for(int y=0; y<en.vecs.size(); y++) { //子弹的速度变成0 if(this.clickcount%2 == 0) en.vecs.get(y).setSuspend(false); else en.vecs.get(y).setSuspend(true); } } this.clickcount++; } 复制代码
总结:
这个文档不是最终版本,如果有不懂的欢迎提issue,承诺给予答复但是不会再改动代码了。