diff --git a/DungeonShooting_Godot/prefab/role/Player.tscn b/DungeonShooting_Godot/prefab/role/Player.tscn index 927bc6b..fb6b78b 100644 --- a/DungeonShooting_Godot/prefab/role/Player.tscn +++ b/DungeonShooting_Godot/prefab/role/Player.tscn @@ -4,11 +4,10 @@ [ext_resource path="res://src/game/role/Player.cs" type="Script" id=2] [ext_resource path="res://prefab/weapon/Weapon.tscn" type="PackedScene" id=4] - [node name="Player" instance=ExtResource( 1 )] collision_layer = 8 script = ExtResource( 2 ) GunPrefab = ExtResource( 4 ) [node name="AnimatedSprite" parent="." index="1"] -frame = 1 +frame = 3 diff --git a/DungeonShooting_Godot/prefab/weapon/Weapon.tscn b/DungeonShooting_Godot/prefab/weapon/Weapon.tscn index d730340..c095c86 100644 --- a/DungeonShooting_Godot/prefab/weapon/Weapon.tscn +++ b/DungeonShooting_Godot/prefab/weapon/Weapon.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=7 format=2] +[gd_scene load_steps=8 format=2] [ext_resource path="res://resource/materlal/Shadow.gdshader" type="Shader" id=2] @@ -71,7 +71,9 @@ [sub_resource type="RectangleShape2D" id=1] extents = Vector2( 7.8, 3.5 ) -[node name="Weapon" type="Node2D"] +[sub_resource type="RectangleShape2D" id=10] + +[node name="Weapon" type="KinematicBody2D"] [node name="WeaponBody" type="Area2D" parent="."] collision_layer = 4 @@ -101,3 +103,7 @@ [node name="Collision" type="CollisionShape2D" parent="WeaponBody"] position = Vector2( 0.59999, 0.199997 ) shape = SubResource( 1 ) + +[node name="Collision" type="CollisionShape2D" parent="."] +shape = SubResource( 10 ) +disabled = true diff --git a/DungeonShooting_Godot/prefab/weapon/bullet/HighSpeedBullet.tscn b/DungeonShooting_Godot/prefab/weapon/bullet/HighSpeedBullet.tscn index e309e2f..51eaeb8 100644 --- a/DungeonShooting_Godot/prefab/weapon/bullet/HighSpeedBullet.tscn +++ b/DungeonShooting_Godot/prefab/weapon/bullet/HighSpeedBullet.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=5 format=2] -[ext_resource path="res://src/game/props/weapon/bullet/HighSpeedBullet.cs" type="Script" id=1] +[ext_resource path="res://src/game/item/weapon/bullet/HighSpeedBullet.cs" type="Script" id=1] [ext_resource path="res://prefab/effect/Hit.tscn" type="PackedScene" id=2] diff --git a/DungeonShooting_Godot/prefab/weapon/bullet/OrdinaryBullets.tscn b/DungeonShooting_Godot/prefab/weapon/bullet/OrdinaryBullets.tscn index 6297774..11c59c4 100644 --- a/DungeonShooting_Godot/prefab/weapon/bullet/OrdinaryBullets.tscn +++ b/DungeonShooting_Godot/prefab/weapon/bullet/OrdinaryBullets.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=4 format=2] -[ext_resource path="res://src/game/props/weapon/bullet/OrdinaryBullets.cs" type="Script" id=1] +[ext_resource path="res://src/game/item/weapon/bullet/OrdinaryBullets.cs" type="Script" id=1] [ext_resource path="res://resource/sprite/bullet/bullet.png" type="Texture" id=2] [ext_resource path="res://prefab/effect/Hit.tscn" type="PackedScene" id=3] diff --git a/DungeonShooting_Godot/src/framework/ActivityObject.cs b/DungeonShooting_Godot/src/framework/ActivityObject.cs index b65f714..dbf9cc7 100644 --- a/DungeonShooting_Godot/src/framework/ActivityObject.cs +++ b/DungeonShooting_Godot/src/framework/ActivityObject.cs @@ -1,22 +1,31 @@  +using System; using Godot; /// /// 房间内活动物体基类 /// -public abstract class ActivityObject : ActivityObject where T : KinematicBody2D +public abstract class ActivityObject : ActivityObject where T : ActivityObject { public ActivityObject() { - ComponentControl = CreateComponentControl(); + ComponentControl = (ComponentControl)Activator.CreateInstance(typeof(ComponentControl), this); + Sprite = GetNodeOrNull("Sprite"); + if (Sprite == null) + { + GD.PrintErr("ActivityObject节点下必须要有一个'Sprite'节点!"); + } + Collision = GetNodeOrNull("Collision"); + if (Collision == null) + { + GD.PrintErr("ActivityObject节点下必须要有一个'Collision'节点!"); + } } - + /// /// 组件管理器 /// - public ComponentControl ComponentControl { get; } - - public abstract ComponentControl CreateComponentControl(); + public new ComponentControl ComponentControl { get; } } /// @@ -24,15 +33,31 @@ /// public abstract class ActivityObject : KinematicBody2D { + + /// + /// 组件管理器 + /// + public ComponentControl ComponentControl { get; } + + /// + /// 当前物体显示的精灵图像, 节点名称必须叫 "Sprite" + /// + public Sprite Sprite { get; protected set; } + + /// + /// 当前物体碰撞器节点, 节点名称必须叫 "Collision" + /// + public CollisionShape2D Collision { get; protected set; } + /// /// 返回是否能与其他ActivityObject互动 /// /// 触发者 - public abstract CheckInteractiveResult CheckInteractive(ActivityObject master) where TU : KinematicBody2D; + public abstract CheckInteractiveResult CheckInteractive(ActivityObject master) where TU : ActivityObject; /// /// 与其它ActivityObject互动时调用 /// /// 触发者 - public abstract void Interactive(ActivityObject master) where TU : KinematicBody2D; + public abstract void Interactive(ActivityObject master) where TU : ActivityObject; } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/Component.cs b/DungeonShooting_Godot/src/framework/Component.cs index acace94..882ccad 100644 --- a/DungeonShooting_Godot/src/framework/Component.cs +++ b/DungeonShooting_Godot/src/framework/Component.cs @@ -4,9 +4,9 @@ /// /// 组件基类 /// -public abstract class Component : Component where TG : KinematicBody2D +public abstract class Component : Component where TG : ActivityObject { - public ComponentControl ComponentControl { get; private set; } + public new ComponentControl ComponentControl { get; private set; } public Vector2 Position { @@ -25,6 +25,10 @@ get => ComponentControl.Visible; set => ComponentControl.Visible = value; } + + public Sprite Sprite => ComponentControl.Sprite; + + public CollisionShape2D Collision => ComponentControl.Collision; public bool Enable { get; set; } = true; @@ -33,7 +37,7 @@ /// /// 当组件销毁 /// - public override void Destroy() + public new void Destroy() { if (IsDestroyed) { @@ -60,18 +64,20 @@ /// public abstract class Component : IProcess, IDestroy { + public ComponentControl ComponentControl { get; } + /// - /// 该组件所绑定的GameObject的坐标 + /// 该组件所绑定的ComponentControl的坐标 /// Vector2 Position { get; set; } /// - /// 该组件所绑定的GameObject的全局坐标 + /// 该组件所绑定的ComponentControl的全局坐标 /// Vector2 GlobalPosition { get; set; } /// - /// 该组件所绑定的GameObject的显示状态 + /// 该组件所绑定的ComponentControl的显示状态 /// bool Visible { get; set; } @@ -80,9 +86,23 @@ /// bool Enable { get; set; } + /// + /// 该组件所绑定的ComponentControl显示的精灵 + /// + Sprite Sprite { get; } + + /// + /// 该组件所绑定的ComponentControl的碰撞器 + /// + CollisionShape2D Collision { get; } + public bool IsDestroyed { get; } private bool _isReady = false; + + public Component() + { + } /// /// 第一次调用 Process 或 PhysicsProcess 之前调用 @@ -116,8 +136,10 @@ public virtual void OnUnMount() { } - - public abstract void Destroy(); + + public void Destroy() + { + } internal void _TriggerProcess(float delta) { diff --git a/DungeonShooting_Godot/src/framework/ComponentControl.cs b/DungeonShooting_Godot/src/framework/ComponentControl.cs index e3c548c..b1beb8e 100644 --- a/DungeonShooting_Godot/src/framework/ComponentControl.cs +++ b/DungeonShooting_Godot/src/framework/ComponentControl.cs @@ -1,8 +1,10 @@ +using System; using System.Collections.Generic; using Godot; -public class ComponentControl : Node, IDestroy where T : KinematicBody2D +public class ComponentControl : Node, IDestroy where T : ActivityObject { + public float Altitude { get; set; } public Vector2 Position @@ -23,11 +25,15 @@ set => Node.Visible = value; } + public Sprite Sprite => Node.Sprite; + + public CollisionShape2D Collision => Node.Collision; + public bool IsDestroyed { get; private set; } public T Node { get; private set; } - private List> _components = new List>(); + private List>> _components = new List>>(); public ComponentControl(T node) { @@ -36,41 +42,11 @@ node.AddChild(this); } - public void AddComponent(NodeComponent nodeComponent) where TN : Node - { - if (!_components.Contains(nodeComponent)) - { - _components.Add(nodeComponent); - nodeComponent.SetGameObject(this); - var parent = nodeComponent.Node.GetParent(); - if (parent == null) - { - Node.AddChild(nodeComponent.Node); - } - else if (parent != Node) - { - parent.RemoveChild(nodeComponent.Node); - Node.AddChild(nodeComponent.Node); - } - nodeComponent.OnMount(); - } - } - - public void RemoveComponent(NodeComponent nodeComponent) where TN : Node - { - if (_components.Remove(nodeComponent)) - { - nodeComponent.SetGameObject(null); - Node.RemoveChild(nodeComponent.Node); - nodeComponent.OnUnMount(); - } - } - public void AddComponent(Component component) { - if (!_components.Contains(component)) + if (!ContainsComponent(component)) { - _components.Add(component); + _components.Add(new KeyValuePair>(component.GetType(), component)); component.SetGameObject(this); component.OnMount(); } @@ -78,20 +54,41 @@ public void RemoveComponent(Component component) { - if (_components.Remove(component)) + if (ContainsComponent(component)) { component.SetGameObject(null); component.OnUnMount(); } } + public Component GetComponent(Type type) + { + for (int i = 0; i < _components.Count; i++) + { + var temp = _components[i]; + if (temp.Key == type) + { + return temp.Value; + } + } + + return null; + } + + public TC GetComponent() where TC : Component + { + var component = GetComponent(typeof(TC)); + if (component == null) return null; + return (TC)component; + } + public override void _Process(float delta) { var arr = _components.ToArray(); for (int i = 0; i < arr.Length; i++) { if (IsDestroyed) return; - var temp = arr[i]; + var temp = arr[i].Value; if (temp != null && temp.ComponentControl == this && temp.Enable) { temp._TriggerProcess(delta); @@ -105,7 +102,7 @@ for (int i = 0; i < arr.Length; i++) { if (IsDestroyed) return; - var temp = arr[i]; + var temp = arr[i].Value; if (temp != null && temp.ComponentControl == this && temp.Enable) { temp._TriggerPhysicsProcess(delta); @@ -125,7 +122,19 @@ var arr = _components.ToArray(); for (int i = 0; i < arr.Length; i++) { - arr[i].Destroy(); + arr[i].Value?.Destroy(); } } + + private bool ContainsComponent(Component component) + { + for (int i = 0; i < _components.Count; i++) + { + if (_components[i].Value == component) + { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/NodeComponent.cs b/DungeonShooting_Godot/src/framework/NodeComponent.cs deleted file mode 100644 index 4ae2121..0000000 --- a/DungeonShooting_Godot/src/framework/NodeComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Godot; - -public abstract class NodeComponent : Component where TN : Node where TG : KinematicBody2D -{ - public TN Node { get; } - - public NodeComponent(TN inst) - { - Node = inst; - } - - public override void OnDestroy() - { - Node.QueueFree(); - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/common/NodeExtend.cs b/DungeonShooting_Godot/src/game/common/NodeExtend.cs index 9f1242b..8cb5c41 100644 --- a/DungeonShooting_Godot/src/game/common/NodeExtend.cs +++ b/DungeonShooting_Godot/src/game/common/NodeExtend.cs @@ -104,4 +104,20 @@ } return null; } + + public static T StartThrow(this ActivityObject node, Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed, float ySpeed, float rotate) where T : ThrowComponent + { + T throwNode = node.ComponentControl.GetComponent(); + if (throwNode == null) + { + throwNode = Activator.CreateInstance(); + node.ComponentControl.AddComponent(throwNode); + } + else + { + throwNode.StopThrow(); + } + throwNode.StartThrow(size, start, startHeight, direction, xSpeed, ySpeed, rotate); + return throwNode; + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/effect/ThrowNode.cs b/DungeonShooting_Godot/src/game/effect/ThrowNode.cs index 5073764..a5ebe35 100644 --- a/DungeonShooting_Godot/src/game/effect/ThrowNode.cs +++ b/DungeonShooting_Godot/src/game/effect/ThrowNode.cs @@ -148,7 +148,8 @@ /// 旋转速度 /// 需要挂载的节点 /// 抛射的节点显示的纹理, 用于渲染阴影用 - public virtual void StartThrow(Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed, float ySpeed, float rotate, Node2D mount, Sprite shadowTarget) + public virtual void StartThrow(Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed, + float ySpeed, float rotate, Node2D mount, Sprite shadowTarget) { StartThrow(size, start, startHeight, direction, xSpeed, ySpeed, rotate, mount); ShadowTarget = shadowTarget; @@ -163,6 +164,7 @@ ShadowSprite.Material = ResourceManager.ShadowMaterial; AddChild(ShadowSprite); } + inversionX = mount.Scale.y < 0 ? true : false; if (inversionX) { @@ -172,6 +174,7 @@ { ShadowSprite.Scale = shadowTarget.Scale; } + ShadowSprite.Texture = shadowTarget.Texture; } else if (ShadowSprite != null) diff --git a/DungeonShooting_Godot/src/game/item/CheckInteractiveResult.cs b/DungeonShooting_Godot/src/game/item/CheckInteractiveResult.cs new file mode 100644 index 0000000..eb8676b --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/CheckInteractiveResult.cs @@ -0,0 +1,28 @@ + +/// +/// 检测互动返回的数据集 +/// +public class CheckInteractiveResult +{ + /// + /// 互动物体 + /// + public ActivityObject Target; + /// + /// 是否可以互动 + /// + public bool CanInteractive; + /// + /// 互动提示信息 + /// + public string Message; + /// + /// 互动提示显示的图标 + /// + public string ShowIcon; + + public CheckInteractiveResult(ActivityObject target) + { + Target = target; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/ThrowComponent.cs b/DungeonShooting_Godot/src/game/item/ThrowComponent.cs new file mode 100644 index 0000000..6b0d129 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/ThrowComponent.cs @@ -0,0 +1,21 @@ + +using Godot; + +public class ThrowComponent : Component +{ + public override void Ready() + { + + } + + public virtual void StartThrow(Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed, + float ySpeed, float rotate) + { + + } + + public virtual void StopThrow() + { + + } +} diff --git a/DungeonShooting_Godot/src/game/item/package/Holster.cs b/DungeonShooting_Godot/src/game/item/package/Holster.cs new file mode 100644 index 0000000..bbe7c9b --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/package/Holster.cs @@ -0,0 +1,272 @@ +using Godot; + +/// +/// 角色身上的武器袋, 存储角色携带的武器 +/// +public class Holster +{ + /// + /// 插槽类 + /// + public class WeaponSlot + { + /// + /// 是否启用 + /// + public bool Enable = false; + /// + /// 当前插槽存放的武器类型 + /// + public WeaponWeightType Type = WeaponWeightType.MainWeapon; + /// + /// 插槽存放的武器 + /// + public Weapon Weapon; + } + + /// + /// 归属者 + /// + public Role Master { get; } + + /// + /// 当前使用的武器对象 + /// + public Weapon ActiveWeapon { get; private set; } + + /// + /// 当前使用的武器的索引 + /// + public int ActiveIndex { get; private set; } = 0; + + public WeaponSlot[] SlotList { get; } = new WeaponSlot[4]; + + public Holster(Role master) + { + Master = master; + + //创建武器的插槽, 默认前两个都是启用的 + WeaponSlot slot1 = new WeaponSlot(); + slot1.Enable = true; + SlotList[0] = slot1; + + WeaponSlot slot2 = new WeaponSlot(); + slot2.Enable = true; + slot2.Type = WeaponWeightType.DeputyWeapon; + SlotList[1] = slot2; + + WeaponSlot slot3 = new WeaponSlot(); + SlotList[2] = slot3; + + WeaponSlot slot4 = new WeaponSlot(); + slot4.Type = WeaponWeightType.DeputyWeapon; + SlotList[3] = slot4; + } + + /// + /// 根据索引获取武器 + /// + public Weapon GetWeapon(int index) { + if (index >= SlotList.Length) + { + return null; + } + return SlotList[index].Weapon; + } + + /// + /// 根据武器id查找武器袋中该武器所在的位置, 如果没有, 则返回 -1 + /// + /// 武器id + public int FindWeapon(string id) + { + for (int i = 0; i < SlotList.Length; i++) + { + var item = SlotList[i]; + if (item.Weapon != null && item.Weapon.Id == id) + { + return i; + } + } + return -1; + } + + /// + /// 返回是否能放入武器 + /// + /// 武器对象 + public bool CanPickupWeapon(Weapon weapon) + { + for (int i = 0; i < SlotList.Length; i++) + { + var item = SlotList[i]; + if (item.Enable && weapon.Attribute.WeightType == item.Type && item.Weapon == null) + { + return true; + } + } + return false; + } + + /// + /// 拾起武器, 存入武器袋中, 返回存放在武器袋的位置, 如果容不下这把武器, 则会返回 -1 + /// + /// 武器对象 + public int PickupWeapon(Weapon weapon) + { + for (int i = 0; i < SlotList.Length; i++) + { + var item = SlotList[i]; + if (item.Enable && weapon.Attribute.WeightType == item.Type && item.Weapon == null) + { + weapon.Pickup(); + item.Weapon = weapon; + ExchangeByIndex(i); + weapon._PickUpWeapon(Master); + return i; + } + } + return -1; + } + + /// + /// 移除指定位置的武器, 并返回这个武器对象, 如果移除正在使用的这把武器, 则会自动切换到上一把武器 + /// + /// 所在武器袋的位置索引 + public Weapon RmoveWeapon(int index) + { + if (index < 0 || index >= SlotList.Length) + { + return null; + } + var slot = SlotList[index]; + if (slot.Weapon == null) + { + return null; + } + var weapon = slot.Weapon; + weapon.GetParent().RemoveChild(weapon); + slot.Weapon = null; + + //如果是当前手持的武器, 就需要调用切换武器操作 + if (index == ActiveIndex) + { + //没有其他武器了 + if (ExchangePrev() == index) + { + ActiveIndex = 0; + ActiveWeapon = null; + } + } + weapon._ThrowOutWeapon(); + return weapon; + } + + /// + /// 切换到上一个武器 + /// + public int ExchangePrev() + { + var index = ActiveIndex - 1; + do + { + if (index < 0) + { + index = SlotList.Length - 1; + } + if (ExchangeByIndex(index)) + { + return index; + } + } while (index-- != ActiveIndex); + return -1; + } + + /// + /// 切换到下一个武器, + /// + public int ExchangeNext() + { + var index = ActiveIndex + 1; + do + { + if (index >= SlotList.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 > SlotList.Length) return false; + var slot = SlotList[index]; + if (slot == null || slot.Weapon == null) return false; + + //将上一把武器放到背后 + if (ActiveWeapon != null) + { + var tempParent = ActiveWeapon.GetParentOrNull(); + if (tempParent != null) + { + tempParent.RemoveChild(ActiveWeapon); + Master.BackMountPoint.AddChild(ActiveWeapon); + if (ActiveIndex == 0) + { + ActiveWeapon.Position = new Vector2(0, 5); + ActiveWeapon.RotationDegrees = 50; + ActiveWeapon.Scale = new Vector2(-1, 1); + } + else if (ActiveIndex == 1) + { + ActiveWeapon.Position = new Vector2(0, 0); + ActiveWeapon.RotationDegrees = 120; + ActiveWeapon.Scale = new Vector2(1, -1); + } + else if (ActiveIndex == 2) + { + ActiveWeapon.Position = new Vector2(0, 5); + ActiveWeapon.RotationDegrees = 310; + ActiveWeapon.Scale = new Vector2(1, 1); + } + else if (ActiveIndex == 3) + { + ActiveWeapon.Position = new Vector2(0, 0); + ActiveWeapon.RotationDegrees = 60; + ActiveWeapon.Scale = new Vector2(1, 1); + } + ActiveWeapon._Conceal(); + } + } + + //更改父节点 + var parent = slot.Weapon.GetParentOrNull(); + if (parent == null) + { + Master.MountPoint.AddChild(slot.Weapon); + } + else if (parent != Master.MountPoint) + { + parent.RemoveChild(slot.Weapon); + Master.MountPoint.AddChild(slot.Weapon); + } + + slot.Weapon.Position = Vector2.Zero; + slot.Weapon.Scale = Vector2.One; + slot.Weapon.RotationDegrees = 0; + ActiveWeapon = slot.Weapon; + ActiveIndex = index; + ActiveWeapon._Active(); + return true; + } +} diff --git a/DungeonShooting_Godot/src/game/item/weapon/RegisterWeapon.cs b/DungeonShooting_Godot/src/game/item/weapon/RegisterWeapon.cs new file mode 100644 index 0000000..3cbcd57 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/RegisterWeapon.cs @@ -0,0 +1,23 @@ +using System; + +/// +/// 用作 Weapon 子类上, 用于注册武器, 允许同时存在多个 RegisterWeapon 特性 +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class RegisterWeapon : Attribute +{ + + public string Id { get; private set; } + public Type AttributeType { get; private set; } + + public RegisterWeapon(string id) + { + Id = id; + } + + public RegisterWeapon(string id, Type attributeType) + { + Id = id; + AttributeType = attributeType; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/RegisterWeaponFunction.cs b/DungeonShooting_Godot/src/game/item/weapon/RegisterWeaponFunction.cs new file mode 100644 index 0000000..1796a95 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/RegisterWeaponFunction.cs @@ -0,0 +1,16 @@ +using System; + +/// +/// 用作静态函数上, 用于注册武器, 函数必须返回一个 Weapon 对象, 且参数为 string id, +/// 那么它看起来应该像这样: static Weapon Method(string id); +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class RegisterWeaponFunction : Attribute +{ + public string Id { get; private set; } + + public RegisterWeaponFunction(string id) + { + Id = id; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/ThrowGun.cs b/DungeonShooting_Godot/src/game/item/weapon/ThrowGun.cs new file mode 100644 index 0000000..d3c652a --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/ThrowGun.cs @@ -0,0 +1,44 @@ +using Godot; + +public class ThrowWeapon : ThrowNode +{ + + private bool fristOver = true; + + public override void _Ready() + { + base._Ready(); + ZIndex = 2; + } + + public override void StartThrow(Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed, float ySpeed, float rotate, Node2D mount) + { + base.StartThrow(size, start, startHeight, direction, xSpeed, ySpeed, rotate, mount); + fristOver = true; + } + + protected override void OnOver() + { + if (fristOver) + { + fristOver = false; + if (Mount is Weapon gun) + { + gun._FallToGround(); + } + } + //如果落地高度不够低, 再抛一次 + if (StartYSpeed > 1) + { + StartThrow(Size, GlobalPosition, 0, Direction, XSpeed * 0.8f, StartYSpeed * 0.5f, RotateSpeed * 0.5f, null); + } + else //结束 + { + base.OnOver(); + } + } + protected override void OnMaxHeight(float height) + { + ZIndex = 0; + } +} \ 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 new file mode 100644 index 0000000..752862c --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs @@ -0,0 +1,784 @@ +using Godot; +using System; + +/// +/// 武器的基类 +/// +public abstract class Weapon : ActivityObject +{ + + /// + /// 武器的唯一id + /// + public string Id { get; } + + /// + /// 开火回调事件 + /// + public event Action FireEvent; + + /// + /// 属性数据 + /// + public WeaponAttribute Attribute { get; private set; } + + /// + /// 武器的图片 + /// + public Sprite WeaponSprite { get; private set; } + + /// + /// 动画播放器 + /// + /// + public AnimationPlayer AnimationPlayer { get; private set; } + + /// + /// 武器攻击的目标阵营 + /// + public CampEnum TargetCamp { get; set; } + + /// + /// 该武器的拥有者 + /// + public Role Master { get; private set; } + + /// + /// 当前弹夹弹药剩余量 + /// + public int CurrAmmo { get; private set; } + /// + /// 剩余弹药量 + /// + public int ResidueAmmo { get; private set; } + + /// + /// 武器管的开火点 + /// + public Position2D FirePoint { get; private set; } + /// + /// 武器管的原点 + /// + public Position2D OriginPoint { get; private set; } + /// + /// 弹壳抛出的点 + /// + public Position2D ShellPoint { get; private set; } + /// + /// 碰撞器节点 + /// + /// + public CollisionShape2D CollisionShape2D { get; private 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; + } + } + + //是否按下 + 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; + + /// + /// 根据属性创建一把武器 + /// + /// 武器唯一id + /// 属性 + public Weapon(string id, WeaponAttribute attribute) + { + Id = id; + Attribute = attribute; + //加载预制体 + var tempPrefab = ResourceManager.Load(Attribute.WeaponPrefab); + if (tempPrefab == null) + { + throw new Exception("WeaponAttribute中未设置'WeaponPrefab'属性!"); + } + var tempNode = tempPrefab.Instance(); + var body = tempNode.GetChild(0); + tempNode.RemoveChild(body); + AddChild(body); + + WeaponSprite = GetNode("WeaponBody/WeaponSprite"); + FirePoint = GetNode("WeaponBody/FirePoint"); + OriginPoint = GetNode("WeaponBody/OriginPoint"); + ShellPoint = GetNode("WeaponBody/ShellPoint"); + AnimationPlayer = GetNode("WeaponBody/AnimationPlayer"); + CollisionShape2D = GetNode("WeaponBody/Collision"); + + //更新图片 + WeaponSprite.Texture = ResourceLoader.Load(Attribute.Sprite); + WeaponSprite.Position = Attribute.CenterPosition; + //开火位置 + FirePoint.Position = new Vector2(Attribute.FirePosition.x, -Attribute.FirePosition.y); + OriginPoint.Position = new Vector2(0, -Attribute.FirePosition.y); + + //弹药量 + CurrAmmo = Attribute.AmmoCapacity; + //剩余弹药量 + ResidueAmmo = Attribute.MaxAmmoCapacity - Attribute.AmmoCapacity; + } + + /// + /// 当按下扳机时调用 + /// + protected abstract void OnDownTrigger(); + + /// + /// 当松开扳机时调用 + /// + protected abstract void OnUpTrigger(); + + /// + /// 单次开火时调用的函数 + /// + protected abstract void OnFire(); + + /// + /// 发射子弹时调用的函数, 每发射一枚子弹调用一次, + /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次 + /// + protected abstract void OnShoot(); + + /// + /// 当开始换弹时调用 + /// + protected abstract void OnReload(); + + /// + /// 当换弹完成时调用 + /// + protected abstract void OnReloadFinish(); + + /// + /// 当武器被拾起时调用 + /// + /// 拾起该武器的角色 + protected abstract void OnPickUp(Role master); + + /// + /// 当武器从武器袋中扔掉时调用 + /// + protected abstract void OnThrowOut(); + + /// + /// 当武器被激活时调用, 也就是使用当武器是调用 + /// + protected abstract void OnActive(); + + /// + /// 当武器被收起时调用 + /// + protected abstract void OnConceal(); + + public override void _Process(float delta) + { + if (Master == null) //这把武器被扔在地上 + { + Reloading = false; + ReloadTimer = 0; + triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0; + triggerFlag = false; + attackFlag = false; + attackTimer = attackTimer > 0 ? attackTimer - delta : 0; + CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange); + continuousCount = 0; + delayedTime = 0; + } + else if (Master.Holster.ActiveWeapon != this) //当前武器没有被使用 + { + Reloading = false; + ReloadTimer = 0; + triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0; + triggerFlag = false; + attackFlag = false; + attackTimer = attackTimer > 0 ? attackTimer - delta : 0; + CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange); + continuousCount = 0; + delayedTime = 0; + } + else //正在使用中 + { + + //换弹 + if (Reloading) + { + ReloadTimer -= delta; + if (ReloadTimer <= 0) + { + ReloadSuccess(); + } + } + + if (triggerFlag) + { + if (upTimer > 0) //第一帧按下扳机 + { + upTimer = 0; + DownTrigger(); + } + downTimer += delta; + } + else + { + if (downTimer > 0) //第一帧松开扳机 + { + downTimer = 0; + UpTrigger(); + } + upTimer += delta; + } + + // 攻击的计时器 + if (attackTimer > 0) + { + attackTimer -= delta; + if (attackTimer < 0) + { + delayedTime += attackTimer; + attackTimer = 0; + } + } + else if (delayedTime > 0) //攻击延时 + { + delayedTime -= delta; + if (attackTimer < 0) + { + delayedTime = 0; + } + } + + //连发判断 + if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0) + { + //开火 + TriggerFire(); + } + + if (!attackFlag && attackTimer <= 0) + { + CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange); + } + triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0; + triggerFlag = false; + attackFlag = false; + + //武器身回归 + Position = Position.MoveToward(Vector2.Zero, 35 * delta); + if (fireInterval == 0) + { + RotationDegrees = 0; + } + else + { + RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval); + } + } + } + + /// + /// 扳机函数, 调用即视为扣动扳机 + /// + public void Trigger() + { + //是否第一帧按下 + 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) + { + 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; + //子弹不够 + _Reload(); + } + + if (fireFlag) + { + if (justDown) + { + //开火前延时 + delayedTime = Attribute.DelayedTime; + //扳机按下间隔 + triggerTimer = Attribute.TriggerInterval; + //连发数量 + if (!Attribute.ContinuousShoot) + { + continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount); + } + } + if (delayedTime <= 0 && attackTimer <= 0) + { + TriggerFire(); + } + attackFlag = true; + } + + } + triggerFlag = true; + } + + /// + /// 刚按下扳机 + /// + private void DownTrigger() + { + OnDownTrigger(); + } + + /// + /// 刚松开扳机 + /// + private void UpTrigger() + { + continuousShootFlag = false; + if (delayedTime > 0) + { + continuousCount = 0; + } + OnUpTrigger(); + } + + /// + /// 触发开火 + /// + private void TriggerFire() + { + continuousCount = continuousCount > 0 ? continuousCount - 1 : 0; + + //减子弹数量 + CurrAmmo--; + //开火间隙 + fireInterval = 60 / Attribute.StartFiringSpeed; + //攻击冷却 + attackTimer += fireInterval; + + //触发开火函数 + OnFire(); + + //开火发射的子弹数量 + var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount); + //武器口角度 + var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle(); + + //创建子弹 + for (int i = 0; i < bulletCount; i++) + { + //先算武器口方向 + Rotation = (float)GD.RandRange(-angle, angle); + //发射子弹 + OnShoot(); + } + + //当前的散射半径 + CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange); + //武器的旋转角度 + RotationDegrees -= Attribute.UpliftAngle; + fireAngle = RotationDegrees; + //武器身位置 + Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y); + + if (FireEvent != null) + { + FireEvent(this); + } + } + + /// + /// 返回弹药是否到达上限 + /// + public bool IsFullAmmo() + { + return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity; + } + + /// + /// 返回是否弹药耗尽 + /// + public bool IsEmptyAmmo() + { + return CurrAmmo + ResidueAmmo == 0; + } + + /// + /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量 + /// + /// 弹药数量 + public 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; + 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; + OnReload(); + } + } + else //换弹结束 + { + if (ResidueAmmo >= Attribute.AmmoCapacity) + { + ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo; + CurrAmmo = Attribute.AmmoCapacity; + } + else + { + CurrAmmo = ResidueAmmo; + ResidueAmmo = 0; + } + Reloading = false; + ReloadTimer = 0; + OnReloadFinish(); + } + } + + 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(Id); + if (index != -1) //如果有这个武器 + { + if (CurrAmmo + ResidueAmmo != 0) //子弹不为空 + { + var targetWeapon = roleMaster.Holster.GetWeapon(index); + if (!targetWeapon.IsFullAmmo()) //背包里面的武器子弹未满 + { + //可以互动拾起弹药 + result.CanInteractive = true; + result.Message = Attribute.Name; + result.ShowIcon = "res://resource/sprite/ui/icon/icon_bullet.png"; + return result; + } + } + } + else //没有武器 + { + if (roleMaster.Holster.CanPickupWeapon(this)) //能拾起武器 + { + //可以互动, 拾起武器 + result.CanInteractive = true; + result.Message = Attribute.Name; + result.ShowIcon = "res://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 = "res://resource/sprite/ui/icon/icon_replace.png"; + return result; + } + } + } + } + + return result; + } + + public override void Interactive(ActivityObject master) + { + if (master is Role roleMaster) //与role碰撞 + { + //查找是否有同类型武器 + var index = roleMaster.Holster.FindWeapon(Id); + if (index != -1) //如果有这个武器 + { + if (CurrAmmo + ResidueAmmo == 0) //没有子弹了 + { + return; + } + + var weapon = roleMaster.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) + { + this.StartThrow(new Vector2(20, 20), GlobalPosition, 0, 0, + MathUtils.RandRangeInt(-20, 20), MathUtils.RandRangeInt(20, 50), + MathUtils.RandRangeInt(-180, 180), WeaponSprite); + } + } + else //没有武器 + { + if (roleMaster.Holster.PickupWeapon(this) == -1) + { + var slot = roleMaster.Holster.SlotList[roleMaster.Holster.ActiveIndex]; + if (slot.Type == Attribute.WeightType) + { + var weapon = roleMaster.Holster.RmoveWeapon(roleMaster.Holster.ActiveIndex); + weapon.StartThrowWeapon(roleMaster); + roleMaster.PickUpWeapon(this); + } + } + } + } + } + + public Vector2 GetItemPosition() + { + return GlobalPosition; + } + + /// + /// 触发落到地面 + /// + public void _FallToGround() + { + //启用碰撞 + CollisionShape2D.Disabled = false; + } + + /// + /// 触发拾起 + /// + public void _PickUpWeapon(Role master) + { + Master = master; + //握把位置 + WeaponSprite.Position = Attribute.HoldPosition; + //清除泛白效果 + ShaderMaterial sm = WeaponSprite.Material as ShaderMaterial; + sm.SetShaderParam("schedule", 0); + //停止动画 + AnimationPlayer.Stop(); + ZIndex = 0; + //禁用碰撞 + CollisionShape2D.Disabled = true; + OnPickUp(master); + } + + /// + /// 触发抛出 + /// a + public void _ThrowOutWeapon() + { + Master = null; + WeaponSprite.Position = Attribute.CenterPosition; + AnimationPlayer.Play("Floodlight"); + OnThrowOut(); + } + + /// + /// 触发启用武器 + /// + public void _Active() + { + OnActive(); + } + + /// + /// 触发收起武器 + /// + public void _Conceal() + { + OnConceal(); + } + + /// + /// 实例化并返回子弹对象 + /// + /// 子弹的预制体 + protected T CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) where T : Node2D, IBullet + { + return (T)CreateBullet(bulletPack, globalPostion, globalRotation, parent); + } + + /// + /// 实例化并返回子弹对象 + /// + /// 子弹的预制体 + protected IBullet CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) + { + // 实例化子弹 + Node2D bullet = bulletPack.Instance(); + // 设置坐标 + bullet.GlobalPosition = globalPostion; + // 旋转角度 + bullet.GlobalRotation = globalRotation; + if (parent == null) + { + RoomManager.Current.SortRoot.AddChild(bullet); + } + else + { + parent.AddChild(bullet); + } + // 调用初始化 + IBullet result = (IBullet)bullet; + result.Init(TargetCamp, this, null); + return result; + } +} \ 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 new file mode 100644 index 0000000..c6cad38 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/WeaponAttribute.cs @@ -0,0 +1,152 @@ +using Godot; + +/// +/// 武器上的属性 +/// +public class WeaponAttribute +{ + /// + /// 武器显示的名称 + /// + public string Name = "Gun1"; + /// + /// 武器 Prefab, 必须继承场景 "res://prefab/weapon/Weapon.tscn" + /// + public string WeaponPrefab = "res://prefab/weapon/Weapon.tscn"; + /// + /// 武器类型 + /// + public WeaponWeightType WeightType = WeaponWeightType.MainWeapon; + /// + /// 武器的图片 + /// + public string Sprite = "res://resource/sprite/gun/gun1.png"; + /// + /// 是否连续发射, 如果为false, 则每次发射都需要扣动扳机 + /// + public bool ContinuousShoot = true; + /// + /// 弹夹容量 + /// + public int AmmoCapacity = 30; + /// + /// 弹药容量上限 + /// + public int MaxAmmoCapacity = 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; + /// + /// 连续发射最小次数, 仅当 ContinuousShoot 为 false 时生效 + /// + public int MinContinuousCount = 3; + /// + /// 连续发射最大次数, 仅当 ContinuousShoot 为 false 时生效 + /// + public int MaxContinuousCount = 3; + /// + /// 按下一次扳机后需要多长时间才能再次按下 + /// + public float TriggerInterval = 0; + /// + /// 初始射速, 初始每秒分钟能发射多少发子弹 + /// + public float StartFiringSpeed = 300; + /// + /// 最终射速, 最终每秒分钟能发射多少发子弹 + /// + 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 MaxDistance = 600; + /// + /// 子弹飞行最小距离 + /// + public float MinDistance = 800; + /// + /// 武器精灵的旋转中心坐标 + /// + public Vector2 CenterPosition = new Vector2(0, 0); + /// + /// 开火位置 + /// + public Vector2 FirePosition = new Vector2(11, 0); + /// + /// 握把位置 + /// + public Vector2 HoldPosition = new Vector2(4, -3); + /// + /// 重量 + /// + public float Weight = 11; + /// + /// 最大后坐力 (仅用于开火后武器身抖动) + /// + public float MaxBacklash = 4; + /// + /// 最小后坐力 (仅用于开火后武器身抖动) + /// + public float MinBacklash = 2; + /// + /// 开火后武器口上抬角度 + /// + public float UpliftAngle = 30; + /// + /// 开火后武器口角度恢复速度倍数 + /// + public float UpliftAngleRestore = 1; +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/WeaponManager.cs b/DungeonShooting_Godot/src/game/item/weapon/WeaponManager.cs new file mode 100644 index 0000000..d5e8bf1 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/WeaponManager.cs @@ -0,0 +1,118 @@ +using System.Reflection; +using System; +using System.Collections.Generic; +using Godot; + +/// +/// 武器管理类, 负责武器注册和创建 +/// +public static class WeaponManager +{ + private static Dictionary> registerData = new Dictionary>(); + + /// + /// 从一个指定的程序集中扫描并注册武器对象 + /// + /// 数据集 + public static void RegisterWeaponFromAssembly(Assembly assembly) + { + var types = assembly.GetTypes(); + foreach (var type in types) + { + //注册类 + Attribute[] attribute = Attribute.GetCustomAttributes(type, typeof(RegisterWeapon), false); + if (attribute != null && attribute.Length > 0) + { + if (!typeof(Weapon).IsAssignableFrom(type)) + { + throw new Exception($"注册武器类'{type.FullName}'没有继承类'Weapon'!"); + } + var atts = (RegisterWeapon[])attribute; + foreach (var att in atts) + { + //注册类 + if (att.AttributeType == null) //没有指定属性类型 + { + RegisterWeapon(att.Id, () => + { + return Activator.CreateInstance(type, att.Id, new WeaponAttribute()) as Weapon; + }); + } + else + { + if (!typeof(WeaponAttribute).IsAssignableFrom(att.AttributeType)) + { + throw new Exception($"注册武器类'{type.FullName}'标注的特性中参数'AttributeType'类型没有继承'WeaponAttribute'!"); + } + RegisterWeapon(att.Id, () => + { + return Activator.CreateInstance(type, att.Id, Activator.CreateInstance(att.AttributeType)) as Weapon; + }); + } + } + } + + //注册函数 + MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + foreach (var method in methods) + { + Attribute mAttribute; + // + if ((mAttribute = Attribute.GetCustomAttribute(method, typeof(RegisterWeaponFunction), false)) != null) + { + if (!typeof(Weapon).IsAssignableFrom(method.ReturnType)) //返回值类型不是 Weapon + { + throw new Exception($"注册武器函数'{method.DeclaringType.FullName}.{method.Name}'返回值类型不为'Weapon'!"); + } + var args = method.GetParameters(); + if (args == null || args.Length != 1 || args[0].ParameterType != typeof(string)) //参数类型不正确 + { + throw new Exception($"注册武器函数'{method.DeclaringType.FullName}.{method.Name}'参数不满足(string id)类型"); + } + var att = (RegisterWeaponFunction)mAttribute; + //注册函数 + RegisterWeapon(att.Id, () => + { + return method.Invoke(null, new object[] { att.Id }) as Weapon; + }); + } + } + } + } + + /// + /// 注册当个武器对象 + /// + /// 武器唯一id, 该id不能重复 + /// 获取武器时的回调函数, 函数返回武器对象 + public static void RegisterWeapon(string id, Func callBack) + { + if (registerData.ContainsKey(id)) + { + throw new Exception($"武器id: '{id} 已经被注册!'"); + } + registerData.Add(id, callBack); + } + + /// + /// 根据武器唯一id获取 + /// + /// 武器id + public static Weapon GetGun(string id) + { + if (registerData.TryGetValue(id, out var callback)) + { + return callback(); + } + throw new Exception($"当前武器'{id}未被注册'"); + } + + /// + /// 根据武器唯一id获取 + /// + /// 武器id + public static T GetGun(string id) where T : Weapon + { + return (T)GetGun(id); + } +} diff --git a/DungeonShooting_Godot/src/game/item/weapon/WeaponWeightType.cs b/DungeonShooting_Godot/src/game/item/weapon/WeaponWeightType.cs new file mode 100644 index 0000000..5528683 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/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/item/weapon/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/item/weapon/bullet/Bullet.cs new file mode 100644 index 0000000..4c19b4b --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/bullet/Bullet.cs @@ -0,0 +1,27 @@ +using Godot; + +/// +/// 子弹接口 +/// +public interface IBullet +{ + /// + /// 攻击目标阵营 + /// + CampEnum TargetCamp { get; } + /// + /// 发射该子弹的武器 + /// + Weapon Gun { get; } + /// + /// 发射该子弹的物体对象 + /// + Node2D Master { get; } + /// + /// 初始化基础数据 + /// + /// 攻击的目标阵营 + /// 发射该子弹的枪对象 + /// 发射该子弹的角色 + void Init(CampEnum target, Weapon gun, Node2D master); +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/bullet/HighSpeedBullet.cs b/DungeonShooting_Godot/src/game/item/weapon/bullet/HighSpeedBullet.cs new file mode 100644 index 0000000..53ef711 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/bullet/HighSpeedBullet.cs @@ -0,0 +1,72 @@ +using Godot; + +/// +/// 高速子弹 +/// +public class HighSpeedBullet : Node2D, IBullet +{ + public CampEnum TargetCamp { get; private set; } + + public Weapon Gun { get; private set; } + + public Node2D Master { get; private set; } + + /// + /// 碰撞物体后产生的火花 + /// + [Export] public PackedScene Hit; + + //射线检测节点 + private RayCast2D RayCast2D; + private Line2D Line; + private float ca = 1; + + public void Init(CampEnum target, Weapon gun, Node2D master) + { + TargetCamp = target; + Gun = gun; + Master = master; + + //飞行距离 + var distance = MathUtils.RandRange(gun.Attribute.MinDistance, gun.Attribute.MaxDistance); + + //初始化子弹数据 + RayCast2D = GetNode("RayCast2D"); + Line = GetNode("Line"); + Modulate = Colors.White; + + // 目标点 + Vector2 targetPos = new Vector2(distance, 0); + RayCast2D.CastTo = targetPos; + RayCast2D.ForceRaycastUpdate(); + if (RayCast2D.IsColliding()) + { + //碰到物体 + Vector2 collPosition = RayCast2D.GetCollisionPoint(); + Node2D hit = Hit.Instance(); + hit.RotationDegrees = MathUtils.RandRangeInt(0, 360); + hit.GlobalPosition = collPosition; + GetTree().CurrentScene.AddChild(hit); + //划线的点坐标 + Line.SetPointPosition(1, new Vector2(Line.GlobalPosition.DistanceTo(collPosition), 0)); + } + else + { + //划线的点坐标 + Line.SetPointPosition(1, targetPos); + } + RayCast2D.Enabled = false; + } + + public override void _Process(float delta) + { + ca -= 12 * delta; + if (ca <= 0) { + QueueFree(); + return; + } + Color c = Modulate; + c.a = ca; + Modulate = c; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/item/weapon/bullet/OrdinaryBullets.cs b/DungeonShooting_Godot/src/game/item/weapon/bullet/OrdinaryBullets.cs new file mode 100644 index 0000000..4458e5f --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/bullet/OrdinaryBullets.cs @@ -0,0 +1,97 @@ +using System; +using Godot; + +/// +/// 普通的子弹 +/// +public class OrdinaryBullets : Node2D, IBullet +{ + public CampEnum TargetCamp { get; private set; } + + public Weapon Gun { get; private set; } + + public Node2D Master { get; private set; } + + /// + /// 碰撞物体后产生的火花 + /// + [Export] public PackedScene Hit; + + // 起始点坐标 + private Vector2 StartPosition; + // 最大飞行距离 + private float MaxDistance; + // 子弹飞行速度 + private float FlySpeed = 1500; + //当前子弹已经飞行的距离 + private float CurrFlyDistance = 0; + //射线碰撞节点 + private RayCast2D RayCast; + //子弹的精灵 + private Sprite BulletSprite; + //绘制阴影的精灵 + private Sprite ShadowSprite; + + private int frame = 0; + + public void Init(CampEnum target, Weapon gun, Node2D master) + { + TargetCamp = target; + Gun = gun; + Master = master; + + MaxDistance = MathUtils.RandRange(gun.Attribute.MinDistance, gun.Attribute.MaxDistance); + StartPosition = GlobalPosition; + BulletSprite = GetNode("Bullet"); + BulletSprite.Visible = false; + RayCast = GetNode("RayCast2D"); + + //创建阴影 + ShadowSprite = new Sprite(); + ShadowSprite.Visible = false; + ShadowSprite.ZIndex = -1; + ShadowSprite.Texture = BulletSprite.Texture; + ShadowSprite.Offset = BulletSprite.Offset; + ShadowSprite.Material = ResourceManager.ShadowMaterial; + AddChild(ShadowSprite); + } + + public override void _Ready() + { + //生成时播放音效 + SoundManager.PlaySoundEffect("ordinaryBullet.ogg", this, 6f); + } + + public override void _PhysicsProcess(float delta) + { + if (frame++ == 0) + { + BulletSprite.Visible = true; + ShadowSprite.Visible = true; + } + //碰到墙壁 + if (RayCast.IsColliding()) + { + //var target = RayCast.GetCollider(); + var pos = RayCast.GetCollisionPoint(); + //播放受击动画 + Node2D hit = Hit.Instance(); + hit.RotationDegrees = MathUtils.RandRangeInt(0, 360); + hit.GlobalPosition = pos; + GetTree().CurrentScene.AddChild(hit); + QueueFree(); + } + else //没有碰到, 继续移动 + { + ShadowSprite.GlobalPosition = GlobalPosition + new Vector2(0, 5); + Position += new Vector2(FlySpeed * delta, 0).Rotated(Rotation); + + CurrFlyDistance += FlySpeed * delta; + if (CurrFlyDistance >= MaxDistance) + { + QueueFree(); + } + } + } + +} \ 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 new file mode 100644 index 0000000..31fbc29 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/gun/Gun.cs @@ -0,0 +1,161 @@ +using Godot; + +/// +/// 普通的枪 +/// +[RegisterWeapon("1001", typeof(Gun.RifleAttribute))] +[RegisterWeapon("1003", typeof(Gun.PistolAttribute))] +public class Gun : Weapon +{ + //步枪属性数据 + private class RifleAttribute : WeaponAttribute + { + public RifleAttribute() + { + Name = "步枪"; + Sprite = "res://resource/sprite/gun/gun4.png"; + Weight = 40; + CenterPosition = new Vector2(0.4f, -2.6f); + StartFiringSpeed = 480; + StartScatteringRange = 30; + FinalScatteringRange = 90; + ScatteringRangeAddValue = 2f; + ScatteringRangeBackSpeed = 40; + //连发 + ContinuousShoot = true; + //扳机检测间隔 + TriggerInterval = 0f; + //连发数量 + MinContinuousCount = 3; + MaxContinuousCount = 3; + //开火前延时 + DelayedTime = 0f; + //攻击距离 + MinDistance = 500; + MaxDistance = 600; + //发射子弹数量 + MinFireBulletCount = 1; + MaxFireBulletCount = 1; + //抬起角度 + UpliftAngle = 10; + //枪身长度 + FirePosition = new Vector2(16, 1.5f); + } + } + + //手枪属性数据 + private class PistolAttribute : WeaponAttribute + { + public PistolAttribute() + { + Name = "手枪"; + Sprite = "res://resource/sprite/gun/gun3.png"; + Weight = 20; + CenterPosition = new Vector2(0.4f, -2.6f); + WeightType = WeaponWeightType.DeputyWeapon; + StartFiringSpeed = 300; + StartScatteringRange = 5; + FinalScatteringRange = 60; + ScatteringRangeAddValue = 8f; + ScatteringRangeBackSpeed = 40; + //连发 + ContinuousShoot = false; + AmmoCapacity = 12; + MaxAmmoCapacity = 72; + //扳机检测间隔 + TriggerInterval = 0.1f; + //连发数量 + MinContinuousCount = 1; + MaxContinuousCount = 1; + //开火前延时 + DelayedTime = 0f; + //攻击距离 + MinDistance = 500; + MaxDistance = 600; + //发射子弹数量 + MinFireBulletCount = 1; + MaxFireBulletCount = 1; + //抬起角度 + UpliftAngle = 30; + //枪身长度 + FirePosition = new Vector2(10, 1.5f); + } + } + + /// + /// 子弹预制体 + /// + public PackedScene BulletPack; + /// + /// 弹壳预制体 + /// + public PackedScene ShellPack; + + public Gun(string id, WeaponAttribute attribute): base(id, attribute) + { + BulletPack = ResourceManager.Load("res://prefab/weapon/bullet/OrdinaryBullets.tscn"); + ShellPack = ResourceManager.Load("res://prefab/weapon/shell/ShellCase.tscn"); + } + + protected override void OnFire() + { + //创建一个弹壳 + var startPos = GlobalPosition + new Vector2(0, 5); + var startHeight = 6; + var direction = GlobalRotationDegrees + MathUtils.RandRangeInt(-30, 30) + 180; + var xf = MathUtils.RandRangeInt(20, 60); + var yf = MathUtils.RandRangeInt(60, 120); + var rotate = MathUtils.RandRangeInt(-720, 720); + var sprite = ShellPack.Instance(); + sprite.StartThrow(new Vector2(5, 10), startPos, startHeight, direction, xf, yf, rotate, sprite); + //创建抖动 + MainCamera.Main.ProssesDirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 1.5f); + } + + protected override void OnShoot() + { + //创建子弹 + CreateBullet(BulletPack, FirePoint.GlobalPosition, (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle()); + } + + protected override void OnReload() + { + + } + + protected override void OnReloadFinish() + { + + } + + protected override void OnDownTrigger() + { + + } + + protected override void OnUpTrigger() + { + + } + + protected override void OnPickUp(Role master) + { + + } + + protected override void OnThrowOut() + { + + } + + protected override void OnActive() + { + + } + + protected override void OnConceal() + { + + } + +} \ 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 new file mode 100644 index 0000000..66cff82 --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/gun/Shotgun.cs @@ -0,0 +1,125 @@ +using Godot; + +[RegisterWeapon("1002", typeof(Shotgun.ShotgunAttribute))] +public class Shotgun : Weapon +{ + + private class ShotgunAttribute : WeaponAttribute + { + public ShotgunAttribute() + { + Name = "霰弹枪"; + Sprite = "res://resource/sprite/gun/gun2.png"; + Weight = 40; + CenterPosition = new Vector2(0.4f, -2.6f); + StartFiringSpeed = 120; + StartScatteringRange = 30; + FinalScatteringRange = 90; + ScatteringRangeAddValue = 50f; + ScatteringRangeBackSpeed = 50; + //连发 + ContinuousShoot = false; + AmmoCapacity = 7; + MaxAmmoCapacity = 42; + AloneReload = true; + AloneReloadCanShoot = true; + ReloadTime = 0.3f; + //连发数量 + MinContinuousCount = 1; + MaxContinuousCount = 1; + //开火前延时 + DelayedTime = 0f; + //攻击距离 + MinDistance = 500; + MaxDistance = 600; + //发射子弹数量 + MinFireBulletCount = 1; + MaxFireBulletCount = 1; + //抬起角度 + UpliftAngle = 15; + MaxBacklash = 6; + MinBacklash = 5; + //枪身长度 + FirePosition = new Vector2(16, 1.5f); + } + } + + /// + /// 子弹预制体 + /// + public PackedScene BulletPack; + /// + /// 弹壳预制体 + /// + public PackedScene ShellPack; + + public Shotgun(string id, WeaponAttribute attribute) : base(id, attribute) + { + BulletPack = ResourceManager.Load("res://prefab/weapon/bullet/OrdinaryBullets.tscn"); + ShellPack = ResourceManager.Load("res://prefab/weapon/shell/ShellCase.tscn"); + } + + protected override void OnFire() + { + //创建一个弹壳 + var startPos = GlobalPosition + new Vector2(0, 5); + var startHeight = 6; + var direction = GlobalRotationDegrees + MathUtils.RandRangeInt(-30, 30) + 180; + var xf = MathUtils.RandRangeInt(20, 60); + var yf = MathUtils.RandRangeInt(60, 120); + var rotate = MathUtils.RandRangeInt(-720, 720); + var sprite = ShellPack.Instance(); + sprite.StartThrow(new Vector2(5, 10), startPos, startHeight, direction, xf, yf, rotate, sprite); + //创建抖动 + MainCamera.Main.ProssesDirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 1.5f); + } + + protected override void OnShoot() + { + for (int i = 0; i < 5; i++) + { + //创建子弹 + CreateBullet(BulletPack, FirePoint.GlobalPosition, (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle() + MathUtils.RandRange(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi)); + } + } + + protected override void OnReload() + { + + } + + protected override void OnReloadFinish() + { + + } + + protected override void OnDownTrigger() + { + + } + + protected override void OnUpTrigger() + { + + } + + protected override void OnPickUp(Role master) + { + + } + + protected override void OnThrowOut() + { + + } + + protected override void OnActive() + { + + } + + protected override void OnConceal() + { + + } +} diff --git a/DungeonShooting_Godot/src/game/item/weapon/shell/ThrowShell.cs b/DungeonShooting_Godot/src/game/item/weapon/shell/ThrowShell.cs new file mode 100644 index 0000000..914ee5d --- /dev/null +++ b/DungeonShooting_Godot/src/game/item/weapon/shell/ThrowShell.cs @@ -0,0 +1,42 @@ +using Godot; + +/// +/// 弹壳 +/// +public class ThrowShell : ThrowNode +{ + + public override void _Ready() + { + base._Ready(); + ZIndex = 2; + } + + protected override void OnOver() + { + //如果落地高度不够低, 再抛一次 + if (StartYSpeed > 1) + { + StartThrow(Size, GlobalPosition, 0, Direction, XSpeed * 0.8f, StartYSpeed * 0.5f, RotateSpeed * 0.5f, null); + } + else + { + base.OnOver(); + //等待被销毁 + AwaitDestroy(); + } + } + + private async void AwaitDestroy() + { + CollisionShape.Disabled = true; + //60秒后销毁 + await ToSignal(GetTree().CreateTimer(60), "timeout"); + QueueFree(); + } + + protected override void OnMaxHeight(float height) + { + ZIndex = 0; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/CheckInteractiveResult.cs b/DungeonShooting_Godot/src/game/props/CheckInteractiveResult.cs deleted file mode 100644 index eb8676b..0000000 --- a/DungeonShooting_Godot/src/game/props/CheckInteractiveResult.cs +++ /dev/null @@ -1,28 +0,0 @@ - -/// -/// 检测互动返回的数据集 -/// -public class CheckInteractiveResult -{ - /// - /// 互动物体 - /// - public ActivityObject Target; - /// - /// 是否可以互动 - /// - public bool CanInteractive; - /// - /// 互动提示信息 - /// - public string Message; - /// - /// 互动提示显示的图标 - /// - public string ShowIcon; - - public CheckInteractiveResult(ActivityObject target) - { - Target = target; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/package/Holster.cs b/DungeonShooting_Godot/src/game/props/package/Holster.cs deleted file mode 100644 index bbe7c9b..0000000 --- a/DungeonShooting_Godot/src/game/props/package/Holster.cs +++ /dev/null @@ -1,272 +0,0 @@ -using Godot; - -/// -/// 角色身上的武器袋, 存储角色携带的武器 -/// -public class Holster -{ - /// - /// 插槽类 - /// - public class WeaponSlot - { - /// - /// 是否启用 - /// - public bool Enable = false; - /// - /// 当前插槽存放的武器类型 - /// - public WeaponWeightType Type = WeaponWeightType.MainWeapon; - /// - /// 插槽存放的武器 - /// - public Weapon Weapon; - } - - /// - /// 归属者 - /// - public Role Master { get; } - - /// - /// 当前使用的武器对象 - /// - public Weapon ActiveWeapon { get; private set; } - - /// - /// 当前使用的武器的索引 - /// - public int ActiveIndex { get; private set; } = 0; - - public WeaponSlot[] SlotList { get; } = new WeaponSlot[4]; - - public Holster(Role master) - { - Master = master; - - //创建武器的插槽, 默认前两个都是启用的 - WeaponSlot slot1 = new WeaponSlot(); - slot1.Enable = true; - SlotList[0] = slot1; - - WeaponSlot slot2 = new WeaponSlot(); - slot2.Enable = true; - slot2.Type = WeaponWeightType.DeputyWeapon; - SlotList[1] = slot2; - - WeaponSlot slot3 = new WeaponSlot(); - SlotList[2] = slot3; - - WeaponSlot slot4 = new WeaponSlot(); - slot4.Type = WeaponWeightType.DeputyWeapon; - SlotList[3] = slot4; - } - - /// - /// 根据索引获取武器 - /// - public Weapon GetWeapon(int index) { - if (index >= SlotList.Length) - { - return null; - } - return SlotList[index].Weapon; - } - - /// - /// 根据武器id查找武器袋中该武器所在的位置, 如果没有, 则返回 -1 - /// - /// 武器id - public int FindWeapon(string id) - { - for (int i = 0; i < SlotList.Length; i++) - { - var item = SlotList[i]; - if (item.Weapon != null && item.Weapon.Id == id) - { - return i; - } - } - return -1; - } - - /// - /// 返回是否能放入武器 - /// - /// 武器对象 - public bool CanPickupWeapon(Weapon weapon) - { - for (int i = 0; i < SlotList.Length; i++) - { - var item = SlotList[i]; - if (item.Enable && weapon.Attribute.WeightType == item.Type && item.Weapon == null) - { - return true; - } - } - return false; - } - - /// - /// 拾起武器, 存入武器袋中, 返回存放在武器袋的位置, 如果容不下这把武器, 则会返回 -1 - /// - /// 武器对象 - public int PickupWeapon(Weapon weapon) - { - for (int i = 0; i < SlotList.Length; i++) - { - var item = SlotList[i]; - if (item.Enable && weapon.Attribute.WeightType == item.Type && item.Weapon == null) - { - weapon.Pickup(); - item.Weapon = weapon; - ExchangeByIndex(i); - weapon._PickUpWeapon(Master); - return i; - } - } - return -1; - } - - /// - /// 移除指定位置的武器, 并返回这个武器对象, 如果移除正在使用的这把武器, 则会自动切换到上一把武器 - /// - /// 所在武器袋的位置索引 - public Weapon RmoveWeapon(int index) - { - if (index < 0 || index >= SlotList.Length) - { - return null; - } - var slot = SlotList[index]; - if (slot.Weapon == null) - { - return null; - } - var weapon = slot.Weapon; - weapon.GetParent().RemoveChild(weapon); - slot.Weapon = null; - - //如果是当前手持的武器, 就需要调用切换武器操作 - if (index == ActiveIndex) - { - //没有其他武器了 - if (ExchangePrev() == index) - { - ActiveIndex = 0; - ActiveWeapon = null; - } - } - weapon._ThrowOutWeapon(); - return weapon; - } - - /// - /// 切换到上一个武器 - /// - public int ExchangePrev() - { - var index = ActiveIndex - 1; - do - { - if (index < 0) - { - index = SlotList.Length - 1; - } - if (ExchangeByIndex(index)) - { - return index; - } - } while (index-- != ActiveIndex); - return -1; - } - - /// - /// 切换到下一个武器, - /// - public int ExchangeNext() - { - var index = ActiveIndex + 1; - do - { - if (index >= SlotList.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 > SlotList.Length) return false; - var slot = SlotList[index]; - if (slot == null || slot.Weapon == null) return false; - - //将上一把武器放到背后 - if (ActiveWeapon != null) - { - var tempParent = ActiveWeapon.GetParentOrNull(); - if (tempParent != null) - { - tempParent.RemoveChild(ActiveWeapon); - Master.BackMountPoint.AddChild(ActiveWeapon); - if (ActiveIndex == 0) - { - ActiveWeapon.Position = new Vector2(0, 5); - ActiveWeapon.RotationDegrees = 50; - ActiveWeapon.Scale = new Vector2(-1, 1); - } - else if (ActiveIndex == 1) - { - ActiveWeapon.Position = new Vector2(0, 0); - ActiveWeapon.RotationDegrees = 120; - ActiveWeapon.Scale = new Vector2(1, -1); - } - else if (ActiveIndex == 2) - { - ActiveWeapon.Position = new Vector2(0, 5); - ActiveWeapon.RotationDegrees = 310; - ActiveWeapon.Scale = new Vector2(1, 1); - } - else if (ActiveIndex == 3) - { - ActiveWeapon.Position = new Vector2(0, 0); - ActiveWeapon.RotationDegrees = 60; - ActiveWeapon.Scale = new Vector2(1, 1); - } - ActiveWeapon._Conceal(); - } - } - - //更改父节点 - var parent = slot.Weapon.GetParentOrNull(); - if (parent == null) - { - Master.MountPoint.AddChild(slot.Weapon); - } - else if (parent != Master.MountPoint) - { - parent.RemoveChild(slot.Weapon); - Master.MountPoint.AddChild(slot.Weapon); - } - - slot.Weapon.Position = Vector2.Zero; - slot.Weapon.Scale = Vector2.One; - slot.Weapon.RotationDegrees = 0; - ActiveWeapon = slot.Weapon; - ActiveIndex = index; - ActiveWeapon._Active(); - return true; - } -} diff --git a/DungeonShooting_Godot/src/game/props/weapon/RegisterWeapon.cs b/DungeonShooting_Godot/src/game/props/weapon/RegisterWeapon.cs deleted file mode 100644 index 3cbcd57..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/RegisterWeapon.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -/// -/// 用作 Weapon 子类上, 用于注册武器, 允许同时存在多个 RegisterWeapon 特性 -/// -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class RegisterWeapon : Attribute -{ - - public string Id { get; private set; } - public Type AttributeType { get; private set; } - - public RegisterWeapon(string id) - { - Id = id; - } - - public RegisterWeapon(string id, Type attributeType) - { - Id = id; - AttributeType = attributeType; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/RegisterWeaponFunction.cs b/DungeonShooting_Godot/src/game/props/weapon/RegisterWeaponFunction.cs deleted file mode 100644 index 1796a95..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/RegisterWeaponFunction.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -/// -/// 用作静态函数上, 用于注册武器, 函数必须返回一个 Weapon 对象, 且参数为 string id, -/// 那么它看起来应该像这样: static Weapon Method(string id); -/// -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -public class RegisterWeaponFunction : Attribute -{ - public string Id { get; private set; } - - public RegisterWeaponFunction(string id) - { - Id = id; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/ThrowGun.cs b/DungeonShooting_Godot/src/game/props/weapon/ThrowGun.cs deleted file mode 100644 index d3c652a..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/ThrowGun.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Godot; - -public class ThrowWeapon : ThrowNode -{ - - private bool fristOver = true; - - public override void _Ready() - { - base._Ready(); - ZIndex = 2; - } - - public override void StartThrow(Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed, float ySpeed, float rotate, Node2D mount) - { - base.StartThrow(size, start, startHeight, direction, xSpeed, ySpeed, rotate, mount); - fristOver = true; - } - - protected override void OnOver() - { - if (fristOver) - { - fristOver = false; - if (Mount is Weapon gun) - { - gun._FallToGround(); - } - } - //如果落地高度不够低, 再抛一次 - if (StartYSpeed > 1) - { - StartThrow(Size, GlobalPosition, 0, Direction, XSpeed * 0.8f, StartYSpeed * 0.5f, RotateSpeed * 0.5f, null); - } - else //结束 - { - base.OnOver(); - } - } - protected override void OnMaxHeight(float height) - { - ZIndex = 0; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/props/weapon/Weapon.cs deleted file mode 100644 index 0812079..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/Weapon.cs +++ /dev/null @@ -1,789 +0,0 @@ -using Godot; -using System; - -/// -/// 武器的基类 -/// -public abstract class Weapon : ActivityObject -{ - - /// - /// 武器的唯一id - /// - public string Id { get; } - - /// - /// 开火回调事件 - /// - public event Action FireEvent; - - /// - /// 属性数据 - /// - public WeaponAttribute Attribute { get; private set; } - - /// - /// 武器的图片 - /// - public Sprite WeaponSprite { get; private set; } - - /// - /// 动画播放器 - /// - /// - public AnimationPlayer AnimationPlayer { get; private set; } - - /// - /// 武器攻击的目标阵营 - /// - public CampEnum TargetCamp { get; set; } - - /// - /// 该武器的拥有者 - /// - public Role Master { get; private set; } - - /// - /// 当前弹夹弹药剩余量 - /// - public int CurrAmmo { get; private set; } - /// - /// 剩余弹药量 - /// - public int ResidueAmmo { get; private set; } - - /// - /// 武器管的开火点 - /// - public Position2D FirePoint { get; private set; } - /// - /// 武器管的原点 - /// - public Position2D OriginPoint { get; private set; } - /// - /// 弹壳抛出的点 - /// - public Position2D ShellPoint { get; private set; } - /// - /// 碰撞器节点 - /// - /// - public CollisionShape2D CollisionShape2D { get; private 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; - } - } - - //是否按下 - 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; - - /// - /// 根据属性创建一把武器 - /// - /// 武器唯一id - /// 属性 - public Weapon(string id, WeaponAttribute attribute) - { - Id = id; - Attribute = attribute; - //加载预制体 - var tempPrefab = ResourceManager.Load(Attribute.WeaponPrefab); - if (tempPrefab == null) - { - throw new Exception("WeaponAttribute中未设置'WeaponPrefab'属性!"); - } - var tempNode = tempPrefab.Instance(); - var body = tempNode.GetChild(0); - tempNode.RemoveChild(body); - AddChild(body); - - WeaponSprite = GetNode("WeaponBody/WeaponSprite"); - FirePoint = GetNode("WeaponBody/FirePoint"); - OriginPoint = GetNode("WeaponBody/OriginPoint"); - ShellPoint = GetNode("WeaponBody/ShellPoint"); - AnimationPlayer = GetNode("WeaponBody/AnimationPlayer"); - CollisionShape2D = GetNode("WeaponBody/Collision"); - - //更新图片 - WeaponSprite.Texture = ResourceLoader.Load(Attribute.Sprite); - WeaponSprite.Position = Attribute.CenterPosition; - //开火位置 - FirePoint.Position = new Vector2(Attribute.FirePosition.x, -Attribute.FirePosition.y); - OriginPoint.Position = new Vector2(0, -Attribute.FirePosition.y); - - //弹药量 - CurrAmmo = Attribute.AmmoCapacity; - //剩余弹药量 - ResidueAmmo = Attribute.MaxAmmoCapacity - Attribute.AmmoCapacity; - } - - /// - /// 当按下扳机时调用 - /// - protected abstract void OnDownTrigger(); - - /// - /// 当松开扳机时调用 - /// - protected abstract void OnUpTrigger(); - - /// - /// 单次开火时调用的函数 - /// - protected abstract void OnFire(); - - /// - /// 发射子弹时调用的函数, 每发射一枚子弹调用一次, - /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次 - /// - protected abstract void OnShoot(); - - /// - /// 当开始换弹时调用 - /// - protected abstract void OnReload(); - - /// - /// 当换弹完成时调用 - /// - protected abstract void OnReloadFinish(); - - /// - /// 当武器被拾起时调用 - /// - /// 拾起该武器的角色 - protected abstract void OnPickUp(Role master); - - /// - /// 当武器从武器袋中扔掉时调用 - /// - protected abstract void OnThrowOut(); - - /// - /// 当武器被激活时调用, 也就是使用当武器是调用 - /// - protected abstract void OnActive(); - - /// - /// 当武器被收起时调用 - /// - protected abstract void OnConceal(); - - public override ComponentControl CreateComponentControl() - { - return new ComponentControl(this); - } - - public override void _Process(float delta) - { - if (Master == null) //这把武器被扔在地上 - { - Reloading = false; - ReloadTimer = 0; - triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0; - triggerFlag = false; - attackFlag = false; - attackTimer = attackTimer > 0 ? attackTimer - delta : 0; - CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange); - continuousCount = 0; - delayedTime = 0; - } - else if (Master.Holster.ActiveWeapon != this) //当前武器没有被使用 - { - Reloading = false; - ReloadTimer = 0; - triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0; - triggerFlag = false; - attackFlag = false; - attackTimer = attackTimer > 0 ? attackTimer - delta : 0; - CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange); - continuousCount = 0; - delayedTime = 0; - } - else //正在使用中 - { - - //换弹 - if (Reloading) - { - ReloadTimer -= delta; - if (ReloadTimer <= 0) - { - ReloadSuccess(); - } - } - - if (triggerFlag) - { - if (upTimer > 0) //第一帧按下扳机 - { - upTimer = 0; - DownTrigger(); - } - downTimer += delta; - } - else - { - if (downTimer > 0) //第一帧松开扳机 - { - downTimer = 0; - UpTrigger(); - } - upTimer += delta; - } - - // 攻击的计时器 - if (attackTimer > 0) - { - attackTimer -= delta; - if (attackTimer < 0) - { - delayedTime += attackTimer; - attackTimer = 0; - } - } - else if (delayedTime > 0) //攻击延时 - { - delayedTime -= delta; - if (attackTimer < 0) - { - delayedTime = 0; - } - } - - //连发判断 - if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0) - { - //开火 - TriggerFire(); - } - - if (!attackFlag && attackTimer <= 0) - { - CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange); - } - triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0; - triggerFlag = false; - attackFlag = false; - - //武器身回归 - Position = Position.MoveToward(Vector2.Zero, 35 * delta); - if (fireInterval == 0) - { - RotationDegrees = 0; - } - else - { - RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval); - } - } - } - - /// - /// 扳机函数, 调用即视为扣动扳机 - /// - public void Trigger() - { - //是否第一帧按下 - 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) - { - 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; - //子弹不够 - _Reload(); - } - - if (fireFlag) - { - if (justDown) - { - //开火前延时 - delayedTime = Attribute.DelayedTime; - //扳机按下间隔 - triggerTimer = Attribute.TriggerInterval; - //连发数量 - if (!Attribute.ContinuousShoot) - { - continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount); - } - } - if (delayedTime <= 0 && attackTimer <= 0) - { - TriggerFire(); - } - attackFlag = true; - } - - } - triggerFlag = true; - } - - /// - /// 刚按下扳机 - /// - private void DownTrigger() - { - OnDownTrigger(); - } - - /// - /// 刚松开扳机 - /// - private void UpTrigger() - { - continuousShootFlag = false; - if (delayedTime > 0) - { - continuousCount = 0; - } - OnUpTrigger(); - } - - /// - /// 触发开火 - /// - private void TriggerFire() - { - continuousCount = continuousCount > 0 ? continuousCount - 1 : 0; - - //减子弹数量 - CurrAmmo--; - //开火间隙 - fireInterval = 60 / Attribute.StartFiringSpeed; - //攻击冷却 - attackTimer += fireInterval; - - //触发开火函数 - OnFire(); - - //开火发射的子弹数量 - var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount); - //武器口角度 - var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle(); - - //创建子弹 - for (int i = 0; i < bulletCount; i++) - { - //先算武器口方向 - Rotation = (float)GD.RandRange(-angle, angle); - //发射子弹 - OnShoot(); - } - - //当前的散射半径 - CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange); - //武器的旋转角度 - RotationDegrees -= Attribute.UpliftAngle; - fireAngle = RotationDegrees; - //武器身位置 - Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y); - - if (FireEvent != null) - { - FireEvent(this); - } - } - - /// - /// 返回弹药是否到达上限 - /// - public bool IsFullAmmo() - { - return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity; - } - - /// - /// 返回是否弹药耗尽 - /// - public bool IsEmptyAmmo() - { - return CurrAmmo + ResidueAmmo == 0; - } - - /// - /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量 - /// - /// 弹药数量 - public 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; - 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; - OnReload(); - } - } - else //换弹结束 - { - if (ResidueAmmo >= Attribute.AmmoCapacity) - { - ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo; - CurrAmmo = Attribute.AmmoCapacity; - } - else - { - CurrAmmo = ResidueAmmo; - ResidueAmmo = 0; - } - Reloading = false; - ReloadTimer = 0; - OnReloadFinish(); - } - } - - 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(Id); - if (index != -1) //如果有这个武器 - { - if (CurrAmmo + ResidueAmmo != 0) //子弹不为空 - { - var targetWeapon = roleMaster.Holster.GetWeapon(index); - if (!targetWeapon.IsFullAmmo()) //背包里面的武器子弹未满 - { - //可以互动拾起弹药 - result.CanInteractive = true; - result.Message = Attribute.Name; - result.ShowIcon = "res://resource/sprite/ui/icon/icon_bullet.png"; - return result; - } - } - } - else //没有武器 - { - if (roleMaster.Holster.CanPickupWeapon(this)) //能拾起武器 - { - //可以互动, 拾起武器 - result.CanInteractive = true; - result.Message = Attribute.Name; - result.ShowIcon = "res://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 = "res://resource/sprite/ui/icon/icon_replace.png"; - return result; - } - } - } - } - - return result; - } - - public override void Interactive(ActivityObject master) - { - if (master is Role roleMaster) //与role碰撞 - { - //查找是否有同类型武器 - var index = roleMaster.Holster.FindWeapon(Id); - if (index != -1) //如果有这个武器 - { - if (CurrAmmo + ResidueAmmo == 0) //没有子弹了 - { - return; - } - - var weapon = roleMaster.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) - { - this.StartThrow(new Vector2(20, 20), GlobalPosition, 0, 0, - MathUtils.RandRangeInt(-20, 20), MathUtils.RandRangeInt(20, 50), - MathUtils.RandRangeInt(-180, 180), WeaponSprite); - } - } - else //没有武器 - { - if (roleMaster.Holster.PickupWeapon(this) == -1) - { - var slot = roleMaster.Holster.SlotList[roleMaster.Holster.ActiveIndex]; - if (slot.Type == Attribute.WeightType) - { - var weapon = roleMaster.Holster.RmoveWeapon(roleMaster.Holster.ActiveIndex); - weapon.StartThrowWeapon(roleMaster); - roleMaster.PickUpWeapon(this); - } - } - } - } - } - - public Vector2 GetItemPosition() - { - return GlobalPosition; - } - - /// - /// 触发落到地面 - /// - public void _FallToGround() - { - //启用碰撞 - CollisionShape2D.Disabled = false; - } - - /// - /// 触发拾起 - /// - public void _PickUpWeapon(Role master) - { - Master = master; - //握把位置 - WeaponSprite.Position = Attribute.HoldPosition; - //清除泛白效果 - ShaderMaterial sm = WeaponSprite.Material as ShaderMaterial; - sm.SetShaderParam("schedule", 0); - //停止动画 - AnimationPlayer.Stop(); - ZIndex = 0; - //禁用碰撞 - CollisionShape2D.Disabled = true; - OnPickUp(master); - } - - /// - /// 触发抛出 - /// a - public void _ThrowOutWeapon() - { - Master = null; - WeaponSprite.Position = Attribute.CenterPosition; - AnimationPlayer.Play("Floodlight"); - OnThrowOut(); - } - - /// - /// 触发启用武器 - /// - public void _Active() - { - OnActive(); - } - - /// - /// 触发收起武器 - /// - public void _Conceal() - { - OnConceal(); - } - - /// - /// 实例化并返回子弹对象 - /// - /// 子弹的预制体 - protected T CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) where T : Node2D, IBullet - { - return (T)CreateBullet(bulletPack, globalPostion, globalRotation, parent); - } - - /// - /// 实例化并返回子弹对象 - /// - /// 子弹的预制体 - protected IBullet CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) - { - // 实例化子弹 - Node2D bullet = bulletPack.Instance(); - // 设置坐标 - bullet.GlobalPosition = globalPostion; - // 旋转角度 - bullet.GlobalRotation = globalRotation; - if (parent == null) - { - RoomManager.Current.SortRoot.AddChild(bullet); - } - else - { - parent.AddChild(bullet); - } - // 调用初始化 - IBullet result = (IBullet)bullet; - result.Init(TargetCamp, this, null); - return result; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/WeaponAttribute.cs b/DungeonShooting_Godot/src/game/props/weapon/WeaponAttribute.cs deleted file mode 100644 index c6cad38..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/WeaponAttribute.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Godot; - -/// -/// 武器上的属性 -/// -public class WeaponAttribute -{ - /// - /// 武器显示的名称 - /// - public string Name = "Gun1"; - /// - /// 武器 Prefab, 必须继承场景 "res://prefab/weapon/Weapon.tscn" - /// - public string WeaponPrefab = "res://prefab/weapon/Weapon.tscn"; - /// - /// 武器类型 - /// - public WeaponWeightType WeightType = WeaponWeightType.MainWeapon; - /// - /// 武器的图片 - /// - public string Sprite = "res://resource/sprite/gun/gun1.png"; - /// - /// 是否连续发射, 如果为false, 则每次发射都需要扣动扳机 - /// - public bool ContinuousShoot = true; - /// - /// 弹夹容量 - /// - public int AmmoCapacity = 30; - /// - /// 弹药容量上限 - /// - public int MaxAmmoCapacity = 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; - /// - /// 连续发射最小次数, 仅当 ContinuousShoot 为 false 时生效 - /// - public int MinContinuousCount = 3; - /// - /// 连续发射最大次数, 仅当 ContinuousShoot 为 false 时生效 - /// - public int MaxContinuousCount = 3; - /// - /// 按下一次扳机后需要多长时间才能再次按下 - /// - public float TriggerInterval = 0; - /// - /// 初始射速, 初始每秒分钟能发射多少发子弹 - /// - public float StartFiringSpeed = 300; - /// - /// 最终射速, 最终每秒分钟能发射多少发子弹 - /// - 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 MaxDistance = 600; - /// - /// 子弹飞行最小距离 - /// - public float MinDistance = 800; - /// - /// 武器精灵的旋转中心坐标 - /// - public Vector2 CenterPosition = new Vector2(0, 0); - /// - /// 开火位置 - /// - public Vector2 FirePosition = new Vector2(11, 0); - /// - /// 握把位置 - /// - public Vector2 HoldPosition = new Vector2(4, -3); - /// - /// 重量 - /// - public float Weight = 11; - /// - /// 最大后坐力 (仅用于开火后武器身抖动) - /// - public float MaxBacklash = 4; - /// - /// 最小后坐力 (仅用于开火后武器身抖动) - /// - public float MinBacklash = 2; - /// - /// 开火后武器口上抬角度 - /// - public float UpliftAngle = 30; - /// - /// 开火后武器口角度恢复速度倍数 - /// - public float UpliftAngleRestore = 1; -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/WeaponManager.cs b/DungeonShooting_Godot/src/game/props/weapon/WeaponManager.cs deleted file mode 100644 index d5e8bf1..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/WeaponManager.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System.Reflection; -using System; -using System.Collections.Generic; -using Godot; - -/// -/// 武器管理类, 负责武器注册和创建 -/// -public static class WeaponManager -{ - private static Dictionary> registerData = new Dictionary>(); - - /// - /// 从一个指定的程序集中扫描并注册武器对象 - /// - /// 数据集 - public static void RegisterWeaponFromAssembly(Assembly assembly) - { - var types = assembly.GetTypes(); - foreach (var type in types) - { - //注册类 - Attribute[] attribute = Attribute.GetCustomAttributes(type, typeof(RegisterWeapon), false); - if (attribute != null && attribute.Length > 0) - { - if (!typeof(Weapon).IsAssignableFrom(type)) - { - throw new Exception($"注册武器类'{type.FullName}'没有继承类'Weapon'!"); - } - var atts = (RegisterWeapon[])attribute; - foreach (var att in atts) - { - //注册类 - if (att.AttributeType == null) //没有指定属性类型 - { - RegisterWeapon(att.Id, () => - { - return Activator.CreateInstance(type, att.Id, new WeaponAttribute()) as Weapon; - }); - } - else - { - if (!typeof(WeaponAttribute).IsAssignableFrom(att.AttributeType)) - { - throw new Exception($"注册武器类'{type.FullName}'标注的特性中参数'AttributeType'类型没有继承'WeaponAttribute'!"); - } - RegisterWeapon(att.Id, () => - { - return Activator.CreateInstance(type, att.Id, Activator.CreateInstance(att.AttributeType)) as Weapon; - }); - } - } - } - - //注册函数 - MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - foreach (var method in methods) - { - Attribute mAttribute; - // - if ((mAttribute = Attribute.GetCustomAttribute(method, typeof(RegisterWeaponFunction), false)) != null) - { - if (!typeof(Weapon).IsAssignableFrom(method.ReturnType)) //返回值类型不是 Weapon - { - throw new Exception($"注册武器函数'{method.DeclaringType.FullName}.{method.Name}'返回值类型不为'Weapon'!"); - } - var args = method.GetParameters(); - if (args == null || args.Length != 1 || args[0].ParameterType != typeof(string)) //参数类型不正确 - { - throw new Exception($"注册武器函数'{method.DeclaringType.FullName}.{method.Name}'参数不满足(string id)类型"); - } - var att = (RegisterWeaponFunction)mAttribute; - //注册函数 - RegisterWeapon(att.Id, () => - { - return method.Invoke(null, new object[] { att.Id }) as Weapon; - }); - } - } - } - } - - /// - /// 注册当个武器对象 - /// - /// 武器唯一id, 该id不能重复 - /// 获取武器时的回调函数, 函数返回武器对象 - public static void RegisterWeapon(string id, Func callBack) - { - if (registerData.ContainsKey(id)) - { - throw new Exception($"武器id: '{id} 已经被注册!'"); - } - registerData.Add(id, callBack); - } - - /// - /// 根据武器唯一id获取 - /// - /// 武器id - public static Weapon GetGun(string id) - { - if (registerData.TryGetValue(id, out var callback)) - { - return callback(); - } - throw new Exception($"当前武器'{id}未被注册'"); - } - - /// - /// 根据武器唯一id获取 - /// - /// 武器id - public static T GetGun(string id) where T : Weapon - { - return (T)GetGun(id); - } -} diff --git a/DungeonShooting_Godot/src/game/props/weapon/WeaponWeightType.cs b/DungeonShooting_Godot/src/game/props/weapon/WeaponWeightType.cs deleted file mode 100644 index 5528683..0000000 --- a/DungeonShooting_Godot/src/game/props/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/props/weapon/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/props/weapon/bullet/Bullet.cs deleted file mode 100644 index 4c19b4b..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/bullet/Bullet.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Godot; - -/// -/// 子弹接口 -/// -public interface IBullet -{ - /// - /// 攻击目标阵营 - /// - CampEnum TargetCamp { get; } - /// - /// 发射该子弹的武器 - /// - Weapon Gun { get; } - /// - /// 发射该子弹的物体对象 - /// - Node2D Master { get; } - /// - /// 初始化基础数据 - /// - /// 攻击的目标阵营 - /// 发射该子弹的枪对象 - /// 发射该子弹的角色 - void Init(CampEnum target, Weapon gun, Node2D master); -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/bullet/HighSpeedBullet.cs b/DungeonShooting_Godot/src/game/props/weapon/bullet/HighSpeedBullet.cs deleted file mode 100644 index 53ef711..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/bullet/HighSpeedBullet.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Godot; - -/// -/// 高速子弹 -/// -public class HighSpeedBullet : Node2D, IBullet -{ - public CampEnum TargetCamp { get; private set; } - - public Weapon Gun { get; private set; } - - public Node2D Master { get; private set; } - - /// - /// 碰撞物体后产生的火花 - /// - [Export] public PackedScene Hit; - - //射线检测节点 - private RayCast2D RayCast2D; - private Line2D Line; - private float ca = 1; - - public void Init(CampEnum target, Weapon gun, Node2D master) - { - TargetCamp = target; - Gun = gun; - Master = master; - - //飞行距离 - var distance = MathUtils.RandRange(gun.Attribute.MinDistance, gun.Attribute.MaxDistance); - - //初始化子弹数据 - RayCast2D = GetNode("RayCast2D"); - Line = GetNode("Line"); - Modulate = Colors.White; - - // 目标点 - Vector2 targetPos = new Vector2(distance, 0); - RayCast2D.CastTo = targetPos; - RayCast2D.ForceRaycastUpdate(); - if (RayCast2D.IsColliding()) - { - //碰到物体 - Vector2 collPosition = RayCast2D.GetCollisionPoint(); - Node2D hit = Hit.Instance(); - hit.RotationDegrees = MathUtils.RandRangeInt(0, 360); - hit.GlobalPosition = collPosition; - GetTree().CurrentScene.AddChild(hit); - //划线的点坐标 - Line.SetPointPosition(1, new Vector2(Line.GlobalPosition.DistanceTo(collPosition), 0)); - } - else - { - //划线的点坐标 - Line.SetPointPosition(1, targetPos); - } - RayCast2D.Enabled = false; - } - - public override void _Process(float delta) - { - ca -= 12 * delta; - if (ca <= 0) { - QueueFree(); - return; - } - Color c = Modulate; - c.a = ca; - Modulate = c; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/bullet/OrdinaryBullets.cs b/DungeonShooting_Godot/src/game/props/weapon/bullet/OrdinaryBullets.cs deleted file mode 100644 index 4458e5f..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/bullet/OrdinaryBullets.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using Godot; - -/// -/// 普通的子弹 -/// -public class OrdinaryBullets : Node2D, IBullet -{ - public CampEnum TargetCamp { get; private set; } - - public Weapon Gun { get; private set; } - - public Node2D Master { get; private set; } - - /// - /// 碰撞物体后产生的火花 - /// - [Export] public PackedScene Hit; - - // 起始点坐标 - private Vector2 StartPosition; - // 最大飞行距离 - private float MaxDistance; - // 子弹飞行速度 - private float FlySpeed = 1500; - //当前子弹已经飞行的距离 - private float CurrFlyDistance = 0; - //射线碰撞节点 - private RayCast2D RayCast; - //子弹的精灵 - private Sprite BulletSprite; - //绘制阴影的精灵 - private Sprite ShadowSprite; - - private int frame = 0; - - public void Init(CampEnum target, Weapon gun, Node2D master) - { - TargetCamp = target; - Gun = gun; - Master = master; - - MaxDistance = MathUtils.RandRange(gun.Attribute.MinDistance, gun.Attribute.MaxDistance); - StartPosition = GlobalPosition; - BulletSprite = GetNode("Bullet"); - BulletSprite.Visible = false; - RayCast = GetNode("RayCast2D"); - - //创建阴影 - ShadowSprite = new Sprite(); - ShadowSprite.Visible = false; - ShadowSprite.ZIndex = -1; - ShadowSprite.Texture = BulletSprite.Texture; - ShadowSprite.Offset = BulletSprite.Offset; - ShadowSprite.Material = ResourceManager.ShadowMaterial; - AddChild(ShadowSprite); - } - - public override void _Ready() - { - //生成时播放音效 - SoundManager.PlaySoundEffect("ordinaryBullet.ogg", this, 6f); - } - - public override void _PhysicsProcess(float delta) - { - if (frame++ == 0) - { - BulletSprite.Visible = true; - ShadowSprite.Visible = true; - } - //碰到墙壁 - if (RayCast.IsColliding()) - { - //var target = RayCast.GetCollider(); - var pos = RayCast.GetCollisionPoint(); - //播放受击动画 - Node2D hit = Hit.Instance(); - hit.RotationDegrees = MathUtils.RandRangeInt(0, 360); - hit.GlobalPosition = pos; - GetTree().CurrentScene.AddChild(hit); - QueueFree(); - } - else //没有碰到, 继续移动 - { - ShadowSprite.GlobalPosition = GlobalPosition + new Vector2(0, 5); - Position += new Vector2(FlySpeed * delta, 0).Rotated(Rotation); - - CurrFlyDistance += FlySpeed * delta; - if (CurrFlyDistance >= MaxDistance) - { - QueueFree(); - } - } - } - -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/gun/Gun.cs b/DungeonShooting_Godot/src/game/props/weapon/gun/Gun.cs deleted file mode 100644 index ca9ce7e..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/gun/Gun.cs +++ /dev/null @@ -1,161 +0,0 @@ -using Godot; - -[RegisterWeapon("1001", typeof(Gun.RifleAttribute))] -[RegisterWeapon("1003", typeof(Gun.PistolAttribute))] -/// -/// 普通的枪 -/// -public class Gun : Weapon -{ - //步枪属性数据 - private class RifleAttribute : WeaponAttribute - { - public RifleAttribute() - { - Name = "步枪"; - Sprite = "res://resource/sprite/gun/gun4.png"; - Weight = 40; - CenterPosition = new Vector2(0.4f, -2.6f); - StartFiringSpeed = 480; - StartScatteringRange = 30; - FinalScatteringRange = 90; - ScatteringRangeAddValue = 2f; - ScatteringRangeBackSpeed = 40; - //连发 - ContinuousShoot = true; - //扳机检测间隔 - TriggerInterval = 0f; - //连发数量 - MinContinuousCount = 3; - MaxContinuousCount = 3; - //开火前延时 - DelayedTime = 0f; - //攻击距离 - MinDistance = 500; - MaxDistance = 600; - //发射子弹数量 - MinFireBulletCount = 1; - MaxFireBulletCount = 1; - //抬起角度 - UpliftAngle = 10; - //枪身长度 - FirePosition = new Vector2(16, 1.5f); - } - } - - //手枪属性数据 - private class PistolAttribute : WeaponAttribute - { - public PistolAttribute() - { - Name = "手枪"; - Sprite = "res://resource/sprite/gun/gun3.png"; - Weight = 20; - CenterPosition = new Vector2(0.4f, -2.6f); - WeightType = WeaponWeightType.DeputyWeapon; - StartFiringSpeed = 300; - StartScatteringRange = 5; - FinalScatteringRange = 60; - ScatteringRangeAddValue = 8f; - ScatteringRangeBackSpeed = 40; - //连发 - ContinuousShoot = false; - AmmoCapacity = 12; - MaxAmmoCapacity = 72; - //扳机检测间隔 - TriggerInterval = 0.1f; - //连发数量 - MinContinuousCount = 1; - MaxContinuousCount = 1; - //开火前延时 - DelayedTime = 0f; - //攻击距离 - MinDistance = 500; - MaxDistance = 600; - //发射子弹数量 - MinFireBulletCount = 1; - MaxFireBulletCount = 1; - //抬起角度 - UpliftAngle = 30; - //枪身长度 - FirePosition = new Vector2(10, 1.5f); - } - } - - /// - /// 子弹预制体 - /// - public PackedScene BulletPack; - /// - /// 弹壳预制体 - /// - public PackedScene ShellPack; - - public Gun(string id, WeaponAttribute attribute): base(id, attribute) - { - BulletPack = ResourceManager.Load("res://prefab/weapon/bullet/OrdinaryBullets.tscn"); - ShellPack = ResourceManager.Load("res://prefab/weapon/shell/ShellCase.tscn"); - } - - protected override void OnFire() - { - //创建一个弹壳 - var startPos = GlobalPosition + new Vector2(0, 5); - var startHeight = 6; - var direction = GlobalRotationDegrees + MathUtils.RandRangeInt(-30, 30) + 180; - var xf = MathUtils.RandRangeInt(20, 60); - var yf = MathUtils.RandRangeInt(60, 120); - var rotate = MathUtils.RandRangeInt(-720, 720); - var sprite = ShellPack.Instance(); - sprite.StartThrow(new Vector2(5, 10), startPos, startHeight, direction, xf, yf, rotate, sprite); - //创建抖动 - MainCamera.Main.ProssesDirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 1.5f); - } - - protected override void OnShoot() - { - //创建子弹 - CreateBullet(BulletPack, FirePoint.GlobalPosition, (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle()); - } - - protected override void OnReload() - { - - } - - protected override void OnReloadFinish() - { - - } - - protected override void OnDownTrigger() - { - - } - - protected override void OnUpTrigger() - { - - } - - protected override void OnPickUp(Role master) - { - - } - - protected override void OnThrowOut() - { - - } - - protected override void OnActive() - { - - } - - protected override void OnConceal() - { - - } - -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/props/weapon/gun/Shotgun.cs b/DungeonShooting_Godot/src/game/props/weapon/gun/Shotgun.cs deleted file mode 100644 index 66cff82..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/gun/Shotgun.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Godot; - -[RegisterWeapon("1002", typeof(Shotgun.ShotgunAttribute))] -public class Shotgun : Weapon -{ - - private class ShotgunAttribute : WeaponAttribute - { - public ShotgunAttribute() - { - Name = "霰弹枪"; - Sprite = "res://resource/sprite/gun/gun2.png"; - Weight = 40; - CenterPosition = new Vector2(0.4f, -2.6f); - StartFiringSpeed = 120; - StartScatteringRange = 30; - FinalScatteringRange = 90; - ScatteringRangeAddValue = 50f; - ScatteringRangeBackSpeed = 50; - //连发 - ContinuousShoot = false; - AmmoCapacity = 7; - MaxAmmoCapacity = 42; - AloneReload = true; - AloneReloadCanShoot = true; - ReloadTime = 0.3f; - //连发数量 - MinContinuousCount = 1; - MaxContinuousCount = 1; - //开火前延时 - DelayedTime = 0f; - //攻击距离 - MinDistance = 500; - MaxDistance = 600; - //发射子弹数量 - MinFireBulletCount = 1; - MaxFireBulletCount = 1; - //抬起角度 - UpliftAngle = 15; - MaxBacklash = 6; - MinBacklash = 5; - //枪身长度 - FirePosition = new Vector2(16, 1.5f); - } - } - - /// - /// 子弹预制体 - /// - public PackedScene BulletPack; - /// - /// 弹壳预制体 - /// - public PackedScene ShellPack; - - public Shotgun(string id, WeaponAttribute attribute) : base(id, attribute) - { - BulletPack = ResourceManager.Load("res://prefab/weapon/bullet/OrdinaryBullets.tscn"); - ShellPack = ResourceManager.Load("res://prefab/weapon/shell/ShellCase.tscn"); - } - - protected override void OnFire() - { - //创建一个弹壳 - var startPos = GlobalPosition + new Vector2(0, 5); - var startHeight = 6; - var direction = GlobalRotationDegrees + MathUtils.RandRangeInt(-30, 30) + 180; - var xf = MathUtils.RandRangeInt(20, 60); - var yf = MathUtils.RandRangeInt(60, 120); - var rotate = MathUtils.RandRangeInt(-720, 720); - var sprite = ShellPack.Instance(); - sprite.StartThrow(new Vector2(5, 10), startPos, startHeight, direction, xf, yf, rotate, sprite); - //创建抖动 - MainCamera.Main.ProssesDirectionalShake(Vector2.Right.Rotated(GlobalRotation) * 1.5f); - } - - protected override void OnShoot() - { - for (int i = 0; i < 5; i++) - { - //创建子弹 - CreateBullet(BulletPack, FirePoint.GlobalPosition, (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle() + MathUtils.RandRange(-20 / 180f * Mathf.Pi, 20 / 180f * Mathf.Pi)); - } - } - - protected override void OnReload() - { - - } - - protected override void OnReloadFinish() - { - - } - - protected override void OnDownTrigger() - { - - } - - protected override void OnUpTrigger() - { - - } - - protected override void OnPickUp(Role master) - { - - } - - protected override void OnThrowOut() - { - - } - - protected override void OnActive() - { - - } - - protected override void OnConceal() - { - - } -} diff --git a/DungeonShooting_Godot/src/game/props/weapon/shell/ThrowShell.cs b/DungeonShooting_Godot/src/game/props/weapon/shell/ThrowShell.cs deleted file mode 100644 index 914ee5d..0000000 --- a/DungeonShooting_Godot/src/game/props/weapon/shell/ThrowShell.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Godot; - -/// -/// 弹壳 -/// -public class ThrowShell : ThrowNode -{ - - public override void _Ready() - { - base._Ready(); - ZIndex = 2; - } - - protected override void OnOver() - { - //如果落地高度不够低, 再抛一次 - if (StartYSpeed > 1) - { - StartThrow(Size, GlobalPosition, 0, Direction, XSpeed * 0.8f, StartYSpeed * 0.5f, RotateSpeed * 0.5f, null); - } - else - { - base.OnOver(); - //等待被销毁 - AwaitDestroy(); - } - } - - private async void AwaitDestroy() - { - CollisionShape.Disabled = true; - //60秒后销毁 - await ToSignal(GetTree().CreateTimer(60), "timeout"); - QueueFree(); - } - - protected override void OnMaxHeight(float height) - { - ZIndex = 0; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/role/Role.cs b/DungeonShooting_Godot/src/game/role/Role.cs index d5e6583..dffd83d 100644 --- a/DungeonShooting_Godot/src/game/role/Role.cs +++ b/DungeonShooting_Godot/src/game/role/Role.cs @@ -107,11 +107,6 @@ /// 检测是否可互动时的返回值 protected abstract void ChangeInteractiveItem(CheckInteractiveResult result); - public override ComponentControl CreateComponentControl() - { - return new ComponentControl(this); - } - public override CheckInteractiveResult CheckInteractive(ActivityObject master) { return null;