基于Java语言坦克大战游戏demo的提升与修改

1|0使用Java程序语言开发的坦克大战小游戏模型
目录
- 使用Java程序语言开发的坦克大战小游戏模型
- 1.项目介绍
- 2.修改思路与方案
- 2.1 原项目的思路分析和代码
- 2.1.1原项目思路概括:
- (1)利用Panel类调用其本身的paint函数在Jframe上绘制坦克,在Jframe上监听键盘事件从而实现坦克的上下左右移动和发射子弹。
- (2)子弹类实现Runnable接口,每当有一个子弹射出时会将子弹加入我方坦克的子弹集合并开启一个线程,当子弹超出某个范围或者集中目标则结束这个线程
- (3)子弹的移动和坦克的移动就是简单的坐标变换,动态效果的绘制必须在paint里面完成
- (4)循环调用repaint函数刷新屏幕使得画面出现变化效果
- 总结:事件监听和屏幕刷新是游戏最基础的功能。事件监听保证坦克和子弹坐标能够变化,屏幕刷新保证屏幕能不断绘制变化的坦克和子弹。所以只要是运行时期的代码都要在paint函数里面调用。
- 整个流程没有什么太大的问题,只是缺少了一些功能,下面提出一些改进方案
- 2.1.2原项目部分代码
- 敌方坦克类
- 我方坦克类
- 2.1.1原项目思路概括:
- 2.2 项目缺陷
- 2.3 改进思路
- 2.1 原项目的思路分析和代码
- 3.代码实现
- 4.运行效果汇总
- 5.总结
2|01.项目介绍
2|11.1项目名称:使用Java程序语言开发的坦克大战小游戏模型
2|21.2项目来源:某黄姓同学假期学习项目
2|31.3项目已实现功能(代码太长,只展示部分关键代码):
1|0(1)我方坦克的移动
点击查看代码
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_W){//向上转
hero.setDirection(0);
if (hero.getY()>=0) {
hero.moveUp();
}
}else if (e.getKeyCode()==KeyEvent.VK_D){
hero.setDirection(1);
if (hero.getX()+60<=1000) {
hero.moveRight();
}
}else if (e.getKeyCode()==KeyEvent.VK_S){
hero.setDirection(2);
if (hero.getY()+80<=750) {
hero.moveDown();
}
}else if(e.getKeyCode()==KeyEvent.VK_A){
hero.setDirection(3);
if (hero.getX()>=0) {
hero.moveLeft();
}
}
1|0(2)地方坦克的随机移动
点击查看代码
switch (getDirection()){
case 0:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getY()>=0) {
moveUp();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
case 1:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getX()+60<=1000) {
moveRight();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
case 2:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getY()+60<=750) {
moveDown();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
case 3:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getX()>=0) {
moveLeft();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
}
setDirection((int)(Math.random()*4));
if(!isLive) break;
1|0(3)我方坦克的射击
点击查看代码
if(e.getKeyCode()==KeyEvent.VK_J){
hero.shot();
}
shot函数的实现:
public void shot(){
switch (getDirection()){
case 0:
shot= new Shot(getX()+20,getY(),getDirection());
break;
case 1:
shot= new Shot(getX()+60,getY()+20,getDirection());
break;
case 2:
shot= new Shot(getX()+20,getY()+60,getDirection());
break;
case 3:
shot= new Shot(getX(),getY()+20,getDirection());
break;
}
shots.add(shot);
new Thread(shot).start();
1|0(4)地方坦克的射击
点击查看代码
switch (getDirection()){
case 0:
shot= new Shot(getX()+20,getY(),getDirection());
break;
case 1:
shot= new Shot(getX()+60,getY()+20,getDirection());
break;
case 2:
shot= new Shot(getX()+20,getY()+60,getDirection());
break;
case 3:
shot= new Shot(getX(),getY()+20,getDirection());
break;
}
shots.add(shot);
new Thread(shot).start();
1|0(5)效果展示
3|02.修改思路与方案
3|12.1 原项目的思路分析和代码
1|02.1.1原项目思路概括:
1|0(1)利用Panel类调用其本身的paint函数在Jframe上绘制坦克,在Jframe上监听键盘事件从而实现坦克的上下左右移动和发射子弹。
1|0(2)子弹类实现Runnable接口,每当有一个子弹射出时会将子弹加入我方坦克的子弹集合并开启一个线程,当子弹超出某个范围或者集中目标则结束这个线程
1|0(3)子弹的移动和坦克的移动就是简单的坐标变换,动态效果的绘制必须在paint里面完成
1|0(4)循环调用repaint函数刷新屏幕使得画面出现变化效果
1|0总结:事件监听和屏幕刷新是游戏最基础的功能。事件监听保证坦克和子弹坐标能够变化,屏幕刷新保证屏幕能不断绘制变化的坦克和子弹。所以只要是运行时期的代码都要在paint函数里面调用。
1|0 整个流程没有什么太大的问题,只是缺少了一些功能,下面提出一些改进方案
1|02.1.2原项目部分代码
1|0敌方坦克类
点击查看代码
package com.TankGame;
import java.io.Serializable;
import java.util.Vector;
public class EnemyTank extends Tank implements Runnable, Serializable {
private Vector<Shot> shots =new Vector<>();
private boolean isLive=true;
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public Vector<Shot> getShots() {
return shots;
}
public void setShots(Vector<Shot> shots) {
this.shots = shots;
}
public double distance(int heroX,int heroY, int shotX,int shotY){
return Math.sqrt(Math.pow((double) (heroX-shotX),2)+Math.pow((double) (heroY-shotY),2));
}
public EnemyTank(int x, int y) {
super(x, y);
}
@Override
public void run() {
Shot shot=null;
while (true){
//坦克随机发射子弹
if (isLive&&shots.size()!=0 && distance(getX(),getY(),shots.lastElement().x,shots.lastElement().y)>75) {
switch (getDirection()){
case 0:
shot= new Shot(getX()+20,getY(),getDirection());
break;
case 1:
shot= new Shot(getX()+60,getY()+20,getDirection());
break;
case 2:
shot= new Shot(getX()+20,getY()+60,getDirection());
break;
case 3:
shot= new Shot(getX(),getY()+20,getDirection());
break;
}
shots.add(shot);
new Thread(shot).start();
}else if (isLive){
switch (getDirection()){
case 0:
shot= new Shot(getX()+20,getY(),getDirection());
break;
case 1:
shot= new Shot(getX()+60,getY()+20,getDirection());
break;
case 2:
shot= new Shot(getX()+20,getY()+60,getDirection());
break;
case 3:
shot= new Shot(getX(),getY()+20,getDirection());
break;
}
shots.add(shot);
new Thread(shot).start();
}
//坦克随机移动
switch (getDirection()){
case 0:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getY()>=0) {
moveUp();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
case 1:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getX()+60<=1000) {
moveRight();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
case 2:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getY()+60<=750) {
moveDown();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
case 3:
for (int i=0;i<(int)((Math.random()+1)*15);i++){
if (getX()>=0) {
moveLeft();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}break;
}
setDirection((int)(Math.random()*4));
if(!isLive) break;
}
}
}
1|0我方坦克类
点击查看代码
package com.TankGame;
import java.util.Vector;
public class Hero extends Tank{
Shot shot= null;
boolean isLive = true;
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
Vector<Shot> shots = new Vector<>();
public Hero(int x, int y) {
super(x, y);
this.setSpeed(10);
this.setType(0);
}
public void shot(){
switch (getDirection()){
case 0:
shot= new Shot(getX()+20,getY(),getDirection());
break;
case 1:
shot= new Shot(getX()+60,getY()+20,getDirection());
break;
case 2:
shot= new Shot(getX()+20,getY()+60,getDirection());
break;
case 3:
shot= new Shot(getX(),getY()+20,getDirection());
break;
}
shots.add(shot);
new Thread(shot).start();
}
}
3|22.2 项目缺陷
1|0(1)目前项目没有游戏结束的提示
1|0(2)我方坦克子弹设计无时间见隔,不符合常理
1|0(3)坦克消失的时候没有爆炸效果
1|0(4)没有击杀地方坦克的记录而且无法保存当前进度到本地
3|32.3 改进思路
1|0(1)在游戏结束的时候往屏幕输出“game over”
1|0只需要在我方坦克被击中或者敌方坦克全部销毁的时候改变一个值,这里设置的是坦克的方向(上:0,右:1,下:2,左:3)为5(任意一个非0,1,2,3的数字),当每次刷新时会检测上述条件是否成立,并在每次调用绘制坦克的函数判断方向,如果为5就会显示game over
1|0代码
1|0判断是否设置结束的标志
点击查看代码
if (hero.isLive==false || enemyTanks.size()==0){
hero.setDirection(5);
}
1|0如果坦克的Dirtection为5则视为游戏结束
点击查看代码
switch (direction){
case 0://向上的方向
g.fill3DRect(x,y,10,60,false);
g.fill3DRect(x+30,y,10,60,false);
g.fill3DRect(x+10,y+10,20,40,false);
g.fillOval(x+10,y+20,20,20);
g.drawLine(x+20,y+30,x+20,y);
break;
case 1://向右的方向
g.fill3DRect(x,y,60,10,false);
g.fill3DRect(x,y+30,60,10,false);
g.fill3DRect(x+10,y+10,40,20,false);
g.fillOval(x+20,y+10,20,20);
g.drawLine(x+30,y+20,x+60,y+20);
break;
case 2://向下的方向
g.fill3DRect(x,y,10,60,false);
g.fill3DRect(x+30,y,10,60,false);
g.fill3DRect(x+10,y+10,20,40,false);
g.fillOval(x+10,y+20,20,20);
g.drawLine(x+20,y+30,x+20,y+60);
break;
case 3://向左的方向
g.fill3DRect(x,y,60,10,false);
g.fill3DRect(x,y+30,60,10,false);
g.fill3DRect(x+10,y+10,40,20,false);
g.fillOval(x+20,y+10,20,20);
g.drawLine(x+30,y+20,x,y+20);
break;
default:
g.setColor(Color.pink);
g.setFont(new Font("微软雅黑",Font.BOLD,50));
g.drawString("GAME OVER!!!",350,375);
}
1|0运行效果
1|0(2)子弹发射间隔用时间判定比较难实现,改为上一发子弹距离坦克位置距离判断
由于根据子弹发射时间来判断是否能发射下一发子弹比较难实现,现用子弹位置离炮筒位置的距离来判断是否能发射下一发子弹
1|0计算距离的代码
点击查看代码
public double distance(int heroX,int heroY, int shotX,int shotY){
return Math.sqrt(Math.pow((double) (heroX-shotX),2)+Math.pow((double) (heroY-shotY),2));
}
1|0判断子弹是否应该射出
点击查看代码
if(e.getKeyCode()==KeyEvent.VK_J){//监听j键
//遍历子弹的集合,如果距离枪口的位置大于某个值才能shot
if (hero.shots.size()!=0) {
Shot shot = hero.shots.lastElement();
if(distance(hero.getX()+25,hero.getY()+25,shot.x,shot.y)>=80)
hero.shot();
// System.out.println(distance(hero.getX(),hero.getY(),shot.x,shot.y));
}else{
hero.shot();//保证能开第一枪
}
1|0运行效果
1|0(3)用一个炸弹集合,当地方坦克死亡就add一个炸弹,循环检测💣集合,一旦集合不为空则绘制炸弹💣
在Panel里面加一个存放炸弹的集合,一旦有坦克被击中就往炸弹集合里面加一个炸弹。每次刷新都检查这个集合,如果存在炸弹就循环绘制爆炸图片最后并删除这个炸弹
1|0炸弹类代码
点击查看代码
package com.TankGame;
import java.awt.*;
public class Bomb {
Image image01,image02,image03;
private int x,y,life=60;
boolean isLive=true;
public Bomb(int x, int y) {
this.x = x;
this.y = y;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
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 getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public Bomb(Image image01, Image image02, Image image03) {
this.image01 = image01;
this.image02 = image02;
this.image03 = image03;
}
public void lifeDown(){
if(life>0){
life--;
}else {
isLive=false;
}
}
}
1|0判断集合是否存在炸弹,一旦存在直接绘制
点击查看代码
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
//画炸弹
for (int i=0;i<bombs.size();i++){
Bomb bomb = bombs.get(i);
if(bomb.getLife()>45){
g.drawImage(image01,bomb.getX(),bomb.getY(),60,60,this);
}else if (bomb.getLife()>30){
g.drawImage(image02,bomb.getX(),bomb.getY(),60,60,this);
}else if(bomb.getLife()>15){
g.drawImage(image03,bomb.getX(),bomb.getY(),60,60,this);
} else {
g.drawImage(image04,bomb.getX(),bomb.getY(),60,60,this);
}
bomb.lifeDown();
if(bomb.getLife()==0){
bombs.remove(bomb);
}
}
点击查看代码
//添加炸弹进入集合(我方被击中)
bombs.add(new Bomb(hero.getX(),hero.getY()));
//添加炸弹进入集合(敌方被击中)
bombs.add(new Bomb(enemyTank.getX(),enemyTank.getY()));
1|0运行效果(找不到爆炸图片就随便拿了一张图片)
1|0(4)使用文件记录比赛各个坦克的坐标以及玩家分数
1|0记录信息类代码
点击查看代码
package com.TankGame;
import java.io.*;
import java.util.List;
import java.util.Vector;
public class Recorder {
public static int getAllEnemy() {
return AllEnemy;
}
public static void setList(Vector<EnemyTank> list) {
Recorder.list = list;
}
private static Vector<EnemyTank> list;
public static void setNodes(Vector<Node> nodes) {
Recorder.nodes = nodes;
}
public static void setHero(Hero hero) {
Recorder.hero = hero;
}
private static Hero hero;
private static Vector<Node> nodes;
public static void setAllEnemy(int allEnemy) {
AllEnemy = allEnemy;
}
private static String path="src\\record.txt";
private static String path1="src\\rec";
private static int AllEnemy;
private static ObjectOutputStream objectOutputStream;
private static BufferedWriter bufferedWriter;
private static BufferedReader bufferedReader;
public static void setBufferedReader(BufferedReader bufferedReader) {
Recorder.bufferedReader = bufferedReader;
}
public static void KillOne(){
AllEnemy++;
}
public static void save() throws IOException {
try {
bufferedWriter=new BufferedWriter(new FileWriter(path,false));
bufferedWriter.write(AllEnemy+"\r\n");
bufferedWriter.write(hero.getX()+" "+
hero.getY()+" "+hero.getDirection()+"\r\n");
for (int i =0;i<list.size();i++){
EnemyTank enemyTank = list.get(i);
if (enemyTank.isLive()){
bufferedWriter.write(enemyTank.getX()+" "+
enemyTank.getY()+" "+enemyTank.getType()+"\r\n");
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bufferedWriter != null) {
bufferedWriter.close();
}
}
}
public static void saveBySer() throws IOException {
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(path1));
objectOutputStream.writeInt(AllEnemy);
for (int i = 0; i<list.size(); i++){
EnemyTank enemyTank = list.get(i);
if (enemyTank.isLive()){
objectOutputStream.writeObject(enemyTank);
}
}
} finally {
objectOutputStream.close();
}
}
public static Vector<Node> Recordergetted() throws IOException {
bufferedReader = new BufferedReader(new FileReader(path));
AllEnemy=Integer.parseInt((bufferedReader.readLine()));
String line;
while ((line = bufferedReader.readLine()) != null){
String[] s = line.split(" ");
Node node = new Node(Integer.parseInt(s[0]), Integer.parseInt(s[1]),Integer.parseInt(s[2]));
nodes.add(node);
}
bufferedReader.close();
return nodes;
}
}
1|0Node节点类代码(用于从文件中获取坦克坐标)
点击查看代码
package com.TankGame;
public class Node {
public int getX() {
return x;
}
public Node(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
private int x;
private int y;
private int direction;
}
1|0在界面上绘制玩家得分
点击查看代码
public void showKill(Graphics g){
g.setColor(Color.BLACK);
Font font = new Font("宋体",Font.BOLD,25);
g.setFont(font);
g.drawString("累计击杀坦克",1120,30);
DrawTank(1120,60,g,0,0);
g.setColor(Color.BLACK);
g.drawString(Recorder.getAllEnemy()+"",1180,100);
}
1|0在玩家退出时保存记录
点击查看代码
this.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
try {
Recorder.save();
System.exit(0);
} catch (IOException ex) {
ex.printStackTrace();
}
}
1|0选择新游戏还是继续上局的游戏
点击查看代码
System.out.println("1:新游戏\n2:继续上局");
String key = scanner.next();
hxwTankGame01 hxwTankGame01= new hxwTankGame01(key);
点击查看代码
public MyPanel(String key) throws IOException {
hero = new Hero(600, 600);
Recorder.setList(enemyTanks);
Recorder.setNodes(nodes);
Recorder.setHero(hero);
switch (key) {
case "1":
;//在画布上初始化一个坦克
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = new EnemyTank((int) (Math.random() * 1000), (int) (Math.random() * 600));
enemyTank.setDirection((int) (Math.random() * 4));
enemyTank.setType(1);
new Thread(enemyTank).start();
enemyTanks.add(enemyTank);
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
enemyTank.getShots().add(shot);
//开了三个地方坦克的子弹线程
new Thread(shot).start();
}
break;
case "2":
nodes= Recorder.Recordergetted();
Node node = nodes.get(0);
hero = new Hero(node.getX(),node.getY());
hero.setDirection(node.getDirection());
for (int i = 1; i < nodes.size(); i++) {
node = nodes.get(i);
EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
enemyTank.setDirection(node.getDirection());
enemyTank.setType(1);
new Thread(enemyTank).start();
enemyTanks.add(enemyTank);
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
enemyTank.getShots().add(shot);
//开了三个地方坦克的子弹线程
new Thread(shot).start();
}break;
default:System.exit(0);
}
1|0运行效果
4|03.代码实现
4|1主要逻辑代码
点击查看代码
package com.TankGame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.security.Key;
import java.util.Vector;
public class MyPanel extends JPanel implements KeyListener ,Runnable{
//主角坦克
Hero hero = null;
//敌人
Vector<EnemyTank> enemyTanks = new Vector<>();
Vector<Bomb> bombs = new Vector<>();
Vector<Node> nodes = new Vector<>();
int enemyTankSize=3;
Graphics G=null;
//爆炸效果
Image image01=Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/1.png"));
Image image02=Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/9.png"));
Image image03=Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/17.png"));
Image image04=Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/25.png"));
public void showKill(Graphics g){
g.setColor(Color.BLACK);
Font font = new Font("宋体",Font.BOLD,25);
g.setFont(font);
g.drawString("累计击杀坦克",1120,30);
DrawTank(1120,60,g,0,0);
g.setColor(Color.BLACK);
g.drawString(Recorder.getAllEnemy()+"",1180,100);
}
@Override
public void paint(Graphics g) {
G=g;
super.paint(g);
//游戏区域
g.fillRect(0,0,1000,750);
showKill(g);
System.out.println(hero.getX()+","+hero.getY());
if (hero.isLive==false || enemyTanks.size()==0){
hero.setDirection(5);
}
//大佬说这个是为了让第一次爆爆炸能显示
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
//画炸弹
for (int i=0;i<bombs.size();i++){
Bomb bomb = bombs.get(i);
if(bomb.getLife()>45){
g.drawImage(image01,bomb.getX(),bomb.getY(),60,60,this);
}else if (bomb.getLife()>30){
g.drawImage(image02,bomb.getX(),bomb.getY(),60,60,this);
}else if(bomb.getLife()>15){
g.drawImage(image03,bomb.getX(),bomb.getY(),60,60,this);
} else {
g.drawImage(image04,bomb.getX(),bomb.getY(),60,60,this);
}
bomb.lifeDown();
if(bomb.getLife()==0){
bombs.remove(bomb);
}
}
//画坦克
DrawTank(hero.getX(),hero.getY(),g,hero.getDirection(),hero.getType());
//画敌人
for (EnemyTank i:enemyTanks
) {
if(i.isLive()){
DrawTank(i.getX(),i.getY(),g,i.getDirection(),i.getType());
for(int j=0;j<i.getShots().size();j++){
Shot shot;
if((shot=i.getShots().get(j))!=null && shot.isLive ==true){
switch (i.getType()){
case 0://Hero
g.setColor(Color.cyan);
break;
case 1://
g.setColor(Color.yellow);
break;
case 2:
g.setColor(Color.pink);
break;
}
g.draw3DRect(shot.x,shot.y,2,2,false);
}else{
i.getShots().remove(shot);
}
}
}else{
}
}
//画子弹
for (int i =0;i<hero.shots.size();i++) {
if(hero.shots.get(i)!=null&&hero.shots.get(i).isLive==true){
switch (hero.getType()){
case 0://Hero
g.setColor(Color.cyan);
break;
case 1://
g.setColor(Color.yellow);
break;
case 2:
g.setColor(Color.pink);
break;
}
g.draw3DRect(hero.shots.get(i).x,hero.shots.get(i).y,2,2,false);
}
}
}
public MyPanel(String key) throws IOException {
hero = new Hero(600, 600);
Recorder.setList(enemyTanks);
Recorder.setNodes(nodes);
Recorder.setHero(hero);
switch (key) {
case "1":
;//在画布上初始化一个坦克
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = new EnemyTank((int) (Math.random() * 1000), (int) (Math.random() * 600));
enemyTank.setDirection((int) (Math.random() * 4));
enemyTank.setType(1);
new Thread(enemyTank).start();
enemyTanks.add(enemyTank);
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
enemyTank.getShots().add(shot);
//开了三个地方坦克的子弹线程
new Thread(shot).start();
}
break;
case "2":
nodes= Recorder.Recordergetted();
Node node = nodes.get(0);
hero = new Hero(node.getX(),node.getY());
hero.setDirection(node.getDirection());
for (int i = 1; i < nodes.size(); i++) {
node = nodes.get(i);
EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
enemyTank.setDirection(node.getDirection());
enemyTank.setType(1);
new Thread(enemyTank).start();
enemyTanks.add(enemyTank);
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
enemyTank.getShots().add(shot);
//开了三个地方坦克的子弹线程
new Thread(shot).start();
}break;
default:System.exit(0);
}
}
//将话坦克封装为一个方法
/**
*
* @param x 坦克左上角坐标
* @param y 坦克左上角坐标
* @param g 画笔
* @param direction 坦克的方向
* @param type 坦克类型
*/
public void DrawTank(int x,int y,Graphics g,int direction,int type){
switch (type){
case 0://Hero
g.setColor(Color.cyan);
break;
case 1://
g.setColor(Color.yellow);
break;
case 2:
g.setColor(Color.pink);
break;
}
switch (direction){
case 0://向上的方向
g.fill3DRect(x,y,10,60,false);
g.fill3DRect(x+30,y,10,60,false);
g.fill3DRect(x+10,y+10,20,40,false);
g.fillOval(x+10,y+20,20,20);
g.drawLine(x+20,y+30,x+20,y);
break;
case 1://向右的方向
g.fill3DRect(x,y,60,10,false);
g.fill3DRect(x,y+30,60,10,false);
g.fill3DRect(x+10,y+10,40,20,false);
g.fillOval(x+20,y+10,20,20);
g.drawLine(x+30,y+20,x+60,y+20);
break;
case 2://向下的方向
g.fill3DRect(x,y,10,60,false);
g.fill3DRect(x+30,y,10,60,false);
g.fill3DRect(x+10,y+10,20,40,false);
g.fillOval(x+10,y+20,20,20);
g.drawLine(x+20,y+30,x+20,y+60);
break;
case 3://向左的方向
g.fill3DRect(x,y,60,10,false);
g.fill3DRect(x,y+30,60,10,false);
g.fill3DRect(x+10,y+10,40,20,false);
g.fillOval(x+20,y+10,20,20);
g.drawLine(x+30,y+20,x,y+20);
break;
default:
g.setColor(Color.pink);
g.setFont(new Font("微软雅黑",Font.BOLD,50));
g.drawString("GAME OVER!!!",350,375);
}
}
//击中玩家的方法
public Hero hitHero(Shot shot,Hero hero){
switch (hero.getDirection()){
case 0:
case 2:
if(shot.x >= hero.getX() && shot.x<=hero.getX()+40 && shot.y>=hero.getY() && shot.y<=hero.getY()+60){
shot.isLive=false;
hero.isLive=false;
bombs.add(new Bomb(hero.getX(),hero.getY()));
}break;
case 1:
case 3:
if(shot.x>=hero.getX()&&shot.x<=hero.getX()+60 && shot.y>=hero.getY()&&shot.x<=hero.getY()+40){
shot.isLive=false;
hero.isLive=false;
}break;
}if(hero!=null && hero.isLive==false){
return hero;
}else return null;
}
//击中敌方坦克的方法
public EnemyTank hitTank(Shot shot,EnemyTank enemyTank){
switch (enemyTank.getDirection()){
case 0://坦克向上
case 2://坦克向下
if(shot.x>enemyTank.getX() && shot.x<enemyTank.getX()+40 && shot.y>enemyTank.getY()&&shot.y<enemyTank.getY()+60){
shot.isLive=false;
enemyTank.setLive(false);
bombs.add(new Bomb(enemyTank.getX(),enemyTank.getY()));
Recorder.KillOne();
}break;
case 1://坦克向右
case 3://坦克向左
if(shot.x>enemyTank.getX() && shot.x<enemyTank.getX()+60 && shot.y>enemyTank.getY()&&shot.y<enemyTank.getY()+40){
shot.isLive=false;
enemyTank.setLive(false);
bombs.add(new Bomb(enemyTank.getX(),enemyTank.getY()));
Recorder.KillOne();
}break;
}if(!enemyTank.isLive())
return enemyTank;
else return null;
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_W){//向上转
hero.setDirection(0);
if (hero.getY()>=0) {
hero.moveUp();
}
}else if (e.getKeyCode()==KeyEvent.VK_D){
hero.setDirection(1);
if (hero.getX()+60<=1000) {
hero.moveRight();
}
}else if (e.getKeyCode()==KeyEvent.VK_S){
hero.setDirection(2);
if (hero.getY()+80<=750) {
hero.moveDown();
}
}else if(e.getKeyCode()==KeyEvent.VK_A){
hero.setDirection(3);
if (hero.getX()>=0) {
hero.moveLeft();
}
}else if(e.getKeyCode()==KeyEvent.VK_C){
hero.setType((hero.getType()+1)%3);
}
if(e.getKeyCode()==KeyEvent.VK_J){//监听j键
//遍历子弹的集合,如果距离枪口的位置大于某个值才能shot
if (hero.shots.size()!=0) {
Shot shot = hero.shots.lastElement();
if(distance(hero.getX()+25,hero.getY()+25,shot.x,shot.y)>=80)
hero.shot();
// System.out.println(distance(hero.getX(),hero.getY(),shot.x,shot.y));
}else{
hero.shot();//保证能开第一枪
}
}
}
public double distance(int heroX,int heroY, int shotX,int shotY){
return Math.sqrt(Math.pow((double) (heroX-shotX),2)+Math.pow((double) (heroY-shotY),2));
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {
try {//
while (true){
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i=0;i<enemyTanks.size();i++){//循环检测子弹是否打中地方坦克
for (int j=0;j<hero.shots.size();j++) {
if(hero.shots.get(j)!=null && hero.shots.get(j).isLive){
EnemyTank enemyTank= null;
Shot shot = hero.shots.get(j);
EnemyTank enemyTank1 = enemyTanks.get(i);
try {
enemyTank = hitTank(hero.shots.get(j), enemyTank1);
} catch (Exception e) {
System.out.println("出现小BUG,嘻嘻!,原因:"+e.toString());
continue;
}
if(enemyTank !=null && !enemyTank.isLive()){
enemyTanks.remove(enemyTank);
hero.shots.remove(shot);
}
}
}
}
for (int i=0;i<enemyTanks.size();i++){//循环检测子弹是否打中玩家
EnemyTank enemyTank=enemyTanks.get(i);
Vector<Shot> s = enemyTank.getShots();
for (int j=0;j<enemyTank.getShots().size();j++) {//每个敌人的子弹集合
if(s.size()!=0 && hero.isLive){
Shot shot = s.get(j);
Hero hero1 = hitHero(shot,hero);
if(hero1 !=null && !hero1.isLive()){
System.out.println(hero.isLive);
}
}
}
}
//刷新屏幕
this.repaint();
if (!hero.isLive || enemyTanks.size()==0){
hero.setDirection(4);
break;
}
}
this.repaint();
} catch (Exception e) {
System.out.println("未知异常请勿在意");
}
for (int i=0;i<enemyTanks.size();i++){
for (int j=0;j<enemyTanks.get(i).getShots().size();j++){
Shot shot;
if((shot=enemyTanks.get(i).getShots().get(j)).isLive==false){
enemyTanks.get(i).getShots().remove(shot);
}
}
}
}
}
5|04.运行效果汇总
6|05.总结
1|0在本次优化过程中,感觉上做了很多工作,但是最后一运行发现其实好像也没有做很多优化,也就只能基本完成原先找出来的项目缺陷,最后成品依然不堪入目
1|0在处理子弹间隔的时候想了很久要如何通过时间间隔来控制子弹的发射,最后发先如果想要按照时间来控制的话需要改的地方很多,几乎无从下手,最后灵机一
1|0动才想到子弹速度,时间和路程的物理关系,最后转化成距离来计算。本次实验还有一些额外收获,懂得了制作一个小游戏的基本思路,保持屏幕刷新和检测。
1|0最后,在写代码时,一定要写注释!
__EOF__

本文作者:来自由
本文链接:https://www.cnblogs.com/laizeyou/p/15937782.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/laizeyou/p/15937782.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)