diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
index b4bfe60..eef5518 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
@@ -1735,6 +1735,6 @@
///
public Vector2 GetCenterPosition()
{
- return AnimatedSprite.Position + Position;
+ return AnimatedSprite.GlobalPosition + AnimatedSprite.Offset;
}
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs b/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs
index c1350c1..ceaad7e 100644
--- a/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/AdvancedRole.cs
@@ -326,7 +326,7 @@
//WeaponPack.ActiveItem.TriggerMeleeAttack(this);
//播放近战动画
- PlayAnimation_MeleeAttack(() =>
+ this.PlayAnimation_MeleeAttack(() =>
{
MountLookTarget = true;
IsMeleeAttack = false;
@@ -399,6 +399,21 @@
return -MountPoint.Position.Y;
}
+ public override float GetAttackRotation()
+ {
+ return MountPoint.RealRotation;
+ }
+
+ public override Vector2 GetMountPosition()
+ {
+ return MountPoint.GlobalPosition;
+ }
+
+ public override Node2D GetMountNode()
+ {
+ return MountPoint;
+ }
+
protected override void OnDestroy()
{
base.OnDestroy();
diff --git a/DungeonShooting_Godot/src/game/activity/role/AdvancedRole_Animation.cs b/DungeonShooting_Godot/src/game/activity/role/AdvancedRole_Animation.cs
deleted file mode 100644
index e829a1f..0000000
--- a/DungeonShooting_Godot/src/game/activity/role/AdvancedRole_Animation.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-
-using System;
-using Godot;
-using Vector2 = Godot.Vector2;
-
-public partial class AdvancedRole
-{
- ///
- /// 播放近战攻击动画
- ///
- public virtual void PlayAnimation_MeleeAttack(Action finish)
- {
- var r = MountPoint.RotationDegrees;
- //var gp = MountPoint.GlobalPosition;
- var p1 = MountPoint.Position;
- var p2 = p1 + new Vector2(6, 0).Rotated(Mathf.DegToRad(r - MeleeAttackAngle / 2f));
- var p3 = p1 + new Vector2(6, 0).Rotated(Mathf.DegToRad(r + MeleeAttackAngle / 2f));
-
- var tween = CreateTween();
- tween.SetParallel();
-
- tween.TweenProperty(MountPoint, "rotation_degrees", r - MeleeAttackAngle / 2f, 0.1);
- tween.TweenProperty(MountPoint, "position", p2, 0.1);
- tween.TweenProperty(MountPoint, "position", p2, 0.1);
- tween.Chain();
-
- tween.TweenCallback(Callable.From(() =>
- {
- MountPoint.RotationDegrees = r + MeleeAttackAngle / 2f;
- MountPoint.Position = p3;
- //重新计算武器阴影位置
- var activeItem = WeaponPack.ActiveItem;
- activeItem.CalcShadowTransform();
- //创建屏幕抖动
- if (Face == FaceDirection.Right)
- {
- //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 90)) * 5);
- GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 180)) * 6);
- }
- else
- {
- //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(270 - r)) * 5);
- GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(-r)) * 6);
- }
- //播放特效
- var effect = ObjectManager.GetPoolItem(ResourcePath.prefab_effect_weapon_MeleeAttack1_tscn);
- var sprite = (Node2D)effect;
- var localFirePosition = activeItem.GetLocalFirePosition() - activeItem.GripPoint.Position;
- localFirePosition *= 0.9f;
- sprite.Position = p1 + localFirePosition.Rotated(Mathf.DegToRad(r));
- sprite.RotationDegrees = r;
- AddChild(sprite);
- effect.PlayEffect();
-
- //启用近战碰撞区域
- MeleeAttackCollision.Disabled = false;
- }));
- tween.Chain();
-
- tween.TweenInterval(0.1f);
- tween.Chain();
-
- tween.TweenCallback(Callable.From(() =>
- {
- //关闭近战碰撞区域
- MeleeAttackCollision.Disabled = true;
- }));
- tween.TweenProperty(MountPoint, "rotation_degrees", r, 0.2);
- tween.TweenProperty(MountPoint, "position", p1, 0.2);
- tween.Chain();
-
- tween.TweenCallback(Callable.From(() =>
- {
- finish();
- }));
- tween.Play();
- }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs
index fcea8b0..a63cc35 100644
--- a/DungeonShooting_Godot/src/game/activity/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs
@@ -737,7 +737,15 @@
// blood.Rotation = angle;
// GameApplication.Instance.Node3D.GetRoot().AddChild(blood);
}
- OnHit(target, damage, angle, !flag);
+
+ if (target == null || target.IsDestroyed)
+ {
+ OnHit(null, damage, angle, !flag);
+ }
+ else
+ {
+ OnHit(target, damage, angle, !flag);
+ }
//受伤特效
PlayHitAnimation();
@@ -886,6 +894,30 @@
{
return -AnimatedSprite.Position.Y;
}
+
+ ///
+ /// 获取攻击标角度, 弧度制
+ ///
+ public virtual float GetAttackRotation()
+ {
+ return GetCenterPosition().AngleTo(LookPosition);
+ }
+
+ ///
+ /// 获取物品挂载点
+ ///
+ public virtual Vector2 GetMountPosition()
+ {
+ return AnimatedSprite.Position;
+ }
+
+ ///
+ /// 获取物品挂载节点对象
+ ///
+ public virtual Node2D GetMountNode()
+ {
+ return AnimatedSprite;
+ }
protected override void OnDestroy()
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/RoleAnimation.cs b/DungeonShooting_Godot/src/game/activity/role/RoleAnimation.cs
new file mode 100644
index 0000000..227fb3f
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/RoleAnimation.cs
@@ -0,0 +1,149 @@
+
+using System;
+using Godot;
+using Vector2 = Godot.Vector2;
+
+public static class RoleAnimation
+{
+ ///
+ /// 播放近战攻击动画
+ ///
+ public static void PlayAnimation_MeleeAttack(this AdvancedRole role, Action finish)
+ {
+ var r = role.MountPoint.RotationDegrees;
+ //var gp = MountPoint.GlobalPosition;
+ var p1 = role.MountPoint.Position;
+ var p2 = p1 + new Vector2(6, 0).Rotated(Mathf.DegToRad(r - role.MeleeAttackAngle / 2f));
+ var p3 = p1 + new Vector2(6, 0).Rotated(Mathf.DegToRad(r + role.MeleeAttackAngle / 2f));
+
+ var tween = role.CreateTween();
+ tween.SetParallel();
+
+ tween.TweenProperty(role.MountPoint, "rotation_degrees", r - role.MeleeAttackAngle / 2f, 0.1);
+ tween.TweenProperty(role.MountPoint, "position", p2, 0.1);
+ tween.TweenProperty(role.MountPoint, "position", p2, 0.1);
+ tween.Chain();
+
+ tween.TweenCallback(Callable.From(() =>
+ {
+ role.MountPoint.RotationDegrees = r + role.MeleeAttackAngle / 2f;
+ role.MountPoint.Position = p3;
+ //重新计算武器阴影位置
+ var activeItem = role.WeaponPack.ActiveItem;
+ activeItem.CalcShadowTransform();
+ //创建屏幕抖动
+ if (role.Face == FaceDirection.Right)
+ {
+ //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 90)) * 5);
+ GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 180)) * 6);
+ }
+ else
+ {
+ //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(270 - r)) * 5);
+ GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(-r)) * 6);
+ }
+ //播放特效
+ var effect = ObjectManager.GetPoolItem(ResourcePath.prefab_effect_weapon_MeleeAttack1_tscn);
+ var sprite = (Node2D)effect;
+ var localFirePosition = activeItem.GetLocalFirePosition() - activeItem.GripPoint.Position;
+ localFirePosition *= 0.9f;
+ sprite.Position = p1 + localFirePosition.Rotated(Mathf.DegToRad(r));
+ sprite.RotationDegrees = r;
+ role.AddChild(sprite);
+ effect.PlayEffect();
+
+ //启用近战碰撞区域
+ role.MeleeAttackCollision.Disabled = false;
+ }));
+ tween.Chain();
+
+ tween.TweenInterval(0.1f);
+ tween.Chain();
+
+ tween.TweenCallback(Callable.From(() =>
+ {
+ //关闭近战碰撞区域
+ role.MeleeAttackCollision.Disabled = true;
+ }));
+ tween.TweenProperty(role.MountPoint, "rotation_degrees", r, 0.2);
+ tween.TweenProperty(role.MountPoint, "position", p1, 0.2);
+ tween.Chain();
+
+ tween.TweenCallback(Callable.From(() =>
+ {
+ finish();
+ }));
+ tween.Play();
+ }
+
+ ///
+ /// 播放近战攻击动画
+ ///
+ public static void PlayAnimation_MeleeAttack(this AdvancedEnemy role, Action finish)
+ {
+ var r = role.MountPoint.RotationDegrees;
+ //var gp = MountPoint.GlobalPosition;
+ var p1 = role.MountPoint.Position;
+ var p2 = p1 + new Vector2(6, 0).Rotated(Mathf.DegToRad(r - role.MeleeAttackAngle / 2f));
+ var p3 = p1 + new Vector2(6, 0).Rotated(Mathf.DegToRad(r + role.MeleeAttackAngle / 2f));
+
+ var tween = role.CreateTween();
+ tween.SetParallel();
+
+ tween.TweenProperty(role.MountPoint, "rotation_degrees", r - role.MeleeAttackAngle / 2f, 0.1);
+ tween.TweenProperty(role.MountPoint, "position", p2, 0.1);
+ tween.TweenProperty(role.MountPoint, "position", p2, 0.1);
+ tween.Chain();
+
+ tween.TweenCallback(Callable.From(() =>
+ {
+ role.MountPoint.RotationDegrees = r + role.MeleeAttackAngle / 2f;
+ role.MountPoint.Position = p3;
+ //重新计算武器阴影位置
+ var activeItem = role.WeaponPack.ActiveItem;
+ activeItem.CalcShadowTransform();
+ //创建屏幕抖动
+ if (role.Face == FaceDirection.Right)
+ {
+ //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 90)) * 5);
+ GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 180)) * 6);
+ }
+ else
+ {
+ //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(270 - r)) * 5);
+ GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(-r)) * 6);
+ }
+ //播放特效
+ var effect = ObjectManager.GetPoolItem(ResourcePath.prefab_effect_weapon_MeleeAttack1_tscn);
+ var sprite = (Node2D)effect;
+ var localFirePosition = activeItem.GetLocalFirePosition() - activeItem.GripPoint.Position;
+ localFirePosition *= 0.9f;
+ sprite.Position = p1 + localFirePosition.Rotated(Mathf.DegToRad(r));
+ sprite.RotationDegrees = r;
+ role.AddChild(sprite);
+ effect.PlayEffect();
+
+ //启用近战碰撞区域
+ role.MeleeAttackCollision.Disabled = false;
+ }));
+ tween.Chain();
+
+ tween.TweenInterval(0.1f);
+ tween.Chain();
+
+ tween.TweenCallback(Callable.From(() =>
+ {
+ //关闭近战碰撞区域
+ role.MeleeAttackCollision.Disabled = true;
+ }));
+ tween.TweenProperty(role.MountPoint, "rotation_degrees", r, 0.2);
+ tween.TweenProperty(role.MountPoint, "position", p1, 0.2);
+ tween.Chain();
+
+ tween.TweenCallback(Callable.From(() =>
+ {
+ finish();
+ }));
+ tween.Play();
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs
index b2d184d..75f7900 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/AdvancedEnemy.cs
@@ -14,66 +14,93 @@
using System;
using AdvancedState;
using Godot;
+using NnormalState;
+using AiAstonishedState = AdvancedState.AiAstonishedState;
+using AiAttackState = AdvancedState.AiAttackState;
+using AiFollowUpState = AdvancedState.AiFollowUpState;
+using AiLeaveForState = AdvancedState.AiLeaveForState;
+using AiNormalState = AdvancedState.AiNormalState;
+using AiNotifyState = AdvancedState.AiNotifyState;
+using AiSurroundState = AdvancedState.AiSurroundState;
+using AiTailAfterState = AdvancedState.AiTailAfterState;
///
/// 高级敌人,可以携带武器
///
[Tool]
-public partial class AdvancedEnemy : AdvancedRole
+public partial class AdvancedEnemy : Enemy
{
///
- /// 目标是否在视野内
+ /// 角色携带的武器背包
///
- public bool TargetInView { get; set; } = true;
+ public Package WeaponPack { get; private set; }
///
- /// 敌人身上的状态机控制器
- ///
- public StateController StateController { get; private set; }
-
- ///
- /// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙
- ///
- public float ViewRange { get; set; } = 250;
-
- ///
- /// 发现玩家后的视野半径
- ///
- public float TailAfterViewRange { get; set; } = 400;
-
- ///
- /// 背后的视野半径, 单位像素
- ///
- public float BackViewRange { get; set; } = 50;
-
- ///
- /// 视野检测射线, 朝玩家打射线, 检测是否碰到墙
+ /// 武器挂载点
///
[Export, ExportFillNode]
- public RayCast2D ViewRay { get; private set; }
-
- ///
- /// 导航代理
- ///
- [Export, ExportFillNode]
- public NavigationAgent2D NavigationAgent2D { get; private set; }
-
- ///
- /// 导航代理中点
- ///
- [Export, ExportFillNode]
- public Marker2D NavigationPoint { get; private set; }
+ public MountRotation MountPoint { get; set; }
///
- /// 当前敌人所看向的对象, 也就是枪口指向的对象
+ /// 近战碰撞检测区域
///
- public ActivityObject LookTarget { get; set; }
+ [Export, ExportFillNode]
+ public Area2D MeleeAttackArea { get; set; }
///
- /// 锁定目标已经走过的时间
+ /// 近战碰撞检测区域的碰撞器
///
- public float LockTargetTime { get; set; } = 0;
+ [Export, ExportFillNode]
+ public CollisionPolygon2D MeleeAttackCollision { get; set; }
+ ///
+ /// 近战攻击时挥动武器的角度
+ ///
+ [Export]
+ public float MeleeAttackAngle { get; set; } = 120;
+
+ ///
+ /// 武器挂载点是否始终指向目标
+ ///
+ public bool MountLookTarget { get; set; } = true;
+
+ ///
+ /// 背后武器的挂载点
+ ///
+ [Export, ExportFillNode]
+ public Marker2D BackMountPoint { get; set; }
+
+ ///
+ /// 是否处于近战攻击中
+ ///
+ public bool IsMeleeAttack { get; private set; }
+
+ //近战计时器
+ private float _meleeAttackTimer = 0;
+
+
+ ///
+ /// 当拾起某个武器时调用
+ ///
+ protected virtual void OnPickUpWeapon(Weapon weapon)
+ {
+ }
+
+ ///
+ /// 当扔掉某个武器时调用
+ ///
+ protected virtual void OnThrowWeapon(Weapon weapon)
+ {
+ }
+
+ ///
+ /// 当切换到某个武器时调用
+ ///
+ protected virtual void OnExchangeWeapon(Weapon weapon)
+ {
+ }
+
+
public override void OnInit()
{
base.OnInit();
@@ -180,15 +207,32 @@
//拾起武器操作
EnemyPickUpWeapon();
}
-
- protected override void OnHit(ActivityObject target, int damage, float angle, bool realHarm)
+
+ ///
+ /// 当武器放到后背时调用, 用于设置武器位置和角度
+ ///
+ /// 武器实例
+ /// 放入武器背包的位置
+ public virtual void OnPutBackMount(Weapon weapon, int index)
{
- //受到伤害
- var state = StateController.CurrState;
- if (state == AIAdvancedStateEnum.AiNormal || state == AIAdvancedStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe
+ if (index < 8)
{
- LookTarget = target;
- StateController.ChangeState(AIAdvancedStateEnum.AiTailAfter);
+ if (index % 2 == 0)
+ {
+ weapon.Position = new Vector2(-4, 3);
+ weapon.RotationDegrees = 90 - (index / 2f) * 20;
+ weapon.Scale = new Vector2(-1, 1);
+ }
+ else
+ {
+ weapon.Position = new Vector2(4, 3);
+ weapon.RotationDegrees = 270 + (index - 1) / 2f * 20;
+ weapon.Scale = new Vector2(1, 1);
+ }
+ }
+ else
+ {
+ weapon.Visible = false;
}
}
@@ -297,60 +341,7 @@
return 0;
}
-
- ///
- /// 返回目标点是否在视野范围内
- ///
- public bool IsInViewRange(Vector2 target)
- {
- var isForward = IsPositionInForward(target);
- if (isForward)
- {
- if (GlobalPosition.DistanceSquaredTo(target) <= ViewRange * ViewRange) //没有超出视野半径
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- /// 返回目标点是否在跟随状态下的视野半径内
- ///
- public 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)
- {
- ViewRay.Enabled = true;
- ViewRay.TargetPosition = ViewRay.ToLocal(target);
- ViewRay.ForceRaycastUpdate();
- return ViewRay.IsColliding();
- }
-
- ///
- /// 调用视野检测完毕后, 需要调用 TestViewRayCastOver() 来关闭视野检测射线
- ///
- public void TestViewRayCastOver()
- {
- ViewRay.Enabled = false;
- }
-
+
///
/// AI 拾起武器操作
///
@@ -358,7 +349,7 @@
{
//这几个状态不需要主动拾起武器操作
var state = StateController.CurrState;
- if (state == AIAdvancedStateEnum.AiNormal)
+ if (state == AINormalStateEnum.AiNormal)
{
return;
}
@@ -410,7 +401,7 @@
///
/// 获取锁定目标的剩余时间
///
- public float GetLockRemainderTime()
+ public override float GetLockRemainderTime()
{
var weapon = WeaponPack.ActiveItem;
if (weapon == null)
@@ -420,48 +411,263 @@
return weapon.Attribute.AiAttackAttr.LockingTime - LockTargetTime;
}
- ///
- /// 强制设置锁定目标时间
- ///
- public void SetLockTargetTime(float time)
- {
- LockTargetTime = time;
- }
-
public override void LookTargetPosition(Vector2 pos)
{
LookTarget = null;
- base.LookTargetPosition(pos);
+ LookPosition = pos;
+ if (MountLookTarget)
+ {
+ //脸的朝向
+ 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);
+ }
}
///
- /// 执行移动操作
+ /// 返回所有武器是否弹药都打光了
///
- public void DoMove()
+ public bool IsAllWeaponTotalAmmoEmpty()
{
- AnimatedSprite.Play(AnimatorNames.Run);
- //计算移动
- var nextPos = NavigationAgent2D.GetNextPathPosition();
- BasisVelocity = (nextPos - Position - NavigationPoint.Position).Normalized() * RoleState.MoveSpeed;
+ foreach (var weapon in WeaponPack.ItemSlot)
+ {
+ if (weapon != null && !weapon.IsTotalAmmoEmpty())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override float GetAttackRotation()
+ {
+ return MountPoint.RealRotation;
+ }
+
+ public override Vector2 GetMountPosition()
+ {
+ return MountPoint.GlobalPosition;
+ }
+
+ public override Node2D GetMountNode()
+ {
+ return MountPoint;
}
///
- /// 执行站立操作
+ /// 拾起一个武器, 返回是否成功拾起, 如果不想立刻切换到该武器, exchange 请传 false
///
- public void DoIdle()
+ /// 武器对象
+ /// 是否立即切换到该武器, 默认 true
+ public bool PickUpWeapon(Weapon weapon, bool exchange = true)
{
- AnimatedSprite.Play(AnimatorNames.Idle);
- BasisVelocity = Vector2.Zero;
+ if (WeaponPack.PickupItem(weapon, exchange) != -1)
+ {
+ //从可互动队列中移除
+ InteractiveItemList.Remove(weapon);
+ OnPickUpWeapon(weapon);
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 切换到下一个武器
+ ///
+ public void ExchangeNextWeapon()
+ {
+ var weapon = WeaponPack.ActiveItem;
+ WeaponPack.ExchangeNext();
+ if (WeaponPack.ActiveItem != weapon)
+ {
+ OnExchangeWeapon(WeaponPack.ActiveItem);
+ }
+ }
+
+ ///
+ /// 切换到上一个武器
+ ///
+ public void ExchangePrevWeapon()
+ {
+ var weapon = WeaponPack.ActiveItem;
+ WeaponPack.ExchangePrev();
+ if (WeaponPack.ActiveItem != weapon)
+ {
+ OnExchangeWeapon(WeaponPack.ActiveItem);
+ }
+ }
+
+ ///
+ /// 扔掉当前使用的武器, 切换到上一个武器
+ ///
+ public void ThrowWeapon()
+ {
+ ThrowWeapon(WeaponPack.ActiveIndex);
+ }
+
+ ///
+ /// 扔掉指定位置的武器
+ ///
+ /// 武器在武器背包中的位置
+ public void ThrowWeapon(int index)
+ {
+ var weapon = WeaponPack.GetItem(index);
+ if (weapon == null)
+ {
+ return;
+ }
+
+ var temp = weapon.AnimatedSprite.Position;
+ if (Face == FaceDirection.Left)
+ {
+ temp.Y = -temp.Y;
+ }
+ //var pos = GlobalPosition + temp.Rotated(weapon.GlobalRotation);
+ WeaponPack.RemoveItem(index);
+ //播放抛出效果
+ weapon.ThrowWeapon(this, GlobalPosition);
}
///
- /// 更新房间中标记的目标位置
+ /// 切换到下一个武器
///
- public void UpdateMarkTargetPosition()
+ public void ExchangeNextActiveProp()
{
- if (LookTarget != null)
+ var prop = ActivePropsPack.ActiveItem;
+ ActivePropsPack.ExchangeNext();
+ if (prop != ActivePropsPack.ActiveItem)
{
- AffiliationArea.RoomInfo.MarkTargetPosition[LookTarget.Id] = LookTarget.Position;
+ OnExchangeActiveProp(ActivePropsPack.ActiveItem);
+ }
+ }
+
+ ///
+ /// 切换到上一个武器
+ ///
+ public void ExchangePrevActiveProp()
+ {
+ var prop = ActivePropsPack.ActiveItem;
+ ActivePropsPack.ExchangePrev();
+ if (prop != ActivePropsPack.ActiveItem)
+ {
+ OnExchangeActiveProp(ActivePropsPack.ActiveItem);
+ }
+ }
+
+ //-------------------------------------------------------------------------------------
+
+ ///
+ /// 触发换弹
+ ///
+ public virtual void Reload()
+ {
+ if (WeaponPack.ActiveItem != null)
+ {
+ WeaponPack.ActiveItem.Reload();
+ }
+ }
+
+ public override void Attack()
+ {
+ if (!IsMeleeAttack && WeaponPack.ActiveItem != null)
+ {
+ WeaponPack.ActiveItem.Trigger(this);
+ }
+ }
+
+ ///
+ /// 触发近战攻击
+ ///
+ public virtual void MeleeAttack()
+ {
+ if (IsMeleeAttack || _meleeAttackTimer > 0)
+ {
+ return;
+ }
+
+ if (WeaponPack.ActiveItem != null && WeaponPack.ActiveItem.Attribute.CanMeleeAttack)
+ {
+ IsMeleeAttack = true;
+ _meleeAttackTimer = RoleState.MeleeAttackTime;
+ MountLookTarget = false;
+
+ //WeaponPack.ActiveItem.TriggerMeleeAttack(this);
+ //播放近战动画
+ this.PlayAnimation_MeleeAttack(() =>
+ {
+ MountLookTarget = true;
+ IsMeleeAttack = false;
+ });
+ }
+ }
+
+ ///
+ /// 切换当前使用的武器的回调
+ ///
+ private void OnChangeActiveItem(Weapon weapon)
+ {
+ //这里处理近战区域
+ if (weapon != null)
+ {
+ MeleeAttackCollision.Polygon = Utils.CreateSectorPolygon(
+ Utils.ConvertAngle(-MeleeAttackAngle / 2f),
+ (weapon.GetLocalFirePosition() - weapon.GripPoint.Position).Length() * 1.2f,
+ MeleeAttackAngle,
+ 6
+ );
+ MeleeAttackArea.CollisionMask = AttackLayer | PhysicsLayer.Bullet;
+ }
+ }
+
+ ///
+ /// 近战区域碰到敌人
+ ///
+ private void OnMeleeAttackBodyEntered(Node2D body)
+ {
+ var activeWeapon = WeaponPack.ActiveItem;
+ if (activeWeapon == null)
+ {
+ return;
+ }
+ var activityObject = body.AsActivityObject();
+ if (activityObject != null)
+ {
+ if (activityObject is AdvancedRole role) //攻击角色
+ {
+ var damage = Utils.Random.RandomConfigRange(activeWeapon.Attribute.MeleeAttackHarmRange);
+ damage = RoleState.CalcDamage(damage);
+
+ //击退
+ if (role is not Player) //目标不是玩家才会触发击退
+ {
+ var attr = IsAi ? activeWeapon.AiUseAttribute : activeWeapon.PlayerUseAttribute;
+ var repel = Utils.Random.RandomConfigRange(attr.MeleeAttackRepelRange);
+ var position = role.GlobalPosition - MountPoint.GlobalPosition;
+ var v2 = position.Normalized() * repel;
+ role.MoveController.AddForce(v2);
+ }
+
+ role.CallDeferred(nameof(Hurt), this, damage, (role.GetCenterPosition() - GlobalPosition).Angle());
+ }
+ else if (activityObject is Bullet bullet) //攻击子弹
+ {
+ var attackLayer = bullet.AttackLayer;
+ if (CollisionWithMask(attackLayer)) //是攻击玩家的子弹
+ {
+ bullet.PlayDisappearEffect();
+ bullet.Destroy();
+ }
+ }
}
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
index 1513d7c..e711869 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
@@ -75,12 +75,15 @@
public ActivityObject LookTarget { get; set; }
///
+ /// 锁定目标已经走过的时间
+ ///
+ public float LockTargetTime { get; set; } = 0;
+
+ ///
/// Ai 攻击属性
///
public ExcelConfig.AiAttackAttr AttackAttribute { get; private set; }
- //锁定目标时间
- private float _lockTargetTime = 0;
//攻击冷却计时器
private float _attackTimer = 0;
@@ -171,11 +174,11 @@
var currState = StateController.CurrState;
if (currState == AINormalStateEnum.AiAttack && _attackTimer <= 0) //必须在可以开火时记录时间
{
- _lockTargetTime += delta;
+ LockTargetTime += delta;
}
else
{
- _lockTargetTime = 0;
+ LockTargetTime = 0;
}
}
@@ -183,14 +186,11 @@
{
//受到伤害
var state = StateController.CurrState;
- // if (state == AINormalStateEnum.AiNormal)
- // {
- // StateController.ChangeState(AINormalStateEnum.AiLeaveFor, target);
- // }
- // else if (state == AINormalStateEnum.AiLeaveFor)
- // {
- //
- // }
+ if (target != null && state == AINormalStateEnum.AiNormal || state == AINormalStateEnum.AiLeaveFor) //|| state == AiStateEnum.AiProbe
+ {
+ LookTarget = target;
+ StateController.ChangeState(AINormalStateEnum.AiTailAfter);
+ }
}
protected override void OnDie()
@@ -268,29 +268,13 @@
{
ViewRay.Enabled = false;
}
-
- ///
- /// 获取锁定目标的时间
- ///
- public float GetLockTime()
- {
- return _lockTargetTime;
- }
///
/// 获取锁定目标的剩余时间
///
- public float GetLockRemainderTime()
+ public virtual float GetLockRemainderTime()
{
- return AttackAttribute.LockingTime - _lockTargetTime;
- }
-
- ///
- /// 强制设置锁定目标时间
- ///
- public void SetLockTargetTime(float time)
- {
- _lockTargetTime = time;
+ return AttackAttribute.LockingTime - LockTargetTime;
}
///
@@ -321,6 +305,17 @@
}
///
+ /// 更新房间中标记的目标位置
+ ///
+ public void UpdateMarkTargetPosition()
+ {
+ if (LookTarget != null)
+ {
+ AffiliationArea.RoomInfo.MarkTargetPosition[LookTarget.Id] = LookTarget.Position;
+ }
+ }
+
+ ///
/// 执行移动操作
///
public void DoMove()
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs
index 35e56dd..f731d72 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/normalState/AINormalStateEnum.cs
@@ -11,7 +11,7 @@
///
AiNotify,
///
- /// 发现目标, 惊讶状态
+ /// 惊讶状态
///
AiAstonished,
///
@@ -31,7 +31,11 @@
///
AiSurround,
///
- /// 攻击状态
+ /// Ai 寻找弹药
+ ///
+ AiFindAmmo,
+ ///
+ /// Ai攻击
///
AiAttack,
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
index 9a2fd78..e39f771 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
@@ -6,7 +6,7 @@
///
/// 武器的基类
///
-public abstract partial class Weapon : ActivityObject, IPackageItem
+public abstract partial class Weapon : ActivityObject, IPackageItem
{
///
/// 武器使用的属性数据, 该属性会根据是否是玩家使用武器, 如果是Ai使用武器, 则会返回 AiUseAttribute 的属性对象
@@ -32,7 +32,7 @@
///
public CampEnum TargetCamp { get; set; }
- public AdvancedRole Master { get; set; }
+ public Role Master { get; set; }
public int PackageIndex { get; set; } = -1;
@@ -127,7 +127,19 @@
///
/// 返回是否真正使用该武器
///
- public bool IsActive => Master != null && Master.WeaponPack.ActiveItem == this;
+ public bool IsActive
+ {
+ get
+ {
+ if (Master == null)
+ return false;
+ else if (Master is AdvancedRole advancedRole)
+ return advancedRole.WeaponPack.ActiveItem == this;
+ else if (Master is AdvancedEnemy advancedEnemy)
+ return advancedEnemy.WeaponPack.ActiveItem == this;
+ return false;
+ }
+ }
///
/// 动画播放器
@@ -148,7 +160,7 @@
///
/// 上一次触发改武器开火的角色, 可能为 null
///
- public AdvancedRole TriggerRole { get; private set; }
+ public Role TriggerRole { get; private set; }
///
/// 上一次触发改武器开火的触发开火攻击的层级, 数据源自于:
@@ -397,7 +409,7 @@
/// 当武器被拾起时调用
///
/// 拾起该武器的角色
- protected virtual void OnPickUp(AdvancedRole master)
+ protected virtual void OnPickUp(Role master)
{
}
@@ -405,7 +417,7 @@
/// 当武器从武器背包中移除时调用
///
/// 移除该武器的角色
- protected virtual void OnRemove(AdvancedRole master)
+ protected virtual void OnRemove(Role master)
{
}
@@ -452,7 +464,7 @@
//这把武器被扔在地上, 或者当前武器没有被使用
//if (Master == null || Master.WeaponPack.ActiveItem != this)
- if ((Master != null && Master.WeaponPack.ActiveItem != this) || !_triggerRoleFlag) //在背上, 或者被扔出去了
+ if (!IsActive || !_triggerRoleFlag) //在背上, 或者被扔出去了
{
//_triggerTimer
_triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0;
@@ -695,7 +707,7 @@
/// 扳机函数, 调用即视为按下扳机
///
/// 按下扳机的角色, 如果传 null, 则视为走火
- public void Trigger(AdvancedRole triggerRole)
+ public void Trigger(Role triggerRole)
{
//不能触发扳机
if (!NoMasterCanTrigger && Master == null) return;
@@ -1041,7 +1053,7 @@
if (Master != null)
{
bulletCount = Master.RoleState.CalcBulletCount(bulletCount);
- fireRotation += Master.MountPoint.RealRotation;
+ fireRotation += Master.GetAttackRotation();
}
else
{
@@ -1105,7 +1117,7 @@
///
/// 根据触扳机的角色对象判断该角色使用的武器数据
///
- public ExcelConfig.WeaponBase GetUseAttribute(AdvancedRole triggerRole)
+ public ExcelConfig.WeaponBase GetUseAttribute(Role triggerRole)
{
if (triggerRole == null || !triggerRole.IsAi)
{
@@ -1734,14 +1746,14 @@
///
public float GetRealGlobalRotation()
{
- return Mathf.DegToRad(Master.MountPoint.RealRotationDegrees) + Rotation;
+ return Master.GetAttackRotation() + Rotation;
}
///
/// 触发扔掉武器时抛出的效果, 并不会管武器是否在武器背包中
///
/// 触发扔掉该武器的的角色
- public void ThrowWeapon(AdvancedRole master)
+ public void ThrowWeapon(Role master)
{
ThrowWeapon(master, master.GlobalPosition);
}
@@ -1751,7 +1763,7 @@
///
/// 触发扔掉该武器的的角色
/// 投抛起始位置
- public void ThrowWeapon(AdvancedRole master, Vector2 startPosition)
+ public void ThrowWeapon(Role master, Vector2 startPosition)
{
//阴影偏移
ShadowOffset = new Vector2(0, 2);
@@ -1761,11 +1773,29 @@
Scale *= new Vector2(1, -1);
}
- var rotation = master.MountPoint.GlobalRotation;
+ float rotation;
+ float startHeight;
+ if (master is AdvancedRole advancedRole)
+ {
+ var mountPoint = advancedRole.MountPoint;
+ rotation = mountPoint.GlobalRotation;
+ startHeight = -mountPoint.Position.Y;
+ }
+ else if (master is AdvancedEnemy advancedEnemy)
+ {
+ var mountPoint = advancedEnemy.MountPoint;
+ rotation = mountPoint.GlobalRotation;
+ startHeight = -mountPoint.Position.Y;
+ }
+ else
+ {
+ rotation = master.AnimatedSprite.GlobalRotation;
+ startHeight = -GetCenterPosition().Y;
+ }
+
GlobalRotation = rotation;
startPosition -= GripPoint.Position.Rotated(rotation);
- var startHeight = -master.MountPoint.Position.Y;
var velocity = new Vector2(20, 0).Rotated(rotation);
var yf = Utils.Random.RandomRangeInt(50, 70);
Throw(startPosition, startHeight, yf, velocity, 0);
@@ -1799,7 +1829,19 @@
{
//调整阴影
//ShadowOffset = new Vector2(0, Master.GlobalPosition.Y - GlobalPosition.Y);
- ShadowOffset = new Vector2(0, -Master.MountPoint.Position.Y);
+ if (Master is AdvancedRole advancedRole)
+ {
+ ShadowOffset = new Vector2(0, -advancedRole.MountPoint.Position.Y);
+ }
+ else if (Master is AdvancedEnemy advancedEnemy)
+ {
+ ShadowOffset = new Vector2(0, -advancedEnemy.MountPoint.Position.Y);
+ }
+ else
+ {
+ ShadowOffset = new Vector2(0, -Master.GetCenterPosition().Y);
+ }
+
//枪口默认抬起角度
RotationDegrees = -Attribute.DefaultAngle;
ShowShadowSprite();
@@ -1863,16 +1905,33 @@
public void OnActiveItem()
{
- //更改父节点
- var parent = GetParentOrNull();
- if (parent == null)
+ if (Master is AdvancedRole advancedRole)
{
- Master.MountPoint.AddChild(this);
+ //更改父节点
+ var parent = GetParentOrNull();
+ if (parent == null)
+ {
+ advancedRole.MountPoint.AddChild(this);
+ }
+ else if (parent != advancedRole.MountPoint)
+ {
+ parent.RemoveChild(this);
+ advancedRole.MountPoint.AddChild(this);
+ }
}
- else if (parent != Master.MountPoint)
+ else if (Master is AdvancedEnemy advancedEnemy)
{
- parent.RemoveChild(this);
- Master.MountPoint.AddChild(this);
+ //更改父节点
+ var parent = GetParentOrNull();
+ if (parent == null)
+ {
+ advancedEnemy.MountPoint.AddChild(this);
+ }
+ else if (parent != advancedEnemy.MountPoint)
+ {
+ parent.RemoveChild(this);
+ advancedEnemy.MountPoint.AddChild(this);
+ }
}
Position = Vector2.Zero;
@@ -1884,19 +1943,41 @@
public void OnConcealItem()
{
- var tempParent = GetParentOrNull();
- if (tempParent != null)
+ if (Master is AdvancedRole advancedRole)
{
- tempParent.RemoveChild(this);
- Master.BackMountPoint.AddChild(this);
- Master.OnPutBackMount(this, PackageIndex);
- Conceal();
+ var tempParent = GetParentOrNull();
+ if (tempParent != null)
+ {
+ tempParent.RemoveChild(this);
+ advancedRole.BackMountPoint.AddChild(this);
+ advancedRole.OnPutBackMount(this, PackageIndex);
+ Conceal();
+ }
}
+ else if (Master is AdvancedEnemy advancedEnemy)
+ {
+ var tempParent = GetParentOrNull();
+ if (tempParent != null)
+ {
+ tempParent.RemoveChild(this);
+ advancedEnemy.BackMountPoint.AddChild(this);
+ advancedEnemy.OnPutBackMount(this, PackageIndex);
+ Conceal();
+ }
+ }
+
}
public void OnOverflowItem()
{
- Master.ThrowWeapon(PackageIndex);
+ if (Master is AdvancedRole advancedRole)
+ {
+ advancedRole.ThrowWeapon(PackageIndex);
+ }
+ else if (Master is AdvancedEnemy advancedEnemy)
+ {
+ advancedEnemy.ThrowWeapon(PackageIndex);
+ }
}
///
@@ -1925,12 +2006,13 @@
AiAttackEnum flag;
if (IsTotalAmmoEmpty()) //当前武器弹药打空
{
+ var enemy = (AdvancedEnemy)Master;
//切换到有子弹的武器
- var index = Master.WeaponPack.FindIndex((we, i) => !we.IsTotalAmmoEmpty());
+ var index = enemy.WeaponPack.FindIndex((we, i) => !we.IsTotalAmmoEmpty());
if (index != -1)
{
flag = AiAttackEnum.ExchangeWeapon;
- Master.WeaponPack.ExchangeByIndex(index);
+ enemy.WeaponPack.ExchangeByIndex(index);
}
else //所有子弹打光
{
@@ -1977,7 +2059,7 @@
enemy.Attack();
if (_attackFlag)
{
- enemy.SetLockTargetTime(0);
+ enemy.LockTargetTime = 0;
}
}
else
@@ -1988,7 +2070,7 @@
enemy.Attack();
if (_attackFlag)
{
- enemy.SetLockTargetTime(0);
+ enemy.LockTargetTime = 0;
}
}
else //单发
@@ -1997,7 +2079,7 @@
enemy.Attack();
if (_attackFlag)
{
- enemy.SetLockTargetTime(0);
+ enemy.LockTargetTime = 0;
}
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
index b5db0d6..d32b28d 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
@@ -50,7 +50,7 @@
if (IsActive)
{
//让碰撞节点与武器挂载节点位置保持一致, 而不跟着武器走
- _hitArea.GlobalPosition = Master.MountPoint.GlobalPosition;
+ _hitArea.GlobalPosition = Master.GetMountPosition();
}
}
@@ -85,8 +85,8 @@
SpecialEffectManager.Play(
Master,
ResourcePath.resource_spriteFrames_effect_KnifeHit1_tres, "default",
- Master.MountPoint.Position,
- Master.MountPoint.Rotation + Mathf.DegToRad(Attribute.UpliftAngle + 60),
+ Master.GetMountPosition(),
+ Master.GetAttackRotation() + Mathf.DegToRad(Attribute.UpliftAngle + 60),
AnimatedSprite.Scale,
new Vector2(17, 4), 1
);
@@ -95,7 +95,7 @@
if (Master == Player.Current)
{
- var r = Master.MountPoint.RotationDegrees;
+ var r = Mathf.RadToDeg(Master.GetAttackRotation());
//创建屏幕抖动
if (Master.Face == FaceDirection.Right)
{
@@ -148,7 +148,7 @@
Vector2 position;
if (TriggerRole != null)
{
- position = role.GlobalPosition - TriggerRole.MountPoint.GlobalPosition;
+ position = role.GlobalPosition - TriggerRole.GetMountPosition();
}
else
{
diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs
index 3cf058f..ab4560a 100644
--- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs
+++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs
@@ -566,23 +566,9 @@
//不与玩家处于同一个房间
if (!enemy.IsDestroyed && enemy.AffiliationArea != playerAffiliationArea)
{
- if (enemy is Enemy e)
+ if (enemy.StateController.CurrState != AINormalStateEnum.AiNormal)
{
- if (e.StateController.CurrState != AINormalStateEnum.AiNormal)
- {
- e.StateController.ChangeState(AINormalStateEnum.AiNormal);
- }
- }
- else if (enemy is AdvancedEnemy ae)
- {
- if (ae.StateController.CurrState != AIAdvancedStateEnum.AiNormal)
- {
- ae.StateController.ChangeState(AIAdvancedStateEnum.AiNormal);
- }
- }
- else
- {
- throw new Exception("World.Enemy_InstanceList 混入了非 Enemy 和 AdvancedEnemy 类型的对象!");
+ enemy.StateController.ChangeState(AINormalStateEnum.AiNormal);
}
}
}
diff --git a/DungeonShooting_Godot/src/game/room/World.cs b/DungeonShooting_Godot/src/game/room/World.cs
index 1ed2eab..1285582 100644
--- a/DungeonShooting_Godot/src/game/room/World.cs
+++ b/DungeonShooting_Godot/src/game/room/World.cs
@@ -63,7 +63,7 @@
///
/// 记录所有存活的敌人
///
- public List Enemy_InstanceList { get; } = new List();
+ public List Enemy_InstanceList { get; } = new List();
private bool _pause = false;
private List _coroutineList;