java简单坦克大战制作代码
利用java语言中的集合、swing、线程等知识点编写一个坦克大战游戏。
(1) 画出敌我坦克的原理:
在坦克类里面有一个布尔类型变量good。用于判断坦克的阵营,在创建坦克对象时在tank类的构造方法中传入good的值。在画坦克的时候判断good的值,区分敌我坦克的颜色;
(2) 坦克运动的原理:
在坦克类里写入了监听键盘摁键的响应事件,对监听到的上下左右键进行记录,并合成坦克移动的八个方向的变量。之后对应每个方向的不同对坦克坐标x,y的值做响应的更改实现我方坦克的移动。而敌方坦克则自动移动,通过随机数对敌方坦克移动方向的随机,并且随机出每次移动的次数。两个随机值相结合即实现了敌方坦克的移动。
(3) 坦克发射子弹的原理:
通过键盘监听,检测到发射子弹命令后将主类的子弹类集合中添加一个子弹类。将炮筒的方向以及坦克的位置以及坦克的阵营传入给子弹类,在主类paint画方法中一直循环子弹类集合,如果集合内有子弹,就画出来。这样就实现了发射子弹。
(4) 坦克、子弹、墙的碰撞原理:
在坦克类子弹类墙类中分别getrect方法获取自身的范围,然后在每次画坦克、子弹时都会进行相应的碰撞检测(在坦克类里有与墙和出自己外的坦克相撞的处理方法、在子弹类里有与墙和坦克相碰撞的处理方法。),如果自身与不该碰撞的物体的范围相重合,则代表两物体相撞。
(5)坦克加血的原理:
在血块类中有血块与我方坦克相碰撞的处理方法,如果血块范围与坦克范围重合则血块类死亡,并且坦克类的血量回复置满。
(6)坦克复活的原理:
通过键盘监听,检测到我方坦克复活命令后,如果我方坦克处于死亡状态,则将我方坦克存货状态改为活着并且将我方坦克血量回置满血。
编程思想:
坦克大战的编程思想在主类开启一个线程,没50毫秒循环一次画方法(绘制整个界面内的所有东西)。画的东西有敌我坦克(颜色区分)、子弹、墙、血块、爆炸。所以总共写出了几个类:tank坦克类、missile子弹类、wall墙类、blood血块类、tankclient主类。在每一个类中均写有画方法实现本类属性的绘制功能。在主类中有键盘监听事件调用这tank类的键盘监听事件。通过键盘监听判断出对tank做出相应的移动,而敌方tank则是随机运动。并且每次刷新都有调用各类的碰撞方法,判断一些不该碰撞的对象的情况时做出处理。而每个对象的创建例如子弹这些是在触发产生之后将新建子弹类加入一个子弹类集合之中,在绘制的时候判断集合中的数量进行绘制,出界或者打死坦克则在集合中删除。其他类也均相似,不在细说。
代码中每步都注释有相应的解释。
tankclient.java
import java.awt.color; import java.awt.font; import java.awt.graphics; import java.awt.image; import java.awt.event.keyadapter; import java.awt.event.keyevent; import java.awt.event.windowadapter; import java.awt.event.windowevent; import java.util.arraylist; import java.util.list; import javax.swing.jframe; public class tankclient extends jframe{ /** * @param args */ image offscrennimage = null; //双缓冲内存图片存储 /*游戏大小*/ public static final int game_width = 800; //界面宽 public static final int game_heigth = 600; //界面高 tank mytank = new tank(500,400,true,color.red,tank.direction.stop, this);//我方坦克类 list<missile> missiles = new arraylist<missile>();//子弹的集合 list<explode> explode = new arraylist<explode>();//爆炸集合 list<tank> tanks = new arraylist<tank>(); //坦克集合 wall wall1 = new wall(150,200,20,300,this); //墙1 wall wall2 = new wall(250,500,300,20,this); //墙2 wall wall3 = new wall(650,200,20,300,this); //墙2 wall wall4 = new wall(250,300,300,20,this); //墙2 wall wb = new wall(750,550,40,40,this); //墙2 blood b = new blood(); //血类 public static void main(string[] args) { // todo auto-generated method stub tankclient tc=new tankclient(); tc.lauchframe(); } private void lauchframe() { // todo auto-generated method stub for (int i = 0; i < 10; i++){ tanks.add(new tank(50+40*(i+1), 50, false,color.blue,tank.direction.d, this)); } this.setlocation(100, 100); //窗口初始坐标点 this.setsize(game_width, game_heigth); //窗口初始大小 this.settitle("tankwar"); //窗口名称 /*窗口监听*/ this.addwindowlistener(new windowadapter() { @override /*点退出叉之后运行*/ public void windowclosing(windowevent e) { // todo auto-generated method stub system.exit(0); //退出 } }); this.addkeylistener(new keymoniton()); //设置键盘监听 this.setvisible(true); //设置窗口显现 this.setresizable(false); //设置窗口不可改变大小 this.getcontentpane().setbackground(color.green); //设置窗口前景色为绿色 new thread(new paintthread()).start(); //开始运行paintthread类run } @override public void paint(graphics g) { // todo auto-generated method stub //graphics为画笔类 super.paint(g); mytank.draw(g); wall1.draw(g); wall2.draw(g); wall3.draw(g); wall4.draw(g); wb.draw(g); b.draw(g); mytank.eatblood(b); mytank.hitwall(wall1); mytank.hitwall(wall2); mytank.hitwall(wall3); mytank.hitwall(wall4); /*循环子弹集合*/ for (int i = 0; i < missiles.size(); i++){ missile m = missiles.get(i); //获取当前子弹 m.hittanks(tanks); //自己子弹打死敌方坦克 m.hitwall(wall1); //子弹与墙 m.hitwall(wall2); m.hitwall(wall3); m.hitwall(wall4); m.hittank(mytank);//敌人子弹打击自己的坦克 m.draw(g); //画子弹 } for (int i = 0; i < explode.size(); i++){ explode.get(i).draw(g); //画爆炸 } for (int i = 0; i < tanks.size(); i++){ tank t = tanks.get(i); t.draw(g); //画敌方坦克 t.hittanks(tanks); t.hitwall(wall1); //坦克与墙 t.hitwall(wall2); t.hitwall(wall3); t.hitwall(wall4); } //g.setfont(new font("宋体",font.bold,20)); g.drawstring("missiles count:"+missiles.size(), 10, 50);//显示 g.drawstring("explode count:"+explode.size(), 10, 80);//显示 g.drawstring("tanks count:"+tanks.size(),10, 110); g.drawstring("mytank life:"+mytank.getlife(), 10, 130); g.drawstring("回血:", 750, 540); g.drawstring("方向键移动方向;e:释放移动血快", 10, 590); g.drawstring("z:发射东风-31;a:发射东风-41;", 10, 570); g.drawstring("f2:复活;f3:敌方复活(对多20)", 10, 550); g.drawstring("r:位置还原;q:血量加满", 10, 530); } @override /*repaint-〉update->paint*/ public void update(graphics g) { // todo auto-generated method stub super.update(g); if(offscrennimage == null) offscrennimage = this.createimage(game_width, game_heigth); graphics goffscrenn = offscrennimage.getgraphics(); //设置一个内存画笔颜色为前景图片颜色 color c = goffscrenn.getcolor(); //还是先保存前景颜色 goffscrenn.setcolor(color.green); //设置内存画笔颜色为绿色 goffscrenn.fillrect(0, 0, game_width, game_heigth); //画成图片,大小为游戏大小 goffscrenn.setcolor(c); //还原颜色 g.drawimage(offscrennimage, 0, 0, null); //在界面画出保存的图片 paint(goffscrenn); //把内存画笔调用给paint } private class paintthread implements runnable{ @override public void run() { // todo auto-generated method stub while(true){ repaint(); //运行顺序repaint->update->paint try{ thread.sleep(50); //每隔50毫秒刷新画面一次 }catch(exception e){ e.printstacktrace(); } } } } /*键盘响应*/ private class keymoniton extends keyadapter{ /*摁下键盘响应*/ @override public void keypressed(keyevent e) { // todo auto-generated method stub super.keypressed(e); mytank.keypressed(e); } /*抬起键盘响应*/ @override public void keyreleased(keyevent e) { // todo auto-generated method stub super.keyreleased(e); mytank.keyreleased(e); } } }
tank.java
import java.awt.color; import java.awt.graphics; import java.awt.image; import java.awt.rectangle; import java.awt.event.keyevent; import java.util.list; import java.util.random; import javax.swing.imageicon; public class tank { /*坦克本身数据*/ int x, y;//坦克坐标 private int oldx, oldy; //坦克上一步坐标 public static final int whith = 30; //坦克宽 public static final int higth = 30; //坦克高 public static final int xspeed = 5; //横向移动速度 public static final int yspeed = 5; //纵向移动速度 private color color; //坦克颜色 private boolean bl=false, bu=false, br=false, bd=false; //四个方向控制值 enum direction {l, lu, u, ru, r, rd, d, ld, stop}; //由四个方向值合成八个方向的移动 private direction dir = direction.stop; //出场方向 private direction ptdir = direction.d; //炮筒初始方向 private boolean good; //判断坦克的阵营 private boolean live = true; //判断坦克是否存活 private static random r = new random();//设置一个随机值变量 private static int step = r.nextint(12)+3; //敌方坦克随机移动步骤3-14步 private int life = 100; //血量 private bloodbar bb = new bloodbar(); //血块类 // imageicon icon = new imageicon("res\\mytank.jpg"); // imageicon icon2 = new imageicon("res\\enemytank.jpg"); // image image = icon.getimage(); // image image2 = icon2.getimage(); private tankclient tc; //主类权限 public tank(int x, int y, boolean good, color color) { super(); this.x = x; this.y = y; this.color = color; this.good = good; } public tank(int x, int y, boolean good,color color,direction dir,tankclient tc){ this(x,y,good,color); this.dir = dir; this.tc = tc; } /*获取坦克生命值*/ public int getlife() { return life; } /*设置坦克生命值*/ public void setlife(int life) { this.life = life; } /*获取坦克阵营*/ public boolean isgood() { return good; } /*设置坦克阵营*/ public void setgood(boolean good) { this.good = good; } /*获取坦克存活状态*/ public boolean islive() { return live; } /*设置坦克存活状态*/ public void setlive(boolean live) { this.live = live; } /*画坦克*/ public void draw(graphics g){ if(!live){ if(!good){ tc.tanks.remove(this); //敌方坦克死亡时在集合中删除 //tc.tanks.add(new tank(r.nextint(700),r.nextint(500),false,color.blue,direction.d,this.tc)); } return; } /*先保存之前的画笔颜色,画完之后再还原画笔颜色*/ color c = g.getcolor(); //获取当前画笔颜色 g.setcolor(color); //设置画笔颜色为红色 /*画坦克*/ g.filloval(x, y, whith, higth); /*两种方法绘制敌我坦克,运用之前加入的图片或者颜色区分*/ // if(good) // g.drawimage(image, x, y,whith,higth,null); // else // g.drawimage(image2, x, y, whith, higth, null); if(good) bb.draw(g); //我方坦克画血条 g.setcolor(color.black); /*通过炮筒方向画出炮筒*/ switch(ptdir){ case l: g.drawline(x+tank.whith/2, y+tank.higth/2, x, y+tank.higth/2); break; case lu: g.drawline(x+tank.whith/2, y+tank.higth/2, x, y); break; case u: g.drawline(x+tank.whith/2, y+tank.higth/2, x+tank.whith/2, y); break; case ru: g.drawline(x+tank.whith/2, y+tank.higth/2, x+tank.whith, y); break; case r: g.drawline(x+tank.whith/2, y+tank.higth/2, x+tank.whith, y+tank.higth/2); break; case rd: g.drawline(x+tank.whith/2, y+tank.higth/2, x+tank.whith, y+tank.higth); break; case d: g.drawline(x+tank.whith/2, y+tank.higth/2, x+tank.whith/2, y+tank.higth); break; case ld: g.drawline(x+tank.whith/2, y+tank.higth/2, x, y+tank.higth); break; } g.setcolor(c); //还原画笔颜色 move();//移动 } /*键盘监听;摁键*/ public void keypressed(keyevent e){ int key = e.getkeycode(); //将键盘监听到的摁键以整数保存 /*键盘移动坦克*/ switch(key){ /*移动摁键*/ case keyevent.vk_up: bu=true; break; case keyevent.vk_down: bd=true; break; case keyevent.vk_right: br=true; break; case keyevent.vk_left: bl=true; break; } locatedirection(); } /*键盘监听;抬起键*/ public void keyreleased(keyevent e){ int key = e.getkeycode(); //将键盘监听到的摁键以整数保存 /*键盘移动坦克*/ switch(key){ case keyevent.vk_up: bu=false; break; case keyevent.vk_down: bd=false; break; case keyevent.vk_right: br=false; break; case keyevent.vk_left: bl=false; break; case keyevent.vk_z: //单发子弹 if(live) fire(); break; case keyevent.vk_f2: //我方复活 if(!this.live){ this.live=true; this.setlife(100); } break; case keyevent.vk_f3: //敌方复活 fuhuo(); break; case keyevent.vk_a: //无敌导弹 superfire(); break; case keyevent.vk_q: //回血 if(this.live) this.life = 100; break; case keyevent.vk_e: //释放血块 tc.b.fh(); break; /*还原位置键*/ case keyevent.vk_r: x = 50; y = 50; break; } locatedirection(); //合成方向 } /*合成移动方向*/ void locatedirection(){ if(bl&&!bu&&!br&&!bd) dir=direction.l; else if(bl&&bu&&!br&&!bd) dir=direction.lu; else if(!bl&&bu&&!br&&!bd) dir=direction.u; else if(!bl&&bu&&br&&!bd) dir=direction.ru; else if(!bl&&!bu&&br&&!bd) dir=direction.r; else if(!bl&&!bu&&br&&bd) dir=direction.rd; else if(!bl&&!bu&&!br&&bd) dir=direction.d; else if(bl&&!bu&&!br&&bd) dir=direction.ld; else if(!bl&&!bu&&!br&&!bd) dir=direction.stop; } void move(){ //移动 /*记录上一步的位置*/ oldx = x; oldy = y; switch(dir){ case l: x-=xspeed; break; case lu: x-=xspeed; y-=yspeed; break; case u: y-=yspeed; break; case ru: x+=xspeed; y-=yspeed; break; case r: x+=xspeed; break; case rd: x+=xspeed; y+=yspeed; break; case d: y+=yspeed; break; case ld: x-=xspeed; y+=yspeed; break; case stop: break; } /*判断坦克移动越界情况(游戏边界)*/ if(x < 5) x = 5; if(y < 25) y = 25; if(x+whith > tc.game_width-5) x = tc.game_width-whith-5; if(y+higth > tc.game_heigth-5) y = tc.game_heigth-higth-5; if(dir != direction.stop) //如果坦克不静止就改变炮筒方向 ptdir = dir; /*敌方坦克自动移动*/ if(!good){ direction[] dirs = direction.values(); //将方向变量设为数组 if(step == 0){ step = r.nextint(12)+3; //随机移动步骤 int randomnumber = r.nextint(dirs.length); //随机移动方向 dir = dirs[randomnumber]; } step--; if(r.nextint(40)>30) this.fire(); //随机是否发射炮弹 } } /*敌方坦克复活*/ public void fuhuo(){ if(tc.tanks.size() < 20) while(true){ int x = r.nextint(700); int y = r.nextint(500); tank t = new tank(x,y,false,color.blue,direction.d,tc); /*如果坦克与墙重合则重新随机位置直到不重合为止才将新坦克加入集合*/ if(t.getrect().intersects(tc.wall1.getrect())||t.getrect().intersects(tc.wall2.getrect()) ||t.getrect().intersects(tc.wall3.getrect()) ||t.getrect().intersects(tc.wall4.getrect())){ continue; } else{ tc.tanks.add(t); break; } } } /*子弹发射*/ public void fire(){ int x = this.x + whith/2 - missile.whith/2; //控制子弹方向为坦克中间 int y = this.y + higth/2 - missile.higth/2; tc.missiles.add(new missile(ptdir,color,x,y,good,tc)); //创建新的子弹类加入到子弹集合中 } /*碰撞;获取坦克的范围*/ public rectangle getrect(){ return new rectangle(x,y,whith,higth); } /*回执上一步位置*/ private void stay(){ x = oldx; y = oldy; } /*如果撞墙,调用stay方法,返回上一步位置*/ public boolean hitwall(wall w){ if(this.live&&this.getrect().intersects(w.getrect())){ this.stay(); return true; } return false; } /*坦克互相撞击事件*/ public boolean hittanks(list<tank> tanks){ for(int i=0;i<tanks.size();i++){ tank t=tanks.get(i); if(this!=t){//自己与自己不可相撞 /*如果相撞返回上一步位置*/ if(this.live&&t.islive()&&this.getrect().intersects(t.getrect())){ this.stay(); t.stay(); return true; } } } return false; } /*带开火方向的发射函数*/ public missile fire(direction dir){ if(!live) return null; int x=this.x+whith/2-missile.whith/2; int y=this.y+higth/2-missile.higth/2; missile m=new missile(dir,color,x, y,good, this.tc); tc.missiles.add(m); return m; } /*超级射击导弹*/ private void superfire(){ direction[] dirs=direction.values(); for(int i=0;i<8;i++){ fire(dirs[i]);//循环调用八个方向 } } /*新增血块类*/ private class bloodbar{ /*画血条*/ public void draw(graphics g){ color c=g.getcolor(); g.setcolor(color.red); g.drawrect(x, y-10, whith, 10); int w=whith*life/100; g.fillrect(x, y-10, w, 10); g.setcolor(c); } } /*吃血方法*/ public boolean eatblood(blood b){ if(this.live&&b.islive()&&this.isgood()&&this.getrect().intersects(b.getrect())){ this.setlife(100); b.setlive(false); return true; } if(this.getrect().intersects(tc.wb.getrect())) this.life = 100; return false; } }
missile.java
import java.awt.color; import java.awt.graphics; import java.awt.rectangle; import java.util.list; public class missile { /*子弹本身数据*/ tank.direction dir; //子弹方向 color c; //子弹颜色 int x,y; //子弹位置 public static final int xspeed = 15; //横向移动速度 public static final int yspeed = 15; //纵向移动速度 public static final int whith = 10; //子弹宽 public static final int higth = 10; //子弹高 private boolean live = true; //判断子弹的存活 private boolean good; //判断子弹和阵营 private tankclient tc;//主类权限 public missile(tank.direction dir,color c, int x, int y) { super(); this.dir = dir; this.x = x; this.y = y; this.c = c; } public missile(tank.direction dir,color c, int x, int y,boolean good,tankclient tc){ this(dir,c,x,y); this.good = good; this.tc = tc; } /*获取子弹的存活*/ public boolean islive() { return live; } /*设置子弹的存活*/ public void setlive(boolean live) { this.live = live; } public void draw(graphics g){ /*如果子弹死亡状态将这个子弹在子弹集合中删除*/ if(!live){ tc.missiles.remove(this); //集合中删除 return; } /*先保存之前的画笔颜色,画完之后再还原画笔颜色*/ color d = g.getcolor(); //获取当前画笔颜色 g.setcolor(c); //设置画笔颜色为红色 /*画子弹*/ g.filloval(x, y, whith, higth); g.setcolor(d); //还原画笔颜色 move(); //移动 } public void move(){ /*判断移动方向移动坦克位置*/ switch(dir){ case l: x-=xspeed; break; case lu: x-=xspeed; y-=yspeed; break; case u: y-=yspeed; break; case ru: x+=xspeed; y-=yspeed; break; case r: x+=xspeed; break; case rd: x+=xspeed; y+=yspeed; break; case d: y+=yspeed; break; case ld: x-=xspeed; y+=yspeed; break; case stop: break; } /*判断子弹的越界情况;出界则子弹死亡,在子弹集合中删去*/ if(x<0||y<0||x>tankclient.game_width||y>tankclient.game_heigth) live = false; } /*碰撞;获取子弹的范围*/ public rectangle getrect(){ return new rectangle(x,y,whith,higth); } /*子弹与坦克碰撞过程*/ public boolean hittank(tank t){ /*如果子弹与坦克在同一范围则子弹和坦克同时死亡;且子弹只能杀死对方坦克*/ if(this.live&&this.getrect().intersects(t.getrect())&&t.islive()&&this.good!=t.isgood()){ if(t.isgood()){ //好坦克 /*我方坦克子弹射中会减少生命值,生命值0的时候会死亡*/ t.setlife(t.getlife()-20); if(t.getlife()<=0) t.setlive(false); }else{ //坏坦克 t.setlive(false);//死亡 } this.live=false;//子弹死亡 tc.explode.add(new explode(x, y, tc));//新建爆炸加入集合 return true; } return false; } /*循环坦克集合分别进行判断子弹碰撞*/ public boolean hittanks(list<tank> tanks){ for (int i = 0; i < tanks.size(); i++){ if(hittank(tanks.get(i))) return true; } return false; } /*子弹与墙的碰撞过程*/ public boolean hitwall(wall w){ /*如果子弹与墙的范围重合子弹死亡*/ if(this.live&&this.getrect().intersects(w.getrect())){ this.live=false; //子弹死亡 return true; } return false; } }
wall.java
import java.awt.graphics; import java.awt.rectangle; public class wall { /*墙数据*/ int x,y,w,h; //位置和宽高 private tankclient tc; //主类权限 public wall(int x, int y, int w, int h, tankclient tc) { super(); this.x = x; this.y = y; this.w = w; this.h = h; this.tc = tc; } /*获取墙的范围*/ public rectangle getrect(){ return new rectangle(x,y,w,h); } /*画墙*/ public void draw(graphics g){ g.fillrect(x, y, w, h); } }
explode.java
import java.awt.color; import java.awt.graphics; public class explode { /*坦克爆炸属性*/ int x,y; //爆炸位置 private boolean live = true; //爆炸是否存在 int step = 0; //爆炸时间控制 int [] diameter = new int[] {4, 7, 12, 18, 26, 32, 49, 56, 65, 77, 80, 50, 40, 30, 14, 6};//爆炸范围 private tankclient tc; //主类权限 public explode(int x, int y, tankclient tc) { super(); this.x = x; this.y = y; this.tc = tc; } /*画爆炸*/ public void draw(graphics g){ if(!live) return; //如果爆炸死亡状态不画结束 /*如果爆炸时间结束爆炸不存在并在集合中删除*/ if(step == diameter.length){ live = false; //爆炸死亡 step = 0; //步骤时间归0 tc.explode.remove(this); //集合中删除 return; } /*画爆炸*/ color c = g.getcolor(); g.setcolor(color.orange); g.filloval(x, y, diameter[step], diameter[step]); g.setcolor(c); step++; } }
blood.java
import java.awt.color; import java.awt.graphics; import java.awt.rectangle; import java.util.random; public class blood { /*血块数据*/ int x, y, w, h;//血块位置和大小 private tankclient tc; //主类权限 private boolean live=true;//血块的存活 private static random r = new random();//设置一个随机值变量 /*获取血块的存活状态*/ public boolean islive() { return live; } /*设置血块的存活状态*/ public void setlive(boolean live) { this.live = live; } /*血块位置初值随机一个数值*/ public blood(){ x=r.nextint(600)+100; y=r.nextint(400)+100; w=h=15; } /*画血块*/ public void draw(graphics g){ if(!live) return; color c=g.getcolor(); g.setcolor(color.magenta); g.fillrect(x, y, w, h); g.setcolor(c); } /*释放血块*/ public void fh(){ if(!live){ x = r.nextint(600)+100; y = r.nextint(400)+100; live = true; } } /*获取血块范围*/ public rectangle getrect(){ return new rectangle(x, y, w, h); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。