Java小项目 – 坦克大战
1.任务分析
- 玩家进入游戏,通过操纵坦克来守卫基地,摧毁全部敌方坦克来取得胜利,如果基地被摧毁,或者玩家坦克被摧毁,则判定游戏失败
2.具体分析
- 图形用户界面使用GUI技术实现,游戏中坦克的方向转动可以通过四种不同的图片(上下左右)来模拟实现,爆炸特效可以通过一连串递进的图片来模拟实现。
3.程序预览
- 如图随机生成了可以被敌我双方坦克击碎的方块,固定生成了我方坦克和我方基地的位置,通过WSAD 空格 或者 上下左右键盘移动 K 攻击键 来实现我方坦克的移动攻击, 随机生成敌方坦克并随机进行攻击
如果需要图片可以在文末的百度网盘链接自取
4.代码部分
- panel类 实现了程序的面板,并在面板上显示所有对象
package tankwar;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Panel extends JFrame {
Image offScreenImage = null;
//游戏状态 0 游戏未开始, 1 单人模式, 2 双人模式, 3 游戏暂停, 4 游戏失败, 5 游戏胜利
int state= 0;
//游戏是否开始
private boolean start = false;
//临时变量
int a = 1;
//重绘次数
public int count = 0;
//窗口长宽
int width = 1600;
int height = 1000;
//敌人数量
private int enemyCount = 0;
//物体集合
public List<Bullet> bulletList = new ArrayList<>();
public List<Tank> tankList = new ArrayList<>();
public List<Computer_Tank> computerTankList = new ArrayList<>();
public List<Bullet> removeList = new ArrayList<>();
public List<Wall> wallList = new ArrayList<>();
public List<JiDi> jiDiList = new ArrayList<>();
public List<JiDi_Object> blastList = new ArrayList<>();
//游戏指针
Image select = Toolkit.getDefaultToolkit().getImage("images/selecttank.gif");
//指针初始高度
int y = 250;
//基地
JiDi jiDi = new JiDi("images/star.gif", 800, 950, this);
//玩家一
private PlayerOne playerOne = new PlayerOne("images/player1/p1tankU.gif", 125, 800,
"images/player1/p1tankU.gif","images/player1/p1tankD.gif",
"images/player1/p1tankL.gif","images/player1/p1tankR.gif", this);
//玩家二
private PlayerTwo playerTwo = new PlayerTwo("images/player2/p2tankU.gif", 1125, 800,
"images/player2/p2tankU.gif","images/player2/p2tankD.gif",
"images/player2/p2tankL.gif","images/player2/p2tankR.gif", this);
//窗口的启动方法
public void launch(){
//标题
setTitle("坦克大战");
//窗口初始大小
setSize(width, height);
//使屏幕居中
setLocationRelativeTo(null);
//添加关闭事件
setDefaultCloseOperation(3);
//用户不能调整大小
setResizable(false);
//使窗口可见
setVisible(true);
//添加键盘事件
this.addKeyListener(new Panel.KeyMonitor());
//添加围墙
for(int i = 0; i< 100; i ++){
wallList.add(new Wall("images/walls.gif", i*60 ,170, this ));
}
for(int i = 0; i< 100; i ++){
Random r = new Random();
int runm = r.nextInt(20);
int nunm = r.nextInt(20);
wallList.add(new Wall("images/walls.gif", runm*60 ,nunm*60, this ));
}
//添加基地围墙
wallList.add(new Wall("images/walls.gif", 845 ,930,this ));
wallList.add(new Wall("images/walls.gif", 730 ,900,this ));
wallList.add(new Wall("images/walls.gif", 790 ,900,this ));
wallList.add(new Wall("images/walls.gif", 850 ,900,this ));
wallList.add(new Wall("images/walls.gif", 740 ,930,this ));
//添加基地
jiDiList.add(jiDi);
while (true){
//游戏胜利判定
if(computerTankList.size() == 0 && enemyCount == 10 && (state == 1|| state == 2)){
state = 5;
}
if(tankList.size() == 0 && (state == 1 || state == 2) || jiDiList.size() == 0){
state = 4;
}
if(state == 1 || state == 2){
if (count % 100 == 1 && enemyCount < 10) {
Random r = new Random();
int rnum =r.nextInt(800);
computerTankList.add(new Computer_Tank("images/enemy/enemy1U.gif", rnum, 110,
"images/enemy/enemy1U.gif","images/enemy/enemy1D.gif",
"images/enemy/enemy1L.gif","images/enemy/enemy1R.gif", this));
enemyCount++;
//System.out.println("bot: " + botList.size());
}
}
repaint();
try {
//线程休眠
Thread.sleep(25);
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
public void paint(Graphics g) {
//创建和容器一样大小的Image图片
if(offScreenImage ==null){
offScreenImage=this.createImage(width, height);
}
//获得该图片的画布
Graphics gImage= offScreenImage.getGraphics();
//设置背景颜色
gImage.setColor(Color.gray);
//填充整个画布
gImage.fillRect(0, 0, width, height);
//挂变画笔颜色
gImage.setColor(Color.BLUE);
//改变文字大小和样式
gImage.setFont(new Font("仿宋",Font.BOLD,50));
if(state == 0){
//添加文字
gImage.drawString("选择游戏模式",600,300);
gImage.drawString("单人游戏",600,400);
gImage.drawString("双人游戏",600,500);
gImage.drawString("按1,2选择模式,按回车开始游戏",300,700);
gImage.drawImage(select,450,y,null);
}
else if(state == 1||state == 2){
//添加文字
gImage.setFont(new Font("楷书", Font.BOLD, 30));
gImage.setColor(Color.red);
gImage.drawString("剩余敌人:" + computerTankList.size(), 10, 100);
//paint重绘游戏元素
for(Tank player: tankList){
player.paintSelf(gImage);
}
for(Bullet bullet: bulletList){
bullet.paintSelf(gImage);
}
bulletList.removeAll(removeList);
for(Computer_Tank computerTank : computerTankList){
computerTank.paintSelf(gImage);
}
for (Wall wall: wallList){
wall.paintSelf(gImage);
}
for(JiDi jiDi : jiDiList){
jiDi.paintSelf(gImage);
}
for(JiDi_Object blast : blastList){
blast.paintSelf(gImage);
}
//重绘次数+1
count++;
}
else if(state == 3){
gImage.drawString("游戏暂停",700,500);
}
else if(state == 4){
gImage.drawString("游戏失败",700,500);
}
else if(state == 5){
gImage.drawString("游戏胜利",700,500);
}
g.drawImage(offScreenImage, 0, 0, null);
}
private class KeyMonitor extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
//super.keyPressed(e);
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_1:
if(!start){
y = 350;
a = 1;
}
//System.out.println(state);
break;
case KeyEvent.VK_2:
if(!start){
y = 450;
a = 2;
}
//System.out.println(state);
break;
case KeyEvent.VK_ENTER:
tankList.add(playerOne);
state = a;
start = true;
tankList.add(playerOne);
if(state == 2){
tankList.add(playerTwo);
}
//System.out.println("state:"+""+state);
break;
case KeyEvent.VK_P:
if(state != 3){
a = state;
state = 3;
}
else{
state = a;
if(a == 0) {
a = 1;
}
}
break;
default:
playerOne.keyPressed(e);
playerTwo.keyPressed(e);
break;
}
}
@Override
public void keyReleased(KeyEvent e){
playerOne.keyReleased(e);
playerTwo.keyReleased(e);
}
}
}
- Game 类 存储了游戏中主要的方法的父类
package tankwar;
import java.awt.*;
public abstract class Game {
//游戏元素图片
Image img;
//游戏元素的横坐标
int x;
//游戏元素的纵坐标
int y;
//游戏元素的宽
int width;
//游戏元素的高
int height;
//游戏元素的移动速度
int speed;
//游戏元素的移动方向
Direction direction;
//引入主界面
Panel panel;
public Game(){}
public Game(String img, int x, int y, Panel panel) {
this.img = Toolkit.getDefaultToolkit().getImage(img);
this.x = x;
this.y = y;
this.panel = panel;
}
public Image getImg() {
return img;
}
public void setImg(String img) {
this.img = Toolkit.getDefaultToolkit().getImage(img);
}
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 int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public double getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public Panel getGamePanel() {
return panel;
}
public void setGamePanel(Panel gamepanel) {
this.panel = panel;
}
//继承元素绘制自己的方法
public abstract void paintSelf(Graphics g);
//获取当前游戏元素的矩形,是为碰撞检测而写
public abstract Rectangle getRec();
}
- direction枚举类 , 枚举了弹可移动所需要的四种反向
package tankwar;
public enum Direction {
UP,LEFT,RIGHT,DOWN
}
- bullet类 存储了关于子弹的方法(子弹的移动,子弹的碰撞检测)
package tankwar;
import java.awt.*;
import java.util.List;
public class Bullet extends Game {
//长宽
private int width = 10;
private int height = 10;
//速度
private int speed = 7;
//方向
Direction direction;
//构造函数
public Bullet(String img, int x, int y, Direction direction, Panel panel) {
super(img, x, y, panel);
this.direction = direction;
}
public void go(){
moveToBorder();
hitBase();
hitWall();
switch (direction){
case UP:
upward();
break;
case LEFT:
leftward();
break;
case DOWN:
downward();
break;
case RIGHT:
rightward();
break;
}
}
/**子弹与坦克碰撞检测*/
public void hitBot(){
Rectangle next= this.getRec();
List<Computer_Tank> computerTanks = this.panel.computerTankList;
//子弹和bot
for(Computer_Tank computerTank : computerTanks){
if(computerTank.getRec().intersects(next)){
System.out.println("hit bot");
this.panel.blastList.add(new JiDi_Object(computerTank.x-34, computerTank.y-14));
this.panel.computerTankList.remove(computerTank);
this.panel.removeList.add(this);
break;
}
}
}
public void hitWall() {
Rectangle next = this.getRec();
List<Wall> walls = this.panel.wallList;
for (Wall w : walls) {
if (w.getRec().intersects(next)) {
this.panel.wallList.remove(w);
this.panel.removeList.add(this);
break;
}
}
}
public void moveToBorder(){
if (x < 0||x > this.panel.getWidth()) {
this.panel.removeList.add(this);
System.out.println("bullet hit border");
}
if(y < 0||y > this.panel.getHeight()){
this.panel.removeList.add(this);
System.out.println("bullet hit border");
}
}
public void hitBase(){
Rectangle next = this.getRec();
for(JiDi jiDi : panel.jiDiList) {
if (jiDi.getRec().intersects(next)) {
this.panel.jiDiList.remove(jiDi);
this.panel.removeList.add(this);
break;
}
}
}
public void leftward(){
x -= speed;
}
public void rightward(){
x += speed;
}
public void upward(){
y -= speed;
}
public void downward(){
y += speed;
}
@Override
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, null);
go();
hitBot();
}
@Override
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- tank类 坦克父类 存储了所有坦克(敌我双方坦克)所需要的用到的方法的父类:如移动,射击等
package tankwar;
import java.awt.*;
import java.util.List;
public class Tank extends Game {
private boolean attackCoolDown =true;//攻击冷却状态
private int attackCoolDownTime =1000;//攻击冷却时间毫秒间隔1000ms发射子弹
private String upImage; //向上移动时的图片
private String downImage;//向下移动时的图片
private String rightImage;//向右移动时的图片
private String leftImage;//向左移动时的图片
boolean alive = true;
//坦克size
int width = 40;
int height = 50;
//坦克初始方向
Direction direction = Direction.UP;
//坦克速度
private int speed = 3;
//坦克坐标,方向,图片,方向,面板
public Tank(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage, Panel panel) {
super(img, x, y, panel);
this.upImage = upImage;
this.leftImage = leftImage;
this.downImage = downImage;
this.rightImage = rightImage;
}
public void leftward(){
direction = Direction.LEFT;
setImg(leftImage);
if(!hitWall(x-speed, y) && !moveToBorder(x-speed, y)){
this.x -= speed;
}
}
public void rightward(){
direction = Direction.RIGHT;
setImg(rightImage);
if(!hitWall(x+speed, y) && !moveToBorder(x+speed, y)){
this.x += speed;
}
}
public void upward(){
direction = Direction.UP;
setImg(upImage);
if(!hitWall(x, y-speed) && !moveToBorder(x, y- speed)){
this.y -= speed;
}
}
public void downward(){
direction = Direction.DOWN;
setImg(downImage);
if(!hitWall(x, y+speed) && !moveToBorder(x, y+speed)){
this.y += speed;
}
}
public void attack(){
Point p = getHeadPoint();
if(attackCoolDown && alive){
Bullet bullet = new Bullet("images/bullet/bulletGreen.gif",p.x,p.y,direction, this.panel);
this.panel.bulletList.add(bullet);
attackCoolDown = false;
new AttackCD().start();
}
}
public class AttackCD extends Thread{
public void run(){
attackCoolDown=false;//将攻击功能设置为冷却状态
try{
Thread.sleep(attackCoolDownTime);//休眠1秒
}catch(InterruptedException e){
e.printStackTrace();
}
attackCoolDown=true;//将攻击功能解除冷却状态
this.stop();
}
}
//根据方向确定头部位置,x和y是左下角的点
public Point getHeadPoint(){
switch (direction){
case UP:
return new Point(x + width/2, y );
case LEFT:
return new Point(x, y + height/2);
case DOWN:
return new Point(x + width/2, y + height);
case RIGHT:
return new Point(x + width, y + height/2);
default:
return null;
}
}
public boolean hitWall(int x, int y){
//假设玩家坦克前进,下一个位置形成的矩形
Rectangle next = new Rectangle(x, y, width, height);
//地图里所有的墙体
List<Wall> walls = this.panel.wallList;
//判断两个矩形是否相交(即是否撞墙)
for(Wall w:walls){
if(w.getRec().intersects(next)){
return true;
}
}
return false;
}
public boolean moveToBorder(int x, int y){
if(x < 0){
return true;
}else if(x > this.panel.getWidth()-width){
return true;
}
if(y < 0){
return true;
}else if(y > this.panel.getHeight()-height){
return true;
}
return false;
}
@Override
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, null);
}
@Override
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- 玩家一坦克类 由玩家一控制操控的坦克
package tankwar;
import java.awt.*;
import java.awt.event.KeyEvent;
public class PlayerOne extends Tank {
private boolean up = false;
private boolean left = false;
private boolean right = false;
private boolean down = false;
public PlayerOne(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage, Panel panel){
super(img, x, y, upImage, downImage, leftImage, rightImage, panel);
}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_A:
left = true;
break;
case KeyEvent.VK_S:
down = true;
break;
case KeyEvent.VK_D:
right = true;
break;
case KeyEvent.VK_W:
up = true;
break;
default:
break;
}
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_A:
left = false;
break;
case KeyEvent.VK_S:
down = false;
break;
case KeyEvent.VK_D:
right = false;
break;
case KeyEvent.VK_W:
up = false;
break;
case KeyEvent.VK_SPACE:
this.attack();
break;
default:
break;
}
}
public void move(){
if(left){
leftward();
}
else if(right){
rightward();
}
else if(up){
upward();
}else if(down){
downward();
}
}
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, null);
move();
}
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- 玩家二坦克类 由玩家二操控的坦克类 ( 和坦克一基本相似)
package tankwar;
import java.awt.*;
import java.awt.event.KeyEvent;
public class PlayerTwo extends Tank {
private boolean up = false;
private boolean left = false;
private boolean right = false;
private boolean down = false;
public PlayerTwo(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage, Panel panel){
super(img, x, y, upImage, downImage, leftImage, rightImage, panel);
}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_LEFT:
left = true;
break;
case KeyEvent.VK_DOWN:
down = true;
break;
case KeyEvent.VK_RIGHT:
right = true;
break;
case KeyEvent.VK_UP:
up = true;
break;
case KeyEvent.VK_K:
this.attack();
break;
default:
break;
}
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_LEFT:
left = false;
break;
case KeyEvent.VK_DOWN:
down = false;
break;
case KeyEvent.VK_RIGHT:
right = false;
break;
case KeyEvent.VK_UP:
up = false;
break;
default:
break;
}
}
public void move(){
if(left){
leftward();
}
else if(right){
rightward();
}
else if(up){
upward();
}else if(down){
downward();
}
}
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, null);
move();
}
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- 电脑坦克类 ,存储了自动生成的电脑坦克相关的方法
package tankwar;
import java.awt.*;
import java.util.Random;
public class Computer_Tank extends Tank{
int moveTime = 0;
public Computer_Tank(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage, Panel panel) {
super(img, x, y, upImage, downImage, leftImage, rightImage, panel);
}
public void go(){
attack();
if(moveTime>=20) {
direction=randomDirection();
moveTime=0;
}else {
moveTime+=1;
}
switch(direction) {
case UP:
upward();
break;
case DOWN:
downward();
break;
case RIGHT:
rightward();
break;
case LEFT:
leftward();
break;
}
}
//电脑坦克随机方向
public Direction randomDirection() {
Random r = new Random();
int rnum = r.nextInt(4);
switch(rnum) {
case 0:
return Direction.UP;
case 1:
return Direction.RIGHT;
case 2:
return Direction.LEFT;
default:
return Direction.DOWN;
}
}
//只有2%几率攻击
public void attack() {
Point p = getHeadPoint();
Random r = new Random();
int rnum =r.nextInt(100);
//System.out.println("r: "+rnum);
if(rnum<2) {
System.out.println(rnum);
Computer_Bullet computerBullet = new Computer_Bullet("images/bullet/bulletYellow.gif",p.x,p.y,direction, panel);
this.panel.bulletList.add(computerBullet);
}
}
@Override
public void paintSelf(Graphics g) {
g.drawImage(img,x,y,null);
go();
}
@Override
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- computer_bullet类 存储了敌方坦克子弹的方法
package tankwar;
import java.awt.*;
public class Computer_Bullet extends Bullet {
public Computer_Bullet(String img, int x, int y, Direction direction, Panel panel){
super(img, x, y, direction, panel);
}
public void hitPlayer(){
Rectangle next= this.getRec();
java.util.List<Tank> tanks = this.panel.tankList;
//子弹和Tank
for(Tank tank: tanks){
if(tank.getRec().intersects(next)){
System.out.println("hit tank");
tank.alive = false;
this.panel.blastList.add(new JiDi_Object(tank.x-34, tank.y-14));
this.panel.tankList.remove(tank);
// this.panel.removeList.add(this);
break;
}
}
}
public void paintSelf(Graphics g){
g.drawImage(img, x, y, null);
go();
hitPlayer();
}
}
- 基地父类 存储了我方基地的数据
package tankwar;
import java.awt.*;
public class JiDi_Object extends Game {
static Image[] imgs = new Image[8];
int explodeCount = 0;
static {
for (int i = 0; i < 8; i++) {
imgs[i] = Toolkit.getDefaultToolkit().getImage("images/blast/blast" +(i + 1)+".gif");
}
}
public JiDi_Object() {
super();
}
public JiDi_Object(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public void paintSelf(Graphics g) {
//绘制点击爆炸效果
if (explodeCount < 8){
g.drawImage(imgs[explodeCount],x,y,null);
explodeCount++;
}
}
@Override
public Rectangle getRec() {
return null;
}
}
- 基地类
package tankwar;
import java.awt.*;
public class JiDi extends Game {
public int width = 60;
public int height = 60;
public JiDi(String img, int x, int y, Panel panel){
super(img, x, y, panel);
}
@Override
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, null);
}
@Override
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- 墙类 创建可以被敌我双方击碎的墙块
package tankwar;
import java.awt.*;
public class Wall extends Game {
public int width = 60;
public int height = 60;
public Wall(String img, int x, int y, Panel panel){
super(img, x, y, panel);
}
@Override
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, null);
}
@Override
public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}
- 游戏开始 在此处启动程序可以启动整个程序
package tankwar;
public class Game_Start {
public static void main(String[] args) {
Panel panel = new Panel();
panel.launch();
}
}
记得需要将图片文件夹image 移入项目文件夹里面
链接:https://pan.baidu.com/s/1JVE608Iz6le172xuppKeLw?pwd=8rf3
提取码:8rf3