diff --git a/DungeonShooting_Godot/prefab/bullet/Bullet0001.tscn b/DungeonShooting_Godot/prefab/bullet/Bullet0001.tscn index 8c2a3c7..4081afc 100644 --- a/DungeonShooting_Godot/prefab/bullet/Bullet0001.tscn +++ b/DungeonShooting_Godot/prefab/bullet/Bullet0001.tscn @@ -1,9 +1,10 @@ [gd_scene load_steps=9 format=3 uid="uid://bj4kmvt8jg1cf"] -[ext_resource type="Script" path="res://src/game/item/bullet/Bullet.cs" id="1_82ma0"] +[ext_resource type="Script" path="res://src/game/activity/bullet/Bullet.cs" id="1_82ma0"] [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="2_p12d3"] [ext_resource type="Texture2D" uid="uid://bu0b11hiuecxy" path="res://resource/sprite/bullet/bullet.png" id="3_hjgpe"] + [sub_resource type="ShaderMaterial" id="ShaderMaterial_5a4f2"] resource_local_to_scene = true shader = ExtResource("2_p12d3") diff --git a/DungeonShooting_Godot/prefab/bullet/Bullet0002.tscn b/DungeonShooting_Godot/prefab/bullet/Bullet0002.tscn index f951e9f..ed25dfe 100644 --- a/DungeonShooting_Godot/prefab/bullet/Bullet0002.tscn +++ b/DungeonShooting_Godot/prefab/bullet/Bullet0002.tscn @@ -1,9 +1,10 @@ [gd_scene load_steps=9 format=3 uid="uid://bqkj0rn72ppge"] -[ext_resource type="Script" path="res://src/game/item/bullet/Bullet.cs" id="1_wphe7"] +[ext_resource type="Script" path="res://src/game/activity/bullet/Bullet.cs" id="1_wphe7"] [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="2_l3yjy"] [ext_resource type="Texture2D" uid="uid://ctsvj4y1t538u" path="res://resource/sprite/bullet/bullet3.png" id="3_nf7ic"] + [sub_resource type="ShaderMaterial" id="ShaderMaterial_5a4f2"] resource_local_to_scene = true shader = ExtResource("2_l3yjy") diff --git a/DungeonShooting_Godot/prefab/shell/Shell0001.tscn b/DungeonShooting_Godot/prefab/shell/Shell0001.tscn index b11de73..6deb5aa 100644 --- a/DungeonShooting_Godot/prefab/shell/Shell0001.tscn +++ b/DungeonShooting_Godot/prefab/shell/Shell0001.tscn @@ -1,9 +1,10 @@ [gd_scene load_steps=7 format=3 uid="uid://bj4yr6ru8nhwr"] -[ext_resource type="Script" path="res://src/game/item/shell/Shell.cs" id="1_ph0ad"] +[ext_resource type="Script" path="res://src/game/activity/shell/Shell.cs" id="1_ph0ad"] [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="2_k705i"] [ext_resource type="Texture2D" uid="uid://dto03bc2qbhnj" path="res://resource/sprite/shell/shellCase.png" id="3_0fth1"] + [sub_resource type="ShaderMaterial" id="ShaderMaterial_px12l"] resource_local_to_scene = true shader = ExtResource("2_k705i") diff --git a/DungeonShooting_Godot/prefab/weapon/Weapon0001.tscn b/DungeonShooting_Godot/prefab/weapon/Weapon0001.tscn index 6fd7f8c..c140971 100644 --- a/DungeonShooting_Godot/prefab/weapon/Weapon0001.tscn +++ b/DungeonShooting_Godot/prefab/weapon/Weapon0001.tscn @@ -1,10 +1,11 @@ [gd_scene load_steps=7 format=3 uid="uid://c6etppq4v63xw"] [ext_resource type="PackedScene" uid="uid://cxltmhhp4rbyk" path="res://prefab/weapon/WeaponTemplate.tscn" id="1_0nysf"] -[ext_resource type="Script" path="res://src/game/item/weapon/gun/Gun.cs" id="2_bd6qw"] +[ext_resource type="Script" path="res://src/game/activity/weapon/gun/Gun.cs" id="2_bd6qw"] [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="3_ksckd"] [ext_resource type="SpriteFrames" uid="uid://5m0qs7m4er5u" path="res://resource/spriteFrames/Weapon0001.tres" id="4_xo84l"] + [sub_resource type="ShaderMaterial" id="ShaderMaterial_5bfqf"] resource_local_to_scene = true shader = ExtResource("3_ksckd") diff --git a/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001.png.import b/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001.png.import index c36be94..b20c9a6 100644 --- a/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001.png.import +++ b/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001.png.import @@ -3,15 +3,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://chd2vtesap5cf" -path="res://.godot/imported/Enemy0001.png-148a38dfa95953b26d890356e8875de4.ctex" +path="res://.godot/imported/enemy0001.png-1247a3ddf8a1a163d812cad12c4340fd.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://resource/sprite/role/enemy0001/Enemy0001.png" -dest_files=["res://.godot/imported/Enemy0001.png-148a38dfa95953b26d890356e8875de4.ctex"] +source_file="res://resource/sprite/role/enemy0001/enemy0001.png" +dest_files=["res://.godot/imported/enemy0001.png-1247a3ddf8a1a163d812cad12c4340fd.ctex"] [params] diff --git a/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001_Debris.png.import b/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001_Debris.png.import index d563acf..56388a2 100644 --- a/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001_Debris.png.import +++ b/DungeonShooting_Godot/resource/sprite/role/enemy0001/enemy0001_Debris.png.import @@ -3,15 +3,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://d2f55lu60x64i" -path="res://.godot/imported/Enemy0001_Debris.png-ac416dc79cd3c1217b27e1ef1fbe0d0b.ctex" +path="res://.godot/imported/enemy0001_Debris.png-297a2fb6680cb862a9a085cf58f8268c.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://resource/sprite/role/enemy0001/Enemy0001_Debris.png" -dest_files=["res://.godot/imported/Enemy0001_Debris.png-ac416dc79cd3c1217b27e1ef1fbe0d0b.ctex"] +source_file="res://resource/sprite/role/enemy0001/enemy0001_Debris.png" +dest_files=["res://.godot/imported/enemy0001_Debris.png-297a2fb6680cb862a9a085cf58f8268c.ctex"] [params] diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 271affb..1fc0257 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -95,6 +95,8 @@ InitRoomConfig(); //初始化 ActivityObject ActivityObject.InitActivity(); + //初始化武器数据 + Weapon.InitWeaponAttribute(); DungeonConfig = new DungeonConfig(); DungeonConfig.GroupName = "testGroup"; diff --git a/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs new file mode 100644 index 0000000..bb20329 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs @@ -0,0 +1,96 @@ +using Godot; + +/// +/// 子弹类 +/// +[Tool, GlobalClass] +public partial class Bullet : ActivityObject +{ + /// + /// 碰撞区域 + /// + [Export, ExportFillNode] + public Area2D CollisionArea { get; set; } + + /// + /// 发射该子弹的武器 + /// + public Weapon Weapon { get; private set; } + + // 最大飞行距离 + private float MaxDistance; + + // 子弹飞行速度 + private float FlySpeed; + + //当前子弹已经飞行的距离 + private float CurrFlyDistance = 0; + + public void Init(Weapon weapon, float speed, float maxDistance, Vector2 position, float rotation, uint targetLayer) + { + Weapon = weapon; + CollisionArea.CollisionMask = targetLayer; + CollisionArea.AreaEntered += OnArea2dEntered; + + //只有玩家使用该武器才能获得正常速度的子弹 + if (weapon.Master is Player) + { + FlySpeed = speed; + } + else + { + FlySpeed = speed * weapon.Attribute.AiBulletSpeedScale; + } + MaxDistance = maxDistance; + Position = position; + Rotation = rotation; + ShadowOffset = new Vector2(0, 5); + + BasisVelocity = new Vector2(FlySpeed, 0).Rotated(Rotation); + } + + protected override void PhysicsProcessOver(float delta) + { + //移动 + var lastSlideCollision = GetLastSlideCollision(); + //撞到墙 + if (lastSlideCollision != null) + { + //创建粒子特效 + var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_BulletSmoke_tscn); + var smoke = packedScene.Instantiate(); + smoke.GlobalPosition = lastSlideCollision.GetPosition(); + smoke.GlobalRotation = lastSlideCollision.GetNormal().Angle(); + smoke.AddToActivityRoot(RoomLayerEnum.YSortLayer); + + Destroy(); + return; + } + //距离太大, 自动销毁 + CurrFlyDistance += FlySpeed * delta; + if (CurrFlyDistance >= MaxDistance) + { + var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_BulletDisappear_tscn); + var node = packedScene.Instantiate(); + node.GlobalPosition = GlobalPosition; + node.AddToActivityRoot(RoomLayerEnum.YSortLayer); + + Destroy(); + } + } + + private void OnArea2dEntered(Area2D other) + { + var role = other.AsActivityObject(); + if (role != null) + { + var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_BulletDisappear_tscn); + var node = packedScene.Instantiate(); + node.GlobalPosition = GlobalPosition; + node.AddToActivityRoot(RoomLayerEnum.YSortLayer); + + role.CallDeferred(nameof(Role.Hurt), 4, Rotation); + Destroy(); + } + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/bullet/BulletAttribute.cs b/DungeonShooting_Godot/src/game/activity/bullet/BulletAttribute.cs new file mode 100644 index 0000000..aa30af1 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/bullet/BulletAttribute.cs @@ -0,0 +1,5 @@ + +public class BulletAttribute +{ + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/package/Holster.cs b/DungeonShooting_Godot/src/game/activity/package/Holster.cs new file mode 100644 index 0000000..a487f64 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/package/Holster.cs @@ -0,0 +1,369 @@ +using System; +using System.Collections.Generic; +using Godot; + +/// +/// 角色身上的武器袋, 存储角色携带的武器 +/// +public class Holster +{ + /// + /// 归属者 + /// + public Role Master { get; } + + /// + /// 当前使用的武器对象 + /// + public Weapon ActiveWeapon { get; private set; } + + /// + /// 当前使用的武器的索引 + /// + public int ActiveIndex { get; private set; } = 0; + + /// + /// 武器袋容量 + /// + public int Capacity { get; private set; } = 0; + + /// + /// 武器插槽 + /// + public Weapon[] Weapons { get; private set; } + + public Holster(Role master) + { + Master = master; + //默认容量4 + SetCapacity(4); + } + + /// + /// 修改武器袋容量 + /// + public void SetCapacity(int capacity) + { + if (capacity < 0) + { + capacity = 0; + } + + if (capacity == Capacity) + { + return; + } + + if (Weapons == null) + { + Weapons = new Weapon[capacity]; + } + else if (Weapons.Length > capacity) //删减格子 + { + var newArray = new Weapon[capacity]; + for (var i = 0; i < Weapons.Length; i++) + { + if (i < capacity) + { + newArray[i] = Weapons[i]; + } + else + { + Master.ThrowWeapon(i); + } + } + + Weapons = newArray; + } + else //添加格子 + { + var newArray = new Weapon[capacity]; + for (var i = 0; i < Weapons.Length; i++) + { + newArray[i] = Weapons[i]; + } + Weapons = newArray; + } + Capacity = capacity; + + } + + /// + /// 返回当前武器袋是否是空的 + /// + public bool IsEmpty() + { + for (var i = 0; i < Weapons.Length; i++) + { + if (Weapons[i] != null) + { + return false; + } + } + + return true; + } + + /// + /// 返回当前武器袋是否还有空位 + /// + public bool HasVacancy() + { + for (var i = 0; i < Weapons.Length; i++) + { + if (Weapons[i] == null) + { + return true; + } + } + + return false; + } + + /// + /// 根据索引获取武器 + /// + public Weapon GetWeapon(int index) + { + if (index < 0 || index >= Weapons.Length) + { + return null; + } + return Weapons[index]; + } + + /// + /// 根据武器id查找武器袋中该武器所在的位置, 如果没有, 则返回 -1 + /// + /// 武器id + public int FindWeapon(string id) + { + for (var i = 0; i < Weapons.Length; i++) + { + var item = Weapons[i]; + if (item != null && item.ItemId == id) + { + return i; + } + } + return -1; + } + + /// + /// 通过回调函数查询武器在武器袋中的位置, 如果没有, 则返回 -1 + /// + public int FindWeapon(Func handler) + { + for (var i = 0; i < Weapons.Length; i++) + { + var item = Weapons[i]; + if (item != null && handler(item, i)) + { + return i; + } + } + return -1; + } + + /// + /// 遍历所有武器 + /// + public void ForEach(Action handler) + { + for (var i = 0; i < Weapons.Length; i++) + { + var item = Weapons[i]; + if (item != null) + { + handler(item, i); + } + } + } + + /// + /// 从武器袋中移除所有武器, 并返回 + /// + public Weapon[] GetAndClearWeapon() + { + var weapons = new List(); + for (var i = 0; i < Weapons.Length; i++) + { + var weapon = Weapons[i]; + if (weapon != null) + { + weapon.GetParent().RemoveChild(weapon); + weapon.RemoveAt(); + weapons.Add(weapon); + Weapons[i] = null; + } + } + + return weapons.ToArray(); + } + + /// + /// 返回是否能放入武器 + /// + /// 武器对象 + public bool CanPickupWeapon(Weapon weapon) + { + for (var i = 0; i < Weapons.Length; i++) + { + var item = Weapons[i]; + if (item == null) + { + return true; + } + } + return false; + } + + /// + /// 拾起武器, 存入武器袋中, 返回存放在武器袋的位置, 如果容不下这把武器, 则会返回 -1 + /// + /// 武器对象 + /// 是否立即切换到该武器, 默认 true + public int PickupWeapon(Weapon weapon, bool exchange = true) + { + //已经被拾起了 + if (weapon.Master != null) + { + return -1; + } + for (var i = 0; i < Weapons.Length; i++) + { + var item = Weapons[i]; + if (item == null) + { + weapon.Pickup(); + Weapons[i] = weapon; + weapon.PickUpWeapon(Master); + if (exchange) + { + ExchangeByIndex(i); + } + + return i; + } + } + return -1; + } + + /// + /// 移除指定位置的武器, 并返回这个武器对象, 如果移除正在使用的这把武器, 则会自动切换到上一把武器 + /// + /// 所在武器袋的位置索引 + public Weapon RemoveWeapon(int index) + { + if (index < 0 || index >= Weapons.Length) + { + return null; + } + var weapon = Weapons[index]; + if (weapon == null) + { + return null; + } + weapon.GetParent().RemoveChild(weapon); + Weapons[index] = null; + + //如果是当前手持的武器, 就需要调用切换武器操作 + if (index == ActiveIndex) + { + //没有其他武器了 + if (ExchangePrev() == index) + { + ActiveIndex = 0; + ActiveWeapon = null; + } + } + weapon.RemoveAt(); + return weapon; + } + + /// + /// 切换到上一个武器 + /// + public int ExchangePrev() + { + var index = ActiveIndex - 1; + do + { + if (index < 0) + { + index = Weapons.Length - 1; + } + if (ExchangeByIndex(index)) + { + return index; + } + } while (index-- != ActiveIndex); + return -1; + } + + /// + /// 切换到下一个武器, + /// + public int ExchangeNext() + { + var index = ActiveIndex + 1; + do + { + if (index >= Weapons.Length) + { + index = 0; + } + if (ExchangeByIndex(index)) + { + return index; + } + } + while (index++ != ActiveIndex); + return -1; + } + + /// + /// 切换到指定索引的武器 + /// + public bool ExchangeByIndex(int index) + { + if (index == ActiveIndex && ActiveWeapon != null) return true; + if (index < 0 || index > Weapons.Length) return false; + var weapon = Weapons[index]; + if (weapon == null) return false; + + //将上一把武器放到背后 + if (ActiveWeapon != null) + { + var tempParent = ActiveWeapon.GetParentOrNull(); + if (tempParent != null) + { + tempParent.RemoveChild(ActiveWeapon); + Master.BackMountPoint.AddChild(ActiveWeapon); + Master.OnPutBackMount(ActiveWeapon, ActiveIndex); + ActiveWeapon.Conceal(); + } + } + + //更改父节点 + var parent = weapon.GetParentOrNull(); + if (parent == null) + { + Master.MountPoint.AddChild(weapon); + } + else if (parent != Master.MountPoint) + { + parent.RemoveChild(weapon); + Master.MountPoint.AddChild(weapon); + } + + weapon.Position = Vector2.Zero; + weapon.Scale = Vector2.One; + weapon.RotationDegrees = 0; + weapon.Visible = true; + ActiveWeapon = weapon; + ActiveIndex = index; + ActiveWeapon.Active(); + return true; + } +} diff --git a/DungeonShooting_Godot/src/game/activity/shell/Shell.cs b/DungeonShooting_Godot/src/game/activity/shell/Shell.cs new file mode 100644 index 0000000..310ee81 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/shell/Shell.cs @@ -0,0 +1,22 @@ + +using Godot; + +/// +/// 弹壳类 +/// +[Tool, GlobalClass] +public partial class Shell : ActivityObject +{ + public override void OnInit() + { + base.OnInit(); + ShadowOffset = new Vector2(0, 1); + ThrowCollisionSize = new Vector2(5, 5); + } + + protected override void OnThrowOver() + { + EnableBehavior = false; + Collision.QueueFree(); + } +} \ 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 new file mode 100644 index 0000000..6122436 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs @@ -0,0 +1,1183 @@ +using Godot; +using System; +using System.Collections.Generic; +using Config; + +/// +/// 武器的基类 +/// +public abstract partial class Weapon : ActivityObject +{ + /// + /// 开火回调事件 + /// + public event Action FireEvent; + + /// + /// 武器属性数据 + /// + public ExcelConfig.Weapon Attribute => _weaponAttribute; + private ExcelConfig.Weapon _weaponAttribute; + private ExcelConfig.Weapon _playerWeaponAttribute; + private ExcelConfig.Weapon _aiWeaponAttribute; + + /// + /// 武器攻击的目标阵营 + /// + public CampEnum TargetCamp { get; set; } + + /// + /// 该武器的拥有者 + /// + public Role Master { get; private set; } + + /// + /// 当前弹夹弹药剩余量 + /// + public int CurrAmmo { get; private set; } + + /// + /// 剩余弹药量(备用弹药) + /// + public int ResidueAmmo { get; private set; } + + /// + /// 武器管的开火点 + /// + [Export, ExportFillNode] + public Marker2D FirePoint { get; set; } + + /// + /// 弹壳抛出的点 + /// + [Export, ExportFillNode] + public Marker2D ShellPoint { get; set; } + + /// + /// 武器的当前散射半径 + /// + public float CurrScatteringRange { get; private set; } = 0; + + /// + /// 是否在换弹中 + /// + /// + public bool Reloading { get; private set; } = false; + + /// + /// 换弹计时器 + /// + public float ReloadTimer { get; private set; } = 0; + + /// + /// 换弹进度 (0 - 1) + /// + public float ReloadProgress + { + get + { + if (Attribute.AloneReload) + { + var num = 1f / Attribute.AmmoCapacity; + return num * (Attribute.AmmoCapacity - CurrAmmo - 1) + num * (ReloadTimer / Attribute.ReloadTime); + } + + return ReloadTimer / Attribute.ReloadTime; + } + } + + /// + /// 返回是否在蓄力中, + /// 注意, 属性仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 false + /// + public bool IsCharging => _looseShootFlag; + + /// + /// 返回武器是否在武器袋中 + /// + public bool IsInHolster => Master != null; + + /// + /// 返回是否真正使用该武器 + /// + public bool IsActive => Master != null && Master.Holster.ActiveWeapon == this; + + /// + /// 动画播放器 + /// + [Export, ExportFillNode] + public AnimationPlayer AnimationPlayer { get; set; } + + /// + /// 是否自动播放 SpriteFrames 的动画 + /// + public bool IsAutoPlaySpriteFrames { get; set; } = true; + + //-------------------------------------------------------------------------------------------- + + //是否按下 + private bool _triggerFlag = false; + + //扳机计时器 + private float _triggerTimer = 0; + + //开火前延时时间 + private float _delayedTime = 0; + + //开火间隙时间 + private float _fireInterval = 0; + + //开火武器口角度 + private float _fireAngle = 0; + + //攻击冷却计时 + private float _attackTimer = 0; + + //攻击状态 + private bool _attackFlag = false; + + //按下的时间 + private float _downTimer = 0; + + //松开的时间 + private float _upTimer = 0; + + //连发次数 + private float _continuousCount = 0; + + //连发状态记录 + private bool _continuousShootFlag = false; + + //松开扳机是否开火 + private bool _looseShootFlag = false; + + //蓄力攻击时长 + private float _chargeTime = 0; + + //是否需要重置武器数据 + private bool _dirtyFlag = false; + + //当前后坐力导致的偏移长度 + private float _currBacklashLength = 0; + + // ---------------------------------------------- + private uint _tempLayer; + + private static bool _init = false; + private static Dictionary _weaponAttributeMap = + new Dictionary(); + + /// + /// 初始化武器属性数据 + /// + public static void InitWeaponAttribute() + { + if (_init) + { + return; + } + + _init = true; + foreach (var weaponAttr in ExcelConfig.Weapon_List) + { + if (string.IsNullOrEmpty(weaponAttr.WeaponId)) + { + if (!_weaponAttributeMap.TryAdd(weaponAttr.WeaponId, weaponAttr)) + { + GD.PrintErr("发现重复注册的武器属性: " + weaponAttr.Id); + } + } + } + } + + private static ExcelConfig.Weapon _GetWeaponAttribute(string itemId) + { + if (_weaponAttributeMap.TryGetValue(itemId, out var attr)) + { + return attr; + } + + throw new Exception($"武器'{itemId}'没有在 Weapon 表中配置属性数据!"); + } + + public override void OnInit() + { + InitWeapon(_GetWeaponAttribute(ItemId)); + } + + /// + /// 初始化武器属性 + /// + public void InitWeapon(ExcelConfig.Weapon attribute) + { + _playerWeaponAttribute = attribute; + _weaponAttribute = attribute; + if (!string.IsNullOrEmpty(attribute.AiUseAttributeId)) + { + _aiWeaponAttribute = ExcelConfig.Weapon_Map[attribute.AiUseAttributeId]; + } + else + { + _aiWeaponAttribute = attribute; + } + //未完成 + //AnimatedSprite.Position = Attribute.ThrowSpritePosition; + + if (Attribute.AmmoCapacity > Attribute.MaxAmmoCapacity) + { + Attribute.AmmoCapacity = Attribute.MaxAmmoCapacity; + GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + ItemId); + } + //弹药量 + CurrAmmo = Attribute.AmmoCapacity; + //剩余弹药量 + ResidueAmmo = Mathf.Min(Attribute.StandbyAmmoCapacity + CurrAmmo, Attribute.MaxAmmoCapacity) - CurrAmmo; + + ThrowCollisionSize = attribute.ThrowCollisionSize.AsVector2(); + } + + /// + /// 单次开火时调用的函数 + /// + protected abstract void OnFire(); + + /// + /// 发射子弹时调用的函数, 每发射一枚子弹调用一次, + /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次 + /// + /// 开火时枪口旋转角度 + protected abstract void OnShoot(float fireRotation); + + /// + /// 当按下扳机时调用 + /// + protected virtual void OnDownTrigger() + { + } + + /// + /// 当松开扳机时调用 + /// + protected virtual void OnUpTrigger() + { + } + + /// + /// 开始蓄力时调用, + /// 注意, 该函数仅在 Attribute.LooseShoot == false 时才能被调用 + /// + protected virtual void OnStartCharge() + { + } + + /// + /// 当开始换弹时调用 + /// + protected virtual void OnReload() + { + } + + /// + /// 当换弹完成时调用 + /// + protected virtual void OnReloadFinish() + { + } + + /// + /// 当武器被拾起时调用 + /// + /// 拾起该武器的角色 + protected virtual void OnPickUp(Role master) + { + } + + /// + /// 当武器从武器袋中移除时调用 + /// + protected virtual void OnRemove() + { + } + + /// + /// 当武器被激活时调用, 也就是使用当武器时调用 + /// + protected virtual void OnActive() + { + } + + /// + /// 当武器被收起时调用 + /// + protected virtual void OnConceal() + { + } + + /// + /// 射击时调用, 返回消耗弹药数量, 默认为1, 如果返回为 0, 则不消耗弹药 + /// + protected virtual int UseAmmoCount() + { + return 1; + } + + public override void EnterTree() + { + base.EnterTree(); + //收集落在地上的武器 + if (IsInGround()) + { + World.Weapon_UnclaimedWeapons.Add(this); + } + } + + public override void ExitTree() + { + base.ExitTree(); + World.Weapon_UnclaimedWeapons.Remove(this); + } + + protected override void Process(float delta) + { + //GD.Print("AnimatedSprite: " + AnimatedSprite.Position); + //这把武器被扔在地上, 或者当前武器没有被使用 + if (Master == null || Master.Holster.ActiveWeapon != this) + { + //_triggerTimer + _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0; + //攻击冷却计时 + _attackTimer = _attackTimer > 0 ? _attackTimer - delta : 0; + //武器的当前散射半径 + CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, + Attribute.StartScatteringRange); + //松开扳机 + if (_triggerFlag || _downTimer > 0) + { + UpTrigger(); + _downTimer = 0; + } + + _triggerFlag = false; + + //重置数据 + if (_dirtyFlag) + { + _dirtyFlag = false; + Reloading = false; + ReloadTimer = 0; + _attackFlag = false; + _continuousCount = 0; + _delayedTime = 0; + _upTimer = 0; + _looseShootFlag = false; + _chargeTime = 0; + } + } + else //正在使用中 + { + _dirtyFlag = true; + //换弹 + if (Reloading) + { + ReloadTimer -= delta; + if (ReloadTimer <= 0) + { + ReloadSuccess(); + } + } + + // 攻击的计时器 + if (_attackTimer > 0) + { + _attackTimer -= delta; + if (_attackTimer < 0) + { + _delayedTime += _attackTimer; + _attackTimer = 0; + //枪口默认角度 + RotationDegrees = -Attribute.DefaultAngle; + } + } + else if (_delayedTime > 0) //攻击延时 + { + _delayedTime -= delta; + if (_attackTimer < 0) + { + _delayedTime = 0; + } + } + + //扳机判定 + if (_triggerFlag) + { + if (_looseShootFlag) //蓄力时长 + { + _chargeTime += delta; + } + + _downTimer += delta; + if (_upTimer > 0) //第一帧按下扳机 + { + DownTrigger(); + _upTimer = 0; + } + } + else + { + _upTimer += delta; + if (_downTimer > 0) //第一帧松开扳机 + { + UpTrigger(); + _downTimer = 0; + } + } + + //连发判断 + if (!_looseShootFlag && _continuousCount > 0 && _delayedTime <= 0 && _attackTimer <= 0) + { + //连发开火 + TriggerFire(); + } + + if (!_attackFlag && _attackTimer <= 0) + { + if (_upTimer >= Attribute.ScatteringRangeBackTime) + { + CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, + Attribute.StartScatteringRange); + } + } + + _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0; + _triggerFlag = false; + _attackFlag = false; + + //武器身回归 + //Position = Position.MoveToward(Vector2.Zero, Attribute.BacklashRegressionSpeed * delta).Rotated(Rotation); + _currBacklashLength = Mathf.MoveToward(_currBacklashLength, 0, Attribute.BacklashRegressionSpeed * delta); + Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation); + if (_attackTimer > 0) + { + RotationDegrees = Mathf.Lerp( + _fireAngle, -Attribute.DefaultAngle, + Mathf.Clamp((_fireInterval - _attackTimer) * Attribute.UpliftAngleRestore / _fireInterval, 0, 1) + ); + } + } + } + + /// + /// 返回武器是否在地上 + /// + /// + public bool IsInGround() + { + return Master == null && GetParent() == GameApplication.Instance.World.NormalLayer; + } + + /// + /// 扳机函数, 调用即视为按下扳机 + /// + public void Trigger() + { + //这一帧已经按过了, 不需要再按下 + if (_triggerFlag) return; + + //是否第一帧按下 + var justDown = _downTimer == 0; + //是否能发射 + var flag = false; + if (_continuousCount <= 0) //不能处于连发状态下 + { + if (Attribute.ContinuousShoot) //自动射击 + { + if (_triggerTimer > 0) + { + if (_continuousShootFlag) + { + flag = true; + } + } + else + { + flag = true; + if (_delayedTime <= 0 && _attackTimer <= 0) + { + _continuousShootFlag = true; + } + } + } + else //半自动 + { + if (justDown && _triggerTimer <= 0 && _attackTimer <= 0) + { + flag = true; + } + } + } + + if (flag) + { + var fireFlag = true; //是否能开火 + if (Reloading) //换弹中 + { + if (CurrAmmo > 0 && Attribute.AloneReload && Attribute.AloneReloadCanShoot) //立即停止换弹 + { + Reloading = false; + ReloadTimer = 0; + } + else + { + fireFlag = false; + } + } + else if (CurrAmmo <= 0) //子弹不够 + { + fireFlag = false; + if (justDown) + { + //第一帧按下, 触发换弹 + Reload(); + } + } + + if (fireFlag) + { + if (justDown) + { + //开火前延时 + _delayedTime = Attribute.DelayedTime; + //扳机按下间隔 + _triggerTimer = Attribute.TriggerInterval; + //连发数量 + if (!Attribute.ContinuousShoot) + { + _continuousCount = + Utils.RandomRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount); + } + } + + if (_delayedTime <= 0 && _attackTimer <= 0) + { + if (Attribute.LooseShoot) //松发开火 + { + _looseShootFlag = true; + OnStartCharge(); + } + else + { + //开火 + TriggerFire(); + } + } + + _attackFlag = true; + } + + } + + _triggerFlag = true; + } + + /// + /// 返回是否按下扳机 + /// + public bool IsPressTrigger() + { + return _triggerFlag; + } + + /// + /// 获取本次扳机按下的时长, 单位: 秒 + /// + public float GetTriggerDownTime() + { + return _downTimer; + } + + /// + /// 获取扳机蓄力时长, 计算按下扳机后从可以开火到当前一共经过了多长时间, 可用于计算蓄力攻击 + /// 注意, 该函数仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 0 + /// + public float GetTriggerChargeTime() + { + return _chargeTime; + } + + /// + /// 获取延时射击倒计时, 单位: 秒 + /// + public float GetDelayedAttackTime() + { + return _delayedTime; + } + + /// + /// 刚按下扳机 + /// + private void DownTrigger() + { + OnDownTrigger(); + } + + /// + /// 刚松开扳机 + /// + private void UpTrigger() + { + _continuousShootFlag = false; + if (_delayedTime > 0) + { + _continuousCount = 0; + } + + //松发开火执行 + if (_looseShootFlag) + { + _looseShootFlag = false; + if (_chargeTime >= Attribute.MinChargeTime) //判断蓄力是否够了 + { + TriggerFire(); + } + else //不能攻击 + { + _continuousCount = 0; + } + _chargeTime = 0; + } + + OnUpTrigger(); + } + + /// + /// 触发开火 + /// + private void TriggerFire() + { + _continuousCount = _continuousCount > 0 ? _continuousCount - 1 : 0; + + //减子弹数量 + if (_playerWeaponAttribute != _weaponAttribute) //Ai使用该武器, 有一定概率不消耗弹药 + { + if (Utils.RandomRangeFloat(0, 1) < _weaponAttribute.AiAmmoConsumptionProbability) //触发消耗弹药 + { + CurrAmmo -= UseAmmoCount(); + } + } + else + { + CurrAmmo -= UseAmmoCount(); + } + + //开火间隙 + _fireInterval = 60 / Attribute.StartFiringSpeed; + //攻击冷却 + _attackTimer += _fireInterval; + + //播放开火动画 + if (IsAutoPlaySpriteFrames) + { + PlaySpriteAnimation(AnimatorNames.Fire); + } + //触发开火函数 + OnFire(); + + //开火发射的子弹数量 + var bulletCount = Utils.RandomRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount); + //武器口角度 + var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle(); + + //先算武器口方向 + var tempRotation = Utils.RandomRangeFloat(-angle, angle); + var tempAngle = Mathf.RadToDeg(tempRotation); + + //开火时枪口角度 + var fireRotation = Mathf.DegToRad(Master.MountPoint.RealRotationDegrees) + tempRotation; + //创建子弹 + for (int i = 0; i < bulletCount; i++) + { + //发射子弹 + OnShoot(fireRotation); + } + + //当前的散射半径 + CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, + Attribute.FinalScatteringRange); + //武器的旋转角度 + tempAngle -= Attribute.UpliftAngle; + RotationDegrees = tempAngle; + _fireAngle = tempAngle; + + //武器身位置 + var max = Mathf.Abs(Mathf.Max(Attribute.MaxBacklash, Attribute.MinBacklash)); + _currBacklashLength = Mathf.Clamp( + _currBacklashLength - Utils.RandomRangeFloat(Attribute.MinBacklash, Attribute.MaxBacklash), + -max, max + ); + Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation); + + if (FireEvent != null) + { + FireEvent(this); + } + } + + /// + /// 获取武器攻击的目标层级 + /// + /// + public uint GetAttackLayer() + { + return Master != null ? Master.AttackLayer : Role.DefaultAttackLayer; + } + + /// + /// 返回弹药是否到达上限 + /// + public bool IsAmmoFull() + { + return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity; + } + + /// + /// 返回弹夹是否打空 + /// + public bool IsAmmoEmpty() + { + return CurrAmmo == 0; + } + + /// + /// 返回是否弹药耗尽 + /// + public bool IsTotalAmmoEmpty() + { + return CurrAmmo + ResidueAmmo == 0; + } + + /// + /// 强制修改当前弹夹弹药量 + /// + public void SetCurrAmmo(int count) + { + CurrAmmo = Mathf.Clamp(count, 0, Attribute.AmmoCapacity); + } + + /// + /// 强制修改备用弹药量 + /// + public void SetResidueAmmo(int count) + { + ResidueAmmo = Mathf.Clamp(count, 0, Attribute.MaxAmmoCapacity - CurrAmmo); + } + + /// + /// 强制修改弹药量, 优先改动备用弹药 + /// + public void SetTotalAmmo(int total) + { + if (total < 0) + { + return; + } + var totalAmmo = CurrAmmo + ResidueAmmo; + if (totalAmmo == total) + { + return; + } + + if (total > totalAmmo) //弹药增加 + { + ResidueAmmo = Mathf.Min(total - CurrAmmo, Attribute.MaxAmmoCapacity - CurrAmmo); + } + else //弹药减少 + { + if (CurrAmmo < total) + { + ResidueAmmo = total - CurrAmmo; + } + else + { + CurrAmmo = total; + ResidueAmmo = 0; + } + } + } + + /// + /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量 + /// + /// 弹药数量 + private int PickUpAmmo(int count) + { + var num = ResidueAmmo; + ResidueAmmo = Mathf.Min(ResidueAmmo + count, Attribute.MaxAmmoCapacity - CurrAmmo); + return count - ResidueAmmo + num; + } + + /// + /// 触发换弹 + /// + public void Reload() + { + if (CurrAmmo < Attribute.AmmoCapacity && ResidueAmmo > 0 && !Reloading) + { + Reloading = true; + ReloadTimer = Attribute.ReloadTime; + //播放换弹动画 + if (IsAutoPlaySpriteFrames) + { + PlaySpriteAnimation(AnimatorNames.Reload); + } + OnReload(); + } + } + + /// + /// 换弹计时器时间到, 执行换弹操作 + /// + private void ReloadSuccess() + { + if (Attribute.AloneReload) //单独装填 + { + if (ResidueAmmo >= Attribute.AloneReloadCount) //剩余子弹充足 + { + if (CurrAmmo + Attribute.AloneReloadCount <= Attribute.AmmoCapacity) + { + ResidueAmmo -= Attribute.AloneReloadCount; + CurrAmmo += Attribute.AloneReloadCount; + } + else //子弹满了 + { + var num = Attribute.AmmoCapacity - CurrAmmo; + CurrAmmo = Attribute.AmmoCapacity; + ResidueAmmo -= num; + } + } + else if (ResidueAmmo != 0) //剩余子弹不足 + { + if (ResidueAmmo + CurrAmmo <= Attribute.AmmoCapacity) + { + CurrAmmo += ResidueAmmo; + ResidueAmmo = 0; + } + else //子弹满了 + { + var num = Attribute.AmmoCapacity - CurrAmmo; + CurrAmmo = Attribute.AmmoCapacity; + ResidueAmmo -= num; + } + } + + if (ResidueAmmo == 0 || CurrAmmo == Attribute.AmmoCapacity) //换弹结束 + { + Reloading = false; + ReloadTimer = 0; + OnReloadFinish(); + } + else + { + ReloadTimer = Attribute.ReloadTime; + //播放换弹动画 + if (IsAutoPlaySpriteFrames) + { + PlaySpriteAnimation(AnimatorNames.Reload); + } + OnReload(); + } + } + else //换弹结束 + { + if (CurrAmmo + ResidueAmmo >= Attribute.AmmoCapacity) + { + ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo; + CurrAmmo = Attribute.AmmoCapacity; + } + else + { + CurrAmmo += ResidueAmmo; + ResidueAmmo = 0; + } + + Reloading = false; + ReloadTimer = 0; + OnReloadFinish(); + } + } + + //播放动画 + private void PlaySpriteAnimation(string name) + { + var spriteFrames = AnimatedSprite.SpriteFrames; + if (spriteFrames != null && spriteFrames.HasAnimation(name)) + { + AnimatedSprite.Play(name); + } + } + + public override CheckInteractiveResult CheckInteractive(ActivityObject master) + { + var result = new CheckInteractiveResult(this); + + if (master is Role roleMaster) //碰到角色 + { + if (Master == null) + { + var masterWeapon = roleMaster.Holster.ActiveWeapon; + //查找是否有同类型武器 + var index = roleMaster.Holster.FindWeapon(ItemId); + if (index != -1) //如果有这个武器 + { + if (CurrAmmo + ResidueAmmo != 0) //子弹不为空 + { + var targetWeapon = roleMaster.Holster.GetWeapon(index); + if (!targetWeapon.IsAmmoFull()) //背包里面的武器子弹未满 + { + //可以互动拾起弹药 + result.CanInteractive = true; + result.Message = Attribute.Name; + result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_bullet_png; + return result; + } + } + } + else //没有武器 + { + if (roleMaster.Holster.CanPickupWeapon(this)) //能拾起武器 + { + //可以互动, 拾起武器 + result.CanInteractive = true; + result.Message = Attribute.Name; + result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_pickup_png; + return result; + } + else if (masterWeapon != null && masterWeapon.Attribute.WeightType == Attribute.WeightType) //替换武器 + { + //可以互动, 切换武器 + result.CanInteractive = true; + result.Message = Attribute.Name; + result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_replace_png; + return result; + } + } + } + } + + return result; + } + + public override void Interactive(ActivityObject master) + { + if (master is Role roleMaster) //与role互动 + { + var holster = roleMaster.Holster; + //查找是否有同类型武器 + var index = holster.FindWeapon(ItemId); + if (index != -1) //如果有这个武器 + { + if (CurrAmmo + ResidueAmmo == 0) //没有子弹了 + { + return; + } + + var weapon = holster.GetWeapon(index); + //子弹上限 + var maxCount = Attribute.MaxAmmoCapacity; + //是否捡到子弹 + var flag = false; + if (ResidueAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount) + { + var count = weapon.PickUpAmmo(ResidueAmmo); + if (count != ResidueAmmo) + { + ResidueAmmo = count; + flag = true; + } + } + + if (CurrAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount) + { + var count = weapon.PickUpAmmo(CurrAmmo); + if (count != CurrAmmo) + { + CurrAmmo = count; + flag = true; + } + } + + //播放互动效果 + if (flag) + { + Throw(GlobalPosition, 0, Utils.RandomRangeInt(20, 50), Vector2.Zero, Utils.RandomRangeInt(-180, 180)); + } + } + else //没有武器 + { + if (holster.PickupWeapon(this) == -1) + { + //替换武器 + roleMaster.ThrowWeapon(); + roleMaster.PickUpWeapon(this); + } + } + } + } + + /// + /// 获取当前武器真实的旋转角度(弧度制), 由于武器旋转时加入了旋转吸附, 所以需要通过该函数来来知道当前武器的真实旋转角度 + /// + public float GetRealGlobalRotation() + { + return Mathf.DegToRad(Master.MountPoint.RealRotationDegrees) + Rotation; + } + + /// + /// 触发扔掉武器抛出的效果, 并不会管武器是否在武器袋中 + /// + /// 触发扔掉该武器的的角色 + public void ThrowWeapon(Role master) + { + ThrowWeapon(master, master.GlobalPosition); + } + + /// + /// 触发扔掉武器抛出的效果, 并不会管武器是否在武器袋中 + /// + /// 触发扔掉该武器的的角色 + /// 投抛起始位置 + public void ThrowWeapon(Role master, Vector2 startPosition) + { + //阴影偏移 + ShadowOffset = new Vector2(0, 2); + + if (master.Face == FaceDirection.Left) + { + Scale *= new Vector2(1, -1); + } + + var angle = master.MountPoint.GlobalRotationDegrees; + GlobalRotationDegrees = angle; + + //继承role的移动速度 + InheritVelocity(master); + + var startHeight = -master.MountPoint.Position.Y; + var direction = angle + Utils.RandomRangeInt(-20, 20); + var velocity = new Vector2(20, 0).Rotated(direction * Mathf.Pi / 180); + var yf = Utils.RandomRangeInt(50, 70); + var rotate = Utils.RandomRangeInt(-60, 60); + Throw(startPosition, startHeight, yf, velocity, rotate); + } + + protected override void OnThrowStart() + { + //禁用碰撞 + //Collision.Disabled = true; + AnimationPlayer.Play(AnimatorNames.Floodlight); + } + + protected override void OnThrowOver() + { + //启用碰撞 + //Collision.Disabled = false; + AnimationPlayer.Play(AnimatorNames.Floodlight); + } + + /// + /// 触发拾起到 Holster, 这个函数由 Holster 对象调用 + /// + public void PickUpWeapon(Role master) + { + Master = master; + if (master.IsAi) + { + _weaponAttribute = _aiWeaponAttribute; + } + else + { + _weaponAttribute = _playerWeaponAttribute; + } + //停止动画 + AnimationPlayer.Stop(); + //清除泛白效果 + SetBlendSchedule(0); + ZIndex = 0; + //禁用碰撞 + //Collision.Disabled = true; + //修改层级 + _tempLayer = CollisionLayer; + CollisionLayer = PhysicsLayer.InHand; + //清除 Ai 拾起标记 + RemoveSign(SignNames.AiFindWeaponSign); + OnPickUp(master); + } + + /// + /// 触发从 Holster 中移除, 这个函数由 Holster 对象调用 + /// + public void RemoveAt() + { + Master = null; + CollisionLayer = _tempLayer; + _weaponAttribute = _playerWeaponAttribute; + //未完成 + //AnimatedSprite.Position = Attribute.ThrowSpritePosition; + //清除 Ai 拾起标记 + RemoveSign(SignNames.AiFindWeaponSign); + OnRemove(); + } + + /// + /// 触发启用武器 + /// + public void Active() + { + //调整阴影 + ShadowOffset = new Vector2(0, Master.GlobalPosition.Y - GlobalPosition.Y); + //枪口默认抬起角度 + RotationDegrees = -Attribute.DefaultAngle; + ShowShadowSprite(); + OnActive(); + } + + /// + /// 触发收起武器 + /// + public void Conceal() + { + HideShadowSprite(); + OnConceal(); + } + + //-------------------------- ----- 子弹相关 ----------------------------- + + /// + /// 投抛弹壳的默认实现方式, shellId为弹壳id, 不需要前缀 + /// + protected ActivityObject ThrowShell(string shellId) + { + var shellPosition = Master.MountPoint.Position + ShellPoint.Position; + var startPos = ShellPoint.GlobalPosition; + var startHeight = -shellPosition.Y; + startPos.Y += startHeight; + var direction = GlobalRotationDegrees + Utils.RandomRangeInt(-30, 30) + 180; + var verticalSpeed = Utils.RandomRangeInt(60, 120); + var velocity = new Vector2(Utils.RandomRangeInt(20, 60), 0).Rotated(direction * Mathf.Pi / 180); + var rotate = Utils.RandomRangeInt(-720, 720); + var shell = Create(ActivityIdPrefix.Shell + shellId); + shell.Rotation = Master.MountPoint.RealRotation; + shell.InheritVelocity(Master); + shell.Throw(startPos, startHeight, verticalSpeed, velocity, rotate); + return shell; + } + + //-------------------------------- Ai相关 ----------------------------- + + /// + /// 获取 Ai 对于该武器的评分, 评分越高, 代表 Ai 会越优先选择该武器, 如果为 -1, 则表示 Ai 不会使用该武器 + /// + public float GetAiScore() + { + return 1; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/weapon/WeaponWeightType.cs b/DungeonShooting_Godot/src/game/activity/weapon/WeaponWeightType.cs new file mode 100644 index 0000000..5528683 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/weapon/WeaponWeightType.cs @@ -0,0 +1,19 @@ + +/// +/// 根据重量划分的武器类型 +/// +public enum WeaponWeightType +{ + /// + /// 副武器 + /// + DeputyWeapon = 1, + /// + /// 主武器 + /// + MainWeapon = 2, + /// + /// 重型武器 + /// + HeavyWeapon = 3 +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs b/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs new file mode 100644 index 0000000..4267f78 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/weapon/gun/Gun.cs @@ -0,0 +1,197 @@ +using Godot; + +/// +/// 普通的枪 +/// +[Tool, GlobalClass] +public partial class Gun : Weapon +{ + // //步枪属性数据 + // private class RifleAttribute : WeaponAttribute + // { + // public RifleAttribute() + // { + // Name = "步枪"; + // Icon = ResourcePath.resource_sprite_gun_gun4_png; + // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0001_tres; + // Weight = 40; + // ThrowSpritePosition = new Vector2(0.4f, -2.6f); + // StartFiringSpeed = 480; + // StartScatteringRange = 30; + // FinalScatteringRange = 90; + // ScatteringRangeAddValue = 2f; + // ScatteringRangeBackSpeed = 40; + // //连发 + // ContinuousShoot = true; + // AmmoCapacity = 30; + // StandbyAmmoCapacity = 30 * 3; + // MaxAmmoCapacity = 30 * 3; + // //扳机检测间隔 + // TriggerInterval = 0f; + // + // //开火前延时 + // DelayedTime = 0f; + // //攻击距离 + // MinDistance = 300; + // MaxDistance = 400; + // //发射子弹数量 + // MinFireBulletCount = 1; + // MaxFireBulletCount = 1; + // //抬起角度 + // UpliftAngle = 10; + // //开火位置 + // FirePosition = new Vector2(21, -3f); + // //精灵位置 + // SpritePosition = new Vector2(6, -1); + // ShellPosition = new Vector2(7.5f, -4.5f); + // + // AiUseAttribute = Clone(); + // AiUseAttribute.AiTargetLockingTime = 0.5f; + // AiUseAttribute.TriggerInterval = 3f; + // AiUseAttribute.ContinuousShoot = false; + // AiUseAttribute.MinContinuousCount = 3; + // AiUseAttribute.MaxContinuousCount = 3; + // } + // } + // + // //手枪属性数据 + // private class PistolAttribute : WeaponAttribute + // { + // public PistolAttribute() + // { + // Name = "手枪"; + // Icon = ResourcePath.resource_sprite_gun_gun3_png; + // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0003_tres; + // Weight = 20; + // ThrowSpritePosition = new Vector2(0.4f, -2.6f); + // WeightType = WeaponWeightType.DeputyWeapon; + // StartFiringSpeed = 300; + // FinalFiringSpeed = 300; + // StartScatteringRange = 5; + // FinalScatteringRange = 60; + // ScatteringRangeAddValue = 8f; + // ScatteringRangeBackSpeed = 40; + // ScatteringRangeBackTime = 0.5f; + // //连发 + // ContinuousShoot = false; + // AmmoCapacity = 12; + // StandbyAmmoCapacity = 72; + // MaxAmmoCapacity = 72; + // //扳机检测间隔 + // TriggerInterval = 0.1f; + // //连发数量 + // MinContinuousCount = 1; + // MaxContinuousCount = 1; + // //开火前延时 + // DelayedTime = 0f; + // //攻击距离 + // MinDistance = 250; + // MaxDistance = 300; + // //发射子弹数量 + // MinFireBulletCount = 1; + // MaxFireBulletCount = 1; + // //抬起角度 + // UpliftAngle = 20; + // //开火位置 + // FirePosition = new Vector2(13, -2); + // //精灵位置 + // SpritePosition = new Vector2(5, 0); + // ShellPosition = new Vector2(5, -3); + // + // AiUseAttribute = Clone(); + // AiUseAttribute.AiTargetLockingTime = 1f; + // AiUseAttribute.TriggerInterval = 2f; + // } + // } + // + // //狙击步枪 + // private class SniperRifleAttribute : WeaponAttribute + // { + // public SniperRifleAttribute() + // { + // Name = "狙击步枪"; + // Icon = ResourcePath.resource_sprite_gun_gun3_png; + // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0005_tres; + // Weight = 20; + // ThrowSpritePosition = new Vector2(0.4f, -2.6f); + // WeightType = WeaponWeightType.DeputyWeapon; + // StartFiringSpeed = 60; + // FinalFiringSpeed = 60; + // StartScatteringRange = 0; + // FinalScatteringRange = 20; + // ScatteringRangeAddValue = 10; + // ScatteringRangeBackSpeed = 10; + // //连发 + // ContinuousShoot = false; + // AmmoCapacity = 10; + // StandbyAmmoCapacity = 50; + // MaxAmmoCapacity = 50; + // //扳机检测间隔 + // TriggerInterval = 0.1f; + // //连发数量 + // MinContinuousCount = 1; + // MaxContinuousCount = 1; + // //开火前延时 + // DelayedTime = 0f; + // //攻击距离 + // MinDistance = 600; + // MaxDistance = 800; + // //发射子弹数量 + // MinFireBulletCount = 1; + // MaxFireBulletCount = 1; + // //抬起角度 + // UpliftAngle = 15; + // UpliftAngleRestore = 3.5f; + // //开火位置 + // FirePosition = new Vector2(28, -3.5f); + // //精灵位置 + // SpritePosition = new Vector2(9, 0); + // ShellPosition = new Vector2(7, -3.5f); + // MinBacklash = 6; + // MinBacklash = 8; + // BacklashRegressionSpeed = 20; + // ReloadTime = 3.5f; + // + // AiUseAttribute = Clone(); + // AiUseAttribute.AiTargetLockingTime = 1f; + // AiUseAttribute.TriggerInterval = 2f; + // } + // } + + protected override void OnFire() + { + //创建一个弹壳 + ThrowShell("0001"); + + if (Master == Player.Current) + { + //创建抖动 + GameCamera.Main.DirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 2f); + } + + //创建开火特效 + var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_ShotFire_tscn); + var sprite = packedScene.Instantiate(); + sprite.GlobalPosition = FirePoint.GlobalPosition; + sprite.GlobalRotation = FirePoint.GlobalRotation; + sprite.AddToActivityRoot(RoomLayerEnum.YSortLayer); + + //播放射击音效 + SoundManager.PlaySoundEffectPosition(ResourcePath.resource_sound_sfx_ordinaryBullet2_mp3, GameApplication.Instance.ViewToGlobalPosition(GlobalPosition), -8); + } + + protected override void OnShoot(float fireRotation) + { + //创建子弹 + var bullet = ActivityObject.Create(Attribute.BulletId); + bullet.Init( + this, + 350, + Utils.RandomRangeFloat(Attribute.MinDistance, Attribute.MaxDistance), + FirePoint.GlobalPosition, + fireRotation, + GetAttackLayer() + ); + bullet.PutDown(RoomLayerEnum.YSortLayer); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/weapon/gun/Shotgun.cs b/DungeonShooting_Godot/src/game/activity/weapon/gun/Shotgun.cs new file mode 100644 index 0000000..4490496 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/weapon/gun/Shotgun.cs @@ -0,0 +1,105 @@ +using Godot; + +[Tool, GlobalClass] +public partial class Shotgun : Weapon +{ + + // private class ShotgunAttribute : WeaponAttribute + // { + // public ShotgunAttribute() + // { + // Name = "霰弹枪"; + // Icon = ResourcePath.resource_sprite_gun_gun2_png; + // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0002_tres; + // Weight = 40; + // ThrowSpritePosition = new Vector2(0.4f, -2.6f); + // StartFiringSpeed = 400; + // StartScatteringRange = 30; + // FinalScatteringRange = 90; + // ScatteringRangeAddValue = 50f; + // ScatteringRangeBackSpeed = 50; + // //连发 + // ContinuousShoot = false; + // AmmoCapacity = 7; + // StandbyAmmoCapacity = 42; + // MaxAmmoCapacity = 42; + // AloneReload = true; + // AloneReloadCanShoot = true; + // ReloadTime = 0.6f; + // //连发数量 + // MinContinuousCount = 1; + // MaxContinuousCount = 1; + // //开火前延时 + // DelayedTime = 0f; + // //攻击距离 + // MinDistance = 200; + // MaxDistance = 250; + // //发射子弹数量 + // MinFireBulletCount = 5; + // MaxFireBulletCount = 5; + // //抬起角度 + // UpliftAngle = 15; + // MaxBacklash = 6; + // MinBacklash = 5; + // //开火位置 + // FirePosition = new Vector2(22, -4); + // //精灵位置 + // SpritePosition = new Vector2(9, -2); + // ShellPosition = new Vector2(3, -4); + // + // BulletId = ActivityIdPrefix.Bullet + "0002"; + // + // AiUseAttribute = Clone(); + // AiUseAttribute.AiTargetLockingTime = 0.2f; + // AiUseAttribute.TriggerInterval = 3.5f; + // } + // } + + /// + /// 弹壳预制体 + /// + public PackedScene ShellPack; + + public override void OnInit() + { + base.OnInit(); + ShellPack = ResourceManager.Load(ResourcePath.prefab_weapon_shell_ShellCase_tscn); + } + + protected override void OnFire() + { + //创建一个弹壳 + ThrowShell("0001"); + + if (Master == Player.Current) + { + //创建抖动 + GameCamera.Main.DirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 2f); + } + + //创建开火特效 + var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_ShotFire_tscn); + var sprite = packedScene.Instantiate(); + sprite.GlobalPosition = FirePoint.GlobalPosition; + sprite.GlobalRotation = FirePoint.GlobalRotation; + sprite.AddToActivityRoot(RoomLayerEnum.YSortLayer); + + //播放射击音效 + SoundManager.PlaySoundEffectPosition(ResourcePath.resource_sound_sfx_ordinaryBullet3_mp3, GameApplication.Instance.ViewToGlobalPosition(GlobalPosition), -15); + } + + protected override void OnShoot(float fireRotation) + { + //创建子弹 + var bullet = ActivityObject.Create(Attribute.BulletId); + bullet.Init( + this, + Utils.RandomRangeInt(280, 380), + Utils.RandomRangeFloat(Attribute.MinDistance, Attribute.MaxDistance), + FirePoint.GlobalPosition, + fireRotation + Utils.RandomRangeFloat(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi), + GetAttackLayer() + ); + bullet.PutDown(RoomLayerEnum.YSortLayer); + } +} diff --git a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs new file mode 100644 index 0000000..4912170 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs @@ -0,0 +1,128 @@ + +using Godot; + +[Tool, GlobalClass] +public partial class Knife : Weapon +{ + // private class KnifeAttribute : WeaponAttribute + // { + // public KnifeAttribute() + // { + // Icon = ResourcePath.resource_sprite_gun_knife1_png; + // WeaponPrefab = ResourcePath.prefab_weapon_Knife_tscn; + // //攻速设置 + // StartFiringSpeed = 180; + // FinalFiringSpeed = StartFiringSpeed; + // //关闭连发 + // ContinuousShoot = false; + // //设置成松发开火 + // LooseShoot = true; + // //弹药量, 可以理解为耐久度 + // AmmoCapacity = 180; + // MaxAmmoCapacity = AmmoCapacity; + // //握把位置 + // SpritePosition = new Vector2(10, 0); + // MaxDistance = MinDistance = 35; + // //后坐力改为向前, 模拟手伸长的效果 + // MaxBacklash = -8; + // MinBacklash = -8; + // BacklashRegressionSpeed = 24; + // UpliftAngle = -95; + // + // //AiUseAttribute = Clone(); + // //AiUseAttribute.TriggerInterval = 3f; + // } + // } + + private Area2D _hitArea; + private int _attackIndex = 0; + + public override void OnInit() + { + base.OnInit(); + + _hitArea = GetNode("HitArea"); + _hitArea.Monitoring = false; + _hitArea.Monitorable = false; + _hitArea.BodyEntered += OnBodyEntered; + //禁用自动播放动画 + IsAutoPlaySpriteFrames = false; + } + + protected override void Process(float delta) + { + base.Process(delta); + if (IsActive) + { + //让碰撞节点与武器挂载节点位置保持一致, 而不跟着武器走 + _hitArea.GlobalPosition = Master.MountPoint.GlobalPosition; + } + } + + protected override void PhysicsProcess(float delta) + { + base.PhysicsProcess(delta); + //过去两个物理帧后就能关闭碰撞了 + if (++_attackIndex >= 2) + { + _hitArea.Monitoring = false; + } + } + + protected override void OnStartCharge() + { + //开始蓄力时武器角度上抬120度 + RotationDegrees = -120; + } + + protected override void OnFire() + { + GD.Print("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime()); + //更新碰撞层级 + _hitArea.CollisionMask = GetAttackLayer(); + //启用碰撞 + _hitArea.Monitoring = true; + _attackIndex = 0; + + if (IsActive) //被使用 + { + //播放挥刀特效 + SpecialEffectManager.Play( + ResourcePath.resource_spriteFrames_KnifeHit1_tres, "default", + Master.MountPoint.GlobalPosition, GlobalRotation + Mathf.Pi * 0.5f, new Vector2((int)Master.Face, 1) * AnimatedSprite.Scale, + new Vector2(17, 4), 1 + ); + } + + + if (Master == Player.Current) + { + //创建抖动 + //GameCamera.Main.ProcessDirectionalShake(Vector2.Right.Rotated(GlobalRotation - Mathf.Pi * 0.5f) * 1.5f); + } + } + + protected override void OnShoot(float fireRotation) + { + + } + + protected override int UseAmmoCount() + { + //这里要做判断, 如果没有碰到敌人, 则不消耗弹药 (耐久) + return 0; + } + + private void OnBodyEntered(Node2D body) + { + GD.Print("碰到物体: " + body.Name); + var activityObject = body.AsActivityObject(); + if (activityObject != null) + { + if (activityObject is Role role) + { + role.CallDeferred(nameof(Role.Hurt), 10, (role.GetCenterPosition() - GlobalPosition).Angle()); + } + } + } +} diff --git a/DungeonShooting_Godot/src/game/item/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/item/bullet/Bullet.cs deleted file mode 100644 index bb20329..0000000 --- a/DungeonShooting_Godot/src/game/item/bullet/Bullet.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Godot; - -/// -/// 子弹类 -/// -[Tool, GlobalClass] -public partial class Bullet : ActivityObject -{ - /// - /// 碰撞区域 - /// - [Export, ExportFillNode] - public Area2D CollisionArea { get; set; } - - /// - /// 发射该子弹的武器 - /// - public Weapon Weapon { get; private set; } - - // 最大飞行距离 - private float MaxDistance; - - // 子弹飞行速度 - private float FlySpeed; - - //当前子弹已经飞行的距离 - private float CurrFlyDistance = 0; - - public void Init(Weapon weapon, float speed, float maxDistance, Vector2 position, float rotation, uint targetLayer) - { - Weapon = weapon; - CollisionArea.CollisionMask = targetLayer; - CollisionArea.AreaEntered += OnArea2dEntered; - - //只有玩家使用该武器才能获得正常速度的子弹 - if (weapon.Master is Player) - { - FlySpeed = speed; - } - else - { - FlySpeed = speed * weapon.Attribute.AiBulletSpeedScale; - } - MaxDistance = maxDistance; - Position = position; - Rotation = rotation; - ShadowOffset = new Vector2(0, 5); - - BasisVelocity = new Vector2(FlySpeed, 0).Rotated(Rotation); - } - - protected override void PhysicsProcessOver(float delta) - { - //移动 - var lastSlideCollision = GetLastSlideCollision(); - //撞到墙 - if (lastSlideCollision != null) - { - //创建粒子特效 - var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_BulletSmoke_tscn); - var smoke = packedScene.Instantiate(); - smoke.GlobalPosition = lastSlideCollision.GetPosition(); - smoke.GlobalRotation = lastSlideCollision.GetNormal().Angle(); - smoke.AddToActivityRoot(RoomLayerEnum.YSortLayer); - - Destroy(); - return; - } - //距离太大, 自动销毁 - CurrFlyDistance += FlySpeed * delta; - if (CurrFlyDistance >= MaxDistance) - { - var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_BulletDisappear_tscn); - var node = packedScene.Instantiate(); - node.GlobalPosition = GlobalPosition; - node.AddToActivityRoot(RoomLayerEnum.YSortLayer); - - Destroy(); - } - } - - private void OnArea2dEntered(Area2D other) - { - var role = other.AsActivityObject(); - if (role != null) - { - var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_BulletDisappear_tscn); - var node = packedScene.Instantiate(); - node.GlobalPosition = GlobalPosition; - node.AddToActivityRoot(RoomLayerEnum.YSortLayer); - - role.CallDeferred(nameof(Role.Hurt), 4, Rotation); - Destroy(); - } - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/bullet/BulletAttribute.cs b/DungeonShooting_Godot/src/game/item/bullet/BulletAttribute.cs deleted file mode 100644 index aa30af1..0000000 --- a/DungeonShooting_Godot/src/game/item/bullet/BulletAttribute.cs +++ /dev/null @@ -1,5 +0,0 @@ - -public class BulletAttribute -{ - -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/package/Holster.cs b/DungeonShooting_Godot/src/game/item/package/Holster.cs deleted file mode 100644 index a487f64..0000000 --- a/DungeonShooting_Godot/src/game/item/package/Holster.cs +++ /dev/null @@ -1,369 +0,0 @@ -using System; -using System.Collections.Generic; -using Godot; - -/// -/// 角色身上的武器袋, 存储角色携带的武器 -/// -public class Holster -{ - /// - /// 归属者 - /// - public Role Master { get; } - - /// - /// 当前使用的武器对象 - /// - public Weapon ActiveWeapon { get; private set; } - - /// - /// 当前使用的武器的索引 - /// - public int ActiveIndex { get; private set; } = 0; - - /// - /// 武器袋容量 - /// - public int Capacity { get; private set; } = 0; - - /// - /// 武器插槽 - /// - public Weapon[] Weapons { get; private set; } - - public Holster(Role master) - { - Master = master; - //默认容量4 - SetCapacity(4); - } - - /// - /// 修改武器袋容量 - /// - public void SetCapacity(int capacity) - { - if (capacity < 0) - { - capacity = 0; - } - - if (capacity == Capacity) - { - return; - } - - if (Weapons == null) - { - Weapons = new Weapon[capacity]; - } - else if (Weapons.Length > capacity) //删减格子 - { - var newArray = new Weapon[capacity]; - for (var i = 0; i < Weapons.Length; i++) - { - if (i < capacity) - { - newArray[i] = Weapons[i]; - } - else - { - Master.ThrowWeapon(i); - } - } - - Weapons = newArray; - } - else //添加格子 - { - var newArray = new Weapon[capacity]; - for (var i = 0; i < Weapons.Length; i++) - { - newArray[i] = Weapons[i]; - } - Weapons = newArray; - } - Capacity = capacity; - - } - - /// - /// 返回当前武器袋是否是空的 - /// - public bool IsEmpty() - { - for (var i = 0; i < Weapons.Length; i++) - { - if (Weapons[i] != null) - { - return false; - } - } - - return true; - } - - /// - /// 返回当前武器袋是否还有空位 - /// - public bool HasVacancy() - { - for (var i = 0; i < Weapons.Length; i++) - { - if (Weapons[i] == null) - { - return true; - } - } - - return false; - } - - /// - /// 根据索引获取武器 - /// - public Weapon GetWeapon(int index) - { - if (index < 0 || index >= Weapons.Length) - { - return null; - } - return Weapons[index]; - } - - /// - /// 根据武器id查找武器袋中该武器所在的位置, 如果没有, 则返回 -1 - /// - /// 武器id - public int FindWeapon(string id) - { - for (var i = 0; i < Weapons.Length; i++) - { - var item = Weapons[i]; - if (item != null && item.ItemId == id) - { - return i; - } - } - return -1; - } - - /// - /// 通过回调函数查询武器在武器袋中的位置, 如果没有, 则返回 -1 - /// - public int FindWeapon(Func handler) - { - for (var i = 0; i < Weapons.Length; i++) - { - var item = Weapons[i]; - if (item != null && handler(item, i)) - { - return i; - } - } - return -1; - } - - /// - /// 遍历所有武器 - /// - public void ForEach(Action handler) - { - for (var i = 0; i < Weapons.Length; i++) - { - var item = Weapons[i]; - if (item != null) - { - handler(item, i); - } - } - } - - /// - /// 从武器袋中移除所有武器, 并返回 - /// - public Weapon[] GetAndClearWeapon() - { - var weapons = new List(); - for (var i = 0; i < Weapons.Length; i++) - { - var weapon = Weapons[i]; - if (weapon != null) - { - weapon.GetParent().RemoveChild(weapon); - weapon.RemoveAt(); - weapons.Add(weapon); - Weapons[i] = null; - } - } - - return weapons.ToArray(); - } - - /// - /// 返回是否能放入武器 - /// - /// 武器对象 - public bool CanPickupWeapon(Weapon weapon) - { - for (var i = 0; i < Weapons.Length; i++) - { - var item = Weapons[i]; - if (item == null) - { - return true; - } - } - return false; - } - - /// - /// 拾起武器, 存入武器袋中, 返回存放在武器袋的位置, 如果容不下这把武器, 则会返回 -1 - /// - /// 武器对象 - /// 是否立即切换到该武器, 默认 true - public int PickupWeapon(Weapon weapon, bool exchange = true) - { - //已经被拾起了 - if (weapon.Master != null) - { - return -1; - } - for (var i = 0; i < Weapons.Length; i++) - { - var item = Weapons[i]; - if (item == null) - { - weapon.Pickup(); - Weapons[i] = weapon; - weapon.PickUpWeapon(Master); - if (exchange) - { - ExchangeByIndex(i); - } - - return i; - } - } - return -1; - } - - /// - /// 移除指定位置的武器, 并返回这个武器对象, 如果移除正在使用的这把武器, 则会自动切换到上一把武器 - /// - /// 所在武器袋的位置索引 - public Weapon RemoveWeapon(int index) - { - if (index < 0 || index >= Weapons.Length) - { - return null; - } - var weapon = Weapons[index]; - if (weapon == null) - { - return null; - } - weapon.GetParent().RemoveChild(weapon); - Weapons[index] = null; - - //如果是当前手持的武器, 就需要调用切换武器操作 - if (index == ActiveIndex) - { - //没有其他武器了 - if (ExchangePrev() == index) - { - ActiveIndex = 0; - ActiveWeapon = null; - } - } - weapon.RemoveAt(); - return weapon; - } - - /// - /// 切换到上一个武器 - /// - public int ExchangePrev() - { - var index = ActiveIndex - 1; - do - { - if (index < 0) - { - index = Weapons.Length - 1; - } - if (ExchangeByIndex(index)) - { - return index; - } - } while (index-- != ActiveIndex); - return -1; - } - - /// - /// 切换到下一个武器, - /// - public int ExchangeNext() - { - var index = ActiveIndex + 1; - do - { - if (index >= Weapons.Length) - { - index = 0; - } - if (ExchangeByIndex(index)) - { - return index; - } - } - while (index++ != ActiveIndex); - return -1; - } - - /// - /// 切换到指定索引的武器 - /// - public bool ExchangeByIndex(int index) - { - if (index == ActiveIndex && ActiveWeapon != null) return true; - if (index < 0 || index > Weapons.Length) return false; - var weapon = Weapons[index]; - if (weapon == null) return false; - - //将上一把武器放到背后 - if (ActiveWeapon != null) - { - var tempParent = ActiveWeapon.GetParentOrNull(); - if (tempParent != null) - { - tempParent.RemoveChild(ActiveWeapon); - Master.BackMountPoint.AddChild(ActiveWeapon); - Master.OnPutBackMount(ActiveWeapon, ActiveIndex); - ActiveWeapon.Conceal(); - } - } - - //更改父节点 - var parent = weapon.GetParentOrNull(); - if (parent == null) - { - Master.MountPoint.AddChild(weapon); - } - else if (parent != Master.MountPoint) - { - parent.RemoveChild(weapon); - Master.MountPoint.AddChild(weapon); - } - - weapon.Position = Vector2.Zero; - weapon.Scale = Vector2.One; - weapon.RotationDegrees = 0; - weapon.Visible = true; - ActiveWeapon = weapon; - ActiveIndex = index; - ActiveWeapon.Active(); - return true; - } -} diff --git a/DungeonShooting_Godot/src/game/item/shell/Shell.cs b/DungeonShooting_Godot/src/game/item/shell/Shell.cs deleted file mode 100644 index 310ee81..0000000 --- a/DungeonShooting_Godot/src/game/item/shell/Shell.cs +++ /dev/null @@ -1,22 +0,0 @@ - -using Godot; - -/// -/// 弹壳类 -/// -[Tool, GlobalClass] -public partial class Shell : ActivityObject -{ - public override void OnInit() - { - base.OnInit(); - ShadowOffset = new Vector2(0, 1); - ThrowCollisionSize = new Vector2(5, 5); - } - - protected override void OnThrowOver() - { - EnableBehavior = false; - Collision.QueueFree(); - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs deleted file mode 100644 index 959487f..0000000 --- a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs +++ /dev/null @@ -1,1140 +0,0 @@ -using Godot; -using System; -using Config; - -/// -/// 武器的基类 -/// -public abstract partial class Weapon : ActivityObject -{ - /// - /// 开火回调事件 - /// - public event Action FireEvent; - - /// - /// 武器属性数据 - /// - public ExcelConfig.Weapon Attribute => _weaponAttribute; - private ExcelConfig.Weapon _weaponAttribute; - private ExcelConfig.Weapon _playerWeaponAttribute; - private ExcelConfig.Weapon _aiWeaponAttribute; - - /// - /// 武器攻击的目标阵营 - /// - public CampEnum TargetCamp { get; set; } - - /// - /// 该武器的拥有者 - /// - public Role Master { get; private set; } - - /// - /// 当前弹夹弹药剩余量 - /// - public int CurrAmmo { get; private set; } - - /// - /// 剩余弹药量(备用弹药) - /// - public int ResidueAmmo { get; private set; } - - /// - /// 武器管的开火点 - /// - [Export, ExportFillNode] - public Marker2D FirePoint { get; set; } - - /// - /// 弹壳抛出的点 - /// - [Export, ExportFillNode] - public Marker2D ShellPoint { get; set; } - - /// - /// 武器的当前散射半径 - /// - public float CurrScatteringRange { get; private set; } = 0; - - /// - /// 是否在换弹中 - /// - /// - public bool Reloading { get; private set; } = false; - - /// - /// 换弹计时器 - /// - public float ReloadTimer { get; private set; } = 0; - - /// - /// 换弹进度 (0 - 1) - /// - public float ReloadProgress - { - get - { - if (Attribute.AloneReload) - { - var num = 1f / Attribute.AmmoCapacity; - return num * (Attribute.AmmoCapacity - CurrAmmo - 1) + num * (ReloadTimer / Attribute.ReloadTime); - } - - return ReloadTimer / Attribute.ReloadTime; - } - } - - /// - /// 返回是否在蓄力中, - /// 注意, 属性仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 false - /// - public bool IsCharging => _looseShootFlag; - - /// - /// 返回武器是否在武器袋中 - /// - public bool IsInHolster => Master != null; - - /// - /// 返回是否真正使用该武器 - /// - public bool IsActive => Master != null && Master.Holster.ActiveWeapon == this; - - /// - /// 动画播放器 - /// - [Export, ExportFillNode] - public AnimationPlayer AnimationPlayer { get; set; } - - /// - /// 是否自动播放 SpriteFrames 的动画 - /// - public bool IsAutoPlaySpriteFrames { get; set; } = true; - - //-------------------------------------------------------------------------------------------- - - //是否按下 - private bool _triggerFlag = false; - - //扳机计时器 - private float _triggerTimer = 0; - - //开火前延时时间 - private float _delayedTime = 0; - - //开火间隙时间 - private float _fireInterval = 0; - - //开火武器口角度 - private float _fireAngle = 0; - - //攻击冷却计时 - private float _attackTimer = 0; - - //攻击状态 - private bool _attackFlag = false; - - //按下的时间 - private float _downTimer = 0; - - //松开的时间 - private float _upTimer = 0; - - //连发次数 - private float _continuousCount = 0; - - //连发状态记录 - private bool _continuousShootFlag = false; - - //松开扳机是否开火 - private bool _looseShootFlag = false; - - //蓄力攻击时长 - private float _chargeTime = 0; - - //是否需要重置武器数据 - private bool _dirtyFlag = false; - - //当前后坐力导致的偏移长度 - private float _currBacklashLength = 0; - - // ---------------------------------------------- - private uint _tempLayer; - - /// - /// 初始化武器属性 - /// - public void InitWeapon(ExcelConfig.Weapon attribute) - { - _playerWeaponAttribute = attribute; - _weaponAttribute = attribute; - if (!string.IsNullOrEmpty(attribute.AiUseAttributeId)) - { - _aiWeaponAttribute = ExcelConfig.Weapon_Map[attribute.AiUseAttributeId]; - } - else - { - _aiWeaponAttribute = attribute; - } - //未完成 - //AnimatedSprite.Position = Attribute.ThrowSpritePosition; - - if (Attribute.AmmoCapacity > Attribute.MaxAmmoCapacity) - { - Attribute.AmmoCapacity = Attribute.MaxAmmoCapacity; - GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + ItemId); - } - //弹药量 - CurrAmmo = Attribute.AmmoCapacity; - //剩余弹药量 - ResidueAmmo = Mathf.Min(Attribute.StandbyAmmoCapacity + CurrAmmo, Attribute.MaxAmmoCapacity) - CurrAmmo; - - ThrowCollisionSize = attribute.ThrowCollisionSize.AsVector2(); - } - - /// - /// 单次开火时调用的函数 - /// - protected abstract void OnFire(); - - /// - /// 发射子弹时调用的函数, 每发射一枚子弹调用一次, - /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次 - /// - /// 开火时枪口旋转角度 - protected abstract void OnShoot(float fireRotation); - - /// - /// 当按下扳机时调用 - /// - protected virtual void OnDownTrigger() - { - } - - /// - /// 当松开扳机时调用 - /// - protected virtual void OnUpTrigger() - { - } - - /// - /// 开始蓄力时调用, - /// 注意, 该函数仅在 Attribute.LooseShoot == false 时才能被调用 - /// - protected virtual void OnStartCharge() - { - } - - /// - /// 当开始换弹时调用 - /// - protected virtual void OnReload() - { - } - - /// - /// 当换弹完成时调用 - /// - protected virtual void OnReloadFinish() - { - } - - /// - /// 当武器被拾起时调用 - /// - /// 拾起该武器的角色 - protected virtual void OnPickUp(Role master) - { - } - - /// - /// 当武器从武器袋中移除时调用 - /// - protected virtual void OnRemove() - { - } - - /// - /// 当武器被激活时调用, 也就是使用当武器时调用 - /// - protected virtual void OnActive() - { - } - - /// - /// 当武器被收起时调用 - /// - protected virtual void OnConceal() - { - } - - /// - /// 射击时调用, 返回消耗弹药数量, 默认为1, 如果返回为 0, 则不消耗弹药 - /// - protected virtual int UseAmmoCount() - { - return 1; - } - - public override void EnterTree() - { - base.EnterTree(); - //收集落在地上的武器 - if (IsInGround()) - { - World.Weapon_UnclaimedWeapons.Add(this); - } - } - - public override void ExitTree() - { - base.ExitTree(); - World.Weapon_UnclaimedWeapons.Remove(this); - } - - protected override void Process(float delta) - { - //GD.Print("AnimatedSprite: " + AnimatedSprite.Position); - //这把武器被扔在地上, 或者当前武器没有被使用 - if (Master == null || Master.Holster.ActiveWeapon != this) - { - //_triggerTimer - _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0; - //攻击冷却计时 - _attackTimer = _attackTimer > 0 ? _attackTimer - delta : 0; - //武器的当前散射半径 - CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, - Attribute.StartScatteringRange); - //松开扳机 - if (_triggerFlag || _downTimer > 0) - { - UpTrigger(); - _downTimer = 0; - } - - _triggerFlag = false; - - //重置数据 - if (_dirtyFlag) - { - _dirtyFlag = false; - Reloading = false; - ReloadTimer = 0; - _attackFlag = false; - _continuousCount = 0; - _delayedTime = 0; - _upTimer = 0; - _looseShootFlag = false; - _chargeTime = 0; - } - } - else //正在使用中 - { - _dirtyFlag = true; - //换弹 - if (Reloading) - { - ReloadTimer -= delta; - if (ReloadTimer <= 0) - { - ReloadSuccess(); - } - } - - // 攻击的计时器 - if (_attackTimer > 0) - { - _attackTimer -= delta; - if (_attackTimer < 0) - { - _delayedTime += _attackTimer; - _attackTimer = 0; - //枪口默认角度 - RotationDegrees = -Attribute.DefaultAngle; - } - } - else if (_delayedTime > 0) //攻击延时 - { - _delayedTime -= delta; - if (_attackTimer < 0) - { - _delayedTime = 0; - } - } - - //扳机判定 - if (_triggerFlag) - { - if (_looseShootFlag) //蓄力时长 - { - _chargeTime += delta; - } - - _downTimer += delta; - if (_upTimer > 0) //第一帧按下扳机 - { - DownTrigger(); - _upTimer = 0; - } - } - else - { - _upTimer += delta; - if (_downTimer > 0) //第一帧松开扳机 - { - UpTrigger(); - _downTimer = 0; - } - } - - //连发判断 - if (!_looseShootFlag && _continuousCount > 0 && _delayedTime <= 0 && _attackTimer <= 0) - { - //连发开火 - TriggerFire(); - } - - if (!_attackFlag && _attackTimer <= 0) - { - if (_upTimer >= Attribute.ScatteringRangeBackTime) - { - CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, - Attribute.StartScatteringRange); - } - } - - _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0; - _triggerFlag = false; - _attackFlag = false; - - //武器身回归 - //Position = Position.MoveToward(Vector2.Zero, Attribute.BacklashRegressionSpeed * delta).Rotated(Rotation); - _currBacklashLength = Mathf.MoveToward(_currBacklashLength, 0, Attribute.BacklashRegressionSpeed * delta); - Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation); - if (_attackTimer > 0) - { - RotationDegrees = Mathf.Lerp( - _fireAngle, -Attribute.DefaultAngle, - Mathf.Clamp((_fireInterval - _attackTimer) * Attribute.UpliftAngleRestore / _fireInterval, 0, 1) - ); - } - } - } - - /// - /// 返回武器是否在地上 - /// - /// - public bool IsInGround() - { - return Master == null && GetParent() == GameApplication.Instance.World.NormalLayer; - } - - /// - /// 扳机函数, 调用即视为按下扳机 - /// - public void Trigger() - { - //这一帧已经按过了, 不需要再按下 - if (_triggerFlag) return; - - //是否第一帧按下 - var justDown = _downTimer == 0; - //是否能发射 - var flag = false; - if (_continuousCount <= 0) //不能处于连发状态下 - { - if (Attribute.ContinuousShoot) //自动射击 - { - if (_triggerTimer > 0) - { - if (_continuousShootFlag) - { - flag = true; - } - } - else - { - flag = true; - if (_delayedTime <= 0 && _attackTimer <= 0) - { - _continuousShootFlag = true; - } - } - } - else //半自动 - { - if (justDown && _triggerTimer <= 0 && _attackTimer <= 0) - { - flag = true; - } - } - } - - if (flag) - { - var fireFlag = true; //是否能开火 - if (Reloading) //换弹中 - { - if (CurrAmmo > 0 && Attribute.AloneReload && Attribute.AloneReloadCanShoot) //立即停止换弹 - { - Reloading = false; - ReloadTimer = 0; - } - else - { - fireFlag = false; - } - } - else if (CurrAmmo <= 0) //子弹不够 - { - fireFlag = false; - if (justDown) - { - //第一帧按下, 触发换弹 - Reload(); - } - } - - if (fireFlag) - { - if (justDown) - { - //开火前延时 - _delayedTime = Attribute.DelayedTime; - //扳机按下间隔 - _triggerTimer = Attribute.TriggerInterval; - //连发数量 - if (!Attribute.ContinuousShoot) - { - _continuousCount = - Utils.RandomRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount); - } - } - - if (_delayedTime <= 0 && _attackTimer <= 0) - { - if (Attribute.LooseShoot) //松发开火 - { - _looseShootFlag = true; - OnStartCharge(); - } - else - { - //开火 - TriggerFire(); - } - } - - _attackFlag = true; - } - - } - - _triggerFlag = true; - } - - /// - /// 返回是否按下扳机 - /// - public bool IsPressTrigger() - { - return _triggerFlag; - } - - /// - /// 获取本次扳机按下的时长, 单位: 秒 - /// - public float GetTriggerDownTime() - { - return _downTimer; - } - - /// - /// 获取扳机蓄力时长, 计算按下扳机后从可以开火到当前一共经过了多长时间, 可用于计算蓄力攻击 - /// 注意, 该函数仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 0 - /// - public float GetTriggerChargeTime() - { - return _chargeTime; - } - - /// - /// 获取延时射击倒计时, 单位: 秒 - /// - public float GetDelayedAttackTime() - { - return _delayedTime; - } - - /// - /// 刚按下扳机 - /// - private void DownTrigger() - { - OnDownTrigger(); - } - - /// - /// 刚松开扳机 - /// - private void UpTrigger() - { - _continuousShootFlag = false; - if (_delayedTime > 0) - { - _continuousCount = 0; - } - - //松发开火执行 - if (_looseShootFlag) - { - _looseShootFlag = false; - if (_chargeTime >= Attribute.MinChargeTime) //判断蓄力是否够了 - { - TriggerFire(); - } - else //不能攻击 - { - _continuousCount = 0; - } - _chargeTime = 0; - } - - OnUpTrigger(); - } - - /// - /// 触发开火 - /// - private void TriggerFire() - { - _continuousCount = _continuousCount > 0 ? _continuousCount - 1 : 0; - - //减子弹数量 - if (_playerWeaponAttribute != _weaponAttribute) //Ai使用该武器, 有一定概率不消耗弹药 - { - if (Utils.RandomRangeFloat(0, 1) < _weaponAttribute.AiAmmoConsumptionProbability) //触发消耗弹药 - { - CurrAmmo -= UseAmmoCount(); - } - } - else - { - CurrAmmo -= UseAmmoCount(); - } - - //开火间隙 - _fireInterval = 60 / Attribute.StartFiringSpeed; - //攻击冷却 - _attackTimer += _fireInterval; - - //播放开火动画 - if (IsAutoPlaySpriteFrames) - { - PlaySpriteAnimation(AnimatorNames.Fire); - } - //触发开火函数 - OnFire(); - - //开火发射的子弹数量 - var bulletCount = Utils.RandomRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount); - //武器口角度 - var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle(); - - //先算武器口方向 - var tempRotation = Utils.RandomRangeFloat(-angle, angle); - var tempAngle = Mathf.RadToDeg(tempRotation); - - //开火时枪口角度 - var fireRotation = Mathf.DegToRad(Master.MountPoint.RealRotationDegrees) + tempRotation; - //创建子弹 - for (int i = 0; i < bulletCount; i++) - { - //发射子弹 - OnShoot(fireRotation); - } - - //当前的散射半径 - CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, - Attribute.FinalScatteringRange); - //武器的旋转角度 - tempAngle -= Attribute.UpliftAngle; - RotationDegrees = tempAngle; - _fireAngle = tempAngle; - - //武器身位置 - var max = Mathf.Abs(Mathf.Max(Attribute.MaxBacklash, Attribute.MinBacklash)); - _currBacklashLength = Mathf.Clamp( - _currBacklashLength - Utils.RandomRangeFloat(Attribute.MinBacklash, Attribute.MaxBacklash), - -max, max - ); - Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation); - - if (FireEvent != null) - { - FireEvent(this); - } - } - - /// - /// 获取武器攻击的目标层级 - /// - /// - public uint GetAttackLayer() - { - return Master != null ? Master.AttackLayer : Role.DefaultAttackLayer; - } - - /// - /// 返回弹药是否到达上限 - /// - public bool IsAmmoFull() - { - return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity; - } - - /// - /// 返回弹夹是否打空 - /// - public bool IsAmmoEmpty() - { - return CurrAmmo == 0; - } - - /// - /// 返回是否弹药耗尽 - /// - public bool IsTotalAmmoEmpty() - { - return CurrAmmo + ResidueAmmo == 0; - } - - /// - /// 强制修改当前弹夹弹药量 - /// - public void SetCurrAmmo(int count) - { - CurrAmmo = Mathf.Clamp(count, 0, Attribute.AmmoCapacity); - } - - /// - /// 强制修改备用弹药量 - /// - public void SetResidueAmmo(int count) - { - ResidueAmmo = Mathf.Clamp(count, 0, Attribute.MaxAmmoCapacity - CurrAmmo); - } - - /// - /// 强制修改弹药量, 优先改动备用弹药 - /// - public void SetTotalAmmo(int total) - { - if (total < 0) - { - return; - } - var totalAmmo = CurrAmmo + ResidueAmmo; - if (totalAmmo == total) - { - return; - } - - if (total > totalAmmo) //弹药增加 - { - ResidueAmmo = Mathf.Min(total - CurrAmmo, Attribute.MaxAmmoCapacity - CurrAmmo); - } - else //弹药减少 - { - if (CurrAmmo < total) - { - ResidueAmmo = total - CurrAmmo; - } - else - { - CurrAmmo = total; - ResidueAmmo = 0; - } - } - } - - /// - /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量 - /// - /// 弹药数量 - private int PickUpAmmo(int count) - { - var num = ResidueAmmo; - ResidueAmmo = Mathf.Min(ResidueAmmo + count, Attribute.MaxAmmoCapacity - CurrAmmo); - return count - ResidueAmmo + num; - } - - /// - /// 触发换弹 - /// - public void Reload() - { - if (CurrAmmo < Attribute.AmmoCapacity && ResidueAmmo > 0 && !Reloading) - { - Reloading = true; - ReloadTimer = Attribute.ReloadTime; - //播放换弹动画 - if (IsAutoPlaySpriteFrames) - { - PlaySpriteAnimation(AnimatorNames.Reload); - } - OnReload(); - } - } - - /// - /// 换弹计时器时间到, 执行换弹操作 - /// - private void ReloadSuccess() - { - if (Attribute.AloneReload) //单独装填 - { - if (ResidueAmmo >= Attribute.AloneReloadCount) //剩余子弹充足 - { - if (CurrAmmo + Attribute.AloneReloadCount <= Attribute.AmmoCapacity) - { - ResidueAmmo -= Attribute.AloneReloadCount; - CurrAmmo += Attribute.AloneReloadCount; - } - else //子弹满了 - { - var num = Attribute.AmmoCapacity - CurrAmmo; - CurrAmmo = Attribute.AmmoCapacity; - ResidueAmmo -= num; - } - } - else if (ResidueAmmo != 0) //剩余子弹不足 - { - if (ResidueAmmo + CurrAmmo <= Attribute.AmmoCapacity) - { - CurrAmmo += ResidueAmmo; - ResidueAmmo = 0; - } - else //子弹满了 - { - var num = Attribute.AmmoCapacity - CurrAmmo; - CurrAmmo = Attribute.AmmoCapacity; - ResidueAmmo -= num; - } - } - - if (ResidueAmmo == 0 || CurrAmmo == Attribute.AmmoCapacity) //换弹结束 - { - Reloading = false; - ReloadTimer = 0; - OnReloadFinish(); - } - else - { - ReloadTimer = Attribute.ReloadTime; - //播放换弹动画 - if (IsAutoPlaySpriteFrames) - { - PlaySpriteAnimation(AnimatorNames.Reload); - } - OnReload(); - } - } - else //换弹结束 - { - if (CurrAmmo + ResidueAmmo >= Attribute.AmmoCapacity) - { - ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo; - CurrAmmo = Attribute.AmmoCapacity; - } - else - { - CurrAmmo += ResidueAmmo; - ResidueAmmo = 0; - } - - Reloading = false; - ReloadTimer = 0; - OnReloadFinish(); - } - } - - //播放动画 - private void PlaySpriteAnimation(string name) - { - var spriteFrames = AnimatedSprite.SpriteFrames; - if (spriteFrames != null && spriteFrames.HasAnimation(name)) - { - AnimatedSprite.Play(name); - } - } - - public override CheckInteractiveResult CheckInteractive(ActivityObject master) - { - var result = new CheckInteractiveResult(this); - - if (master is Role roleMaster) //碰到角色 - { - if (Master == null) - { - var masterWeapon = roleMaster.Holster.ActiveWeapon; - //查找是否有同类型武器 - var index = roleMaster.Holster.FindWeapon(ItemId); - if (index != -1) //如果有这个武器 - { - if (CurrAmmo + ResidueAmmo != 0) //子弹不为空 - { - var targetWeapon = roleMaster.Holster.GetWeapon(index); - if (!targetWeapon.IsAmmoFull()) //背包里面的武器子弹未满 - { - //可以互动拾起弹药 - result.CanInteractive = true; - result.Message = Attribute.Name; - result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_bullet_png; - return result; - } - } - } - else //没有武器 - { - if (roleMaster.Holster.CanPickupWeapon(this)) //能拾起武器 - { - //可以互动, 拾起武器 - result.CanInteractive = true; - result.Message = Attribute.Name; - result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_pickup_png; - return result; - } - else if (masterWeapon != null && masterWeapon.Attribute.WeightType == Attribute.WeightType) //替换武器 - { - //可以互动, 切换武器 - result.CanInteractive = true; - result.Message = Attribute.Name; - result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_replace_png; - return result; - } - } - } - } - - return result; - } - - public override void Interactive(ActivityObject master) - { - if (master is Role roleMaster) //与role互动 - { - var holster = roleMaster.Holster; - //查找是否有同类型武器 - var index = holster.FindWeapon(ItemId); - if (index != -1) //如果有这个武器 - { - if (CurrAmmo + ResidueAmmo == 0) //没有子弹了 - { - return; - } - - var weapon = holster.GetWeapon(index); - //子弹上限 - var maxCount = Attribute.MaxAmmoCapacity; - //是否捡到子弹 - var flag = false; - if (ResidueAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount) - { - var count = weapon.PickUpAmmo(ResidueAmmo); - if (count != ResidueAmmo) - { - ResidueAmmo = count; - flag = true; - } - } - - if (CurrAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount) - { - var count = weapon.PickUpAmmo(CurrAmmo); - if (count != CurrAmmo) - { - CurrAmmo = count; - flag = true; - } - } - - //播放互动效果 - if (flag) - { - Throw(GlobalPosition, 0, Utils.RandomRangeInt(20, 50), Vector2.Zero, Utils.RandomRangeInt(-180, 180)); - } - } - else //没有武器 - { - if (holster.PickupWeapon(this) == -1) - { - //替换武器 - roleMaster.ThrowWeapon(); - roleMaster.PickUpWeapon(this); - } - } - } - } - - /// - /// 获取当前武器真实的旋转角度(弧度制), 由于武器旋转时加入了旋转吸附, 所以需要通过该函数来来知道当前武器的真实旋转角度 - /// - public float GetRealGlobalRotation() - { - return Mathf.DegToRad(Master.MountPoint.RealRotationDegrees) + Rotation; - } - - /// - /// 触发扔掉武器抛出的效果, 并不会管武器是否在武器袋中 - /// - /// 触发扔掉该武器的的角色 - public void ThrowWeapon(Role master) - { - ThrowWeapon(master, master.GlobalPosition); - } - - /// - /// 触发扔掉武器抛出的效果, 并不会管武器是否在武器袋中 - /// - /// 触发扔掉该武器的的角色 - /// 投抛起始位置 - public void ThrowWeapon(Role master, Vector2 startPosition) - { - //阴影偏移 - ShadowOffset = new Vector2(0, 2); - - if (master.Face == FaceDirection.Left) - { - Scale *= new Vector2(1, -1); - } - - var angle = master.MountPoint.GlobalRotationDegrees; - GlobalRotationDegrees = angle; - - //继承role的移动速度 - InheritVelocity(master); - - var startHeight = -master.MountPoint.Position.Y; - var direction = angle + Utils.RandomRangeInt(-20, 20); - var velocity = new Vector2(20, 0).Rotated(direction * Mathf.Pi / 180); - var yf = Utils.RandomRangeInt(50, 70); - var rotate = Utils.RandomRangeInt(-60, 60); - Throw(startPosition, startHeight, yf, velocity, rotate); - } - - protected override void OnThrowStart() - { - //禁用碰撞 - //Collision.Disabled = true; - AnimationPlayer.Play(AnimatorNames.Floodlight); - } - - protected override void OnThrowOver() - { - //启用碰撞 - //Collision.Disabled = false; - AnimationPlayer.Play(AnimatorNames.Floodlight); - } - - /// - /// 触发拾起到 Holster, 这个函数由 Holster 对象调用 - /// - public void PickUpWeapon(Role master) - { - Master = master; - if (master.IsAi) - { - _weaponAttribute = _aiWeaponAttribute; - } - else - { - _weaponAttribute = _playerWeaponAttribute; - } - //停止动画 - AnimationPlayer.Stop(); - //清除泛白效果 - SetBlendSchedule(0); - ZIndex = 0; - //禁用碰撞 - //Collision.Disabled = true; - //修改层级 - _tempLayer = CollisionLayer; - CollisionLayer = PhysicsLayer.InHand; - //清除 Ai 拾起标记 - RemoveSign(SignNames.AiFindWeaponSign); - OnPickUp(master); - } - - /// - /// 触发从 Holster 中移除, 这个函数由 Holster 对象调用 - /// - public void RemoveAt() - { - Master = null; - CollisionLayer = _tempLayer; - _weaponAttribute = _playerWeaponAttribute; - //未完成 - //AnimatedSprite.Position = Attribute.ThrowSpritePosition; - //清除 Ai 拾起标记 - RemoveSign(SignNames.AiFindWeaponSign); - OnRemove(); - } - - /// - /// 触发启用武器 - /// - public void Active() - { - //调整阴影 - ShadowOffset = new Vector2(0, Master.GlobalPosition.Y - GlobalPosition.Y); - //枪口默认抬起角度 - RotationDegrees = -Attribute.DefaultAngle; - ShowShadowSprite(); - OnActive(); - } - - /// - /// 触发收起武器 - /// - public void Conceal() - { - HideShadowSprite(); - OnConceal(); - } - - //-------------------------- ----- 子弹相关 ----------------------------- - - /// - /// 投抛弹壳的默认实现方式, shellId为弹壳id, 不需要前缀 - /// - protected ActivityObject ThrowShell(string shellId) - { - var shellPosition = Master.MountPoint.Position + ShellPoint.Position; - var startPos = ShellPoint.GlobalPosition; - var startHeight = -shellPosition.Y; - startPos.Y += startHeight; - var direction = GlobalRotationDegrees + Utils.RandomRangeInt(-30, 30) + 180; - var verticalSpeed = Utils.RandomRangeInt(60, 120); - var velocity = new Vector2(Utils.RandomRangeInt(20, 60), 0).Rotated(direction * Mathf.Pi / 180); - var rotate = Utils.RandomRangeInt(-720, 720); - var shell = Create(ActivityIdPrefix.Shell + shellId); - shell.Rotation = Master.MountPoint.RealRotation; - shell.InheritVelocity(Master); - shell.Throw(startPos, startHeight, verticalSpeed, velocity, rotate); - return shell; - } - - //-------------------------------- Ai相关 ----------------------------- - - /// - /// 获取 Ai 对于该武器的评分, 评分越高, 代表 Ai 会越优先选择该武器, 如果为 -1, 则表示 Ai 不会使用该武器 - /// - public float GetAiScore() - { - return 1; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/WeaponAttribute.cs b/DungeonShooting_Godot/src/game/item/weapon/WeaponAttribute.cs deleted file mode 100644 index 5ac32ed..0000000 --- a/DungeonShooting_Godot/src/game/item/weapon/WeaponAttribute.cs +++ /dev/null @@ -1,277 +0,0 @@ -// using System; -// using Godot; -// -// /// -// /// 武器上的属性 -// /// -// public class WeaponAttribute -// { -// /// -// /// 武器显示的名称 -// /// -// public string Name = "Gun1"; -// /// -// /// 武器 Prefab, 必须继承场景 "res://prefab/weapon/Weapon.tscn" -// /// -// public string WeaponPrefab = ResourcePath.prefab_weapon_Weapon_tscn; -// /// -// /// 武器类型 -// /// -// public WeaponWeightType WeightType = WeaponWeightType.MainWeapon; -// /// -// /// 武器的图标 -// /// -// public string Icon = ResourcePath.resource_sprite_gun_gun1_png; -// /// -// /// 动画序列帧资源名称 -// /// -// public string SpriteFrames; -// /// -// /// 是否连续发射, 如果为false, 则每次发射都需要扣动扳机 -// /// -// public bool ContinuousShoot = true; -// /// -// /// 弹夹容量 -// /// -// public int AmmoCapacity = 30; -// /// -// /// 弹药容量上限 -// /// -// public int MaxAmmoCapacity = 120; -// /// -// /// 起始备用弹药数量 -// /// -// public int StandbyAmmoCapacity = 90; -// /// -// /// 装弹时间, 单位: 秒 -// /// -// public float ReloadTime = 1.5f; -// /// -// /// 每粒子弹是否是单独装填, 如果是, 那么每上一发子弹的时间就是 ReloadTime, 可以做霰弹武器装填效果 -// /// -// public bool AloneReload = false; -// /// -// /// 单独装填时每次装填子弹数量, 必须要将 'AloneReload' 属性设置为 true -// /// -// public int AloneReloadCount = 1; -// /// -// /// 单独装填的子弹时可以立即射击, 必须要将 'AloneReload' 属性设置为 true -// /// -// public bool AloneReloadCanShoot = false; -// /// -// /// 是否为松发开火, 也就是松开扳机才开火, 若要启用该属性, 必须将 'ContinuousShoot' 设置为 false -// /// -// public bool LooseShoot = false; -// /// -// /// 最少需要蓄力多久才能开火, 必须将 'LooseShoot' 设置为 true -// /// -// public float MinChargeTime = 0f; -// /// -// /// 连续发射最小次数, 仅当 ContinuousShoot 为 false 时生效 -// /// -// public int MinContinuousCount = 1; -// /// -// /// 连续发射最大次数, 仅当 ContinuousShoot 为 false 时生效 -// /// -// public int MaxContinuousCount = 1; -// /// -// /// 按下一次扳机后需要多长时间才能再次感应按下 -// /// -// public float TriggerInterval = 0; -// /// -// /// 初始射速, 初始每分钟能开火次数 -// /// -// public float StartFiringSpeed = 300; -// /// -// /// 最终射速, 最终每分钟能开火次数, 仅当 ContinuousShoot 为 true 时生效 -// /// -// public float FinalFiringSpeed = 300; -// /// -// /// 按下扳机并开火后射速增加速率 -// /// -// public float FiringSpeedAddSpeed = 2; -// /// -// /// 松开扳机后射速消散速率 -// /// -// public float FiringSpeedBackSpeed = 10; -// /// -// /// 单次开火发射子弹最小数量 -// /// -// public int MinFireBulletCount = 1; -// /// -// /// 单次开火发射子弹最大数量 -// /// -// public int MaxFireBulletCount = 1; -// /// -// /// 开火前延时 -// /// -// public float DelayedTime = 0f; -// /// -// /// 初始散射半径 -// /// -// public float StartScatteringRange = 0; -// /// -// /// 最终散射半径 -// /// -// public float FinalScatteringRange = 20; -// /// -// /// 每次发射后散射增加值 -// /// -// public float ScatteringRangeAddValue = 2; -// /// -// /// 松开扳机后散射销退速率 -// /// -// public float ScatteringRangeBackSpeed = 10; -// /// -// /// 松开扳机多久后开始销退散射值 -// /// -// public float ScatteringRangeBackTime = 0f; -// /// -// /// 子弹飞行最大距离 -// /// -// public float MaxDistance = 600; -// /// -// /// 子弹飞行最小距离 -// /// -// public float MinDistance = 800; -// /// -// /// 开火位置 -// /// -// public Vector2 FirePosition = new Vector2(11, 0); -// /// -// /// 精灵位置 -// /// -// public Vector2 SpritePosition = new Vector2(4, -3); -// /// -// /// 弹壳投抛起始位置 -// /// -// public Vector2 ShellPosition = new Vector2(5, -2.5f); -// /// -// /// 重量 -// /// -// public float Weight = 11; -// /// -// /// 最大后坐力 (仅用于开火后武器身抖动) -// /// -// public float MaxBacklash = 4; -// /// -// /// 最小后坐力 (仅用于开火后武器身抖动) -// /// -// public float MinBacklash = 2; -// /// -// /// 后坐力偏移回归回归速度 -// /// -// public float BacklashRegressionSpeed = 35f; -// /// -// /// 开火后武器口上抬角度 -// /// -// public float UpliftAngle = 30; -// /// -// /// 武器默认上抬角度 -// /// -// public float DefaultAngle = 0; -// /// -// /// 开火后武器口角度恢复速度倍数 -// /// -// public float UpliftAngleRestore = 1f; -// /// -// /// 默认射出的子弹 -// /// -// public string BulletId = ActivityIdPrefix.Bullet + "0001"; -// /// -// /// 武器精灵投抛时的旋转中心坐标 -// /// -// public Vector2 ThrowSpritePosition = new Vector2(0, 0); -// /// -// /// 投抛状态下物体碰撞器大小 -// /// -// public Vector2 ThrowCollisionSize = new Vector2(20, 15); -// -// /// -// /// 克隆一份新的属性配置 -// /// -// /// -// public WeaponAttribute Clone() -// { -// var attr = _Clone(); -// if (AiUseAttribute != null) -// { -// attr.AiUseAttribute = AiUseAttribute._Clone(); -// } -// return attr; -// } -// -// private WeaponAttribute _Clone() -// { -// var attr = new WeaponAttribute(); -// attr.Name = Name; -// attr.WeaponPrefab = WeaponPrefab; -// attr.WeightType = WeightType; -// attr.Icon = Icon; -// attr.SpriteFrames = SpriteFrames; -// attr.ContinuousShoot = ContinuousShoot; -// attr.AmmoCapacity = AmmoCapacity; -// attr.MaxAmmoCapacity = MaxAmmoCapacity; -// attr.StandbyAmmoCapacity = StandbyAmmoCapacity; -// attr.ReloadTime = ReloadTime; -// attr.AloneReload = AloneReload; -// attr.AloneReloadCount = AloneReloadCount; -// attr.AloneReloadCanShoot = AloneReloadCanShoot; -// attr.LooseShoot = LooseShoot; -// attr.MinChargeTime = MinChargeTime; -// attr.MinContinuousCount = MinContinuousCount; -// attr.MaxContinuousCount = MaxContinuousCount; -// attr.TriggerInterval = TriggerInterval; -// attr.StartFiringSpeed = StartFiringSpeed; -// attr.FinalFiringSpeed = FinalFiringSpeed; -// attr.FiringSpeedAddSpeed = FiringSpeedAddSpeed; -// attr.FiringSpeedBackSpeed = FiringSpeedBackSpeed; -// attr.MinFireBulletCount = MinFireBulletCount; -// attr.MaxFireBulletCount = MaxFireBulletCount; -// attr.DelayedTime = DelayedTime; -// attr.StartScatteringRange = StartScatteringRange; -// attr.FinalScatteringRange = FinalScatteringRange; -// attr.ScatteringRangeAddValue = ScatteringRangeAddValue; -// attr.ScatteringRangeBackSpeed = ScatteringRangeBackSpeed; -// attr.ScatteringRangeBackTime = ScatteringRangeBackTime; -// attr.MaxDistance = MaxDistance; -// attr.MinDistance = MinDistance; -// attr.FirePosition = FirePosition; -// attr.ShellPosition = ShellPosition; -// attr.SpritePosition = SpritePosition; -// attr.Weight = Weight; -// attr.MaxBacklash = MaxBacklash; -// attr.MinBacklash = MinBacklash; -// attr.BacklashRegressionSpeed = BacklashRegressionSpeed; -// attr.UpliftAngle = UpliftAngle; -// attr.DefaultAngle = DefaultAngle; -// attr.UpliftAngleRestore = UpliftAngleRestore; -// attr.AiTargetLockingTime = AiTargetLockingTime; -// attr.BulletId = BulletId; -// attr.ThrowSpritePosition = ThrowSpritePosition; -// attr.ThrowCollisionSize = ThrowCollisionSize; -// return attr; -// } -// -// //------------------------------ Ai相关 ----------------------------- -// -// /// -// /// 用于Ai, 目标锁定时间, 也就是瞄准目标多久才会开火 -// /// -// public float AiTargetLockingTime = 0; -// -// /// -// /// 用于Ai, Ai使用该武器发射的子弹速度缩放比 -// /// -// public float AiBulletSpeedScale = 0.7f; -// -// /// -// /// 用于Ai, Ai使用该武器消耗弹药的概率, (0 - 1) -// /// -// public float AiAmmoConsumptionProbability = 0f; -// -// /// -// /// Ai 使用该武器时的武器数据, 设置该字段, 可让同一把武器在敌人和玩家手上有不同属性 -// /// -// public WeaponAttribute AiUseAttribute; -// } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/WeaponWeightType.cs b/DungeonShooting_Godot/src/game/item/weapon/WeaponWeightType.cs deleted file mode 100644 index 5528683..0000000 --- a/DungeonShooting_Godot/src/game/item/weapon/WeaponWeightType.cs +++ /dev/null @@ -1,19 +0,0 @@ - -/// -/// 根据重量划分的武器类型 -/// -public enum WeaponWeightType -{ - /// - /// 副武器 - /// - DeputyWeapon = 1, - /// - /// 主武器 - /// - MainWeapon = 2, - /// - /// 重型武器 - /// - HeavyWeapon = 3 -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs b/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs deleted file mode 100644 index 4267f78..0000000 --- a/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs +++ /dev/null @@ -1,197 +0,0 @@ -using Godot; - -/// -/// 普通的枪 -/// -[Tool, GlobalClass] -public partial class Gun : Weapon -{ - // //步枪属性数据 - // private class RifleAttribute : WeaponAttribute - // { - // public RifleAttribute() - // { - // Name = "步枪"; - // Icon = ResourcePath.resource_sprite_gun_gun4_png; - // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0001_tres; - // Weight = 40; - // ThrowSpritePosition = new Vector2(0.4f, -2.6f); - // StartFiringSpeed = 480; - // StartScatteringRange = 30; - // FinalScatteringRange = 90; - // ScatteringRangeAddValue = 2f; - // ScatteringRangeBackSpeed = 40; - // //连发 - // ContinuousShoot = true; - // AmmoCapacity = 30; - // StandbyAmmoCapacity = 30 * 3; - // MaxAmmoCapacity = 30 * 3; - // //扳机检测间隔 - // TriggerInterval = 0f; - // - // //开火前延时 - // DelayedTime = 0f; - // //攻击距离 - // MinDistance = 300; - // MaxDistance = 400; - // //发射子弹数量 - // MinFireBulletCount = 1; - // MaxFireBulletCount = 1; - // //抬起角度 - // UpliftAngle = 10; - // //开火位置 - // FirePosition = new Vector2(21, -3f); - // //精灵位置 - // SpritePosition = new Vector2(6, -1); - // ShellPosition = new Vector2(7.5f, -4.5f); - // - // AiUseAttribute = Clone(); - // AiUseAttribute.AiTargetLockingTime = 0.5f; - // AiUseAttribute.TriggerInterval = 3f; - // AiUseAttribute.ContinuousShoot = false; - // AiUseAttribute.MinContinuousCount = 3; - // AiUseAttribute.MaxContinuousCount = 3; - // } - // } - // - // //手枪属性数据 - // private class PistolAttribute : WeaponAttribute - // { - // public PistolAttribute() - // { - // Name = "手枪"; - // Icon = ResourcePath.resource_sprite_gun_gun3_png; - // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0003_tres; - // Weight = 20; - // ThrowSpritePosition = new Vector2(0.4f, -2.6f); - // WeightType = WeaponWeightType.DeputyWeapon; - // StartFiringSpeed = 300; - // FinalFiringSpeed = 300; - // StartScatteringRange = 5; - // FinalScatteringRange = 60; - // ScatteringRangeAddValue = 8f; - // ScatteringRangeBackSpeed = 40; - // ScatteringRangeBackTime = 0.5f; - // //连发 - // ContinuousShoot = false; - // AmmoCapacity = 12; - // StandbyAmmoCapacity = 72; - // MaxAmmoCapacity = 72; - // //扳机检测间隔 - // TriggerInterval = 0.1f; - // //连发数量 - // MinContinuousCount = 1; - // MaxContinuousCount = 1; - // //开火前延时 - // DelayedTime = 0f; - // //攻击距离 - // MinDistance = 250; - // MaxDistance = 300; - // //发射子弹数量 - // MinFireBulletCount = 1; - // MaxFireBulletCount = 1; - // //抬起角度 - // UpliftAngle = 20; - // //开火位置 - // FirePosition = new Vector2(13, -2); - // //精灵位置 - // SpritePosition = new Vector2(5, 0); - // ShellPosition = new Vector2(5, -3); - // - // AiUseAttribute = Clone(); - // AiUseAttribute.AiTargetLockingTime = 1f; - // AiUseAttribute.TriggerInterval = 2f; - // } - // } - // - // //狙击步枪 - // private class SniperRifleAttribute : WeaponAttribute - // { - // public SniperRifleAttribute() - // { - // Name = "狙击步枪"; - // Icon = ResourcePath.resource_sprite_gun_gun3_png; - // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0005_tres; - // Weight = 20; - // ThrowSpritePosition = new Vector2(0.4f, -2.6f); - // WeightType = WeaponWeightType.DeputyWeapon; - // StartFiringSpeed = 60; - // FinalFiringSpeed = 60; - // StartScatteringRange = 0; - // FinalScatteringRange = 20; - // ScatteringRangeAddValue = 10; - // ScatteringRangeBackSpeed = 10; - // //连发 - // ContinuousShoot = false; - // AmmoCapacity = 10; - // StandbyAmmoCapacity = 50; - // MaxAmmoCapacity = 50; - // //扳机检测间隔 - // TriggerInterval = 0.1f; - // //连发数量 - // MinContinuousCount = 1; - // MaxContinuousCount = 1; - // //开火前延时 - // DelayedTime = 0f; - // //攻击距离 - // MinDistance = 600; - // MaxDistance = 800; - // //发射子弹数量 - // MinFireBulletCount = 1; - // MaxFireBulletCount = 1; - // //抬起角度 - // UpliftAngle = 15; - // UpliftAngleRestore = 3.5f; - // //开火位置 - // FirePosition = new Vector2(28, -3.5f); - // //精灵位置 - // SpritePosition = new Vector2(9, 0); - // ShellPosition = new Vector2(7, -3.5f); - // MinBacklash = 6; - // MinBacklash = 8; - // BacklashRegressionSpeed = 20; - // ReloadTime = 3.5f; - // - // AiUseAttribute = Clone(); - // AiUseAttribute.AiTargetLockingTime = 1f; - // AiUseAttribute.TriggerInterval = 2f; - // } - // } - - protected override void OnFire() - { - //创建一个弹壳 - ThrowShell("0001"); - - if (Master == Player.Current) - { - //创建抖动 - GameCamera.Main.DirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 2f); - } - - //创建开火特效 - var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_ShotFire_tscn); - var sprite = packedScene.Instantiate(); - sprite.GlobalPosition = FirePoint.GlobalPosition; - sprite.GlobalRotation = FirePoint.GlobalRotation; - sprite.AddToActivityRoot(RoomLayerEnum.YSortLayer); - - //播放射击音效 - SoundManager.PlaySoundEffectPosition(ResourcePath.resource_sound_sfx_ordinaryBullet2_mp3, GameApplication.Instance.ViewToGlobalPosition(GlobalPosition), -8); - } - - protected override void OnShoot(float fireRotation) - { - //创建子弹 - var bullet = ActivityObject.Create(Attribute.BulletId); - bullet.Init( - this, - 350, - Utils.RandomRangeFloat(Attribute.MinDistance, Attribute.MaxDistance), - FirePoint.GlobalPosition, - fireRotation, - GetAttackLayer() - ); - bullet.PutDown(RoomLayerEnum.YSortLayer); - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs b/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs deleted file mode 100644 index 4490496..0000000 --- a/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Godot; - -[Tool, GlobalClass] -public partial class Shotgun : Weapon -{ - - // private class ShotgunAttribute : WeaponAttribute - // { - // public ShotgunAttribute() - // { - // Name = "霰弹枪"; - // Icon = ResourcePath.resource_sprite_gun_gun2_png; - // SpriteFrames = ResourcePath.resource_spriteFrames_Weapon0002_tres; - // Weight = 40; - // ThrowSpritePosition = new Vector2(0.4f, -2.6f); - // StartFiringSpeed = 400; - // StartScatteringRange = 30; - // FinalScatteringRange = 90; - // ScatteringRangeAddValue = 50f; - // ScatteringRangeBackSpeed = 50; - // //连发 - // ContinuousShoot = false; - // AmmoCapacity = 7; - // StandbyAmmoCapacity = 42; - // MaxAmmoCapacity = 42; - // AloneReload = true; - // AloneReloadCanShoot = true; - // ReloadTime = 0.6f; - // //连发数量 - // MinContinuousCount = 1; - // MaxContinuousCount = 1; - // //开火前延时 - // DelayedTime = 0f; - // //攻击距离 - // MinDistance = 200; - // MaxDistance = 250; - // //发射子弹数量 - // MinFireBulletCount = 5; - // MaxFireBulletCount = 5; - // //抬起角度 - // UpliftAngle = 15; - // MaxBacklash = 6; - // MinBacklash = 5; - // //开火位置 - // FirePosition = new Vector2(22, -4); - // //精灵位置 - // SpritePosition = new Vector2(9, -2); - // ShellPosition = new Vector2(3, -4); - // - // BulletId = ActivityIdPrefix.Bullet + "0002"; - // - // AiUseAttribute = Clone(); - // AiUseAttribute.AiTargetLockingTime = 0.2f; - // AiUseAttribute.TriggerInterval = 3.5f; - // } - // } - - /// - /// 弹壳预制体 - /// - public PackedScene ShellPack; - - public override void OnInit() - { - base.OnInit(); - ShellPack = ResourceManager.Load(ResourcePath.prefab_weapon_shell_ShellCase_tscn); - } - - protected override void OnFire() - { - //创建一个弹壳 - ThrowShell("0001"); - - if (Master == Player.Current) - { - //创建抖动 - GameCamera.Main.DirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 2f); - } - - //创建开火特效 - var packedScene = ResourceManager.Load(ResourcePath.prefab_effect_ShotFire_tscn); - var sprite = packedScene.Instantiate(); - sprite.GlobalPosition = FirePoint.GlobalPosition; - sprite.GlobalRotation = FirePoint.GlobalRotation; - sprite.AddToActivityRoot(RoomLayerEnum.YSortLayer); - - //播放射击音效 - SoundManager.PlaySoundEffectPosition(ResourcePath.resource_sound_sfx_ordinaryBullet3_mp3, GameApplication.Instance.ViewToGlobalPosition(GlobalPosition), -15); - } - - protected override void OnShoot(float fireRotation) - { - //创建子弹 - var bullet = ActivityObject.Create(Attribute.BulletId); - bullet.Init( - this, - Utils.RandomRangeInt(280, 380), - Utils.RandomRangeFloat(Attribute.MinDistance, Attribute.MaxDistance), - FirePoint.GlobalPosition, - fireRotation + Utils.RandomRangeFloat(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi), - GetAttackLayer() - ); - bullet.PutDown(RoomLayerEnum.YSortLayer); - } -} diff --git a/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs deleted file mode 100644 index 4912170..0000000 --- a/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs +++ /dev/null @@ -1,128 +0,0 @@ - -using Godot; - -[Tool, GlobalClass] -public partial class Knife : Weapon -{ - // private class KnifeAttribute : WeaponAttribute - // { - // public KnifeAttribute() - // { - // Icon = ResourcePath.resource_sprite_gun_knife1_png; - // WeaponPrefab = ResourcePath.prefab_weapon_Knife_tscn; - // //攻速设置 - // StartFiringSpeed = 180; - // FinalFiringSpeed = StartFiringSpeed; - // //关闭连发 - // ContinuousShoot = false; - // //设置成松发开火 - // LooseShoot = true; - // //弹药量, 可以理解为耐久度 - // AmmoCapacity = 180; - // MaxAmmoCapacity = AmmoCapacity; - // //握把位置 - // SpritePosition = new Vector2(10, 0); - // MaxDistance = MinDistance = 35; - // //后坐力改为向前, 模拟手伸长的效果 - // MaxBacklash = -8; - // MinBacklash = -8; - // BacklashRegressionSpeed = 24; - // UpliftAngle = -95; - // - // //AiUseAttribute = Clone(); - // //AiUseAttribute.TriggerInterval = 3f; - // } - // } - - private Area2D _hitArea; - private int _attackIndex = 0; - - public override void OnInit() - { - base.OnInit(); - - _hitArea = GetNode("HitArea"); - _hitArea.Monitoring = false; - _hitArea.Monitorable = false; - _hitArea.BodyEntered += OnBodyEntered; - //禁用自动播放动画 - IsAutoPlaySpriteFrames = false; - } - - protected override void Process(float delta) - { - base.Process(delta); - if (IsActive) - { - //让碰撞节点与武器挂载节点位置保持一致, 而不跟着武器走 - _hitArea.GlobalPosition = Master.MountPoint.GlobalPosition; - } - } - - protected override void PhysicsProcess(float delta) - { - base.PhysicsProcess(delta); - //过去两个物理帧后就能关闭碰撞了 - if (++_attackIndex >= 2) - { - _hitArea.Monitoring = false; - } - } - - protected override void OnStartCharge() - { - //开始蓄力时武器角度上抬120度 - RotationDegrees = -120; - } - - protected override void OnFire() - { - GD.Print("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime()); - //更新碰撞层级 - _hitArea.CollisionMask = GetAttackLayer(); - //启用碰撞 - _hitArea.Monitoring = true; - _attackIndex = 0; - - if (IsActive) //被使用 - { - //播放挥刀特效 - SpecialEffectManager.Play( - ResourcePath.resource_spriteFrames_KnifeHit1_tres, "default", - Master.MountPoint.GlobalPosition, GlobalRotation + Mathf.Pi * 0.5f, new Vector2((int)Master.Face, 1) * AnimatedSprite.Scale, - new Vector2(17, 4), 1 - ); - } - - - if (Master == Player.Current) - { - //创建抖动 - //GameCamera.Main.ProcessDirectionalShake(Vector2.Right.Rotated(GlobalRotation - Mathf.Pi * 0.5f) * 1.5f); - } - } - - protected override void OnShoot(float fireRotation) - { - - } - - protected override int UseAmmoCount() - { - //这里要做判断, 如果没有碰到敌人, 则不消耗弹药 (耐久) - return 0; - } - - private void OnBodyEntered(Node2D body) - { - GD.Print("碰到物体: " + body.Name); - var activityObject = body.AsActivityObject(); - if (activityObject != null) - { - if (activityObject is Role role) - { - role.CallDeferred(nameof(Role.Hurt), 10, (role.GetCenterPosition() - GlobalPosition).Angle()); - } - } - } -} diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs index a719a8d..904877c 100644 --- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs +++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs @@ -150,7 +150,6 @@ //玩家手上添加武器 //player.PickUpWeapon(ActivityObject.Create(ActivityObject.Ids.Id_weapon0001)); var weapon = ActivityObject.Create(ActivityObject.Ids.Id_weapon0001); - weapon.InitWeapon(ExcelConfig.Weapon_List[0]); weapon.PutDown(player.Position, RoomLayerEnum.NormalLayer); GameApplication.Instance.Cursor.SetGuiMode(false);