Files
zp1/backend/src/main/java/com/zombie/game/model/Bullet.java
2026-04-26 13:35:10 +08:00

174 lines
5.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}