diff --git a/DungeonShooting_Godot/prefab/weapon/WeaponTemplate.tscn b/DungeonShooting_Godot/prefab/weapon/WeaponTemplate.tscn index 81179a1..7b22ce1 100644 --- a/DungeonShooting_Godot/prefab/weapon/WeaponTemplate.tscn +++ b/DungeonShooting_Godot/prefab/weapon/WeaponTemplate.tscn @@ -11,6 +11,7 @@ shader_parameter/show_outline = true shader_parameter/outline_color = Color(0, 0, 0, 1) shader_parameter/outline_rainbow = false +shader_parameter/outline_use_blend = true [sub_resource type="ShaderMaterial" id="ShaderMaterial_o36tv"] resource_local_to_scene = true @@ -21,6 +22,7 @@ shader_parameter/show_outline = true shader_parameter/outline_color = Color(0, 0, 0, 1) shader_parameter/outline_rainbow = false +shader_parameter/outline_use_blend = true [sub_resource type="Animation" id="Animation_x136i"] length = 0.001 @@ -79,6 +81,7 @@ [node name="GripPoint" type="Marker2D" parent="."] [node name="Collision" type="CollisionShape2D" parent="."] +visible = false [node name="AnimationPlayer" type="AnimationPlayer" parent="."] libraries = { diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs index 3a6a47a..03cead3 100644 --- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs +++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs @@ -753,7 +753,22 @@ { var component = new T(); _components.Add(new KeyValuePair(typeof(T), component)); - component.ActivityInstance = this; + component.Master = this; + component.Ready(); + component.OnEnable(); + return component; + } + + /// + /// 往当前物体上挂载一个组件 + /// + public Component AddComponent(Type type) + { + var component = (Component)Activator.CreateInstance(type); + _components.Add(new KeyValuePair(type, component)); + component.Master = this; + component.Ready(); + component.OnEnable(); return component; } @@ -877,14 +892,8 @@ { if (IsDestroyed) return; var temp = arr[i].Value; - if (temp != null && temp.ActivityInstance == this && temp.Enable) + if (temp != null && temp.Master == this && temp.Enable) { - if (!temp.IsReady) - { - temp.Ready(); - temp.IsReady = true; - } - temp.Process(newDelta); } } @@ -893,12 +902,6 @@ { if (MoveController.Enable) { - if (!MoveController.IsReady) - { - MoveController.Ready(); - MoveController.IsReady = true; - } - MoveController.Process(newDelta); } } @@ -1089,14 +1092,8 @@ { if (IsDestroyed) return; var temp = arr[i].Value; - if (temp != null && temp.ActivityInstance == this && temp.Enable) + if (temp != null && temp.Master == this && temp.Enable) { - if (!temp.IsReady) - { - temp.Ready(); - temp.IsReady = true; - } - temp.PhysicsProcess(newDelta); } } @@ -1105,12 +1102,6 @@ { if (MoveController.Enable) { - if (!MoveController.IsReady) - { - MoveController.Ready(); - MoveController.IsReady = true; - } - MoveController.PhysicsProcess(newDelta); } } @@ -1140,7 +1131,7 @@ { if (IsDestroyed) return; var temp = arr[i].Value; - if (temp != null && temp.ActivityInstance == this && temp.Enable) + if (temp != null && temp.Master == this && temp.Enable) { temp.DebugDraw(); } diff --git a/DungeonShooting_Godot/src/framework/activity/Component.cs b/DungeonShooting_Godot/src/framework/activity/Component.cs index ec1897d..af31e06 100644 --- a/DungeonShooting_Godot/src/framework/activity/Component.cs +++ b/DungeonShooting_Godot/src/framework/activity/Component.cs @@ -1,24 +1,36 @@ +using System; using System.Collections; using Godot; /// /// 组件基类, 用于挂载到游戏物体上, 相比于原生 Node 更加轻量化, 实例化 Component 不会创建额外的 Node, 可以大量添加组件 /// +public abstract class Component : Component where T : ActivityObject +{ + /// + /// 当前组件所挂载的游戏对象 + /// + public new T Master => (T)base.Master; +} + +/// +/// 组件基类, 用于挂载到游戏物体上, 相比于原生 Node 更加轻量化, 实例化 Component 不会创建额外的 Node, 可以大量添加组件 +/// public abstract class Component : IProcess, IDestroy, ICoroutine { /// /// 当前组件所挂载的游戏对象 /// - public ActivityObject ActivityInstance { get; internal set; } + public ActivityObject Master { get; internal set; } /// /// 当前组件所挂载的物体的坐标 /// public Vector2 Position { - get => ActivityInstance.Position; - set => ActivityInstance.Position = value; + get => Master.Position; + set => Master.Position = value; } /// @@ -26,8 +38,8 @@ /// public Vector2 GlobalPosition { - get => ActivityInstance.GlobalPosition; - set => ActivityInstance.GlobalPosition = value; + get => Master.GlobalPosition; + set => Master.GlobalPosition = value; } /// @@ -35,8 +47,8 @@ /// public Vector2 Scale { - get => ActivityInstance.Scale; - set => ActivityInstance.Scale = value; + get => Master.Scale; + set => Master.Scale = value; } /// @@ -44,8 +56,8 @@ /// public Vector2 GlobalScale { - get => ActivityInstance.GlobalScale; - set => ActivityInstance.GlobalScale = value; + get => Master.GlobalScale; + set => Master.GlobalScale = value; } /// @@ -53,8 +65,8 @@ /// public float Rotation { - get => ActivityInstance.Rotation; - set => ActivityInstance.Rotation = value; + get => Master.Rotation; + set => Master.Rotation = value; } /// @@ -62,8 +74,8 @@ /// public float GlobalRotation { - get => ActivityInstance.GlobalRotation; - set => ActivityInstance.GlobalRotation = value; + get => Master.GlobalRotation; + set => Master.GlobalRotation = value; } /// @@ -71,8 +83,8 @@ /// public float RotationDegrees { - get => ActivityInstance.RotationDegrees; - set => ActivityInstance.RotationDegrees = value; + get => Master.RotationDegrees; + set => Master.RotationDegrees = value; } /// @@ -80,8 +92,8 @@ /// public float GlobalRotationDegrees { - get => ActivityInstance.GlobalRotationDegrees; - set => ActivityInstance.GlobalRotationDegrees = value; + get => Master.GlobalRotationDegrees; + set => Master.GlobalRotationDegrees = value; } /// @@ -89,8 +101,8 @@ /// public int ZIndex { - get => ActivityInstance.ZIndex; - set => ActivityInstance.ZIndex = value; + get => Master.ZIndex; + set => Master.ZIndex = value; } /// @@ -98,22 +110,22 @@ /// public bool Visible { - get => ActivityInstance.Visible; - set => ActivityInstance.Visible = value; + get => Master.Visible; + set => Master.Visible = value; } /// /// 挂载物体的动画节点 /// - public AnimatedSprite2D AnimatedSprite2D => ActivityInstance.AnimatedSprite; + public AnimatedSprite2D AnimatedSprite => Master.AnimatedSprite; /// /// 挂载物体的阴影节点 /// - public Sprite2D ShadowSprite => ActivityInstance.ShadowSprite; + public Sprite2D ShadowSprite => Master.ShadowSprite; /// /// 挂载物体的碰撞器节点 /// - public CollisionShape2D Collision => ActivityInstance.Collision; + public CollisionShape2D Collision => Master.Collision; /// /// 是否启用当前组件, 如果禁用, 则不会调用 Process 和 PhysicsProcess @@ -144,12 +156,7 @@ public bool IsDestroyed { get; private set; } /// - /// 是否调用过 Ready 函数 - /// - public bool IsReady { get; set; } - - /// - /// 第一次调用 Process 或 PhysicsProcess 之前调用 + /// 初始化时调用 /// public virtual void Ready() { @@ -210,27 +217,97 @@ } IsDestroyed = true; - ActivityInstance.RemoveComponent(this); + Master.RemoveComponent(this); OnDestroy(); } + public T AddComponent() where T : Component, new() + { + return Master.AddComponent(); + } + + public Component AddComponent(Type type) + { + return Master.AddComponent(type); + } + + public T GetComponent() where T : Component, new() + { + return Master.GetComponent(); + } + + public Component GetComponent(Type type) + { + return Master.GetComponent(type); + } + + public void RemoveComponent(Component component) + { + Master.RemoveComponent(component); + } + + public void AddChild(Node node) + { + Master.AddChild(node); + } + + public void RemoveChild(Node node) + { + Master.RemoveChild(node); + } + + public int GetChildCount() + { + return Master.GetChildCount(); + } + + public Node GetNode(NodePath path) + { + return Master.GetNode(path); + } + + public T GetNode(NodePath path) where T : class + { + return Master.GetNode(path); + } + + public Node GetNodeOrNull(NodePath path) + { + return Master.GetNodeOrNull(path); + } + + public T GetNodeOrNull(NodePath path) where T : class + { + return Master.GetNodeOrNull(path); + } + + public Node GetParent() + { + return Master.GetParent(); + } + + public T GetParent() where T : class + { + return Master.GetParent(); + } + public long StartCoroutine(IEnumerator able) { - return ActivityInstance.StartCoroutine(able); + return Master.StartCoroutine(able); } public void StopCoroutine(long coroutineId) { - ActivityInstance.StopCoroutine(coroutineId); + Master.StopCoroutine(coroutineId); } public bool IsCoroutineOver(long coroutineId) { - return ActivityInstance.IsCoroutineOver(coroutineId); + return Master.IsCoroutineOver(coroutineId); } public void StopAllCoroutine() { - ActivityInstance.StopAllCoroutine(); + Master.StopAllCoroutine(); } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/activity/components/MoveController.cs b/DungeonShooting_Godot/src/framework/activity/components/MoveController.cs index 36167b1..9056451 100644 --- a/DungeonShooting_Godot/src/framework/activity/components/MoveController.cs +++ b/DungeonShooting_Godot/src/framework/activity/components/MoveController.cs @@ -18,7 +18,7 @@ /// 这个速度就是物体当前物理帧移动的真实速率, 该速度由物理帧循环计算, 并不会马上更新 /// 该速度就是 BasisVelocity + 外力总和 /// - public Vector2 Velocity => ActivityInstance.Velocity; + public Vector2 Velocity => Master.Velocity; /// /// 物体的基础移动速率 @@ -267,7 +267,7 @@ { if (_basisVelocity == Vector2.Zero && _forceList.Count == 0) { - ActivityInstance.Velocity = Vector2.Zero; + Master.Velocity = Vector2.Zero; return; } @@ -304,13 +304,13 @@ //处理旋转 if (rotationSpeed != 0) { - ActivityInstance.Rotation += rotationSpeed * delta; + Master.Rotation += rotationSpeed * delta; } //衰减旋转速率 for (var i = 0; i < _forceList.Count; i++) { var force = _forceList[i]; - if (force.RotationResistance != 0 && (force.EnableResistanceInTheAir || !ActivityInstance.IsThrowing)) + if (force.RotationResistance != 0 && (force.EnableResistanceInTheAir || !Master.IsThrowing)) { force.RotationSpeed = Mathf.MoveToward(force.RotationSpeed, 0, force.RotationResistance * delta); } @@ -322,10 +322,10 @@ if (finallyVelocity != Vector2.Zero) { //计算移动 - ActivityInstance.Velocity = finallyVelocity; - ActivityInstance.MoveAndSlide(); + Master.Velocity = finallyVelocity; + Master.MoveAndSlide(); //新速度 - var newVelocity = ActivityInstance.Velocity; + var newVelocity = Master.Velocity; if (newVelocity.X == 0f && _basisVelocity.X * finallyVelocity.X > 0) { @@ -338,13 +338,13 @@ } //是否撞到物体 - var collision = ActivityInstance.GetLastSlideCollision(); + var collision = Master.GetLastSlideCollision(); if (collision != null) //执行反弹操作 { var no = collision.GetNormal().Rotated(Mathf.Pi * 0.5f); newVelocity = (finallyVelocity - _basisVelocity).Reflect(no); var length = _forceList.Count; - var v = newVelocity / (length / ActivityInstance.BounceStrength); + var v = newVelocity / (length / Master.BounceStrength); for (var i = 0; i < _forceList.Count; i++) { _forceList[i].Velocity = v; @@ -365,7 +365,7 @@ ); //力速度衰减 - if (force.VelocityResistance != 0 && (force.EnableResistanceInTheAir || !ActivityInstance.IsThrowing)) + if (force.VelocityResistance != 0 && (force.EnableResistanceInTheAir || !Master.IsThrowing)) { force.Velocity = force.Velocity.MoveToward(Vector2.Zero, force.VelocityResistance * delta); } @@ -375,7 +375,7 @@ } else { - ActivityInstance.Velocity = Vector2.Zero; + Master.Velocity = Vector2.Zero; } } @@ -389,33 +389,33 @@ { //绘制力大小和方向 - if (ActivityInstance is Bullet) //不绘制子弹的力 + if (Master is Bullet) //不绘制子弹的力 { return; } var globalRotation = GlobalRotation; - var flag = ActivityInstance.Scale.Y < 0; + var flag = Master.Scale.Y < 0; if (flag) { - ActivityInstance.DrawLine(Vector2.Zero, (BasisVelocity * new Vector2(1, -1)).Rotated(-globalRotation), + Master.DrawLine(Vector2.Zero, (BasisVelocity * new Vector2(1, -1)).Rotated(-globalRotation), Colors.Yellow); } else { - ActivityInstance.DrawLine(Vector2.Zero, BasisVelocity.Rotated(-globalRotation), Colors.Yellow); + Master.DrawLine(Vector2.Zero, BasisVelocity.Rotated(-globalRotation), Colors.Yellow); } foreach (var force in _forceList) { if (flag) { - ActivityInstance.DrawLine(Vector2.Zero, (force.Velocity * new Vector2(1, -1)).Rotated(globalRotation), + Master.DrawLine(Vector2.Zero, (force.Velocity * new Vector2(1, -1)).Rotated(globalRotation), Colors.YellowGreen); } else { - ActivityInstance.DrawLine(Vector2.Zero, force.Velocity.Rotated(-globalRotation), Colors.YellowGreen); + Master.DrawLine(Vector2.Zero, force.Velocity.Rotated(-globalRotation), Colors.YellowGreen); } } } diff --git a/DungeonShooting_Godot/src/framework/activity/components/StateController.cs b/DungeonShooting_Godot/src/framework/activity/components/StateController.cs index d3c1e20..bb1bbd8 100644 --- a/DungeonShooting_Godot/src/framework/activity/components/StateController.cs +++ b/DungeonShooting_Godot/src/framework/activity/components/StateController.cs @@ -60,7 +60,7 @@ return; } - stateBase.Master = ActivityInstance as T; + stateBase.Master = Master as T; stateBase.StateController = this; _states.Add(stateBase.State, stateBase); } diff --git a/DungeonShooting_Godot/src/game/activity/package/Package.cs b/DungeonShooting_Godot/src/game/activity/package/Package.cs index ca1ad16..378f7ef 100644 --- a/DungeonShooting_Godot/src/game/activity/package/Package.cs +++ b/DungeonShooting_Godot/src/game/activity/package/Package.cs @@ -4,19 +4,12 @@ /// /// 物体背包类 /// -public class Package : IDestroy where T : ActivityObject, IPackageItem +public class Package : Component where T : ActivityObject, IPackageItem { /// /// 当前使用对象改变时回调 /// public event Action ChangeActiveItemEvent; - - public bool IsDestroyed { get; private set; } - - /// - /// 归属者 - /// - public Role Master { get; private set; } /// /// 当前使用的物体对象 @@ -54,12 +47,6 @@ /// public T[] ItemSlot { get; private set; } - public Package(Role master, int capacity) - { - Master = master; - SetCapacity(capacity); - } - /// /// 修改物体背包容量 /// @@ -466,14 +453,8 @@ return null; } - public void Destroy() + public override void OnDestroy() { - if (IsDestroyed) - { - return; - } - - IsDestroyed = true; for (var i = 0; i < ItemSlot.Length; i++) { var activityObject = ItemSlot[i]; diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs index 1d2acd1..cb4d86b 100644 --- a/DungeonShooting_Godot/src/game/activity/role/Role.cs +++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs @@ -50,7 +50,7 @@ public uint EnemyLayer { get; set; } = PhysicsLayer.Enemy; /// - /// 携带的被动道具包裹 + /// 携带的被动道具列表 /// public List BuffPropPack { get; } = new List(); @@ -259,6 +259,11 @@ /// 是否处于近战攻击中 /// public bool IsMeleeAttack { get; private set; } + + /// + /// 瞄准辅助线, 需要手动调用 InitSubLine() 初始化 + /// + public SubLine SubLine { get; private set; } //翻滚冷却计时器 private float _rollCoolingTimer = 0; @@ -407,8 +412,11 @@ public override void OnInit() { - ActivePropsPack = new Package(this, 1); - WeaponPack = new Package(this, 4); + ActivePropsPack = AddComponent>(); + ActivePropsPack.SetCapacity(1); + WeaponPack = AddComponent>(); + WeaponPack.SetCapacity(4); + _startScale = Scale; MountPoint.Master = this; @@ -569,6 +577,19 @@ } /// + /// 初始化瞄准辅助线 + /// + public void InitSubLine() + { + if (SubLine != null) + { + return; + } + + SubLine = AddComponent(); + } + + /// /// 当武器放到后背时调用, 用于设置武器位置和角度 /// /// 武器实例 @@ -1202,4 +1223,19 @@ { return CollisionWithMask(Player.Current.EnemyLayer); } + + /// + /// 将 Role 子节点的旋转角度转换为正常的旋转角度
+ /// 因为 Role 受到 Face 影响, 会出现转向动作, 所以需要该函数来转换旋转角度 + ///
+ /// 角度, 弧度制 + public float ConvertRotation(float rotation) + { + if (Face == FaceDirection.Right) + { + return rotation; + } + + return Mathf.Pi - rotation; + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/SubLine.cs b/DungeonShooting_Godot/src/game/activity/role/SubLine.cs new file mode 100644 index 0000000..87bed10 --- /dev/null +++ b/DungeonShooting_Godot/src/game/activity/role/SubLine.cs @@ -0,0 +1,115 @@ + +using Godot; + +public class SubLine : Component +{ + private Line2D _line2D; + private RayCast2D _rayCast2D; + + private bool _enableSubLine; + private float _range; + + public override void Ready() + { + //初始化瞄准辅助线 + _line2D = new Line2D(); + _line2D.Width = 1; + _line2D.DefaultColor = Colors.Red; + AddChild(_line2D); + + _rayCast2D = new RayCast2D(); + _rayCast2D.CollisionMask = PhysicsLayer.Wall; + //_rayCast2D.Position = Master.MountPoint.Position; + AddChild(_rayCast2D); + + Master.WeaponPack.ChangeActiveItemEvent += OnChangeWeapon; + } + + public override void OnEnable() + { + OnChangeWeapon(Master.WeaponPack.ActiveItem); + } + + public override void OnDisable() + { + _line2D.Visible = false; + _rayCast2D.Enabled = false; + } + + //切换武器 + private void OnChangeWeapon(Weapon weapon) + { + if (!Enable) + { + return; + } + if (weapon == null) + { + _enableSubLine = false; + } + else + { + _enableSubLine = true; + _range = Utils.GetConfigRangeEnd(weapon.Attribute.BulletDistanceRange); + } + } + + public override void PhysicsProcess(float delta) + { + if (_enableSubLine) + { + _line2D.Visible = true; + _rayCast2D.Enabled = true; + UpdateSubLine(); + } + else + { + _line2D.Visible = false; + _rayCast2D.Enabled = false; + } + } + + public override void OnDestroy() + { + Master.WeaponPack.ChangeActiveItemEvent -= OnChangeWeapon; + } + + private void UpdateSubLine() + { + var master = Master; + var weapon = master.WeaponPack.ActiveItem; + float length; + var firePointGlobalPosition = weapon.FirePoint.GlobalPosition; + if (_rayCast2D.IsColliding()) + { + length = firePointGlobalPosition.DistanceTo(_rayCast2D.GetCollisionPoint()); + } + else + { + length = _range; + } + + //更新 Ray 的位置角度 + _rayCast2D.GlobalPosition = weapon.FirePoint.GlobalPosition; + _rayCast2D.TargetPosition = new Vector2(_range, 0); + _rayCast2D.Rotation = master.ConvertRotation(master.MountPoint.RealRotation); + + //计算 line2D 的点 + var position = _line2D.ToLocal(firePointGlobalPosition); + Vector2 position2; + if (master.Face == FaceDirection.Right) + { + position2 = Vector2.FromAngle(master.MountPoint.RealRotation) * length; + } + else + { + position2 = Vector2.FromAngle(Mathf.Pi - master.MountPoint.RealRotation) * length; + } + + _line2D.Points = new Vector2[] + { + position, + position + position2 + }; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs index 8eed250..f0da104 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs @@ -11,6 +11,7 @@ #endregion +using System; using Godot; /// @@ -63,11 +64,6 @@ /// Ai攻击状态, 调用 EnemyAttack() 函数后会刷新 /// public AiAttackState AttackState { get; private set; } - - /// - /// Ai瞄准辅助线 - /// - public Line2D SubLine { get; private set; } //锁定目标时间 private float _lockTargetTime = 0; @@ -105,47 +101,6 @@ //默认状态 StateController.ChangeStateInstant(AiStateEnum.AiNormal); - - InitSubLine(); - } - - /// - /// 初始化瞄准辅助线 - /// - public void InitSubLine() - { - if (SubLine != null) - { - return; - } - SubLine = new Line2D(); - SubLine.Width = 1; - SubLine.DefaultColor = Colors.Red; - AddChild(SubLine); - } - - /// - /// 更新瞄准辅助线信息, length 为辅助线长度 - /// - private void UpdateSubLine(float length) - { - var weapon = WeaponPack.ActiveItem; - var position = SubLine.ToLocal(weapon.FirePoint.GlobalPosition); - Vector2 position2; - if (Face == FaceDirection.Right) - { - position2 = Vector2.FromAngle(MountPoint.RealRotation) * length; - } - else - { - position2 = Vector2.FromAngle(Mathf.Pi - MountPoint.RealRotation) * length; - } - - SubLine.Points = new Vector2[] - { - position, - position + position2 - }; } public override void EnterTree() @@ -215,21 +170,18 @@ //更新瞄准辅助线 if (AttackState == AiAttackState.LockingTime) { - SubLine.Visible = true; - float len; - if (!TargetInView) + if (SubLine == null) { - len = GlobalPosition.DistanceTo(ViewRay.GetCollisionPoint()); + InitSubLine(); } else { - len = 200; + SubLine.Enable = true; } - UpdateSubLine(len); } - else + else if (SubLine != null) { - SubLine.Visible = false; + SubLine.Enable = false; } } else diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs index 906fae8..e067187 100644 --- a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs +++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs @@ -63,6 +63,8 @@ StateController.Register(new PlayerRollState()); //默认状态 StateController.ChangeStateInstant(PlayerStateEnum.Idle); + + //InitSubLine(); } protected override void Process(float delta)