只实现了可以用wasd来控制坦克的移动,控制了自己的坦克发射子弹,
敌方坦克可以自由发射子弹,子弹速度,敌方坦克可以自由移动,
敌方坦克在击中我,以及我击中敌方坦克后坦克会爆炸等等的操作
(主要运用了面向对象,gui,以及多线程这些方面的知识。)
思路在代码中都很详细
主类:
package MyTankGame7;
/*7.0版本
* 目的: ①:添加监听
* ②:子弹连发
* ③:最多只能连发5颗
* ④:我方的坦克击中敌人的坦克,敌人的坦克可以消失
* 5.爆炸地效果
* 6.敌人的坦克做成线程,并且可以自己随机地乱动
* 7.控制坦克可以在指定地范围内活动
* 8.让敌人的子弹在击中我方坦克的时候,我方的坦克也可以爆炸
* 过程:定义一个击中敌人的方法。
* */
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Panel;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tankgame7 extends JFrame {
MyPanel mp=null;
public Tankgame7(){
mp=new MyPanel();
//启动线程
Thread t=new Thread(mp);
t.start();
this.add(mp);
//注册监听
this.setTitle("坦克大战");
this.addKeyListener(mp);
this.setSize(400,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Tankgame7();
}
}
class MyPanel extends JPanel implements KeyListener,Runnable { //panel面板
Hero hero=null;
//声明三张图片,三张图片的切换,才能组成一个炸弹 (不是某一个坦克特有的属性)
Image image1=null;
Image image2=null;
Image image3=null;
//定义炸弹的集合
Vector<Bomb>bombs=new Vector<Bomb>();
Vector<EnemyTank>ets=new Vector<EnemyTank>();
int ensize=7;
public MyPanel(){
image1=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/a.jpg"));
image2=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/b.jpg"));
image3=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/c.jpg"));
hero=new Hero(100, 100);
//初始化敌人的坦克
for(int i=0;i<ensize;i++){
//创建一辆敌人的坦克对象,并且加入集合
EnemyTank et=new EnemyTank((i+1)*50, 0);
et.setColor(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(); //让敌人也可以去发射子弹
}
}
public void paint(Graphics g){ //画坦克
super.paint(g);
g.fillRect(0, 0, 400, 300);
// g.setColor(Color.CYAN);
//画坦克的方法
if(hero.isLive){
this.drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
}
//画子弹 方法:遍历集合,取出子弹
for(int i=0;i<hero.ss.size();i++){
Shot myshot=this.hero.ss.get(i);
if(myshot!=null&&myshot.isLive==true){
g.draw3DRect(myshot.x,myshot.y, 2, 2, false);
}
if(myshot.isLive==false){ //如果子弹死亡,就从原来的集合里面拿出这个死亡的子弹
hero.ss.remove(myshot); //这样就可以保证子弹的数量总共是5颗
}
}
//画出炸弹
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>3){
g.drawImage(image2, b.x, b.y, 30, 30, this);
}else{
g.drawImage(image3, b.x, b.y, 30, 30, this);
}
//让炸弹的生命值减少
b.lifeDown();
//如果炸弹的生命值减少为0,就把这个炸弹从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(ets.get(i).getX(), ets.get(i).getY(), g,ets.get(i).getDirect() , 0);
//顺便画出敌人的子弹
for(int j=0;j<et.ss.size();j++){
//取出子弹
Shot enemyShot=et.ss.get(j);
if(enemyShot.isLive){
g.draw3DRect(enemyShot.x, enemyShot.y, 2, 2, false);
}else{
//如果敌人的坦克死亡了,就从向量里面删除了
et.ss.remove(enemyShot);
}
}
}
}
}
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);
}
}
}
}
}
//敌人的子弹是否击中了我
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 hitTank(Shot s,Tank et){
//根据方向来判断
switch(et.direct){
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;
Bomb b1=new Bomb(et.x, et.y);
bombs.add(b1);
}
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;
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.CYAN);
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 keyPressed(KeyEvent arg0) { //0向上,1向右,2向下,3向左
// TODO Auto-generated method stub
if(arg0.getKeyCode()==KeyEvent.VK_W){
this.hero.setDirect(0); //上
hero.moveup();
}
else if(arg0.getKeyCode()==KeyEvent.VK_D){
this.hero.setDirect(1);
this.hero.moveright();
}else if(arg0.getKeyCode()==KeyEvent.VK_S){
this.hero.setDirect(2);
hero.movedown();
}else if(arg0.getKeyCode()==KeyEvent.VK_A){
this.hero.setDirect(3);
hero.moveleft();
}
if(arg0.getKeyCode()==KeyEvent.VK_J){
if(hero.ss.size()<=4){
this.hero.shotEnemy();
}
}
//必须重新绘制panel
this.repaint();
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
//每隔100ms去重画
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//判断是否击中
this.hitEnemyTank();
//判断敌人的子弹是否击中我了
this.hitMe();
//判断是否需要给坦克加入新的子弹
this.repaint();
for(int i=0;i<ets.size();i++){
EnemyTank et=ets.get(i);
if(et.isLive){
if(et.ss.size()<5){ //敌人的坦克子弹总共4颗
Shot s=null;
//没有子弹
//添加子弹
switch(et.direct){
case 0:
s=new Shot(et.x+10, et.y,0);
et.ss.add(s); //添加子弹
break;
case 1:
s=new Shot(et.x+30, et.y+10,1);
et.ss.add(s);
break;
case 2:
s=new Shot(et.x+10, et.y+30,2);
et.ss.add(s);
break;
case 3:
s=new Shot(et.x, et.y+10,3);
et.ss.add(s);
break;
}
//启动子弹的线程,否则子弹是死的
Thread t=new Thread(s);
t.start();
}
}
}
}
}
}
成员类
package MyTankGame7;
import java.util.Vector;
/*
*
*动态的做成线程,不会动的,就可以做成静态的
* */
class Bomb{ //炸弹类
int x;
int y;
int life=9; //做成爆炸 (炸弹的生命)
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 Tank{ //坦克的父类
int x;
int y;
//方向
int direct=0; // 0表示上,1表示右,2表示下,3表示左
int speed=3; //默认初始化的速度 1px
int color;
boolean isLive=true;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
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 Tank(int x,int y){
this.x=x;
this.y=y;
}
}
//敌人的坦克,把敌人的坦克升级成为线程类
class EnemyTank extends Tank implements Runnable{
//定义敌人的子弹的集合
Vector<Shot>ss=new Vector<Shot>();
// boolean isLive=true; //坦克是否活着
public EnemyTank(int x, int y) {
super(x, y);
// TODO Auto-generated constructor stub
}
@Override
public void run() { //让敌人的坦克可以自己动
// TODO Auto-generated method stub
while(true){
try{
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
switch(this.direct){//0向上,1向右,2向下,3向左'
case 0:
if(y>0){ //国定一下活动的范围
for(int i=0;i<30;i++){ //让敌人地坦克比较平滑地运动1s多变换一次方向
this.y-=speed;
try{
Thread.sleep(50);
}catch(Exception e){
e.printStackTrace();
} //try 的
}
}
break;
case 1:
if(x<400){
for(int i=0;i<30;i++){
this.x+=speed;
try{
Thread.sleep(50);
}catch(Exception e){
e.printStackTrace();
} //try 的
}
}
break;
case 2:
if(y<300){
for(int i=0;i<30;i++){
this.y+=speed;
try{
Thread.sleep(50);
}catch(Exception e){
e.printStackTrace();
} //try 的
}
}
break;
case 3:
if(x>0){
for(int i=0;i<30;i++){
this.x-=speed;
try{
Thread.sleep(50);
}catch(Exception e){
e.printStackTrace();
} //try 的
}
}
break;
}
//判断子弹是否没有了 (在方向还没有随机改变之前就给它创建)
if(ss.size()<1)
{
}
//让坦克产生一个新的随机方向
this.direct=(int) (Math.random()*4); //0--3范围内
//判断敌人是否死亡了
if(this.isLive==false){
break;//让坦克死亡后退出线程 (僵尸进程)
}
} //while 的
}//run 的
}
class Hero extends Tank{ //我的坦克
Vector<Shot>ss=new Vector<>(); //集合,将子弹添加到集合中去
Shot s=null; //声明一个子弹对象
public Hero(int x, int y) {
super(x, y);
// TODO Auto-generated constructor stub
this.setSpeed(8);
}
public void moveup(){ //坦克向上移动
this.y-=speed;
}
public void movedown(){ //向上移动
this.y+=speed;
}
public void moveright(){ //向右移动
this.x+=speed;
}
public void moveleft(){ //向左移动
this.x-=speed;
}
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();
}
}
class Shot implements Runnable{
int x;
int y;
int direct;
int speed=10;
boolean isLive=true;
public Shot(int x,int y,int direct){
this.x=x;
this.y=y;
this.direct=direct;
}
@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(direct){
case 0:
y-=speed;
break;
case 1:
x+=speed;
break;
case 2:
y+=speed;
break;
case 3:
x-=speed;
break;
}
//子弹何时死亡
//判断该子弹是否碰到墙壁
if(x<0||x>500||y<0||y>400){ //子弹死亡
this.isLive=false;
break;
}
}
}
}
坦克爆炸的图片:
效果: