diff --git a/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn b/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn
index 3866ed8..b9cb23d 100644
--- a/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn
+++ b/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn
@@ -33,6 +33,9 @@
position = Vector2(0, -8)
enabled = false
+[node name="MeleeAttackArea" parent="MountPoint" index="0"]
+visible = true
+
[node name="ViewArea" type="Area2D" parent="MountPoint" index="1"]
collision_layer = 0
collision_mask = 16
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json
index 155c178..0008db3 100644
--- a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json
@@ -1 +1 @@
-[{"Name":"Preinstall1","Weight":100,"Remark":"","AutoFill":true,"WaveList":[[{"Position":{"X":-81,"Y":25},"Size":{"X":0,"Y":0},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":21,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"1","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":110,"Y":37},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"-1","Weapon":"weapon0002","CurrAmmon":"7","ResidueAmmo":"7"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":-54,"Y":20},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":5.551115E-14}]}]]}]
\ No newline at end of file
+[{"Name":"Preinstall1","Weight":100,"Remark":"","AutoFill":true,"WaveList":[[{"Position":{"X":-81,"Y":25},"Size":{"X":0,"Y":0},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":21,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"1","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":-54,"Y":20},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":105,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"0","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":0}]}]]}]
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs
index b439592..4111d82 100644
--- a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs
+++ b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs
@@ -285,14 +285,14 @@
if (errorCode == GenerateRoomErrorCode.OutArea)
{
_failCount++;
- Debug.Log("超出区域失败次数: " + _failCount);
+ //Debug.Log("超出区域失败次数: " + _failCount);
if (_failCount >= _maxFailCount)
{
//_enableLimitRange = false;
_failCount = 0;
_rangeX += 50;
_rangeY += 50;
- Debug.Log("生成房间失败次数过多, 增大区域");
+ //Debug.Log("生成房间失败次数过多, 增大区域");
}
}
diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs
index 53a5b93..0c2112e 100644
--- a/DungeonShooting_Godot/src/game/GameApplication.cs
+++ b/DungeonShooting_Godot/src/game/GameApplication.cs
@@ -134,7 +134,7 @@
//固定帧率
//Engine.MaxFps = TargetFps;
//调试绘制开关
- ActivityObject.IsDebug = true;
+ ActivityObject.IsDebug = false;
//Engine.TimeScale = 0.2f;
//调整窗口分辨率
OnWindowSizeChanged();
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
index 2935087..e782e18 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
@@ -9,9 +9,19 @@
public abstract partial class AiRole : Role
{
///
- /// 目标是否在视野内
+ /// 目标是否在视野内, 视野内不能有墙壁遮挡
///
- public bool TargetInView { get; set; } = true;
+ public bool TargetInView { get; private set; } = false;
+
+ ///
+ /// 目标间是否有墙壁遮挡
+ ///
+ public bool TargetHasOcclusion { get; private set; } = false;
+
+ ///
+ /// 目标是否在视野范围内, 不会考虑是否被枪遮挡
+ ///
+ public bool TargetInViewRange { get; private set; } = false;
///
/// 敌人身上的状态机控制器
@@ -79,26 +89,26 @@
{
if (_viewRange != value)
{
- _viewRange = value;
if (ViewAreaCollision != null)
{
- ViewAreaCollision.Polygon = Utils.CreateSectorPolygon(0, _viewRange, 120, 4);
+ ViewAreaCollision.Polygon = Utils.CreateSectorPolygon(0, value, 120, 4);
}
}
+ _viewRange = value;
}
}
private float _viewRange = -1;
///
+ /// 默认视野半径
+ ///
+ public float DefaultViewRange { get; set; } = 250;
+
+ ///
/// 发现玩家后跟随玩家的视野半径
///
public float TailAfterViewRange { get; set; } = 400;
-
- ///
- /// 背后的视野半径, 单位像素
- ///
- public float BackViewRange { get; set; } = 50;
///
/// 攻击间隔时间, 秒
@@ -118,7 +128,7 @@
///
/// 临时存储攻击目标, 获取该值请调用 GetAttackTarget() 函数
///
- private Role AttackTarget { get; set; } = null;
+ private Role _attackTarget = null;
private HashSet _viewTargets = new HashSet();
@@ -147,7 +157,40 @@
//NavigationAgent2D.VelocityComputed += OnVelocityComputed;
}
-
+
+ protected override void Process(float delta)
+ {
+ base.Process(delta);
+
+ if (LookTarget != null)
+ {
+ if (LookTarget.IsDestroyed)
+ {
+ LookTarget = null;
+ TargetInViewRange = false;
+ TargetHasOcclusion = false;
+ TargetInView = false;
+ }
+ else
+ {
+ //判断目标是否被墙壁遮挡
+ TargetHasOcclusion = TestViewRayCast(LookTarget.GetCenterPosition());
+ TestViewRayCastOver();
+
+ if (LookTarget is Role role)
+ {
+ TargetInViewRange = _viewTargets.Contains(role);
+ }
+ else
+ {
+ TargetInViewRange = true;
+ }
+
+ TargetInView = !TargetHasOcclusion && TargetInViewRange;
+ }
+ }
+ }
+
///
/// 获取攻击的目标对象, 当 HasAttackDesire 为 true 时才会调用
///
@@ -155,20 +198,20 @@
public Role GetAttackTarget(bool perspective = true)
{
//目标丢失
- if (AttackTarget == null || AttackTarget.IsDestroyed || !IsEnemy(AttackTarget))
+ if (_attackTarget == null || _attackTarget.IsDestroyed || !IsEnemy(_attackTarget))
{
- AttackTarget = RefreshAttackTargets(AttackTarget);
- return AttackTarget;
+ _attackTarget = RefreshAttackTargets(_attackTarget);
+ return _attackTarget;
}
if (!perspective)
{
//被墙阻挡
- if (TestViewRayCast(AttackTarget.GetCenterPosition()))
+ if (TestViewRayCast(_attackTarget.GetCenterPosition()))
{
- AttackTarget = RefreshAttackTargets(AttackTarget);
+ _attackTarget = RefreshAttackTargets(_attackTarget);
TestViewRayCastOver();
- return AttackTarget;
+ return _attackTarget;
}
else
{
@@ -176,7 +219,7 @@
}
}
- return AttackTarget;
+ return _attackTarget;
}
///
@@ -286,40 +329,6 @@
}
///
- /// 返回目标点是否在视野范围内
- ///
- public virtual bool IsInViewRange(Vector2 target)
- {
- var isForward = IsPositionInForward(target);
- if (isForward)
- {
- if (GlobalPosition.DistanceSquaredTo(target) <= ViewRange * ViewRange) //没有超出视野半径
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- /// 返回目标点是否在跟随状态下的视野半径内
- ///
- public virtual bool IsInTailAfterViewRange(Vector2 target)
- {
- var isForward = IsPositionInForward(target);
- if (isForward)
- {
- if (GlobalPosition.DistanceSquaredTo(target) <= TailAfterViewRange * TailAfterViewRange) //没有超出视野半径
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
/// 调用视野检测, 如果被墙壁和其它物体遮挡, 则返回true
///
public bool TestViewRayCast(Vector2 target)
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
index adc289d..6b171be 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
@@ -131,7 +131,7 @@
if (Master.LookTarget != null)
{
//检测目标没有超出跟随视野距离
- var isInTailAfterRange = Master.IsInTailAfterViewRange(Master.LookTarget.GetCenterPosition());
+ var isInTailAfterRange = Master.TargetInViewRange;
if (isInTailAfterRange)
{
_tailAfterTimer = 0;
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs
index 679ed22..6ea8880 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs
@@ -27,7 +27,6 @@
}
_navigationUpdateTimer = 0;
- Master.TargetInView = true;
}
public override void Process(float delta)
@@ -88,18 +87,6 @@
Master.DoIdle();
}
- //检测玩家是否在视野内
- if (Master.IsInTailAfterViewRange(playerPos))
- {
- Master.TargetInView = !Master.TestViewRayCast(playerPos);
- //关闭射线检测
- Master.TestViewRayCastOver();
- }
- else
- {
- Master.TargetInView = false;
- }
-
//在视野中
if (Master.TargetInView)
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs
index 4760836..559a034 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs
@@ -36,8 +36,7 @@
return;
//throw new Exception("进入 AIAdvancedStateEnum.AiSurround 状态时角色没有攻击目标!");
}
-
- Master.TargetInView = true;
+
_isMoveOver = true;
_pauseTimer = 0;
_moveFlag = false;
@@ -63,19 +62,6 @@
}
}
- var playerPos = Master.LookTarget.GetCenterPosition();
-
- //检测玩家是否在视野内
- if (Master.IsInTailAfterViewRange(playerPos))
- {
- Master.TargetInView = !Master.TestViewRayCast(playerPos);
- //关闭射线检测
- Master.TestViewRayCastOver();
- }
- else
- {
- Master.TargetInView = false;
- }
//在视野中
if (Master.TargetInView)
@@ -90,7 +76,7 @@
}
else if (_isMoveOver) //移动已经完成
{
- RunOver(playerPos);
+ RunOver(Master.LookTarget.GetCenterPosition());
_isMoveOver = false;
}
else
@@ -98,7 +84,7 @@
var masterPosition = Master.Position;
if (_lockTimer >= 1) //卡在一个点超过一秒
{
- RunOver(playerPos);
+ RunOver(Master.LookTarget.GetCenterPosition());
_isMoveOver = false;
_lockTimer = 0;
}
@@ -147,7 +133,7 @@
var weapon = Master.WeaponPack.ActiveItem;
if (weapon != null)
{
- if (masterPosition.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围
+ if (masterPosition.DistanceSquaredTo(Master.LookTarget.GetCenterPosition()) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围
{
ChangeState(AIStateEnum.AiFollowUp);
}
@@ -159,7 +145,7 @@
}
else
{
- if (masterPosition.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.ViewRange * 0.7f, 2)) //玩家离开正常射击范围
+ if (masterPosition.DistanceSquaredTo(Master.LookTarget.GetCenterPosition()) > Mathf.Pow(Master.ViewRange * 0.7f, 2)) //玩家离开正常射击范围
{
ChangeState(AIStateEnum.AiFollowUp);
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs
index 00706f3..0f349ef 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs
@@ -83,26 +83,16 @@
//站立
Master.DoIdle();
}
- //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
- if (Master.IsInTailAfterViewRange(playerPos))
+ //检测玩家是否在视野内
+ if (!Master.TargetHasOcclusion) //直接看到玩家
{
- if (!Master.TestViewRayCast(playerPos)) //看到玩家
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- //切换成发现目标状态
- ChangeState(AIStateEnum.AiFollowUp);
- return;
- }
- else
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- }
+ //切换成发现目标状态
+ ChangeState(AIStateEnum.AiFollowUp);
+ return;
}
//检测玩家是否在穿墙视野范围内, 直接检测距离即可
- _isInViewRange = Master.IsInViewRange(playerPos);
+ _isInViewRange = Master.TargetInViewRange;
if (_isInViewRange)
{
_viewTimer = 0;
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
index 1f8dd9f..f057560 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
@@ -84,8 +84,8 @@
roleState.Acceleration = enemyBase.Acceleration;
roleState.Friction = enemyBase.Friction;
ViewRange = enemyBase.ViewRange;
+ DefaultViewRange = enemyBase.ViewRange;
TailAfterViewRange = enemyBase.TailAfterViewRange;
- BackViewRange = enemyBase.BackViewRange;
AttackInterval = enemyBase.AttackInterval;
roleState.Gold = Mathf.Max(0, Utils.Random.RandomConfigRange(enemyBase.Gold));
@@ -128,27 +128,21 @@
//看向目标
if (LookTarget != null && MountLookTarget)
{
- if (LookTarget.IsDestroyed)
+ var pos = LookTarget.Position;
+ LookPosition = pos;
+ //脸的朝向
+ var gPos = Position;
+ if (pos.X > gPos.X && Face == FaceDirection.Left)
{
- LookTarget = null;
+ Face = FaceDirection.Right;
}
- else
+ else if (pos.X < gPos.X && Face == FaceDirection.Right)
{
- var pos = LookTarget.Position;
- LookPosition = pos;
- //脸的朝向
- var gPos = Position;
- if (pos.X > gPos.X && Face == FaceDirection.Left)
- {
- Face = FaceDirection.Right;
- }
- else if (pos.X < gPos.X && Face == FaceDirection.Right)
- {
- Face = FaceDirection.Left;
- }
- //枪口跟随目标
- MountPoint.SetLookAt(pos);
+ Face = FaceDirection.Left;
}
+
+ //枪口跟随目标
+ MountPoint.SetLookAt(pos);
}
if (RoleState.CanPickUpWeapon)