Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
MingSnake_241120
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
SparkProjects
MingSnake_241120
Commits
e4c4bde0
Commit
e4c4bde0
authored
Nov 20, 2024
by
haiyoucuv
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
init
parent
aa7315ad
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
264 additions
and
140 deletions
+264
-140
AISnake.ts
assets/Scripts/Scenes/MainGame/AISnake.ts
+264
-140
No files found.
assets/Scripts/Scenes/MainGame/AISnake.ts
View file @
e4c4bde0
...
...
@@ -29,26 +29,26 @@ export class AISnake extends Snake {
private
escapeTarget
:
Snake
=
null
;
private
readonly
BASE_VIEW_DISTANCE
=
300
;
private
readonly
INTERCEPT_DISTANCE
=
400
;
private
readonly
PREDICTION_TIME
=
1.0
;
private
readonly
ESCAPE_BOUNDARY
=
200
;
private
readonly
INTERCEPT_DISTANCE
=
350
;
// 降低拦截距离
private
readonly
PREDICTION_TIME
=
1.2
;
// 增加预测时间
private
readonly
ESCAPE_BOUNDARY
=
250
;
// 增加边界安全距离
private
readonly
SAFE_MARGIN
=
3.0
;
// 增加安全边际
private
readonly
COLLISION_CHECK_DISTANCE
=
500
;
// 增加碰撞检测距离
private
readonly
ASSIST_DISTANCE
=
500
;
// 协助攻击的最大距离
private
readonly
SAFE_MARGIN
=
2
;
// 安全边际系数
private
readonly
COLLISION_CHECK_DISTANCE
=
400
;
// 增加碰撞检测距离
private
readonly
BODY_AVOID_MARGIN
=
2.5
;
// 增加身体避让边际
private
readonly
DANGER_ANGLE_THRESHOLD
=
75
;
// 扩大危险角度范围
private
readonly
DANGER_ANGLE_THRESHOLD
=
90
;
// 扩大危险角度范围
private
readonly
COUNTER_ATTACK_THRESHOLD
=
0.8
;
// 反击判定阈值
private
readonly
SAFE_DISTANCE_MULTIPLIER
=
1.5
;
// 安全距离倍数
private
assistTarget
:
AISnake
=
null
;
// 正在协助的AI蛇
private
get
difficultyParams
()
{
return
{
reactionTime
:
math
.
lerp
(
0.8
,
0.2
,
(
this
.
difficulty
-
1
)
/
4
),
viewDistance
:
this
.
BASE_VIEW_DISTANCE
*
(
1
+
(
this
.
difficulty
-
1
)
*
0.2
),
interceptDistance
:
this
.
INTERCEPT_DISTANCE
*
(
1
+
(
this
.
difficulty
-
1
)
*
0.2
),
aggressiveness
:
math
.
lerp
(
0.
3
,
0.9
,
(
this
.
difficulty
-
1
)
/
4
),
predictionAccuracy
:
math
.
lerp
(
0.
5
,
0.9
,
(
this
.
difficulty
-
1
)
/
4
),
turnSpeed
:
math
.
lerp
(
2
,
5
,
(
this
.
difficulty
-
1
)
/
4
)
aggressiveness
:
math
.
lerp
(
0.
2
,
0.7
,
(
this
.
difficulty
-
1
)
/
4
),
// 降低激进程度
predictionAccuracy
:
math
.
lerp
(
0.
6
,
0.9
,
(
this
.
difficulty
-
1
)
/
4
),
turnSpeed
:
math
.
lerp
(
2
,
4.5
,
(
this
.
difficulty
-
1
)
/
4
)
// 略微降低最大转向速度
};
}
...
...
@@ -231,6 +231,7 @@ export class AISnake extends Snake {
}
private
executeCurrentState
(
dt
:
number
)
{
const
threat
=
this
.
findNearbyAIToAvoid
();
if
(
threat
&&
threat
.
dangerLevel
>
30
)
{
// 降低触发避让的阈值
...
...
@@ -295,49 +296,6 @@ export class AISnake extends Snake {
return
this
.
head
.
angle
;
}
// 计算最佳躲避角度
private
calculateAvoidanceAngle
(
threat
:
Snake
):
number
{
const
myPos
=
this
.
head
.
getPosition
();
const
threatPos
=
threat
.
head
.
getPosition
();
const
baseEscapeAngle
=
this
.
calculateEscapeAngle
(
threatPos
);
// 尝试多个躲避角度
const
angles
=
[
baseEscapeAngle
,
baseEscapeAngle
+
45
,
baseEscapeAngle
-
45
,
baseEscapeAngle
+
90
,
baseEscapeAngle
-
90
];
// 选择最安全的角度
let
bestAngle
=
baseEscapeAngle
;
let
maxSafety
=
-
1
;
for
(
const
angle
of
angles
)
{
const
futurePos
=
this
.
predictFuturePosition
(
myPos
,
angle
,
this
.
speed
*
3
);
let
safety
=
Vec3
.
distance
(
futurePos
,
threatPos
);
// 检查这个角度是否会导致撞墙
if
(
this
.
willHitBoundary
(
angle
))
{
continue
;
}
// 检查与威胁物的身体的距离
for
(
const
bodyPart
of
threat
.
bodyArr
)
{
const
bodyDist
=
Vec3
.
distance
(
futurePos
,
bodyPart
.
getPosition
());
safety
=
Math
.
min
(
safety
,
bodyDist
);
}
if
(
safety
>
maxSafety
)
{
maxSafety
=
safety
;
bestAngle
=
angle
;
}
}
return
bestAngle
;
}
private
canInterceptPlayer
(
player
:
Snake
):
boolean
{
if
(
!
player
||
!
player
.
isLife
)
return
false
;
...
...
@@ -346,10 +304,10 @@ export class AISnake extends Snake {
const
playerPos
=
player
.
head
.
getPosition
();
const
distance
=
Vec3
.
distance
(
myPos
,
playerPos
);
// 降低拦截距离和提高长度要求
return
distance
<
params
.
interceptDistance
*
0.8
&&
// 减小拦截距离
this
.
getSnakeLen
()
>
player
.
getSnakeLen
()
*
0.8
&&
// 提高长度要求
math
.
random
()
<
params
.
aggressiveness
*
0.8
;
// 降低激进程度
return
distance
<
params
.
interceptDistance
*
0.7
&&
// 进一步减小拦截距离
this
.
getSnakeLen
()
>
player
.
getSnakeLen
()
*
1.2
&&
// 提高长度要求
math
.
random
()
<
params
.
aggressiveness
*
0.6
&&
// 降低激进程度
!
this
.
isNearBoundary
(
playerPos
);
// 不在边界附近才拦截
}
private
executeHunting
()
{
...
...
@@ -357,24 +315,82 @@ export class AISnake extends Snake {
const
myPos
=
this
.
head
.
getPosition
();
const
distance
=
Vec3
.
distance
(
myPos
,
this
.
targetFood
);
// 计算到食物的直接角度
const
targetAngle
=
this
.
calculateTargetAngle
(
this
.
targetFood
);
const
angleDiff
=
Math
.
abs
(
this
.
head
.
angle
-
targetAngle
);
// 检查是否需要避开自己的身体
const
needAvoidBody
=
this
.
willHitOwnBody
(
targetAngle
);
if
(
needAvoidBody
)
{
// 寻找替代路径
const
alternativeAngle
=
this
.
findAlternativeAngleToFood
(
this
.
targetFood
);
this
.
smoothRotateToAngle
(
alternativeAngle
,
this
.
difficultyParams
.
turnSpeed
);
// 寻找更优的替代路径
const
alternativeAngle
=
this
.
findBetterAngleToFood
(
this
.
targetFood
);
if
(
alternativeAngle
!==
null
)
{
this
.
smoothRotateToAngle
(
alternativeAngle
,
this
.
difficultyParams
.
turnSpeed
*
1.8
);
}
else
{
// 如果没有找到好的替代路径,执行更激进的转向
this
.
executeAggressiveTurn
(
targetAngle
);
}
this
.
isFast
=
false
;
}
else
{
// 直接前进
// 根据角度差决定转向策略
if
(
angleDiff
>
90
)
{
// 大角度差时执行快速转向
this
.
executeAggressiveTurn
(
targetAngle
);
this
.
isFast
=
false
;
}
else
{
// 小角度差时正常追逐
this
.
smoothRotateToAngle
(
targetAngle
,
this
.
difficultyParams
.
turnSpeed
*
1.5
);
this
.
isFast
=
distance
<
this
.
BASE_VIEW_DISTANCE
/
2
;
}
}
}
// 根据距离和路径调整速度
this
.
isFast
=
distance
<
this
.
BASE_VIEW_DISTANCE
/
2
&&
!
needAvoidBody
;
// 更激进的转向方法
private
executeAggressiveTurn
(
targetAngle
:
number
)
{
const
currentAngle
=
this
.
head
.
angle
;
let
angleDiff
=
targetAngle
-
currentAngle
;
// 标准化角度差到 -180 到 180 度范围
while
(
angleDiff
>
180
)
angleDiff
-=
360
;
while
(
angleDiff
<
-
180
)
angleDiff
+=
360
;
// 使用更大的转向速度
const
turnSpeed
=
this
.
difficultyParams
.
turnSpeed
*
2.5
;
this
.
head
.
angle
+=
math
.
clamp
(
angleDiff
,
-
turnSpeed
,
turnSpeed
);
}
// 寻找更好的替代角度
private
findBetterAngleToFood
(
foodPos
:
Vec3
):
number
|
null
{
const
myPos
=
this
.
head
.
getPosition
();
const
directAngle
=
this
.
calculateTargetAngle
(
foodPos
);
const
currentDistance
=
Vec3
.
distance
(
myPos
,
foodPos
);
// 根据当前角度差决定搜索范围
const
angleDiff
=
Math
.
abs
(
this
.
head
.
angle
-
directAngle
);
const
searchRange
=
angleDiff
>
90
?
[
-
120
,
-
90
,
-
60
,
-
45
,
-
30
,
30
,
45
,
60
,
90
,
120
]
:
[
-
60
,
-
45
,
-
30
,
-
15
,
15
,
30
,
45
,
60
];
let
bestAngle
=
null
;
let
bestImprovement
=
0
;
for
(
const
offset
of
searchRange
)
{
const
testAngle
=
directAngle
+
offset
;
if
(
this
.
willHitOwnBody
(
testAngle
))
continue
;
const
futurePos
=
this
.
predictFuturePosition
(
myPos
,
testAngle
,
this
.
radius
*
5
);
const
newDistance
=
Vec3
.
distance
(
futurePos
,
foodPos
);
// 计算路径改善程度
const
improvement
=
currentDistance
-
newDistance
;
// 选择最佳改善路径
if
(
improvement
>
bestImprovement
)
{
bestImprovement
=
improvement
;
bestAngle
=
testAngle
;
}
}
return
bestAngle
;
}
// 检查是否会撞到自己的身体
...
...
@@ -394,32 +410,6 @@ export class AISnake extends Snake {
return
false
;
}
// 寻找到食物的替代角度
private
findAlternativeAngleToFood
(
foodPos
:
Vec3
):
number
{
const
myPos
=
this
.
head
.
getPosition
();
const
directAngle
=
this
.
calculateTargetAngle
(
foodPos
);
// 尝试不同的角度偏移
const
offsets
=
[
30
,
-
30
,
45
,
-
45
,
60
,
-
60
];
for
(
const
offset
of
offsets
)
{
const
testAngle
=
directAngle
+
offset
;
if
(
!
this
.
willHitOwnBody
(
testAngle
))
{
// 检查这个角度是否会让我们更接近食物
const
futurePos
=
this
.
predictFuturePosition
(
myPos
,
testAngle
,
this
.
radius
*
4
);
const
currentDistance
=
Vec3
.
distance
(
myPos
,
foodPos
);
const
futureDistance
=
Vec3
.
distance
(
futurePos
,
foodPos
);
if
(
futureDistance
<
currentDistance
)
{
return
testAngle
;
}
}
}
// 如果没找到更好的角度,返回直接角度
return
directAngle
;
}
private
executeIntercepting
()
{
if
(
!
this
.
targetSnake
||
!
this
.
targetSnake
.
isLife
)
return
;
...
...
@@ -433,12 +423,11 @@ export class AISnake extends Snake {
// 增加躲避权重
const
aiDistance
=
Vec3
.
distance
(
myPos
,
nearbyAI
.
snake
.
head
.
getPosition
());
const
avoidWeight
=
math
.
clamp
(
1
-
aiDistance
/
(
this
.
BASE_VIEW_DISTANCE
*
0.
5
),
0.3
,
0.9
);
// 提高最小
权重
const
avoidWeight
=
math
.
clamp
(
1
-
aiDistance
/
(
this
.
BASE_VIEW_DISTANCE
*
0.
6
),
0.4
,
0.95
);
// 增加避让
权重
const
finalAngle
=
this
.
blendAngles
(
targetAngle
,
avoidAngle
,
avoidWeight
);
// 使用更快的转向速度进行躲避
this
.
smoothRotateToAngle
(
finalAngle
,
this
.
difficultyParams
.
turnSpeed
*
1.8
);
this
.
isFast
=
false
;
// 躲避时降低速度
this
.
smoothRotateToAngle
(
finalAngle
,
this
.
difficultyParams
.
turnSpeed
*
1.5
);
this
.
isFast
=
false
;
// 避让时始终降速
}
else
{
const
predictedPos
=
this
.
predictTargetPosition
(
this
.
targetSnake
);
const
targetAngle
=
this
.
calculateTargetAngle
(
predictedPos
);
...
...
@@ -471,12 +460,15 @@ export class AISnake extends Snake {
}
// 寻找需要躲避的附近AI
private
findNearbyAIToAvoid
():
{
snake
:
Snake
,
dangerLevel
:
number
}
|
null
{
private
findNearbyAIToAvoid
():
{
snake
:
Snake
,
dangerLevel
:
number
,
canCounter
:
boolean
}
|
null
{
const
myPos
=
this
.
head
.
getPosition
();
const
myFuturePos
=
this
.
predictFuturePosition
(
myPos
,
this
.
head
.
angle
,
this
.
speed
*
2
);
let
maxDanger
=
0
;
let
mostDangerousSnake
=
null
;
const
myLength
=
this
.
getSnakeLen
();
let
canCounterAttack
=
false
;
const
allSnakes
=
[...
MainGame
.
ins
.
animalNode
.
children
,
MainGame
.
ins
.
player
.
node
]
.
map
(
node
=>
node
.
getComponent
(
Snake
))
.
filter
(
snake
=>
snake
&&
snake
!==
this
&&
snake
.
isLife
);
...
...
@@ -484,15 +476,25 @@ export class AISnake extends Snake {
for
(
const
snake
of
allSnakes
)
{
let
snakeDanger
=
0
;
const
headDistance
=
Vec3
.
distance
(
myPos
,
snake
.
head
.
getPosition
());
const
isPlayer
=
snake
===
MainGame
.
ins
.
player
;
// 对玩家增加额外的危险系数
const
playerDangerMultiplier
=
isPlayer
?
1.5
:
1.0
;
// 检查头部威胁
if
(
headDistance
<
this
.
COLLISION_CHECK_DISTANCE
)
{
const
angleToHead
=
this
.
calculateTargetAngle
(
snake
.
head
.
getPosition
());
const
headAngleDiff
=
Math
.
abs
(
this
.
head
.
angle
-
angleToHead
);
if
(
headAngleDiff
<
this
.
DANGER_ANGLE_THRESHOLD
)
{
snakeDanger
=
Math
.
max
(
snakeDanger
,
(
this
.
COLLISION_CHECK_DISTANCE
-
headDistance
)
/
this
.
COLLISION_CHECK_DISTANCE
*
100
);
// 对玩家扩大危险角度阈值
const
effectiveAngleThreshold
=
isPlayer
?
this
.
DANGER_ANGLE_THRESHOLD
*
1.2
:
this
.
DANGER_ANGLE_THRESHOLD
;
if
(
headAngleDiff
<
effectiveAngleThreshold
)
{
const
baseDanger
=
(
this
.
COLLISION_CHECK_DISTANCE
-
headDistance
)
/
this
.
COLLISION_CHECK_DISTANCE
*
100
;
snakeDanger
=
Math
.
max
(
snakeDanger
,
baseDanger
*
playerDangerMultiplier
);
}
}
...
...
@@ -502,21 +504,29 @@ export class AISnake extends Snake {
const
bodyDistance
=
Vec3
.
distance
(
myPos
,
bodyPart
.
getPosition
());
const
futureDist
=
Vec3
.
distance
(
myFuturePos
,
bodyPart
.
getPosition
());
// 计算与身体部分的相对运动
const
bodyAngle
=
this
.
calculateTargetAngle
(
bodyPart
.
getPosition
());
const
angleDiff
=
Math
.
abs
(
this
.
head
.
angle
-
bodyAngle
);
// 根据距离和角度计算危险程度
if
(
bodyDistance
<
this
.
COLLISION_CHECK_DISTANCE
&&
angleDiff
<
this
.
DANGER_ANGLE_THRESHOLD
)
{
const
distanceDanger
=
(
this
.
COLLISION_CHECK_DISTANCE
-
bodyDistance
)
/
this
.
COLLISION_CHECK_DISTANCE
;
// 对玩家的身体也使用更大的检测范围
const
effectiveCheckDistance
=
isPlayer
?
this
.
COLLISION_CHECK_DISTANCE
*
1.2
:
this
.
COLLISION_CHECK_DISTANCE
;
if
(
bodyDistance
<
effectiveCheckDistance
&&
angleDiff
<
this
.
DANGER_ANGLE_THRESHOLD
)
{
const
distanceDanger
=
(
effectiveCheckDistance
-
bodyDistance
)
/
effectiveCheckDistance
;
const
angleDanger
=
(
this
.
DANGER_ANGLE_THRESHOLD
-
angleDiff
)
/
this
.
DANGER_ANGLE_THRESHOLD
;
const
futureDanger
=
futureDist
<
bodyDistance
?
1.5
:
1
;
// 如果预测位置更近,增加
危险系数
const
futureDanger
=
futureDist
<
bodyDistance
?
2.5
:
1
;
// 增加未来碰撞的
危险系数
const
partDanger
=
(
distanceDanger
*
angleDanger
*
futureDanger
)
*
1
00
;
const
partDanger
=
(
distanceDanger
*
angleDanger
*
futureDanger
)
*
1
20
*
playerDangerMultiplier
;
snakeDanger
=
Math
.
max
(
snakeDanger
,
partDanger
);
}
}
// 如果是玩家且正在加速,进一步提高危险等级
if
(
isPlayer
&&
snake
.
isFast
)
{
snakeDanger
*=
1.3
;
}
// 更新最危险的蛇
if
(
snakeDanger
>
maxDanger
)
{
maxDanger
=
snakeDanger
;
...
...
@@ -524,7 +534,22 @@ export class AISnake extends Snake {
}
}
return
maxDanger
>
0
?
{
snake
:
mostDangerousSnake
,
dangerLevel
:
maxDanger
}
:
null
;
// 评估是否可以反击
if
(
mostDangerousSnake
)
{
const
threatLength
=
mostDangerousSnake
.
getSnakeLen
();
const
lengthAdvantage
=
myLength
/
threatLength
;
const
distance
=
Vec3
.
distance
(
myPos
,
mostDangerousSnake
.
head
.
getPosition
());
const
isSafeDistance
=
distance
>
this
.
COLLISION_CHECK_DISTANCE
*
this
.
SAFE_DISTANCE_MULTIPLIER
;
canCounterAttack
=
lengthAdvantage
>
this
.
COUNTER_ATTACK_THRESHOLD
&&
isSafeDistance
;
}
// 降低触发避让的阈值,使AI更容易进入避让状态
return
maxDanger
>
15
?
{
snake
:
mostDangerousSnake
,
dangerLevel
:
maxDanger
,
canCounter
:
canCounterAttack
}
:
null
;
}
private
predictFuturePosition
(
currentPos
:
Vec3
,
angle
:
number
,
speed
:
number
):
Vec3
{
...
...
@@ -535,63 +560,163 @@ export class AISnake extends Snake {
}
private
executeEscaping
()
{
if
(
!
this
.
escapeTarget
)
{
// 如果没有特定的逃离目标,检查并避开所有潜在威胁
this
.
avoidAllThreats
();
return
;
}
const
myPos
=
this
.
head
.
getPosition
();
const
threatPos
=
this
.
escapeTarget
.
head
.
getPosition
();
const
distance
=
Vec3
.
distance
(
myPos
,
threatPos
);
if
(
this
.
escapeTarget
)
{
let
escapeAngle
=
this
.
calculateEscapeAngle
(
this
.
escapeTarget
.
head
.
getPosition
());
// 紧急避让判定
const
isEmergency
=
distance
<
this
.
radius
*
3
;
const
escapeAngle
=
this
.
calculateAvoidanceAngle
(
this
.
escapeTarget
);
// 考虑身体部分的位置来调整逃跑角度
for
(
const
bodyPart
of
this
.
escapeTarget
.
bodyArr
)
{
const
bodyDistance
=
Vec3
.
distance
(
myPos
,
bodyPart
.
getPosition
());
if
(
bodyDistance
<
this
.
BASE_VIEW_DISTANCE
*
0.7
)
{
const
bodyEscapeAngle
=
this
.
calculateEscapeAngle
(
bodyPart
.
getPosition
());
// 综合考虑头部和身体的逃跑角度
escapeAngle
=
(
escapeAngle
+
bodyEscapeAngle
)
/
2
;
if
(
isEmergency
)
{
// 紧急情况:直接设置角度
this
.
head
.
angle
=
escapeAngle
;
this
.
isFast
=
false
;
}
else
{
// 非紧急情况:快速但平滑地转向
const
angleDiff
=
escapeAngle
-
this
.
head
.
angle
;
// 标准化角度差到 -180 到 180 度范围
const
normalizedDiff
=
(
angleDiff
+
180
)
%
360
-
180
;
this
.
head
.
angle
+=
math
.
clamp
(
normalizedDiff
,
-
15
,
15
);
this
.
isFast
=
distance
>
this
.
radius
*
5
;
}
}
// 检查逃跑方向是否会导致撞墙
if
(
this
.
willHitBoundary
(
escapeAngle
))
{
escapeAngle
=
this
.
adjustEscapeAngle
(
escapeAngle
);
// 避开所有潜在威胁
private
avoidAllThreats
()
{
const
myPos
=
this
.
head
.
getPosition
();
const
allSnakes
=
[...
MainGame
.
ins
.
animalNode
.
children
,
MainGame
.
ins
.
player
.
node
]
.
map
(
node
=>
node
.
getComponent
(
Snake
))
.
filter
(
snake
=>
snake
&&
snake
!==
this
&&
snake
.
isLife
);
let
nearestThreatDistance
=
Infinity
;
let
bestEscapeAngle
=
this
.
head
.
angle
;
let
hasThreats
=
false
;
// 检查所有潜在威胁
for
(
const
snake
of
allSnakes
)
{
const
distance
=
Vec3
.
distance
(
myPos
,
snake
.
head
.
getPosition
());
if
(
distance
<
this
.
COLLISION_CHECK_DISTANCE
)
{
hasThreats
=
true
;
if
(
distance
<
nearestThreatDistance
)
{
nearestThreatDistance
=
distance
;
bestEscapeAngle
=
this
.
calculateAvoidanceAngle
(
snake
);
}
}
}
this
.
smoothRotateToAngle
(
escapeAngle
,
this
.
difficultyParams
.
turnSpeed
*
1.8
);
if
(
hasThreats
)
{
// 有威胁时执行避让
const
isEmergency
=
nearestThreatDistance
<
this
.
radius
*
3
;
if
(
isEmergency
)
{
this
.
head
.
angle
=
bestEscapeAngle
;
this
.
isFast
=
false
;
}
else
{
const
angleDiff
=
bestEscapeAngle
-
this
.
head
.
angle
;
const
normalizedDiff
=
(
angleDiff
+
180
)
%
360
-
180
;
this
.
head
.
angle
+=
math
.
clamp
(
normalizedDiff
,
-
15
,
15
);
this
.
isFast
=
nearestThreatDistance
>
this
.
radius
*
5
;
}
}
else
{
// 没有威胁时检查边界
this
.
avoidBoundary
();
}
this
.
isFast
=
true
;
}
private
willHitBoundary
(
angle
:
number
):
boolean
{
// 计算避让角度的方法,增加紧急情况下的处理
private
calculateAvoidanceAngle
(
threat
:
Snake
):
number
{
const
myPos
=
this
.
head
.
getPosition
();
const
radian
=
angle
*
Math
.
PI
/
180
;
const
checkDistance
=
this
.
ESCAPE_BOUNDARY
;
const
threatPos
=
threat
.
head
.
getPosition
()
;
const
baseEscapeAngle
=
this
.
calculateEscapeAngle
(
threatPos
)
;
const
futureX
=
myPos
.
x
+
Math
.
cos
(
radian
)
*
checkDistance
;
const
futureY
=
myPos
.
y
+
Math
.
sin
(
radian
)
*
checkDistance
;
// 检查基础逃生角度是否安全
if
(
!
this
.
willHitBoundary
(
baseEscapeAngle
))
{
return
baseEscapeAngle
;
}
return
this
.
isInDangerousPosition
(
v3
(
futureX
,
futureY
,
0
));
// 如果基础角度不安全,寻找最佳替代角度
const
angles
=
[
baseEscapeAngle
,
baseEscapeAngle
+
45
,
baseEscapeAngle
-
45
,
baseEscapeAngle
+
90
,
baseEscapeAngle
-
90
,
baseEscapeAngle
+
135
,
baseEscapeAngle
-
135
,
baseEscapeAngle
+
180
];
let
bestAngle
=
baseEscapeAngle
;
let
maxSafety
=
-
Infinity
;
for
(
const
angle
of
angles
)
{
if
(
this
.
willHitBoundary
(
angle
))
continue
;
const
safety
=
this
.
evaluateEscapeAngleSafety
(
angle
,
threat
);
if
(
safety
>
maxSafety
)
{
maxSafety
=
safety
;
bestAngle
=
angle
;
}
}
return
bestAngle
;
}
private
adjustEscapeAngle
(
originalAngle
:
number
):
number
{
const
adjustAngles
=
[
-
45
,
45
,
-
90
,
90
,
-
135
,
135
,
180
];
// 评估逃生角度的安全性
private
evaluateEscapeAngleSafety
(
angle
:
number
,
threat
:
Snake
):
number
{
const
myPos
=
this
.
head
.
getPosition
();
const
futurePos
=
this
.
predictFuturePosition
(
myPos
,
angle
,
this
.
radius
*
4
);
let
safety
=
100
;
for
(
const
adjustment
of
adjustAngles
)
{
const
newAngle
=
(
originalAngle
+
adjustment
)
%
360
;
if
(
!
this
.
willHitBoundary
(
newAngle
))
{
return
newAngle
;
// 检查与威胁的距离
const
threatDistance
=
Vec3
.
distance
(
futurePos
,
threat
.
head
.
getPosition
());
safety
+=
threatDistance
;
// 检查边界距离
const
boundaryDist
=
this
.
getDistanceToBoundary
(
futurePos
);
safety
+=
boundaryDist
*
2
;
// 检查与其他蛇的距离
const
allSnakes
=
[...
MainGame
.
ins
.
animalNode
.
children
,
MainGame
.
ins
.
player
.
node
]
.
map
(
node
=>
node
.
getComponent
(
Snake
))
.
filter
(
snake
=>
snake
&&
snake
!==
this
&&
snake
!==
threat
&&
snake
.
isLife
);
for
(
const
snake
of
allSnakes
)
{
const
distance
=
Vec3
.
distance
(
futurePos
,
snake
.
head
.
getPosition
());
if
(
distance
<
this
.
COLLISION_CHECK_DISTANCE
)
{
safety
-=
(
this
.
COLLISION_CHECK_DISTANCE
-
distance
);
}
}
return
originalAngle
;
// 如果没有找到更好的角度,返回原角度
return
safety
;
}
private
willHitBoundary
(
angle
:
number
):
boolean
{
const
myPos
=
this
.
head
.
getPosition
();
const
futurePos
=
this
.
predictFuturePosition
(
myPos
,
angle
,
this
.
radius
*
4
);
const
boundaryDist
=
this
.
getDistanceToBoundary
(
futurePos
);
return
boundaryDist
<
this
.
ESCAPE_BOUNDARY
;
}
// 获取到边界的距离
private
getDistanceToBoundary
(
position
:
Vec3
):
number
{
const
mapWidth
=
Global
.
MAP_WIDTH
;
const
mapHeight
=
Global
.
MAP_HEIGHT
;
return
Math
.
min
(
mapWidth
/
2
-
Math
.
abs
(
position
.
x
),
mapHeight
/
2
-
Math
.
abs
(
position
.
y
)
);
}
private
executeWandering
()
{
// 增加方向改变的概率
if
(
math
.
randomRangeInt
(
0
,
20
)
==
0
)
{
// 减少方向改变的频率
if
(
math
.
randomRangeInt
(
0
,
30
)
==
0
)
{
const
direction
=
math
.
randomRangeInt
(
0
,
3
);
const
speed
=
math
.
randomRangeInt
(
1
,
4
);
const
speed
=
math
.
randomRangeInt
(
1
,
3
);
if
(
direction
===
DirectionType
.
LEFT
)
{
this
.
head
.
angle
+=
speed
;
...
...
@@ -601,7 +726,7 @@ export class AISnake extends Snake {
}
// 减少速度变化的频率
this
.
isFast
=
math
.
random
()
<
this
.
difficultyParams
.
aggressiveness
*
0.
1
;
this
.
isFast
=
math
.
random
()
<
this
.
difficultyParams
.
aggressiveness
*
0.
05
;
}
private
avoidBoundary
()
{
...
...
@@ -762,7 +887,6 @@ export class AISnake extends Snake {
return
score
;
}
// 判断是否能在竞争者之前到达食物
private
canReachFoodFirst
(
foodPos
:
Vec3
,
myDistance
:
number
,
competitors
:
Snake
[]):
boolean
{
const
mySpeed
=
this
.
speed
*
(
this
.
isFast
?
2
:
1
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment