Java坦克大战(三)
关于这个坦克大战的项目是在学习Java基础的时候,拿来练习的最近看到这些代码,感觉很亲切,就把他们都复制下来,编辑成博客。回首看去,Java基础的学习确实应该建立在找项目练习上,这样才能将学到的基础知识用到实际当中,不然你知道什么是面向对象编程,什么是线程,什么是死锁,概念都了解了一大堆,等到实际应用的时候,还是力不从心。初学者千万不要灰心,真心是敲着敲着就有感觉了。下面还是循序渐进的介绍这个项目的几个版本,注释我写的很详细,新功能添加后部分代码有改动,如果感兴趣,可以看前几篇博客。
坦克大战(1.4版本)
1.MyTankGame类:
- /*
- * 删掉很多之前的注释
- * 功能:线程(坦克打子弹)进过分析:子弹是个类
- */
- package com.fanghua3;
- import java.awt.*;
- import java.awt.event.KeyEvent;
- import java.util.Vector;
- import javax.swing.*;
- public class MyTankGame1_4 extends JFrame {
- Mypanel1_2 mp = null;
- public static void main(String[] args) {
- new MyTankGame1_4();
- }
- // 构造函数
- public MyTankGame1_4() {
- mp = new Mypanel1_2();
- // 启动mp线程
- Thread t = new Thread(mp);
- t.start();
- this.add(mp);
- // 注册监听
- this.addKeyListener(mp);
- this.setSize(400, 300);
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- this.setVisible(true);
- }
- }
- // 我的面板,拓宽思路:Panel本身就是一个刷新体
- class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {
- // 定义我的坦克
- Hero1_2 hero = null;
- // 定义敌人的坦克(不止一辆,线程安全,集合)
- Vector<EnemyTank> ets = new Vector<EnemyTank>();
- int enSize = 3;// 敌人坦克保持三个
- // 构造函数
- public Mypanel1_2() {
- hero = new Hero1_2(10, 10);
- for (int i = 0; i < enSize; i++) {
- // 创建一辆敌人的坦克
- EnemyTank et = new EnemyTank((i + 1) * 50, 0);
- et.setColor(0);
- // 坦克默认反向是0(向上),这里改一下
- et.setDirect(2);
- // 加入
- ets.add(et);
- }
- }
- // 重写paint函数
- public void paint(Graphics g) {
- // 一定要调用
- super.paint(g);
- g.fillRect(0, 0, 400, 300);
- // 画出自己的坦克(将方向填进去)
- this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
- // 画出子弹(后添加 hero.s.isLive==true,节省资源)
- if (hero.s != null && hero.s.isLive == true) {
- g.draw3DRect(hero.s.x, hero.s.y, 1, 1, false);
- }
- // 画出敌人的坦克
- for (int i = 0; i < enSize; i++) {
- this.drawTank(ets.get(i).getX(), ets.get(i).getY(), g, ets.get(i)
- .getDirect(), 0);
- }
- }
- // 画出坦克的函数
- public void drawTank(int x, int y, Graphics g, int direct, int type) {
- // 坦克类型
- switch (type) {
- case 0:
- g.setColor(Color.green);
- break;
- case 1:
- g.setColor(Color.yellow);
- break;
- }
- // 方向设置
- switch (direct) {
- // 向上
- case 0:
- g.fill3DRect(x, y, 5, 30, false);
- g.fill3DRect(x + 15, y, 5, 30, false);
- g.fill3DRect(x + 5, y + 5, 10, 20, false);
- g.fillOval(x + 5, y + 10, 10, 10);
- g.drawLine(x + 10, y + 15, x + 10, y);
- break;
- // 向右
- case 1:
- g.fill3DRect(x, y, 30, 5, false);
- g.fill3DRect(x, y + 15, 30, 5, false);
- g.fill3DRect(x + 5, y + 5, 20, 10, false);
- g.fillOval(x + 10, y + 5, 10, 10);
- g.drawLine(x + 15, y + 10, x + 30, y + 10);
- break;
- // 向下
- case 2:
- g.fill3DRect(x, y, 5, 30, false);
- g.fill3DRect(x + 15, y, 5, 30, false);
- g.fill3DRect(x + 5, y + 5, 10, 20, false);
- g.fillOval(x + 5, y + 10, 10, 10);
- g.drawLine(x + 10, y + 15, x + 10, y + 30);
- break;
- // 向左
- case 3:
- g.fill3DRect(x, y, 30, 5, false);
- g.fill3DRect(x, y + 15, 30, 5, false);
- g.fill3DRect(x + 5, y + 5, 20, 10, false);
- g.fillOval(x + 10, y + 5, 10, 10);
- g.drawLine(x + 15, y + 10, x, y + 10);
- break;
- }
- }
- @Override
- public void keyTyped(KeyEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void keyPressed(KeyEvent e) {
- // TODO Auto-generated method stub
- // 已更正为顺时针
- if (e.getKeyCode() == KeyEvent.VK_UP
- || e.getKeyCode() == KeyEvent.VK_W) {
- this.hero.moveUp();
- this.hero.setDirect(0);
- } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
- || e.getKeyCode() == KeyEvent.VK_D) {
- this.hero.setDirect(1);
- this.hero.moveRight();
- } else if (e.getKeyCode() == KeyEvent.VK_DOWN
- || e.getKeyCode() == KeyEvent.VK_S) {
- this.hero.moveDown();
- this.hero.setDirect(2);
- } else if (e.getKeyCode() == KeyEvent.VK_LEFT
- || e.getKeyCode() == KeyEvent.VK_A) {
- this.hero.moveLeft();
- this.hero.setDirect(3);
- } else if (e.getKeyCode() == KeyEvent.VK_J) {
- // 将J键设置为发出子弹
- this.hero.shotEnemy();
- this.repaint();
- }
- }
- @Override
- public void keyReleased(KeyEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- // 每隔100毫秒去重绘
- while (true) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- // 重绘
- this.repaint();
- }
- }
- }
2.Menbers类:
- package com.fanghua3;
- //子弹类
- class Shot implements Runnable{
- int x;
- int y;
- int direct;
- //设置子弹的消亡(默认活着的)
- boolean isLive=true;
- //speed要给个初始值1,之前给0,按J键,子弹没有动
- int speed=1;
- public Shot(int x, int y,int direct) {
- super();
- this.x = x;
- this.y= y;
- this.direct=direct;
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- while(true){
- //设置子弹休息50毫秒
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- switch(direct){
- case 0:
- y-=speed;
- break;
- case 1:
- x+=speed;
- break;
- case 2:
- y+=speed;
- break;
- case 3:
- x-=speed;
- break;
- }
- System.out.println("子弹坐标x="+x+"y="+y);
- //子弹什么时候死亡
- //判断该子弹是否碰到边缘
- if(x<0||x>400||y<0||y>300){
- this.isLive=false;
- break;
- }
- }
- }
- }
- //坦克类
- class Tank1_2 {
- int x = 0;
- int y = 0;
- // 坦克方向:0表示上,1表示右,2表示下,3表示左
- int direct = 0;
- int speed = 1;
- //坦克的颜色
- int color;
- public int getColor() {
- return color;
- }
- public void setColor(int color) {
- this.color = color;
- }
- public int getSpeed() {
- return speed;
- }
- public void setSpeed(int speed) {
- this.speed = speed;
- }
- public int getDirect() {
- return direct;
- }
- public void setDirect(int direct) {
- this.direct = direct;
- }
- public int getX() {
- return x;
- }
- public void setX(int x) {
- this.x = x;
- }
- public int getY() {
- return y;
- }
- public void setY(int y) {
- this.y = y;
- }
- // 构造函数
- public Tank1_2(int x, int y) {
- this.x = x;
- this.y = y;
- }
- }
- //敌人的坦克
- class EnemyTank extends Tank1_2{
- public EnemyTank(int x, int y) {
- super(x, y);
- // TODO Auto-generated constructor stub
- }
- }
- //我的坦克
- class Hero1_2 extends Tank1_2 {
- //子弹
- Shot s=null;
- public Hero1_2(int x, int y) {
- super(x, y);
- }
- //坦克开火
- public void shotEnemy(){
- switch(this.direct){
- case 0:
- s=new Shot(x+10,y,0);
- break;
- case 1:
- s=new Shot(x+30,y+10,1);
- break;
- case 2:
- s=new Shot(x+10,y+30,2);
- break;
- case 3:
- s=new Shot(x,y+10,3);
- break;
- }
- //启动子弹线程
- Thread t=new Thread(s);
- t.start();
- }
- public void moveUp() {
- y -= speed;
- }
- public void moveRight() {
- x += speed;
- }
- public void moveDown() {
- y += speed;
- }
- public void moveLeft() {
- x -= speed;
- }
- }
坦克大战(1.5版本)
1.MyTankGame类:
- /*
- * 删掉很多之前的注释
- * 功能:子弹连发,(线程)最多5颗子弹
- * 敌人坦克消失
- */
- package com.fanghua4;
- import java.awt.*;
- import java.awt.event.KeyEvent;
- import java.util.Vector;
- import javax.swing.*;
- public class MyTankGame1_5 extends JFrame {
- Mypanel1_2 mp = null;
- public static void main(String[] args) {
- new MyTankGame1_5();
- }
- // 构造函数
- public MyTankGame1_5() {
- mp = new Mypanel1_2();
- // 启动mp线程
- Thread t = new Thread(mp);
- t.start();
- this.add(mp);
- // 注册监听
- this.addKeyListener(mp);
- this.setSize(400, 300);
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- this.setVisible(true);
- }
- }
- // 我的面板,拓宽思路:Panel本身就是一个刷新体
- class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {
- // 定义我的坦克
- Hero1_2 hero = null;
- // 定义敌人的坦克(不止一辆,线程安全,集合)
- Vector<EnemyTank> ets = new Vector<EnemyTank>();
- int enSize = 3;// 敌人坦克保持三个
- // 构造函数
- public Mypanel1_2() {
- hero = new Hero1_2(10, 10);
- for (int i = 0; i < enSize; i++) {
- // 创建一辆敌人的坦克
- EnemyTank et = new EnemyTank((i + 1) * 50, 0);
- et.setColor(0);
- // 坦克默认反向是0(向上),这里改一下
- et.setDirect(2);
- // 加入
- ets.add(et);
- }
- }
- // 重写paint函数
- public void paint(Graphics g) {
- // 一定要调用
- super.paint(g);
- g.fillRect(0, 0, 400, 300);
- // 画出自己的坦克(将方向填进去)
- this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
- // 从ss中取出每一颗子弹,并画出
- for (int i = 0; i < hero.ss.size(); i++) {
- Shot myShot = hero.ss.get(i);
- if (myShot != null && myShot.isLive == true) {
- g.draw3DRect(myShot.x, myShot.y, 1, 1, false);
- /*
- * 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
- * &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
- * 1, 1,false); }
- */
- }
- if (myShot.isLive == false) {
- // 从ss(向量)中删除该子弹
- // hero.ss.remove(i);会报异常。
- hero.ss.remove(myShot);
- }
- }
- // 画出敌人的坦克
- for (int i = 0; i < enSize; i++) {
- EnemyTank et = ets.get(i);
- if (et.isLive) {
- this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);
- }
- }
- }
- // 写一个函数 专门判断是否击中敌人坦克
- public void hitTank(Shot s, EnemyTank et) {
- // 判断该坦克的方向
- switch (et.direct) {
- // 敌人坦克的方向是0或2,一致
- case 0:
- case 2:
- if (s.x > et.x && s.x < et.x + 20 && s.y > et.y && s.y < et.y + 30) {
- // 击中(子弹死亡,敌人四万)
- s.isLive = false;
- et.isLive = false;
- }
break;- case 1:
- case 3:
- if (s.x > et.x && s.x < et.x + 30 && s.y > et.y && s.y < et.y + 20) {
- // 击中(子弹死亡,敌人四万)
- s.isLive = false;
- et.isLive = false;
- }
break;- }
- }
- // 画出坦克的函数
- public void drawTank(int x, int y, Graphics g, int direct, int type) {
- // 坦克类型
- switch (type) {
- case 0:
- g.setColor(Color.green);
- break;
- case 1:
- g.setColor(Color.yellow);
- break;
- }
- // 方向设置
- switch (direct) {
- // 向上
- case 0:
- g.fill3DRect(x, y, 5, 30, false);
- g.fill3DRect(x + 15, y, 5, 30, false);
- g.fill3DRect(x + 5, y + 5, 10, 20, false);
- g.fillOval(x + 5, y + 10, 10, 10);
- g.drawLine(x + 10, y + 15, x + 10, y);
- break;
- // 向右
- case 1:
- g.fill3DRect(x, y, 30, 5, false);
- g.fill3DRect(x, y + 15, 30, 5, false);
- g.fill3DRect(x + 5, y + 5, 20, 10, false);
- g.fillOval(x + 10, y + 5, 10, 10);
- g.drawLine(x + 15, y + 10, x + 30, y + 10);
- break;
- // 向下
- case 2:
- g.fill3DRect(x, y, 5, 30, false);
- g.fill3DRect(x + 15, y, 5, 30, false);
- g.fill3DRect(x + 5, y + 5, 10, 20, false);
- g.fillOval(x + 5, y + 10, 10, 10);
- g.drawLine(x + 10, y + 15, x + 10, y + 30);
- break;
- // 向左
- case 3:
- g.fill3DRect(x, y, 30, 5, false);
- g.fill3DRect(x, y + 15, 30, 5, false);
- g.fill3DRect(x + 5, y + 5, 20, 10, false);
- g.fillOval(x + 10, y + 5, 10, 10);
- g.drawLine(x + 15, y + 10, x, y + 10);
- break;
- }
- }
- @Override
- public void keyTyped(KeyEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void keyPressed(KeyEvent e) {
- // TODO Auto-generated method stub
- // 已更正为顺时针
- if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
- this.hero.moveUp();
- this.hero.setDirect(0);
- } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
- || e.getKeyCode() == KeyEvent.VK_D) {
- this.hero.setDirect(1);
- this.hero.moveRight();
- } else if (e.getKeyCode() == KeyEvent.VK_DOWN
- || e.getKeyCode() == KeyEvent.VK_S) {
- this.hero.moveDown();
- this.hero.setDirect(2);
- } else if (e.getKeyCode() == KeyEvent.VK_LEFT
- || e.getKeyCode() == KeyEvent.VK_A) {
- this.hero.moveLeft();
- this.hero.setDirect(3);
- } else if (e.getKeyCode() == KeyEvent.VK_J) {
- // 将J键设置为发出子弹
- // 子弹连发,J被按几下,发几颗:this.hero.shotEnemy();
- // this.repaint();在run函数里,不应该设计在这里
- if (this.hero.ss.size() <= 4) {
- this.hero.shotEnemy();
- }
- }
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- // 每隔100毫秒去重绘
- while (true) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- // 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法)
- // 每一颗子弹都要和每个坦克进行匹配
- for (int i = 0; i < hero.ss.size(); i++) {
- // 取出子弹
- Shot myShot = hero.ss.get(i);
- // 判断子弹是否有效
- if (myShot.isLive) {
- // 取出每个坦克,与它判断
- for (int j = 0; j < ets.size(); j++) {
- // 取出坦克
- EnemyTank et = ets.get(j);
- if (et.isLive) {
- this.hitTank(myShot, et);
- }
- }
- }
- }
- // 重绘
- this.repaint();
- }
- }
- @Override
- public void keyReleased(KeyEvent e) {
- // TODO Auto-generated method stub
- }
- }
2.Menbers类:
- package com.fanghua4;
- import java.util.Vector;
- //子弹类
- class Shot implements Runnable {
- int x;
- int y;
- int direct;
- // 设置子弹的消亡(默认活着的)
- boolean isLive = true;
- // speed要给个初始值1,之前给0,按J键,子弹没有动
- int speed = 1;
- public Shot(int x, int y, int direct) {
- super();
- this.x = x;
- this.y = y;
- this.direct = direct;
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- while (true) {
- // 设置子弹休息50毫秒
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- switch (direct) {
- case 0:
- y -= speed;
- break;
- case 1:
- x += speed;
- break;
- case 2:
- y += speed;
- break;
- case 3:
- x -= speed;
- break;
- }
- System.out.println("子弹坐标x=" + x + "y=" + y);
- // 子弹什么时候死亡
- // 判断该子弹是否碰到边缘
- if (x < 0 || x > 400 || y < 0 || y > 300) {
- this.isLive = false;
- break;
- }
- }
- }
- }
- // 坦克类
- class Tank1_2 {
- int x = 0;
- int y = 0;
- // 坦克方向:0表示上,1表示右,2表示下,3表示左
- int direct = 0;
- int speed = 1;
- // 坦克的颜色
- int color;
- public int getColor() {
- return color;
- }
- public void setColor(int color) {
- this.color = color;
- }
- public int getSpeed() {
- return speed;
- }
- public void setSpeed(int speed) {
- this.speed = speed;
- }
- public int getDirect() {
- return direct;
- }
- public void setDirect(int direct) {
- this.direct = direct;
- }
- public int getX() {
- return x;
- }
- public void setX(int x) {
- this.x = x;
- }
- public int getY() {
- return y;
- }
- public void setY(int y) {
- this.y = y;
- }
- // 构造函数
- public Tank1_2(int x, int y) {
- this.x = x;
- this.y = y;
- }
- }
- // 敌人的坦克
- class EnemyTank extends Tank1_2 {
- boolean isLive = true;
- public EnemyTank(int x, int y) {
- super(x, y);
- // TODO Auto-generated constructor stub
- }
- }
- // 我的坦克
- class Hero1_2 extends Tank1_2 {
- // 多个子弹,用向量创建
- Vector<Shot> ss = new Vector<Shot>();
- // 子弹
- Shot s = null;
- public Hero1_2(int x, int y) {
- super(x, y);
- }
- // 坦克开火
- public void shotEnemy() {
- switch (this.direct) {
- case 0:
- s = new Shot(x + 10, y, 0);
- // 把子弹加入向量
- ss.add(s);
- break;
- case 1:
- s = new Shot(x + 30, y + 10, 1);
- // 把子弹加入向量
- ss.add(s);
- break;
- case 2:
- s = new Shot(x + 10, y + 30, 2);
- // 把子弹加入向量
- ss.add(s);
- break;
- case 3:
- s = new Shot(x, y + 10, 3);
- // 把子弹加入向量
- ss.add(s);
- break;
- }
- // 启动子弹线程
- Thread t = new Thread(s);
- t.start();
- }
- public void moveUp() {
- y -= speed;
- }
- public void moveRight() {
- x += speed;
- }
- public void moveDown() {
- y += speed;
- }
- public void moveLeft() {
- x -= speed;
- }
- }
坦克大战(1.6版本)
1.MyTankGame类
- /*
- * 功能:
- * 1.实现爆炸效果
- * 2.敌人坦克可移动,可以连发子弹
- * 3.敌人击中我的坦克,我爆炸
- * 4.击中第一个坦克爆炸的效果不明显
- */
- package com.fanghua5;
- import java.awt.*;
- import java.awt.event.KeyEvent;
- import java.util.Vector;
- import javax.swing.*;
- public class MyTankGame1_6 extends JFrame {
- Mypanel1_2 mp = null;
- public static void main(String[] args) {
- new MyTankGame1_6();
- }
- // 构造函数
- public MyTankGame1_6() {
- mp = new Mypanel1_2();
- // 启动mp线程
- Thread t = new Thread(mp);
- t.start();
- this.add(mp);
- // 注册监听
- this.addKeyListener(mp);
- this.setSize(400, 300);
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- this.setVisible(true);
- }
- }
- // 我的面板,拓宽思路:Panel本身就是一个刷新体
- class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {
- // 定义我的坦克
- Hero1_2 hero = null;
- // 定义敌人的坦克(不止一辆,线程安全,集合)
- Vector<EnemyTank> ets = new Vector<EnemyTank>();
- // 定义炸弹集合
- Vector<Bomb> bombs = new Vector<Bomb>();
- int enSize = 4;// 敌人坦克保持四个
- // 定义三张图片(三张图片才能组成一颗炸弹)
- Image image1 = null;
- Image image2 = null;
- Image image3 = null;
- // 构造函数
- public Mypanel1_2() {
- hero = new Hero1_2(10, 10);
- for (int i = 0; i < enSize; i++) {
- // 创建一辆敌人的坦克
- EnemyTank et = new EnemyTank((i + 1) * 50, 0);
- et.setColor(0);
- // 坦克默认反向是0(向上),这里改一下
- et.setDirect(2);
- // 加入
- ets.add(et);
- // 启动敌人的坦克
- Thread t = new Thread(et);
- t.start();
- // 给敌人坦克添加一颗子弹
- Shot s = new Shot(et.x + 10, et.y + 30, 2);
- // 加入给敌人的坦克
- et.ss.add(s);
- Thread t2 = new Thread(s);
- t2.start();
- ets.add(et);
- }
- // 初始话图片,这样做击中第一个坦克,爆炸的效果不明显。下面优化
- image1 = Toolkit.getDefaultToolkit().getImage(
- Panel.class.getResource("/bomb_1.gif"));
- image2 = Toolkit.getDefaultToolkit().getImage(
- Panel.class.getResource("/bomb_2.gif"));
- image3 = Toolkit.getDefaultToolkit().getImage(
- Panel.class.getResource("/bomb_3.gif"));
- // 引包:import javax.imageio.ImagesssIO;
- // try {
- // image1=ImageIO.read(new File("/bomsb_1.gif"));
- // image2=ImageIO.read(new File("/bomb_2.gif"));
- // image3=ImageIO.read(new File("/bomb_3.gif"));
- // } catch (IOException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- }
- // 重写paint函数
- public void paint(Graphics g) {
- // 一定要调用
- super.paint(g);
- g.fillRect(0, 0, 400, 350);
- // 画出自己的坦克(将方向填进去)
- if (hero.isLive == true) {
- this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
- }
- // 从ss中取出每一颗子弹,并画出
- for (int i = 0; i < hero.ss.size(); i++) {
- Shot myShot = hero.ss.get(i);
- if (myShot != null && myShot.isLive == true) {
- g.draw3DRect(myShot.x, myShot.y, 1, 1, false);
- /*
- * 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
- * &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
- * 1, 1,false); }
- */
- }
- if (myShot.isLive == false) {
- // 从ss(向量)中删除该子弹
- // hero.ss.remove(i);会报异常。
- hero.ss.remove(myShot);
- }
- }
- // 画出炸弹
- for (int i = 0; i < bombs.size(); i++) {
- // 取出炸弹
- Bomb b = bombs.get(i);
- if (b.life > 6) {
- g.drawImage(image1, b.x, b.y, 30, 30, this);
- } else if (b.life > 4) {
- g.drawImage(image2, b.x, b.y, 30, 30, this);
- } else {
- g.drawImage(image3, b.x, b.y, 30, 30, this);
- }
- // 让b的生命值减小
- b.lifeDown();
- // 如果炸弹生命值为零,就把该炸弹从bombs向量中去掉
- if (b.life == 0) {
- bombs.remove(b);
- }
- }
- // 画出敌人的坦克
- for (int i = 0; i < ets.size(); i++) {
- EnemyTank et = ets.get(i);
- if (et.isLive) {
- this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);
- // 画出敌人的子弹
- for (int j = 0; j < et.ss.size(); j++) {
- // 取出子弹
- Shot enemyShot = et.ss.get(j);
- if (enemyShot != null && enemyShot.isLive == true) {
- g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
- }
- if (enemyShot.isLive == false) {
- // 如果敌人的坦克死亡了,就从Vector中删除
- et.ss.remove(enemyShot);
- }
- }
- }
- }
- }
- // 判断敌人的子弹是否击中我
- public void hitMe() {
- // 取出每一个敌人的坦克
- for (int i = 0; i < this.ets.size(); i++) {
- // 取出坦克
- EnemyTank et = ets.get(i);
- // 取出每一颗子弹
- for (int j = 0; j < et.ss.size(); j++) {
- // 取出子弹
- Shot enemyShot = et.ss.get(j);
- this.hitTank(enemyShot, hero);
- }
- }
- }
- // 判断我是否击中敌人的坦克
- public void hitEnemyTank() {
- // 判断是否被击中敌人的坦克
- for (int i = 0; i < hero.ss.size(); i++) {
- // 取出我的子弹与敌人坦克匹配
- Shot myShot = hero.ss.get(i);
- // 判断子弹是否有效
- if (myShot.isLive) {
- // 取出每个坦克,与它判断
- for (int j = 0; j < ets.size(); j++) {
- // 取出坦克
- EnemyTank et = ets.get(j);
- if (et.isLive) {
- this.hitTank(myShot, et);
- }
- }
- }
- }
- }
- // 写一个函数 专门判断是否击中敌人坦克(原来第二参数: EnemyTank et)
- public void hitTank(Shot s, Tank1_2 et) {
- // 判断该坦克的方向
- switch (et.direct) {
- // 敌人坦克的方向是0或2,一致
- case 0:
- case 2:
- if (s.x >= et.x && s.x <= et.x + 20 && s.y >= et.y
- && s.y <= et.y + 30) {
- // 击中(子弹死亡,敌人死亡)
- s.isLive = false;
- et.isLive = false;
- // 创建一颗炸弹,放入Vector中
- Bomb b = new Bomb(et.x, et.y);
- // 放入
- bombs.add(b);
- }
break;- case 1:
- case 3:
- if (s.x >= et.x && s.x <= et.x + 30 && s.y >= et.y
- && s.y <= et.y + 20) {
- // 击中(子弹死亡,敌人死亡)
- s.isLive = false;
- et.isLive = false;
- // 创建一颗炸弹,放入Vector中
- Bomb b = new Bomb(et.x, et.y);
- // 放入
- bombs.add(b);
- }
break;- }
- }
- // 画出坦克的函数
- public void drawTank(int x, int y, Graphics g, int direct, int type) {
- // 坦克类型
- switch (type) {
- case 0:
- g.setColor(Color.green);
- break;
- case 1:
- g.setColor(Color.yellow);
- break;
- }
- // 方向设置
- switch (direct) {
- // 向上
- case 0:
- g.fill3DRect(x, y, 5, 30, false);
- g.fill3DRect(x + 15, y, 5, 30, false);
- g.fill3DRect(x + 5, y + 5, 10, 20, false);
- g.fillOval(x + 5, y + 10, 10, 10);
- g.drawLine(x + 10, y + 15, x + 10, y);
- break;
- // 向右
- case 1:
- g.fill3DRect(x, y, 30, 5, false);
- g.fill3DRect(x, y + 15, 30, 5, false);
- g.fill3DRect(x + 5, y + 5, 20, 10, false);
- g.fillOval(x + 10, y + 5, 10, 10);
- g.drawLine(x + 15, y + 10, x + 30, y + 10);
- break;
- // 向下
- case 2:
- g.fill3DRect(x, y, 5, 30, false);
- g.fill3DRect(x + 15, y, 5, 30, false);
- g.fill3DRect(x + 5, y + 5, 10, 20, false);
- g.fillOval(x + 5, y + 10, 10, 10);
- g.drawLine(x + 10, y + 15, x + 10, y + 30);
- break;
- // 向左
- case 3:
- g.fill3DRect(x, y, 30, 5, false);
- g.fill3DRect(x, y + 15, 30, 5, false);
- g.fill3DRect(x + 5, y + 5, 20, 10, false);
- g.fillOval(x + 10, y + 5, 10, 10);
- g.drawLine(x + 15, y + 10, x, y + 10);
- break;
- }
- }
- @Override
- public void keyTyped(KeyEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void keyPressed(KeyEvent e) {
- // TODO Auto-generated method stub
- // 已更正为顺时针
- if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
- this.hero.moveUp();
- this.hero.setDirect(0);
- } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
- || e.getKeyCode() == KeyEvent.VK_D) {
- this.hero.setDirect(1);
- this.hero.moveRight();
- } else if (e.getKeyCode() == KeyEvent.VK_DOWN
- || e.getKeyCode() == KeyEvent.VK_S) {
- this.hero.moveDown();
- this.hero.setDirect(2);
- } else if (e.getKeyCode() == KeyEvent.VK_LEFT
- || e.getKeyCode() == KeyEvent.VK_A) {
- this.hero.moveLeft();
- this.hero.setDirect(3);
- } else if (e.getKeyCode() == KeyEvent.VK_J) {
- // 将J键设置为发出子弹
- // 子弹连发,J被按几下,发几颗:this.hero.shotEnemy();
- // this.repaint();在run函数里,不应该设计在这里
- if (this.hero.ss.size() <= 4) {
- this.hero.shotEnemy();
- }
- }
- }
- @Override
- public void keyReleased(KeyEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- // 每隔100毫秒去重绘
- while (true) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- // 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法)
- // 每一颗子弹都要和每个坦克进行匹配
- for (int i = 0; i < hero.ss.size(); i++) {
- // 取出子弹
- Shot myShot = hero.ss.get(i);
- // 判断子弹是否有效
- if (myShot.isLive) {
- // 取出每个坦克,与它判断
- for (int j = 0; j < ets.size(); j++) {
- // 取出坦克
- EnemyTank et = ets.get(j);
- if (et.isLive) {
- this.hitTank(myShot, et);
- }
- }
- }
- }
- this.hitEnemyTank();
- this.hitMe();
- // 重绘
- this.repaint();
- }
- }
- }
2.Menbers类:
- package com.fanghua5;
- import java.util.Vector;
- //炸弹类(没必要定义为线程,因为它不会移动,没有坐标改变)
- class Bomb {
- // 定义炸弹的坐标
- int x, y;
- int life = 9;// 炸弹的生命(三张图片)
- // 可以看出isLive很有用,它可以决定类(或者对象)要不要展现在面板上
- boolean isLive = true;
- public Bomb(int x, int y) {
- this.x = x;
- this.y = y;
- }
- // 炸弹减少生命值
- public void lifeDown() {
- if (life > 0) {
- life--;
- } else {
- this.isLive = false;
- }
- }
- }
- // 子弹类
- class Shot implements Runnable {
- int x;
- int y;
- int direct;
- // 设置子弹的消亡(默认活着的)
- boolean isLive = true;
- // speed要给个初始值1,之前给0,按J键,子弹没有动
- int speed = 1;
- public Shot(int x, int y, int direct) {
- super();
- this.x = x;
- this.y = y;
- this.direct = direct;
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- while (true) {
- // 设置子弹休息50毫秒
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- switch (direct) {
- case 0:
- y -= speed;
- break;
- case 1:
- x += speed;
- break;
- case 2:
- y += speed;
- break;
- case 3:
- x -= speed;
- break;
- }
- // 测试用:System.out.println("子弹坐标x=" + x + "y=" + y);
- // 子弹什么时候死亡
- // 判断该子弹是否碰到边缘
- if (x < 0 || x > 400 || y < 0 || y > 300) {
- this.isLive = false;
- break;
- }
- }
- }
- }
- // 坦克类
- class Tank1_2 {
- int x = 0;
- int y = 0;
- boolean isLive=true;
- // 坦克方向:0表示上,1表示右,2表示下,3表示左
- int direct = 0;
- int speed = 1;
- // 坦克的颜色
- int color;
- public int getColor() {
- return color;
- }
- public void setColor(int color) {
- this.color = color;
- }
- public int getSpeed() {
- return speed;
- }
- public void setSpeed(int speed) {
- this.speed = speed;
- }
- public int getDirect() {
- return direct;
- }
- public void setDirect(int direct) {
- this.direct = direct;
- }
- public int getX() {
- return x;
- }
- public void setX(int x) {
- this.x = x;
- }
- public int getY() {
- return y;
- }
- public void setY(int y) {
- this.y = y;
- }
- // 构造函数
- public Tank1_2(int x, int y) {
- this.x = x;
- this.y = y;
- }
- }
- // 敌人的坦克(做成线程,会移动)
- class EnemyTank extends Tank1_2 implements Runnable {
- //从父类继承了,去掉:boolean isLive = true;
- int times = 0;// 让time累积
- // 定义向量,可以存放敌人的子弹
- Vector<Shot> ss = new Vector<Shot>();
- // 敌人添加子弹,应该刚刚创建坦克和敌人子弹死亡后
- public EnemyTank(int x, int y) {
- super(x, y);
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- while (true) {
- try {
- // 设置坦克休息一会
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- switch (this.direct) {
- case 0:
- // 说明坦克正在向上运动(继续往上走,符合实际)
- // y -= speed;设置坦克平滑移动的效果
- for (int i = 0; i < 30; i++) {
- if (y > 0) {
- y -= speed;
- }
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- break;
- case 1:
- for (int i = 0; i < 30; i++) {
- // 这里注意坐标起点问题不是(400x300)
- if (x < 350) {
- x += speed;
- }
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- break;
- case 2:
- for (int i = 0; i < 30; i++) {
- if (y < 250) {
- y += speed;
- }
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- break;
- case 3:
- for (int i = 0; i < 30; i++) {
- if (x > 0) {
- x -= speed;
- }
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- break;
- }
- this.times++;
- // 设置3秒发一颗子弹
- if (times % 2 == 0) {
- if (isLive) {
- if (ss.size() < 5) {
- Shot s = null;
- // 没有子弹,添加
- switch (direct) {
- case 0:
- s = new Shot(x + 10, y, 0);
- ss.add(s);
- break;
- case 1:
- s = new Shot(x + 30, y + 10, 1);
- ss.add(s);
- break;
- case 2:
- s = new Shot(x + 10, y + 30, 2);
- ss.add(s);
- break;
- case 3:
- s = new Shot(x, y + 10, 3);
- ss.add(s);
- break;
- }
- // 启动子弹线程
- Thread t = new Thread(s);
- t.start();
- }
- }
- }
- // 让坦克随机产生一个新的方向
- this.direct = (int) (Math.random() * 4);
- // 判断敌人坦克是否死亡了(双等号)
- if (this.isLive == false) {
- // 让坦克死亡,后退出线程
- return;
- }
- }
- }
- }
- // 我的坦克
- class Hero1_2 extends Tank1_2 {
- // 多个子弹,用向量创建
- Vector<Shot> ss = new Vector<Shot>();
- // 子弹
- Shot s = null;
- public Hero1_2(int x, int y) {
- super(x, y);
- }
- // 坦克开火
- public void shotEnemy() {
- switch (this.direct) {
- case 0:
- s = new Shot(x + 10, y, 0);
- // 把子弹加入向量
- ss.add(s);
- break;
- case 1:
- s = new Shot(x + 30, y + 10, 1);
- // 把子弹加入向量
- ss.add(s);
- break;
- case 2:
- s = new Shot(x + 10, y + 30, 2);
- // 把子弹加入向量
- ss.add(s);
- break;
- case 3:
- s = new Shot(x, y + 10, 3);
- // 把子弹加入向量
- ss.add(s);
- break;
- }
- // 启动子弹线程(创建线程,赶紧传参,我在这里吃了大亏!)
- Thread t = new Thread(s);
- t.start();
- }
- public void moveUp() {
- y -= speed;
- }
- public void moveRight() {
- x += speed;
- }
- public void moveDown() {
- y += speed;
- }
- public void moveLeft() {
- x -= speed;
- }
- }
1.6版本(图:基本功能都已经实现)
之后,我还会继续写一篇博客,来记录该坦克大战的最终版本(2.0),这个坦克大战的项目利用Java图形界面来实现坦克的绘制,画质比较粗糙,部分的坐标没有那么精确。
Java坦克大战(三)的更多相关文章
- Java坦克大战 (三) 之可完全控制坦克朝八个方向运动
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- Java坦克大战(四)
这是我的坦克游戏大战的最后一版,里面添加很多新的功能.这个坦克大战的有很多不足之处,但是对于初学者来说依然是一个很好的练习项目,从中我们可以学习Java基础知识,将知识与项目结合,学习面向对象编程思想 ...
- Java坦克大战(二)
本文紧接上一篇讲解坦克大战这个项目,因为当初在学习的时候,是以这个案例逐步学习Java基础的,过程是先讲知识点,再将知识点逐步的融入到项目中,即给坦克添加新的功能.之前的Demo练习,想都记录下来.这 ...
- Java坦克大战(一)
接下来的几篇博客,想记录一下通过学习坦克大战项目来循序渐进的学习Java基础.主要是为了巩固基础知识,当然学习编程重要的还是多敲,问题通常是在敲代码的过程中发现的,积累也是在敲代码中寻求的经验.这个坦 ...
- Java坦克大战 (七) 之图片版
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- Java坦克大战 (六) 之增加可玩性
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- Java坦克大战 (五) 之产生敌方坦克和爆炸效果
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- Java坦克大战 (四) 之子弹的产生
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- Java坦克大战 (二) 之画一个能动的圆圈代表坦克
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
随机推荐
- Java 线程使用注意事项
事件处理线程说明 如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求,比如只是在内存中记个标识,则直接在IO线程上处理更快,因为减少了线程池调度. 但如果事件处理逻辑较慢,或者需要发起新的IO请求 ...
- 图像质量评价方法PSNR+SSIM&&评估指标SROCC,PLCC
update:2018-04-07 今天发现ssim的计算里面有高斯模糊,为了快速计算,先对每个小块进行计算,然后计算所有块的平均值.可以参考源代码实现,而且代码实现有近似的在里面!matlab中中图 ...
- 构建一个Gods Eye Android应用程序:第1部分 – 收集已安装的Android应用程序
首先问候一下我的黑客伙伴们,在之前的Introduction to Amunet 教程中,我们了解到Amunet可能是一个间谍Android应用程序. 我不浪费太多时间因而直入主题. 在本教程中,我们 ...
- 走你!Github 开源整合
加入知识星球,最好的分享交流平台哦~ <我的知识星球,最好的分享交流平台>,一年的服务平台,对于一个成年人来说,就是小费了(更多详情,请点击文章了解)~ 走你!Github 开源整合 1. ...
- 读取.Properties文件以及Spring注解读取文件内容
public class Main { public static void main(String[] args) throws IOException { //创建Properties对象 Pro ...
- Java中的引用传递和值传递
Java中的引用传递和值传递 关于Java的引用传递和值传递,在听了老师讲解后,还是没有弄清楚是怎么一回事,于是查了资料,所以在这里与大家分享,有不对的地方,欢迎大家留言. java中是没有指针的,j ...
- linux中环境变量PATH设置错误,导致ls cd 等命令不能使用,提示:没有那个文件或目录
在CentOS7中执行了 PATH=/opt/:$PATH 然后执行ls时,出现 ls-bash: ls: 没有那个文件或目录 试了试其他命令也一样无法使用 后来执行 : export PATH=/u ...
- Python Web Service
搞移动端有段时间了,一直使用别人的API,自己也只写过ASP.NET网站作为网络服务,相对来讲是很大的短板.虽然ASP.NET可以提供想要的web服务,但是其体量臃肿,响应速度非常慢,这点我非常不喜欢 ...
- MySql安装与使用(linux)
安装 MySQL 注意:此处安装是yum安装为例: MySQL安装 #yum install mysql-server 完后显示如下: MySQL初始化 #service mysqld start 查 ...
- C语言最最最基础部分(a+b为例)
此篇为C语言最基础的部分知识简单概括,对C语言有一定了解的同学建议绕道哦~另外,文底附有此文知识点详细了解的链接. 下面我们以“a+b”为例,分析这个程序的组成. #include<stdi ...