Java小项目--坦克大战<TankWar1.0>

这个小项目主要是练习j2se的基础内容和面向对象的思想。项目实现了基本的简单功能,我方一辆坦克,用上下左右键控制移动方向,按F键为发射炮弹,敌方有10辆坦克,我方阵亡或者敌方挂光了游戏就结束了。用大小实心圆表示坦克和炮弹。这是最初版本,界面不够友好图形很土鳖,没有网络功能。在后续版本中会添加更炫的图片和网络功能,并加入聊天室,可以局域网内聊天和对战。

效果图:

项目包括4个文件,我把它们贴出来。

文件一:TankClient.java

TankClient为一个类,他的作用就像大管家,将坦克、炮弹、爆炸联系起来。首先是建立界面,然后重写了画图的paint方法,系统循环自动调用paint,所以在paint中调用坦克、炮弹、爆炸类各自的draw方法将各自画出来,而坦克、炮弹各自的draw是如何实现的画了什么大管家是不管它的,这也正是面向对象语言的一个思想。

Java的集合可以装对象,3个List容器分别装敌方坦克,所有炮弹,所有爆炸;

/*
* 版本: version0.9
* 功能: @添加爆炸效果,添加多辆坦克
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.List;
import java.util.*; public class TankClient extends Frame{ public final int SCREENWIDTH=800,SCREENHEIGHT=600;
Tank myTank = new Tank(130,230,true,this);
//new了一辆坦克出来,第3个参数分别是我方坦克还是敌方坦克。 Missile missile=null;
Image screenImage = null;
List<Missile> missiles = new ArrayList<Missile> (); //这个容器装炮弹,任何坦克每打出一发炮弹都装进这个容器中,当炮弹击中对方坦克或者炮弹出界都将该//炮弹从容器中remove;
List<Explode> explodes = new ArrayList<Explode> ();
List<Tank> tanks = new ArrayList<Tank> (); public void update(Graphics g) {
if(screenImage == null)
screenImage = this.createImage(SCREENWIDTH,SCREENHEIGHT);
Graphics graphics = screenImage.getGraphics();
Color c = graphics.getColor();
graphics.setColor(new Color(150,240,215));
graphics.fillRect(0, 0, SCREENWIDTH, SCREENHEIGHT);
graphics.setColor(c);
paint(graphics);
g.drawImage(screenImage, 0, 0, null); }
public void paint(Graphics g) {
g.drawString("Missiles Counts: "+missiles.size(), 30, 50);
g.drawString("Explodes Counts: "+explodes.size(), 30, 70);
g.drawString("Tanks Counts: "+tanks.size(), 30, 90);
myTank.draw(g);
// enemyTank.draw(g);
for(int i=0;i<missiles.size();i++) {
Missile m = missiles.get(i);
//将所有炮弹从容器中取出,调用hitTank方法去判断有没有集中对方坦克,若击中则该炮弹和被击中的坦克都将从相应的容器中移除;
m.hitTanks(tanks);
m.hitTank(myTank); //敌人可击打我方。
m.draw(g); //将每一发炮弹draw出来 }
for(int i= 0;i<explodes.size();i++) {
Explode e = explodes.get(i);
e.draw(g);
}
for(int i=0;i<tanks.size();i++) {
Tank t = tanks.get(i); //取出容器中剩余的坦克将他们画出来。
t.draw(g);
} } class PaintThread implements Runnable { public void run() {
while(true) {
try {
repaint(); //在这个线程中进行重画。每隔一段时间调用repaint,repaint会调用updata,updata会调用paint方法。
Thread.sleep(50);//这个时间决定了所有物体的运动速度。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public static void main(String[] args) {
TankClient tankclient = new TankClient();
tankclient.launch(); } public void launch() {
this.setResizable(false);
this.setTitle("TankWar");
this.setBackground(new Color(150,240,215));
setLocation(200,200);
setSize(SCREENWIDTH,SCREENHEIGHT);
setVisible(true);
this.addWindowListener(new Monitor_Window());
this.addKeyListener(new KeyMonitor());
new Thread(new PaintThread()).start(); for(int i=0; i<10;i++) { //new出来10辆敌方坦克放在容器中。
Tank t = new Tank(50+40*(i+1),80+i,false,Tank.Direction.D,this);
tanks.add(t);
}
} class KeyMonitor extends KeyAdapter {
public void keyReleased(KeyEvent e) {
myTank.keyReleased(e);
}
//按键按下或释放这调用tank类里的方法进行判断处理。
public void keyPressed(KeyEvent e) {
myTank.KeyPress(e); }
} } class Monitor_Window extends WindowAdapter { //窗口关闭事件
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}

文件二:Tank.java

Tank类包含坦克的一些属性,包括坦克的尺寸、速度、位置等,也包含一些方法包括开火fire方法、移动后坐标的计算、按键的处理。

import java.awt.*;
import java.awt.event.*;
import java.util.*; public class Tank {
int x,y;
TankClient tc=null;
private boolean good = true; //用来分辨敌我坦克,若某坦克good属性为true则该坦克为我方坦克 boolean live = true; //用来表明该坦克是否还存活,若live属性为false表示该坦克已死则在draw方法里不将该坦克画出来并从list容器中移除。 public static final int SCREENWIDTH=800,SCREENHEIGHT=600;
public static final int WIDTH=30,HEIGHT=30;
public static final int XSPEED=5,YSPEED=5;
boolean bL=false,bR=false,bU=false,bD=false,bB=false;
enum Direction { L,LD,LU,U,D,R,RD,RU,STOP }; //枚举类型,用来表示坦克的运动方向也决定了炮弹的方向
private Direction dir=Direction.STOP,mdir=Direction.RD;
private static Random r = new Random(); //定义的随机数
private static int dm = r.nextInt(12)+3;
public Tank(int x, int y,boolean good) {
this.x = x;
this.y = y;
this.good = good;
}
//构造方法进行了重载
public Tank(int x, int y,boolean good,TankClient tc) {
this.x = x;
this.y = y;
this.good = good;
this.tc = tc;
} public Tank(int x, int y,boolean good,Direction dir,TankClient tc) {
this.x = x;
this.y = y;
this.good = good;
this.dir = dir;
this.tc = tc;
} public boolean isGood() {
return good;
} public boolean isLive() {
return live;
} public void setLive(boolean live) {
this.live = live;
} public void draw(Graphics g) {
if(!this.isLive()) {
if(!good)
tc.tanks.remove(this);
//如果该坦克是敌方坦克,而且死了,则将该坦克从容器中移除。 return;
} Color c = g.getColor();
if(good)
g.setColor(new Color(100,25,200)); //敌方坦克和我方坦克画成不同的颜色
else
g.setColor(Color.red);
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(Color.blue);
move(); switch(mdir) { //画该坦克的炮台,炮台的方向为坦克的最后运动方向,如果坦克为stop状态则保持上次方向。
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 LD:
g.drawLine(x+Tank.WIDTH/2, y+Tank.HEIGHT/2, x, y+Tank.HEIGHT); break;
case R:
g.drawLine(x+Tank.WIDTH/2, y+Tank.HEIGHT/2, x+Tank.WIDTH, y+Tank.HEIGHT/2); break;
case RU:
g.drawLine(x+Tank.WIDTH/2, y+Tank.HEIGHT/2, x+Tank.WIDTH, y); break;
case RD:
g.drawLine(x+Tank.WIDTH/2, y+Tank.HEIGHT/2, x+Tank.WIDTH, y+Tank.HEIGHT); break;
case U:
g.drawLine(x+Tank.WIDTH/2, y+Tank.HEIGHT/2, x+Tank.WIDTH/2, y); break;
case D:
g.drawLine(x+Tank.WIDTH/2, y+Tank.HEIGHT/2, x+Tank.WIDTH/2, y+Tank.HEIGHT); break;
case STOP:
break; } g.setColor(c); }
public Missile fire() { int x = this.x + Tank.WIDTH/2 - Missile.WIDTH/2;
int y = this.y + Tank.HEIGHT/2 - Missile.HEIGHT/2; //根据坦克的和位置运动方向画出炮弹的位置和方向,第四个属性表示炮弹的敌我属性和坦克的敌我属性一致,坦克的good为true则打出的炮弹也为true。
Missile m = new Missile(x,y,mdir,good,this.tc);
tc.missiles.add(m);
//将炮弹加入进容器
return m; //返回该炮弹
}
public void move() { switch(dir) { //根据方向对坦克位置进行更新
case L:
x -=XSPEED;
break;
case LU:
x -=XSPEED;
y -=YSPEED;
break;
case LD:
x -=XSPEED;
y +=YSPEED;
break;
case R:
x +=XSPEED;
break;
case RU:
x +=XSPEED;
y -=YSPEED;
break;
case RD:
x +=XSPEED;
y +=YSPEED;
break;
case U:
y -=YSPEED;
break;
case D:
y +=YSPEED;
break;
case STOP:
break;
} if(x<0) //坦克不能出界
x=0;
else if(x>tc.SCREENWIDTH-Tank.WIDTH)
x=tc.SCREENWIDTH-Tank.WIDTH;
if(y<30)
y=30;
else if(y>tc.SCREENHEIGHT-Tank.HEIGHT)
y=tc.SCREENHEIGHT-Tank.HEIGHT;
// dir = Direction.STOP; //加了这句速度很慢啊。
if(!good) { //如果为敌方坦克,则运动方向为随机的。
Direction [] dirs = Direction.values();
int rn = r.nextInt(dirs.length-1);
dm--; //注意dirs[dirs.length]为STOP。
if(dm<=0) {
dir = dirs[rn];
mdir = dir;
dm=r.nextInt(15)+3;
}
if(r.nextInt(50)>48) this.fire(); } } public void locationDir() { //根据按下的按键决定方向
if(bR && !bL && !bU && !bD) {
dir = Direction.R; }
else if(bR && !bL && bU && !bD)
dir = Direction.RU;
else if(bR && !bL && !bU && bD)
dir = Direction.RD;
else if(!bR && bL && !bU && !bD)
dir = Direction.L;
else if(!bR && bL && bU && !bD)
dir = Direction.LU;
else if(!bR && bL && !bU && bD)
dir = Direction.LD;
else if(!bR && !bL && bU && !bD)
dir = Direction.U;
else if(!bR && !bL && !bU && bD)
dir = Direction.D;
else
dir = Direction.STOP; if(dir != Direction.STOP) //mdir保存最后一次方向,坦克停下来了保持最后的方向。
mdir=dir;
} public void KeyPress(KeyEvent e) { int key = e.getKeyCode();
switch(key) {
case KeyEvent.VK_RIGHT:
System.out.println("R");
bR = true;
break;
case KeyEvent.VK_LEFT:
bL = true;
break; case KeyEvent.VK_UP:
System.out.println("U");
bU = true;
break;
case KeyEvent.VK_DOWN:
System.out.println("D");
bD = true;
break; }
locationDir();
} public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch(key) {
case KeyEvent.VK_RIGHT:
System.out.println("R");
bR = false;
break;
case KeyEvent.VK_LEFT:
bL = false;
break; case KeyEvent.VK_UP:
System.out.println("U");
bU = false;
break;
case KeyEvent.VK_DOWN:
System.out.println("D");
bD = false;
break;
case KeyEvent.VK_F:
System.out.println("F");
if(this.isLive()) //坦克存活时才能发子弹。
tc.missile = fire();
break;
}
locationDir(); } public Rectangle getRec() {
return new Rectangle(x,y,Tank.WIDTH,Tank.HEIGHT);
} }

文件三:Missile.java

炮弹类包含炮弹的属性和方法:尺寸、速度、位置、方向;坐标的计算,击打坦克等;

import java.awt.*;
import java.util.List;
import java.util.*; public class Missile { int x,y;
TankClient tc;
Tank.Direction dir =Tank.Direction.R;
public static final int XSPEED=10,YSPEED=10;
public static final int WIDTH=10,HEIGHT=10;
private boolean live = true;
private boolean good; public boolean isGood() {
return good;
} public boolean isLive() {
return live;
} public Missile(int x, int y, Tank.Direction dir) {
this.x = x;
this.y = y;
this.dir = dir;
} public Missile(int x, int y, Tank.Direction dir,boolean good,TankClient tc) {
this.x = x;
this.y = y;
this.dir = dir;
this.good = good; //tank的good属性和炮弹的good属性一致;
this.tc = tc;
} public void draw(Graphics g) {
if(!this.live) { //如果炮弹已死则将它从容器中移除并返回,不在把他画出来。
tc.missiles.remove(this);
return;
} Color c = g.getColor();
if(!this.isGood())
g.setColor(Color.red);
else
g.setColor(new Color(100,25,200));
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(c);
move();
} public void move() {
if(dir == Tank.Direction.STOP)
System.out.println("@@@@@@@@@@@@@@@@");
//测出bug,敌人坦克发出来停止的哑弹。
switch(dir) {
case L:
x -=XSPEED;
break;
case LU:
x -=XSPEED;
y -=YSPEED;
break;
case LD:
x -=XSPEED;
y +=YSPEED;
break;
case R:
x +=XSPEED;
break;
case RU:
x +=XSPEED;
y -=YSPEED;
break;
case RD:
x +=XSPEED;
y +=YSPEED;
break;
case U:
y -=YSPEED;
break;
case D:
y +=YSPEED;
break;
}
System.out.println(x+"=x,y= "+y);
if(x<0 || y<30 || x>tc.SCREENWIDTH-10 || y>tc.SCREENHEIGHT-10) {
this.live = false; //如果炮弹出界则死亡
} } public Rectangle getRec() {
return new Rectangle(x,y,WIDTH,HEIGHT);
} public boolean hitTank(Tank t) {
if(this.getRec().intersects(t.getRec()) && t.isLive()
&& this.good!=t.isGood()) {
t.setLive(false);
this.live = false;
Explode e = new Explode(x,y,this.tc);
e.setLive(true);
tc.explodes.add(e);
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;
} }

文件四:Explode.java

爆炸效果类就是画几个圈,主要包含draw方法,当发生爆炸的时候将爆炸效果draw出来。

import java.awt.*;

public class Explode {

	int x,y;
private boolean live = false;
public boolean isLive() {
return live;
} public void setLive(boolean live) {
this.live = live;
} TankClient tc;
int [] diameter = {4,8,12,22,34,32,20,13,6};
int step = 0; public Explode(int x,int y,TankClient tc) {
this.x = x;
this.y = y;
this.tc = tc;
} public void draw(Graphics g) {
if(!this.live) {
tc.explodes.remove(this);
return;
}
if(step==diameter.length) {
step = 0;
this.live = false;
tc.explodes.remove(this);
}
Color c = g.getColor();
g.setColor(Color.GREEN);
g.fillOval(x, y, diameter[step], diameter[step]);
g.setColor(c);
step++;
} }

Java小项目--坦克大战(version1.0)的更多相关文章

  1. java小项目之:植物大战僵尸,这个僵尸有点冷!内附素材源码

    Java小项目之:植物大战僵尸! <植物大战僵尸>是由PopCap Games开发的一款益智策略类单机游戏,于2009年5月5日发售,这款游戏可谓是无人不知无人不晓. 在我身边,上到40岁 ...

  2. Java学习笔记三十:Java小项目之租车系统

    Java小项目之租车系统 一:项目背景介绍: 根据所学知识,编写一个控制台版的“呱呱租车系统” 功能: 1.展示所有可租车辆: 2.选择车型.租车量: 3.展示租车清单,包含:总金额.总载货量以及其车 ...

  3. Java小项目之:五子棋,你下棋下得过电脑吗?

    Java小项目之:五子棋,你下棋下得过电脑吗? Java五子棋功能要求: 1.创建窗口和设计一个棋盘界面 2.实现鼠标点击,棋子出现,黑白棋轮流下 3.能够判断五子相连输赢 4.添加重新开始,悔棋,退 ...

  4. Java小项目之:教你做个聊天系统!

    Java小项目之:聊天系统 今天给大家带来的java练手小项目是一个简单的聊天室,界面简单,操作不难. 分为注册系统,登录系统和聊天系统三部分,很适合java小白练手. 完整的源码和素材请关注并私信我 ...

  5. (java项目)坦克大战 2.0

    这个版本,只能算是一个雏形,把最基本的东西给完成了,不过,后面可添加的也不多.有一点,还是想去实现,那就是敌方坦克自己寻找对手!也就是游戏AI. emmm, 什么时候可以了解一下这个AI.顺便学学py ...

  6. java小项目之:扫雷,这游戏没有你想的那么简单!

    扫雷 我之前分享的小项目和小游戏,电影购票.坦克大战.捕鱼达人.贪吃蛇等,虽然已经是耳熟能详人尽皆知的项目和游戏,但是保不齐真的有人没接触过. 今天分享的这个项目,我不相信没人接触过(仅限80后-00 ...

  7. java学习之坦克大战游戏

    总结:由于这几天快过年比较忙然后没怎么写,写代码途中一些经验总结现在给忘记了.这次的小项目感觉比上次写的思路清楚了点.没有之前第一次写那么逻辑混乱,结构也搞的比之前的要好,添加功能比较容易.学习了之前 ...

  8. Unity项目 - 坦克大战3D TankBattle

    目录 游戏原型 项目演示 绘图资源 代码实现 技术探讨 参考来源 游戏原型 游戏玩法:在有界的战场上,玩家将驾驶坦克,代表绿色阵营,与你的队友一起击溃红蓝阵营的敌人,在这场三方大战中夺得胜利! 操作指 ...

  9. 例子:web版坦克大战1.0

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Jenkins - 持续集成

    Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使持续集成变成可能. Jenkins,之前叫做Hudson,是基于Java开发的一种持续集成工具,用于监控秩序重复的工作,包括: 1. ...

  2. IIS7 常用模块介绍说明

    1.1.0   IIS常用的功能模块介绍: 1)         静态内容:可发布静态 Web 文件格式,比如 HTML 页面和图像文件. 2)         默认文档:允许您配置当用户未在 URL ...

  3. jquery之onchange事件

    $(function(){ $("#opreateHtml").window("close"); $("#deliveryGrid").da ...

  4. 利用ajax从txt读取数据

    html代码: <div id="news"></div> txt: [ {"id":"1", "news ...

  5. hdu 2032

    水题 AC代码: #include <stdio.h> int main() { int a[31][31]; int i,j,n; a[1][1]=a[2][1]=a[2][2]=1; ...

  6. JQuery中常用的 属性选择器

    jQuery中使用$()作为选择符极大提高工作效率以及方便快捷;一些常用属性的选择器由以下几种 1) $('#id') id选择器 2) $('.class') css选择器,class类名 3) $ ...

  7. ORA-00911: invalid character

    出错原因:sql语句后面加了中文状态下的分号. 解决办法:改成英文状态下的分号即可. --本篇文章参考自:http://blog.sina.com.cn/s/blog_5b2a1aee0100n4oy ...

  8. XML预定义的实体

    在TSQL读取XML中一些特定的字符时出错,在XML中有些自付要用实体: 下面是五个在XML文档中预定义好的实体: < < 小于号 > > 大于号 & & 和  ...

  9. C# 读取EXCEL数据

       /// <summary> /// 读取EXCEL数据 /// </summary> /// <param name="Path">< ...

  10. php魔术方法——属性重载方法

    php有一类很神奇的方法,这些方法是保留方法,通常不会在外部被显式调用,他们使用双下划线(__)开头,他们被称为魔术方法(Magic Methods).php官方也不建议定义其他双下划线开头的方法. ...