174 lines
5.1 KiB
Java
174 lines
5.1 KiB
Java
package com.zombie.game.model;
|
||
|
||
import lombok.Getter;
|
||
import java.util.*;
|
||
|
||
import static com.zombie.game.model.Constants.*;
|
||
|
||
/**
|
||
* 子弹/投掷物类
|
||
*
|
||
* 管理玩家和僵尸发射的子弹、手榴弹等投掷物。
|
||
* 支持普通子弹的直线飞行和手榴弹的抛物线轨迹。
|
||
*/
|
||
@Getter
|
||
public class Bullet {
|
||
private int id;
|
||
private float x, y;
|
||
private float z;
|
||
private float vx, vy, vz;
|
||
private float speed;
|
||
private int damage;
|
||
private String ownerId;
|
||
private int weaponIndex;
|
||
private float range;
|
||
private float distanceTraveled;
|
||
private boolean explosive;
|
||
private float explosionRadius;
|
||
private float flightTime;
|
||
private float maxFlightTime;
|
||
private float targetX, targetY;
|
||
private boolean isGrenade;
|
||
|
||
public Bullet(int id, float x, float y, float angle, float speed, int damage,
|
||
String ownerId, int weaponIndex, float range) {
|
||
this.id = id;
|
||
this.x = x;
|
||
this.y = y;
|
||
this.z = 0.5f;
|
||
this.speed = speed;
|
||
this.vx = (float) Math.sin(angle) * speed;
|
||
this.vy = (float) Math.cos(angle) * speed;
|
||
this.vz = 0;
|
||
this.damage = damage;
|
||
this.ownerId = ownerId;
|
||
this.weaponIndex = weaponIndex;
|
||
this.range = range;
|
||
this.distanceTraveled = 0;
|
||
this.explosive = false;
|
||
this.explosionRadius = 0;
|
||
this.flightTime = 0;
|
||
this.maxFlightTime = 0;
|
||
this.isGrenade = false;
|
||
this.targetX = x + (float) Math.sin(angle) * range;
|
||
this.targetY = y + (float) Math.cos(angle) * range;
|
||
}
|
||
|
||
/**
|
||
* 构造函数 - 手榴弹
|
||
*
|
||
* @param id 子弹ID
|
||
* @param startX 起始X坐标
|
||
* @param startY 起始Y坐标
|
||
* @param targetX 目标X坐标
|
||
* @param targetY 目标Y坐标
|
||
* @param flightDuration 飞行时长
|
||
* @param damage 伤害值
|
||
* @param ownerId 发射者ID
|
||
* @param explosionRadius 爆炸半径
|
||
*/
|
||
public Bullet(int id, float startX, float startY, float targetX, float targetY,
|
||
float flightDuration, int damage, String ownerId, float explosionRadius) {
|
||
this.id = id;
|
||
this.x = startX;
|
||
this.y = startY;
|
||
this.z = 0.5f;
|
||
this.targetX = targetX;
|
||
this.targetY = targetY;
|
||
this.damage = damage;
|
||
this.ownerId = ownerId;
|
||
this.weaponIndex = -1;
|
||
this.range = 0;
|
||
this.distanceTraveled = 0;
|
||
this.explosive = true;
|
||
this.explosionRadius = explosionRadius;
|
||
this.flightTime = 0;
|
||
this.maxFlightTime = flightDuration;
|
||
this.isGrenade = true;
|
||
this.speed = 0;
|
||
|
||
float dx = targetX - startX;
|
||
float dy = targetY - startY;
|
||
this.vx = dx / flightDuration;
|
||
this.vy = dy / flightDuration;
|
||
this.vz = 3.0f;
|
||
}
|
||
|
||
public boolean update(float dt, GameMap map) {
|
||
if (isGrenade) {
|
||
flightTime += dt;
|
||
|
||
x += vx * dt;
|
||
y += vy * dt;
|
||
|
||
float progress = flightTime / maxFlightTime;
|
||
z = 0.5f + 4.0f * (float) Math.sin(progress * Math.PI);
|
||
|
||
if (flightTime >= maxFlightTime || z <= 0.5f && progress > 0.5f) {
|
||
return false;
|
||
}
|
||
|
||
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
} else {
|
||
float moveX = vx * dt;
|
||
float moveY = vy * dt;
|
||
x += moveX;
|
||
y += moveY;
|
||
distanceTraveled += (float) Math.sqrt(moveX * moveX + moveY * moveY);
|
||
|
||
if (distanceTraveled >= range) return false;
|
||
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) return false;
|
||
|
||
int gx = (int) Math.floor(x);
|
||
int gy = (int) Math.floor(y);
|
||
// 只有碰到静态墙壁才销毁子弹,碰到坚果墙体让碰撞检测处理
|
||
Wall wall = map.getWall(gx, gy);
|
||
if (wall instanceof StaticWall) return false;
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检测子弹是否命中实体
|
||
*
|
||
* @param ex 实体X坐标
|
||
* @param ey 实体Y坐标
|
||
* @param size 实体碰撞体大小
|
||
* @return true 表示命中
|
||
*/
|
||
public boolean hitsEntity(float ex, float ey, float size) {
|
||
float dx = x - ex;
|
||
float dy = y - ey;
|
||
float dist = (float) Math.sqrt(dx * dx + dy * dy);
|
||
return dist < size / 2 + 0.1f;
|
||
}
|
||
|
||
/**
|
||
* 将子弹状态转换为Map格式,用于网络传输
|
||
*
|
||
* @return 包含子弹状态的Map
|
||
*/
|
||
public Map<String, Object> toStateMap() {
|
||
Map<String, Object> map = new LinkedHashMap<>();
|
||
map.put("id", id);
|
||
map.put("x", x);
|
||
map.put("y", y);
|
||
map.put("z", z);
|
||
if (isGrenade) {
|
||
map.put("angle", (float) Math.atan2(vx, vy));
|
||
map.put("targetX", targetX);
|
||
map.put("targetY", targetY);
|
||
} else {
|
||
map.put("angle", (float) Math.atan2(vx, vy));
|
||
}
|
||
map.put("weaponIndex", weaponIndex);
|
||
map.put("ownerId", ownerId);
|
||
return map;
|
||
}
|
||
}
|