|
|
@@ -82,9 +82,20 @@ export class BallController extends Component {
|
|
|
})
|
|
|
public antiTrapHitThreshold: number = 5;
|
|
|
|
|
|
+ @property({
|
|
|
+ tooltip: '偏移尝试次数阈值(达到后才使用穿透)'
|
|
|
+ })
|
|
|
+ public deflectionAttemptThreshold: number = 3;
|
|
|
+
|
|
|
+ @property({
|
|
|
+ tooltip: '防围困偏移强度倍数'
|
|
|
+ })
|
|
|
+ public antiTrapDeflectionMultiplier: number = 3.0;
|
|
|
+
|
|
|
// 防围困机制状态
|
|
|
private ballHitHistory: Map<string, number[]> = new Map(); // 记录每个球的撞击时间历史
|
|
|
private ballPhaseThrough: Map<string, number> = new Map(); // 记录每个球的穿透结束时间
|
|
|
+ private ballDeflectionAttempts: Map<string, number> = new Map(); // 记录每个球的偏移尝试次数
|
|
|
|
|
|
// 带尾部特效的子弹容器预制体
|
|
|
@property({
|
|
|
@@ -697,16 +708,53 @@ export class BallController extends Component {
|
|
|
|
|
|
// 检查是否达到防围困条件
|
|
|
if (hitHistory.length >= this.antiTrapHitThreshold) {
|
|
|
- // 激活穿透状态,持续0.5秒
|
|
|
- this.ballPhaseThrough.set(ballId, currentTime + 0.5);
|
|
|
- // 清空撞击历史
|
|
|
- hitHistory.length = 0;
|
|
|
- // 禁用当前碰撞
|
|
|
- if (contact) {
|
|
|
- contact.disabled = true;
|
|
|
+ // 获取当前偏移尝试次数
|
|
|
+ const deflectionAttempts = this.ballDeflectionAttempts.get(ballId) || 0;
|
|
|
+
|
|
|
+ if (deflectionAttempts < this.deflectionAttemptThreshold) {
|
|
|
+ // 优先使用偏移方式
|
|
|
+ this.ballDeflectionAttempts.set(ballId, deflectionAttempts + 1);
|
|
|
+
|
|
|
+ // 应用增强偏移反弹
|
|
|
+ const rigidBody = ballNode.getComponent(RigidBody2D);
|
|
|
+ if (rigidBody && contact) {
|
|
|
+ // 获取碰撞法线
|
|
|
+ let normal = new Vec2(0, 1);
|
|
|
+ if ((contact as any).getWorldManifold) {
|
|
|
+ const wm = (contact as any).getWorldManifold();
|
|
|
+ if (wm && wm.normal) {
|
|
|
+ normal = new Vec2(wm.normal.x, wm.normal.y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算增强偏移反弹方向
|
|
|
+ const currentVelocity = rigidBody.linearVelocity;
|
|
|
+ const currentDirection = new Vec2(currentVelocity.x, currentVelocity.y).normalize();
|
|
|
+ const newDirection = this.calculateAntiTrapReflection(currentDirection, normal);
|
|
|
+
|
|
|
+ // 应用新的速度方向
|
|
|
+ const speed = currentVelocity.length();
|
|
|
+ rigidBody.linearVelocity = new Vec2(newDirection.x * speed, newDirection.y * speed);
|
|
|
+
|
|
|
+ console.log(`Ball ${ballId} applied anti-trap deflection (attempt ${deflectionAttempts + 1}/${this.deflectionAttemptThreshold})`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清空撞击历史,给偏移一个机会
|
|
|
+ hitHistory.length = 0;
|
|
|
+ } else {
|
|
|
+ // 偏移尝试次数已达上限,使用穿透
|
|
|
+ this.ballPhaseThrough.set(ballId, currentTime + 0.5);
|
|
|
+ // 重置偏移尝试次数
|
|
|
+ this.ballDeflectionAttempts.set(ballId, 0);
|
|
|
+ // 清空撞击历史
|
|
|
+ hitHistory.length = 0;
|
|
|
+ // 禁用当前碰撞
|
|
|
+ if (contact) {
|
|
|
+ contact.disabled = true;
|
|
|
+ }
|
|
|
+ console.log(`Ball ${ballId} entered phase-through mode after ${this.deflectionAttemptThreshold} deflection attempts failed`);
|
|
|
+ return;
|
|
|
}
|
|
|
- console.log(`Ball ${ballId} entered phase-through mode due to frequent collisions`);
|
|
|
- return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -894,6 +942,56 @@ export class BallController extends Component {
|
|
|
return randomizedReflection;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 计算防围困增强偏移反弹方向
|
|
|
+ * @param direction 当前方向
|
|
|
+ * @param normal 碰撞法线
|
|
|
+ * @returns 增强偏移后的反弹方向
|
|
|
+ */
|
|
|
+ calculateAntiTrapReflection(direction: Vec2, normal: Vec2): Vec2 {
|
|
|
+ // 使用反射公式: R = V - 2(V·N)N
|
|
|
+ const dot = direction.x * normal.x + direction.y * normal.y;
|
|
|
+ const reflection = new Vec2(
|
|
|
+ direction.x - 2 * dot * normal.x,
|
|
|
+ direction.y - 2 * dot * normal.y
|
|
|
+ );
|
|
|
+ reflection.normalize();
|
|
|
+
|
|
|
+ // 应用更强的随机偏移来帮助脱困
|
|
|
+ const enhancedRandomness = this.maxReflectionRandomness * this.antiTrapDeflectionMultiplier;
|
|
|
+ const randomAngle = (Math.random() - 0.5) * enhancedRandomness;
|
|
|
+ const cos = Math.cos(randomAngle);
|
|
|
+ const sin = Math.sin(randomAngle);
|
|
|
+
|
|
|
+ // 应用随机旋转
|
|
|
+ const randomizedReflection = new Vec2(
|
|
|
+ reflection.x * cos - reflection.y * sin,
|
|
|
+ reflection.x * sin + reflection.y * cos
|
|
|
+ );
|
|
|
+
|
|
|
+ // 更强的轴向偏移避免
|
|
|
+ const minAngleFromAxis = 0.3; // 约17度,比普通反弹更大的偏移
|
|
|
+
|
|
|
+ // 检查是否接近水平方向
|
|
|
+ if (Math.abs(randomizedReflection.y) < minAngleFromAxis) {
|
|
|
+ const sign = randomizedReflection.y >= 0 ? 1 : -1;
|
|
|
+ randomizedReflection.y = sign * (minAngleFromAxis + Math.random() * 0.2);
|
|
|
+ randomizedReflection.normalize();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否接近垂直方向
|
|
|
+ if (Math.abs(randomizedReflection.x) < minAngleFromAxis) {
|
|
|
+ const sign = randomizedReflection.x >= 0 ? 1 : -1;
|
|
|
+ randomizedReflection.x = sign * (minAngleFromAxis + Math.random() * 0.2);
|
|
|
+ randomizedReflection.normalize();
|
|
|
+ }
|
|
|
+
|
|
|
+ randomizedReflection.normalize();
|
|
|
+ console.log(`Applied anti-trap enhanced deflection with angle: ${randomAngle}`);
|
|
|
+
|
|
|
+ return randomizedReflection;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 从方块武器发射子弹攻击敌人 - 重构版本
|
|
|
* 现在直接创建子弹实例并使用BulletController的实例方法
|
|
|
@@ -1325,6 +1423,7 @@ export class BallController extends Component {
|
|
|
// 清理防围困状态数据
|
|
|
this.ballHitHistory.clear();
|
|
|
this.ballPhaseThrough.clear();
|
|
|
+ this.ballDeflectionAttempts.clear();
|
|
|
|
|
|
// 重置球速
|
|
|
this.updateBallSpeed();
|
|
|
@@ -1344,6 +1443,17 @@ export class BallController extends Component {
|
|
|
this.ballPhaseThrough.delete(ballId);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 检查并重置长时间未频繁撞击的球的偏移尝试次数
|
|
|
+ for (const [ballId, hitHistory] of this.ballHitHistory.entries()) {
|
|
|
+ // 如果撞击历史为空或最近一次撞击超过时间窗口的一半,重置偏移尝试次数
|
|
|
+ if (hitHistory.length === 0 ||
|
|
|
+ (hitHistory.length > 0 && currentTime - hitHistory[hitHistory.length - 1] > this.antiTrapTimeWindow / 2)) {
|
|
|
+ if (this.ballDeflectionAttempts.has(ballId)) {
|
|
|
+ this.ballDeflectionAttempts.set(ballId, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1353,6 +1463,7 @@ export class BallController extends Component {
|
|
|
public cleanupBallAntiTrapState(ballId: string) {
|
|
|
this.ballHitHistory.delete(ballId);
|
|
|
this.ballPhaseThrough.delete(ballId);
|
|
|
+ this.ballDeflectionAttempts.delete(ballId);
|
|
|
console.log(`Cleaned up anti-trap state for ball ${ballId}`);
|
|
|
}
|
|
|
|