diff --git a/DungeonShooting_Godot/src/game/item/package/Holster.cs b/DungeonShooting_Godot/src/game/item/package/Holster.cs index a737b40..2b281b2 100644 --- a/DungeonShooting_Godot/src/game/item/package/Holster.cs +++ b/DungeonShooting_Godot/src/game/item/package/Holster.cs @@ -29,7 +29,9 @@ /// 归属者 /// public Role Master { get; } - + + //public Weapon HandheldWeapon { get; private set; } + /// /// 当前使用的武器对象 /// @@ -68,6 +70,23 @@ } /// + /// 返回当前武器袋是否还有空位 + /// + public bool HasVacancy() + { + for (int i = 0; i < SlotList.Length; i++) + { + var item = SlotList[i]; + if (item.Enable && item.Weapon == null) + { + return true; + } + } + + return false; + } + + /// /// 根据索引获取武器 /// public Weapon GetWeapon(int index) { @@ -87,7 +106,7 @@ for (int i = 0; i < SlotList.Length; i++) { var item = SlotList[i]; - if (item.Weapon != null && item.Weapon.Id == id) + if (item.Weapon != null && item.Weapon.TypeId == id) { return i; } @@ -134,7 +153,8 @@ /// 拾起武器, 存入武器袋中, 返回存放在武器袋的位置, 如果容不下这把武器, 则会返回 -1 /// /// 武器对象 - public int PickupWeapon(Weapon weapon) + /// 是否立即切换到该武器, 默认 true + public int PickupWeapon(Weapon weapon, bool exchange = true) { //已经被拾起了 if (weapon.Master != null) @@ -149,7 +169,11 @@ weapon.Pickup(); item.Weapon = weapon; weapon.PickUpWeapon(Master); - ExchangeByIndex(i); + if (exchange) + { + ExchangeByIndex(i); + } + return i; } } diff --git a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs index 4bbf70a..297cfd3 100644 --- a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs +++ b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs @@ -7,9 +7,9 @@ public abstract class Weapon : ActivityObject { /// - /// 武器的唯一id + /// 武器的类型 id /// - public string Id { get; } + public string TypeId { get; } /// /// 开火回调事件 @@ -158,15 +158,15 @@ //当前后坐力导致的偏移长度 private float _currBacklashLength = 0; - + /// /// 根据属性创建一把武器 /// - /// 武器唯一id + /// 武器的类型id /// 属性 - public Weapon(string id, WeaponAttribute attribute) : base(attribute.WeaponPrefab) + public Weapon(string typeId, WeaponAttribute attribute) : base(attribute.WeaponPrefab) { - Id = id; + TypeId = typeId; Attribute = attribute; FirePoint = GetNode("WeaponBody/FirePoint"); @@ -186,7 +186,7 @@ if (Attribute.AmmoCapacity > Attribute.MaxAmmoCapacity) { Attribute.AmmoCapacity = Attribute.MaxAmmoCapacity; - GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + id); + GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + typeId); } //弹药量 CurrAmmo = Attribute.AmmoCapacity; @@ -763,7 +763,7 @@ { var masterWeapon = roleMaster.Holster.ActiveWeapon; //查找是否有同类型武器 - var index = roleMaster.Holster.FindWeapon(Id); + var index = roleMaster.Holster.FindWeapon(TypeId); if (index != -1) //如果有这个武器 { if (CurrAmmo + ResidueAmmo != 0) //子弹不为空 @@ -774,7 +774,7 @@ //可以互动拾起弹药 result.CanInteractive = true; result.Message = Attribute.Name; - result.ShowIcon = "res://resource/sprite/ui/icon/icon_bullet.png"; + result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_bullet_png; return result; } } @@ -786,7 +786,7 @@ //可以互动, 拾起武器 result.CanInteractive = true; result.Message = Attribute.Name; - result.ShowIcon = "res://resource/sprite/ui/icon/icon_pickup.png"; + result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_pickup_png; return result; } else if (masterWeapon != null && masterWeapon.Attribute.WeightType == Attribute.WeightType) //替换武器 @@ -794,7 +794,7 @@ //可以互动, 切换武器 result.CanInteractive = true; result.Message = Attribute.Name; - result.ShowIcon = "res://resource/sprite/ui/icon/icon_replace.png"; + result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_replace_png; return result; } } @@ -810,7 +810,7 @@ { var holster = roleMaster.Holster; //查找是否有同类型武器 - var index = holster.FindWeapon(Id); + var index = holster.FindWeapon(TypeId); if (index != -1) //如果有这个武器 { if (CurrAmmo + ResidueAmmo == 0) //没有子弹了 diff --git a/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs b/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs index eddf18b..abee1bf 100644 --- a/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs +++ b/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs @@ -24,8 +24,8 @@ //连发 ContinuousShoot = true; AmmoCapacity = 30; - StandbyAmmoCapacity = 30 * 70; - MaxAmmoCapacity = 30 * 70; + StandbyAmmoCapacity = 30 * 3; + MaxAmmoCapacity = 30 * 3; //扳机检测间隔 TriggerInterval = 0f; //连发数量 @@ -86,7 +86,7 @@ } } - public Gun(string id, WeaponAttribute attribute): base(id, attribute) + public Gun(string typeId, WeaponAttribute attribute): base(typeId, attribute) { } diff --git a/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs b/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs index 3e9d8e3..46713db 100644 --- a/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs +++ b/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs @@ -34,8 +34,8 @@ MinDistance = 200; MaxDistance = 250; //发射子弹数量 - MinFireBulletCount = 1; - MaxFireBulletCount = 1; + MinFireBulletCount = 5; + MaxFireBulletCount = 5; //抬起角度 UpliftAngle = 15; MaxBacklash = 6; @@ -50,7 +50,7 @@ /// public PackedScene ShellPack; - public Shotgun(string id, WeaponAttribute attribute) : base(id, attribute) + public Shotgun(string typeId, WeaponAttribute attribute) : base(typeId, attribute) { ShellPack = ResourceManager.Load(ResourcePath.prefab_weapon_shell_ShellCase_tscn); } @@ -86,20 +86,15 @@ protected override void OnShoot(float fireRotation) { - for (int i = 0; i < 5; i++) - { - //创建子弹 - //CreateBullet(BulletPack, FirePoint.GlobalPosition, fireRotation + MathUtils.RandRange(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi)); - - var bullet = new Bullet( - ResourcePath.prefab_weapon_bullet_Bullet_tscn, - Utils.RandRangeInt(280, 380), - Utils.RandRange(Attribute.MinDistance, Attribute.MaxDistance), - FirePoint.GlobalPosition, - fireRotation + Utils.RandRange(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi), - GetAttackLayer() - ); - bullet.PutDown(); - } + //创建子弹 + var bullet = new Bullet( + ResourcePath.prefab_weapon_bullet_Bullet_tscn, + Utils.RandRangeInt(280, 380), + Utils.RandRange(Attribute.MinDistance, Attribute.MaxDistance), + FirePoint.GlobalPosition, + fireRotation + Utils.RandRange(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi), + GetAttackLayer() + ); + bullet.PutDown(); } } diff --git a/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs index 60a3427..aee151f 100644 --- a/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs +++ b/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs @@ -22,6 +22,7 @@ MaxAmmoCapacity = AmmoCapacity; //握把位置 HoldPosition = new Vector2(10, 0); + MaxDistance = MinDistance = 35; //后坐力改为向前, 模拟手伸长的效果 MaxBacklash = -8; MinBacklash = -8; @@ -34,7 +35,7 @@ private int _attackIndex = 0; - public Knife(string id, WeaponAttribute attribute) : base(id, attribute) + public Knife(string typeId, WeaponAttribute attribute) : base(typeId, attribute) { _hitArea = GetNode("HitArea"); _hitArea.Monitoring = false; diff --git a/DungeonShooting_Godot/src/game/role/Role.cs b/DungeonShooting_Godot/src/game/role/Role.cs index 80a19ee..a524d9b 100644 --- a/DungeonShooting_Godot/src/game/role/Role.cs +++ b/DungeonShooting_Godot/src/game/role/Role.cs @@ -157,7 +157,7 @@ /// /// 可以互动的道具 /// - protected ActivityObject InteractiveItem { get; private set; } + public ActivityObject InteractiveItem { get; private set; } /// /// 当血量改变时调用 @@ -368,12 +368,13 @@ } /// - /// 拾起一个武器, 并且切换到这个武器, 返回是否成功拾取 + /// 拾起一个武器, 返回是否成功拾取, 如果不想立刻切换到该武器, exchange 请传 false /// /// 武器对象 - public virtual bool PickUpWeapon(Weapon weapon) + /// 是否立即切换到该武器, 默认 true + public virtual bool PickUpWeapon(Weapon weapon, bool exchange = true) { - if (Holster.PickupWeapon(weapon) != -1) + if (Holster.PickupWeapon(weapon, exchange) != -1) { //从可互动队列中移除 _interactiveItemList.Remove(weapon); @@ -404,7 +405,16 @@ /// public virtual void ThrowWeapon() { - var weapon = Holster.RemoveWeapon(Holster.ActiveIndex); + ThrowWeapon(Holster.ActiveIndex); + } + + /// + /// 扔掉指定位置的武器 + /// + /// 武器在武器袋中的位置 + public virtual void ThrowWeapon(int index) + { + var weapon = Holster.RemoveWeapon(index); //播放抛出效果 if (weapon != null) { @@ -431,6 +441,7 @@ item.Interactive(this); return item; } + return null; } diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs index 098fb0e..773a1f9 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs @@ -19,12 +19,12 @@ /// public class Enemy : Role { - + /// /// 公共属性, 是否找到目标, 如果找到目标, 则所有敌人都会知道玩家的位置 /// public static bool IsFindTarget { get; private set; } - + /// /// 找到的目标的位置, 如果目标在视野内, 则一直更新 /// @@ -56,7 +56,7 @@ /// 视野检测射线, 朝玩家打射线, 检测是否碰到墙 /// public RayCast2D ViewRay { get; } - + /// /// 导航代理 /// @@ -68,7 +68,7 @@ public Position2D NavigationPoint { get; } private float _enemyAttackTimer = 0; - + public Enemy() : base(ResourcePath.prefab_role_Enemy_tscn) { StateController = new StateController(); @@ -96,14 +96,12 @@ StateController.Register(new AiFollowUpState()); StateController.Register(new AiLeaveForState()); StateController.Register(new AiSurroundState()); + StateController.Register(new AiFindAmmoState()); } public override void _Ready() { base._Ready(); - //防撞速度计算 - NavigationAgent2D.Connect("velocity_computed", this, nameof(OnVelocityComputed)); - //默认状态 StateController.ChangeState(AiStateEnum.AiNormal); @@ -120,6 +118,7 @@ public override void _ExitTree() { + base._ExitTree(); _enemies.Remove(this); } @@ -128,6 +127,8 @@ base._PhysicsProcess(delta); _enemyAttackTimer -= delta; + + EnemyPickUpWeapon(); } /// @@ -157,17 +158,20 @@ { if (weapon.IsTotalAmmoEmpty()) //当前武器弹药打空 { - //扔掉当前武器 - ThrowWeapon(); - // var index = Holster.FindWeapon(we => !we.IsTotalAmmoEmpty()); - // if (index != -1) - // { - // - // } + //切换到有子弹的武器 + var index = Holster.FindWeapon(we => !we.IsTotalAmmoEmpty()); + if (index != -1) + { + Holster.ExchangeByIndex(index); + } + else //所有子弹打光, 去寻找武器 + { + //StateController.ChangeStateLate(AiStateEnum.AiFindAmmo); + } } else if (weapon.Reloading) //换弹中 { - + } else if (weapon.IsAmmoEmpty()) //弹夹已经打空 { @@ -183,7 +187,7 @@ { if (_enemyAttackTimer <= 0) { - _enemyAttackTimer = 60f / weapon.Attribute.StartFiringSpeed; + _enemyAttackTimer = 60f / weapon.Attribute.StartFiringSpeed + Utils.RandRange(0, 0.06f); Attack(); } } @@ -259,8 +263,52 @@ ViewRay.Enabled = false; } - private void OnVelocityComputed(Vector2 velocity) + /// + /// AI 拾起武器操作 + /// + private void EnemyPickUpWeapon() { - GD.Print("velocity: " + velocity); + //拾起地上的武器 + if (InteractiveItem is Weapon weapon) + { + if (Holster.ActiveWeapon == null) //手上没有武器, 无论如何也要拾起 + { + TriggerInteractive(); + return; + } + + //没弹药了 + if (weapon.IsTotalAmmoEmpty()) + { + return; + } + + var index = Holster.FindWeapon(we => we.TypeId == weapon.TypeId); + if (index != -1) //与武器袋中武器类型相同, 补充子弹 + { + if (!Holster.GetWeapon(index).IsAmmoFull()) + { + TriggerInteractive(); + } + + return; + } + + var index2 = Holster.FindWeapon(we => + we.Attribute.WeightType == weapon.Attribute.WeightType && we.IsTotalAmmoEmpty()); + if (index2 != -1) //则扔掉没子弹的武器 + { + ThrowWeapon(index2); + TriggerInteractive(); + return; + } + + if (Holster.HasVacancy()) //有空位, 拾起武器 + { + TriggerInteractive(); + return; + } + } } + } diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs index e94b6fb..816e2c7 100644 --- a/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs @@ -2,7 +2,7 @@ public enum AiStateEnum { /// - /// ai状态, 正常, 未发现目标 + /// Ai 状态, 正常, 未发现目标 /// AiNormal, /// @@ -25,4 +25,8 @@ /// 距离足够进, 在目标附近随机移动 /// AiSurround, + /// + /// Ai 寻找弹药 + /// + AiFindAmmo, } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs new file mode 100644 index 0000000..5ef4304 --- /dev/null +++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs @@ -0,0 +1,27 @@ + +using Godot; + +/// +/// Ai 寻找弹药 +/// +public class AiFindAmmoState : StateBase +{ + public AiFindAmmoState() : base(AiStateEnum.AiFindAmmo) + { + } + + public override void Enter(AiStateEnum prev, params object[] args) + { + GD.Print("寻找武器"); + } + + public override void PhysicsProcess(float delta) + { + + } + + public override void DebugDraw() + { + + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs index 17d5396..c08cbcd 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -95,23 +95,23 @@ // enemyTemp.PickUpWeapon(WeaponManager.GetGun("1001")); // } - var enemy2 = new Enemy(); - enemy2.Name = "Enemy2"; - enemy2.PutDown(new Vector2(540, 100)); - enemy2.PickUpWeapon(WeaponManager.GetGun("1002")); - enemy2.PickUpWeapon(WeaponManager.GetGun("1004")); - enemy2.PickUpWeapon(WeaponManager.GetGun("1003")); - // - var enemy3 = new Enemy(); - enemy3.Name = "Enemy3"; - enemy3.PutDown(new Vector2(540, 300)); - enemy3.PickUpWeapon(WeaponManager.GetGun("1003")); - enemy3.PickUpWeapon(WeaponManager.GetGun("1002")); + // var enemy2 = new Enemy(); + // enemy2.Name = "Enemy2"; + // enemy2.PutDown(new Vector2(540, 100)); + // enemy2.PickUpWeapon(WeaponManager.GetGun("1002")); + // enemy2.PickUpWeapon(WeaponManager.GetGun("1004")); + // enemy2.PickUpWeapon(WeaponManager.GetGun("1003")); + // // + // var enemy3 = new Enemy(); + // enemy3.Name = "Enemy3"; + // enemy3.PutDown(new Vector2(540, 300)); + // enemy3.PickUpWeapon(WeaponManager.GetGun("1003")); + // enemy3.PickUpWeapon(WeaponManager.GetGun("1002")); - WeaponManager.GetGun("1001").PutDown(new Vector2(80, 100)); - WeaponManager.GetGun("1001").PutDown(new Vector2(80, 80)); - WeaponManager.GetGun("1002").PutDown(new Vector2(80, 120)); - WeaponManager.GetGun("1003").PutDown(new Vector2(120, 80)); + // WeaponManager.GetGun("1001").PutDown(new Vector2(80, 100)); + // WeaponManager.GetGun("1001").PutDown(new Vector2(80, 80)); + // WeaponManager.GetGun("1002").PutDown(new Vector2(80, 120)); + // WeaponManager.GetGun("1003").PutDown(new Vector2(120, 80)); WeaponManager.GetGun("1003").PutDown(new Vector2(180, 80)); WeaponManager.GetGun("1003").PutDown(new Vector2(180, 180));