Java-坦克攻击(多线程实现子弹)
Java-坦克攻击(多线程实现子弹)
实现过程
- 定义子弹类(Bullet)
/**
* 子弹类
* @author: SEA
* @date: 2023/3/18
*/
public class Bullet {
//子弹坐标和发射方向
int x;
int y;
int direction;
int speed = 5;//子弹初始速度为 5
public Bullet(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
}
- 普通坦克类(Tank)
- 新增属性:
- (1)子弹对象Bullet;
- 新增方法:
- (1)setBullet() 和 getBullet();
- (2)坦克攻击方法attack(),计算坦克发射出的子弹初始坐标;
- 新增属性:
/**
* 坦克
* @author: SEA
* @date: 2023/3/2
*/
public class Tank{
private int x;//坦克的横坐标
private int y;//坦克的纵坐标
private int direction;//坦克的朝向:0 => 向上 ,1 => 向下 ,2 => 向左 , 3 => 向右
private int speed = 5;//坦克速度
private Bullet bullet;//坦克子弹
public Tank(int x, int y) {
this.x = x;
this.y = y;
}
public void moveUp(){
this.y -= this.speed;
}
public void moveDown(){
this.y += this.speed;
}
public void moveRight(){
this.x += this.speed;
}
public void moveLeft(){
this.x -= this.speed;
}
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 getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Bullet getBullet() {
return bullet;
}
public void setBullet(Bullet bullet) {
this.bullet = bullet;
}
public void attack(){//坦克攻击
int bullet_x = -10, bullet_y = -10;
switch (this.getDirection()){//根据当前坦克的位置和方向来计算子弹的发射方向
case 0:
bullet_x = this.getX()+20;
bullet_y = this.getY()-6;
break;
case 1:
bullet_x = this.getX()+20;
bullet_y = this.getY()+64;
break;
case 2:
bullet_x = this.getX()-6;
bullet_y = this.getY()+20;
break;
case 3:
bullet_x = this.getX()+64;
bullet_y = this.getY()+20;
break;
default:
break;
}
this.bullet = new Bullet(bullet_x, bullet_y, this.direction);
TankAttackThread tankAttackThread = new TankAttackThread(bullet);
Thread thread = new Thread(tankAttackThread);
thread.start();
}
}
-
子弹发射的实现:
- 新建线程类TankAttackThread,用来实现坦克发射子弹进行攻击;(子弹移动)
- 为了能够同时存在多颗子弹,需要使用多线程实现;
/** * 子弹发射(多线程) * @author: SEA * @date: 2023/3/18 */ public class TankAttackThread implements Runnable{ Bullet bullet; public TankAttackThread(Bullet bullet) { this.bullet = bullet; } @Override public void run() { while(true){ try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } switch (this.bullet.direction){ case 0: this.bullet.y -= this.bullet.speed; break; case 1: this.bullet.y += this.bullet.speed; break; case 2: this.bullet.x -= this.bullet.speed; break; case 3: this.bullet.x += this.bullet.speed; break; } System.out.println(this.bullet.x+"==asa=" + this.bullet.y); if(this.bullet.x < -3 || this.bullet.y < -3 || this.bullet.x > 1003 || this.bullet.y > 803 ){ break; } } } }
-
根据子弹的坐标和子弹的方向在GamePanel上绘制出子弹:
- 绘制必须在paint()方法中调用,才能在GamePanel上绘制出来;
- 考虑子弹的移动,需要不断地重绘面板,因此需要:
- 1.让GamePanel实现Runnable接口成为线程类,并且实现Runnable接口中的run()方法,使得每间隔100ms重新绘制GamePanel;
- 2.在GameFrame类中启动GamePanel线程,让子弹动起来;
/**
* 坦克大战绘图区域
* @author: SEA
* @date: 2023/3/2
*/
class GamePanel extends JPanel implements KeyListener, Runnable{//画板
......
//绘制
@Override
public void paint(Graphics g) {
super.paint(g);
//游戏窗口背景
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1000, 800);
//标题
g.setFont(new Font("楷体", Font.BOLD, 32));
g.setColor(Color.RED);
g.drawString("TankGame V0.2 by SEA-365", 60, 40);
//画出坦克-封装成方法
drawTank(hero.getX(), hero.getY(), g, hero.getDirection(), 0);
//绘制玩家坦克的子弹
if(hero.getBullet()!=null)
drawBullet(hero.getBullet().x, hero.getBullet().y, g, hero.getBullet().direction, 0);
for (EnemyTank enemyTank : enemyTanks) {
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
}
}
......
//绘制子弹具体实现
public void drawBullet(int x, int y, Graphics g, int direction, int type){
//不同坦克类型,子弹颜色不同
switch (type){
case 0://玩家坦克
g.setColor(Color.YELLOW);
break;
case 1://敌方坦克
g.setColor(Color.CYAN);
break;
}
g.fill3DRect(x, y, 6, 6, false);//绘制矩形子弹
}
......
//在
@Override
public void keyPressed(KeyEvent e) {
/**
* 监听玩家坦克移动
* 方向键 / wsad / WSAD ==> 上下左右
*/
......
/**
* 监听玩家坦克攻击
*/
if(e.getKeyCode() == 'j' || e.getKeyCode() == 'J'){
this.hero.attack();
}
}
......
//run方法,实现每间隔100ms重新绘制GamePanel
@Override
public void run() {
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.repaint();
}
}
}
//最后,在GameFrame中启动GamePanel线程
实现效果
存在的问题
- 子弹射击时存在问题:
- 1.玩家不能连续发射多颗子弹,发射新的子弹,旧的子弹就会消失;
- 根据输出,旧子弹仅仅是没有绘制上panel,但是坐标依然在变;
- 1.玩家不能连续发射多颗子弹,发射新的子弹,旧的子弹就会消失;