diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot
index 869f9bd..c5ef034 100644
--- a/DungeonShooting_Godot/project.godot
+++ b/DungeonShooting_Godot/project.godot
@@ -27,7 +27,6 @@
window/size/width=1920
window/size/height=1080
window/size/resizable=false
-window/size/always_on_top=true
window/dpi/allow_hidpi=true
window/vsync/use_vsync=false
window/stretch/mode="2d"
diff --git a/DungeonShooting_Godot/src/framework/ActivityObject.cs b/DungeonShooting_Godot/src/framework/ActivityObject.cs
index ef1a1cd..1d448bd 100644
--- a/DungeonShooting_Godot/src/framework/ActivityObject.cs
+++ b/DungeonShooting_Godot/src/framework/ActivityObject.cs
@@ -65,6 +65,21 @@
///
public MoveController MoveController { get; }
+ ///
+ /// 物体移动基础速率
+ ///
+ public Vector2 BasisVelocity
+ {
+ get => MoveController.BasisVelocity;
+ set => MoveController.BasisVelocity = value;
+ }
+
+ ///
+ /// 这个速度就是玩家当前物理帧移动的真实速率, 该速度由物理帧循环更新, 并不会马上更新
+ /// 该速度就是 BasisVelocity + 外力总和
+ ///
+ public Vector2 Velocity => MoveController.Velocity;
+
//组件集合
private List> _components = new List>();
//是否初始化阴影
@@ -120,7 +135,6 @@
case "ShadowSprite":
ShadowSprite = (Sprite)body;
ShadowSprite.Visible = false;
- //ShadowSprite.ZIndex = -5;
break;
case "Collision":
Collision = (CollisionShape2D)body;
@@ -264,6 +278,20 @@
}
///
+ /// 每帧调用一次, 物体的 Process() 会在组件的 Process() 之前调用
+ ///
+ protected virtual void Process(float delta)
+ {
+ }
+
+ ///
+ /// 每物理帧调用一次, 物体的 PhysicsProcess() 会在组件的 PhysicsProcess() 之前调用
+ ///
+ protected virtual void PhysicsProcess(float delta)
+ {
+ }
+
+ ///
/// 如果开启 debug, 则每帧调用该函数, 可用于绘制文字线段等
///
protected virtual void DebugDraw()
@@ -357,7 +385,9 @@
_throwData.StartXSpeed = xSpeed;
_throwData.StartYSpeed = ySpeed;
_throwData.RotateSpeed = rotate;
- _throwData.LinearVelocity = new Vector2(_throwData.XSpeed, 0).Rotated(_throwData.Direction * Mathf.Pi / 180);
+ _throwData.ThrowForce = MoveController.AddForce("ThrowForce");
+ _throwData.ThrowForce.Velocity =
+ new Vector2(_throwData.XSpeed, 0).Rotated(_throwData.Direction * Mathf.Pi / 180);
_throwData.Y = startHeight;
_throwData.Bounce = bounce;
_throwData.BounceStrength = bounceStrength;
@@ -436,8 +466,13 @@
return (TC)component;
}
- public override void _Process(float delta)
+ ///
+ /// 每帧调用一次, 为了防止子类覆盖 _Process(), 给 _Process() 加上了 sealed, 子类需要帧循环函数请重写 Process() 函数
+ ///
+ public sealed override void _Process(float delta)
{
+ Process(delta);
+
//更新组件
if (_components.Count > 0)
{
@@ -462,7 +497,6 @@
//投抛计算
if (_throwData != null && !_throwData.IsOver)
{
- _throwData.LinearVelocity = MoveAndSlide(_throwData.LinearVelocity);
GlobalRotationDegrees = GlobalRotationDegrees + _throwData.RotateSpeed * delta;
CalcThrowAnimatedPosition();
@@ -508,7 +542,7 @@
_throwData.XSpeed = _throwData.StartXSpeed = _throwData.StartXSpeed * _throwData.BounceSpeed;
_throwData.YSpeed = _throwData.StartYSpeed = _throwData.StartYSpeed * _throwData.BounceStrength;
_throwData.RotateSpeed = _throwData.RotateSpeed * _throwData.BounceStrength;
- _throwData.LinearVelocity *= _throwData.BounceSpeed;
+ _throwData.ThrowForce.Velocity *= _throwData.BounceSpeed;
_throwData.FirstOver = false;
_throwData.IsOver = false;
@@ -571,8 +605,13 @@
}
}
- public override void _PhysicsProcess(float delta)
+ ///
+ /// 每物理帧调用一次, 为了防止子类覆盖 _PhysicsProcess(), 给 _PhysicsProcess() 加上了 sealed, 子类需要帧循环函数请重写 PhysicsProcess() 函数
+ ///
+ public sealed override void _PhysicsProcess(float delta)
{
+ PhysicsProcess(delta);
+
//更新组件
if (_components.Count > 0)
{
@@ -595,7 +634,10 @@
}
}
- public override void _Draw()
+ ///
+ /// 绘制函数, 子类不允许重写, 需要绘制函数请重写 DebugDraw()
+ ///
+ public sealed override void _Draw()
{
if (IsDebug)
{
@@ -785,6 +827,9 @@
///
private void ThrowOver()
{
+ //移除投抛的力
+ MoveController.RemoveForce(_throwData.ThrowForce);
+
GetParent().RemoveChild(this);
GameApplication.Instance.Room.GetRoot(UseYSort).AddChild(this);
RestoreCollision();
diff --git a/DungeonShooting_Godot/src/framework/MoveController.cs b/DungeonShooting_Godot/src/framework/MoveController.cs
index 5f79c96..ccedee0 100644
--- a/DungeonShooting_Godot/src/framework/MoveController.cs
+++ b/DungeonShooting_Godot/src/framework/MoveController.cs
@@ -13,11 +13,33 @@
private readonly List _forceList = new List();
///
- /// 这个速度就是玩家当前物理帧移动的真实速率
+ /// 这个速度就是玩家当前物理帧移动的真实速率, 该速度由物理帧循环更新, 并不会马上更新
+ /// 该速度就是 BasisVelocity + 外力总和
///
public Vector2 Velocity => _velocity;
+
private Vector2 _velocity = Vector2.Zero;
+
+ ///
+ /// 玩家的基础移动速率
+ ///
+ public Vector2 BasisVelocity
+ {
+ get => _basisVelocity;
+ set => _basisVelocity = value;
+ }
+
+ private Vector2 _basisVelocity = Vector2.Zero;
+
+ ///
+ /// 获取所有外力对象
+ ///
+ public ExternalForce[] GetAllForce()
+ {
+ return _forceList.ToArray();
+ }
+
///
/// 根据名称添加一个外力, 并返回创建的外力的对象, 如果存在这个名称的外力, 移除之前的外力
///
@@ -103,17 +125,13 @@
_forceList.Clear();
}
- ///
- /// 移除所有外力和基础力, 使物体静止
- ///
- public void Halt()
- {
- ClearForce();
- _velocity = Vector2.Zero;
- }
-
public override void PhysicsProcess(float delta)
{
+ if (_basisVelocity == Vector2.Zero && _forceList.Count == 0)
+ {
+ return;
+ }
+
//先调用更新
var externalForces = _forceList.ToArray();
foreach (var fore in externalForces)
@@ -123,7 +141,7 @@
}
//外力总和
- var finallyEf = Vector2.Zero;
+ var finallyEf = new Vector2();
foreach (var fore in externalForces)
{
if (fore.Enable)
@@ -131,29 +149,33 @@
}
//最终速率
- var finallyVelocity = _velocity + finallyEf;
+ var finallyVelocity = _basisVelocity + finallyEf;
- //计算移动
- _velocity = ActivityObject.MoveAndSlide(finallyVelocity);
-
- //调整外力速率
- if (externalForces.Length > 0)
+ if (finallyVelocity != Vector2.Zero)
{
- var scale = new Vector2();
- //x轴外力
- var efx = _velocity.x - _velocity.x;
- scale.x = finallyEf.x == 0f ? 0 : Mathf.Abs(efx / finallyEf.x);
- //y轴外力
- var efy = _velocity.y - _velocity.y;
- scale.y = finallyEf.y == 0f ? 0 : Mathf.Abs(efy / finallyEf.y);
- foreach (var force in externalForces)
+ //计算移动
+ _velocity = ActivityObject.MoveAndSlide(finallyVelocity);
+
+ //调整外力速率
+ if (externalForces.Length > 0)
{
- if (force.Enable)
+ //x轴外力
+ var scaleX = finallyEf.x == 0f ? 0 : Mathf.Abs((_velocity.x - _basisVelocity.x) / finallyEf.x);
+ //y轴外力
+ var scaleY = finallyEf.y == 0f ? 0 : Mathf.Abs((_velocity.y - _basisVelocity.y) / finallyEf.y);
+ foreach (var force in _forceList)
{
- var velocity = force.Velocity;
- force.Velocity = new Vector2(velocity.x * scale.x, velocity.y * scale.y);
+ if (force.Enable)
+ {
+ var velocity = force.Velocity;
+ force.Velocity = new Vector2(velocity.x * scaleX, velocity.y * scaleY);
+ }
}
}
}
+ else
+ {
+ _velocity = finallyEf;
+ }
}
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/ObjectThrowData.cs b/DungeonShooting_Godot/src/framework/ObjectThrowData.cs
index ec4ffd3..2986397 100644
--- a/DungeonShooting_Godot/src/framework/ObjectThrowData.cs
+++ b/DungeonShooting_Godot/src/framework/ObjectThrowData.cs
@@ -74,8 +74,8 @@
public Vector2 CurrPosition;
public float Y;
- public Vector2 LinearVelocity;
-
+ public ExternalForce ThrowForce;
+
//----------- 用于记录原始信息 --------------
public bool UseOrigin = true;
public Shape2D OriginShape;
diff --git a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs
index c4879b3..96eff98 100644
--- a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs
+++ b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs
@@ -302,9 +302,8 @@
UnclaimedWeapons.Remove(this);
}
- public override void _Process(float delta)
+ protected override void Process(float delta)
{
- base._Process(delta);
//这把武器被扔在地上, 或者当前武器没有被使用
if (Master == null || Master.Holster.ActiveWeapon != this)
{
diff --git a/DungeonShooting_Godot/src/game/item/weapon/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/item/weapon/bullet/Bullet.cs
index 60f7c2c..71a35a0 100644
--- a/DungeonShooting_Godot/src/game/item/weapon/bullet/Bullet.cs
+++ b/DungeonShooting_Godot/src/game/item/weapon/bullet/Bullet.cs
@@ -40,9 +40,8 @@
ShowShadowSprite();
}
- public override void _PhysicsProcess(float delta)
+ protected override void PhysicsProcess(float delta)
{
- base._PhysicsProcess(delta);
//移动
var kinematicCollision = MoveAndCollide(new Vector2(FlySpeed * delta, 0).Rotated(Rotation));
if (kinematicCollision != null)
diff --git a/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs
index ebc604f..e3e1da1 100644
--- a/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs
+++ b/DungeonShooting_Godot/src/game/item/weapon/knife/Knife.cs
@@ -44,10 +44,9 @@
_hitArea.Connect("body_entered", this, nameof(OnBodyEntered));
}
- public override void _Process(float delta)
+ protected override void Process(float delta)
{
- base._Process(delta);
-
+ base.Process(delta);
if (IsActive)
{
//让碰撞节点与武器挂载节点位置保持一致, 而不跟着武器走
@@ -55,10 +54,9 @@
}
}
- public override void _PhysicsProcess(float delta)
+ protected override void PhysicsProcess(float delta)
{
- base._PhysicsProcess(delta);
-
+ base.PhysicsProcess(delta);
//过去两个物理帧后就能关闭碰撞了
if (++_attackIndex >= 2)
{
diff --git a/DungeonShooting_Godot/src/game/role/Player.cs b/DungeonShooting_Godot/src/game/role/Player.cs
index a009b19..f805bc9 100644
--- a/DungeonShooting_Godot/src/game/role/Player.cs
+++ b/DungeonShooting_Godot/src/game/role/Player.cs
@@ -49,10 +49,9 @@
Shield = 30;
}
- public override void _Process(float delta)
+ protected override void Process(float delta)
{
- base._Process(delta);
-
+ base.Process(delta);
//脸的朝向
var gPos = GlobalPosition;
if (LookTarget == null)
@@ -110,9 +109,9 @@
}
}
- public override void _PhysicsProcess(float delta)
+ protected override void PhysicsProcess(float delta)
{
- base._PhysicsProcess(delta);
+ base.PhysicsProcess(delta);
HandleMoveInput(delta);
//播放动画
PlayAnim();
@@ -193,35 +192,35 @@
// 如果 有输入 就以当前速度,用acceleration 插值到 对应方向 * 最大速度
if (Mathf.IsZeroApprox(dir.x))
{
- Velocity = new Vector2(Mathf.MoveToward(Velocity.x, 0, Friction * delta), Velocity.y);
+ BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.x, 0, Friction * delta), BasisVelocity.y);
}
else
{
- Velocity = new Vector2(Mathf.MoveToward(Velocity.x, dir.x * MoveSpeed, Acceleration * delta), Velocity.y);
+ BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.x, dir.x * MoveSpeed, Acceleration * delta),
+ BasisVelocity.y);
}
if (Mathf.IsZeroApprox(dir.y))
{
- Velocity = new Vector2(Velocity.x, Mathf.MoveToward(Velocity.y, 0, Friction * delta));
+ BasisVelocity = new Vector2(BasisVelocity.x, Mathf.MoveToward(BasisVelocity.y, 0, Friction * delta));
}
else
{
- Velocity = new Vector2(Velocity.x, Mathf.MoveToward(Velocity.y, dir.y * MoveSpeed, Acceleration * delta));
+ BasisVelocity = new Vector2(BasisVelocity.x,
+ Mathf.MoveToward(BasisVelocity.y, dir.y * MoveSpeed, Acceleration * delta));
}
-
- CalcMove(delta);
}
-
+
// 播放动画
private void PlayAnim()
{
- if (Velocity != Vector2.Zero)
+ if (BasisVelocity != Vector2.Zero)
{
- if ((Face == FaceDirection.Right && Velocity.x >= 0) || Face == FaceDirection.Left && Velocity.x <= 0) //向前走
+ if ((Face == FaceDirection.Right && BasisVelocity.x >= 0) || Face == FaceDirection.Left && BasisVelocity.x <= 0) //向前走
{
AnimatedSprite.Animation = AnimatorNames.Run;
}
- else if ((Face == FaceDirection.Right && Velocity.x < 0) || Face == FaceDirection.Left && Velocity.x > 0) //向后走
+ else if ((Face == FaceDirection.Right && BasisVelocity.x < 0) || Face == FaceDirection.Left && BasisVelocity.x > 0) //向后走
{
AnimatedSprite.Animation = AnimatorNames.ReverseRun;
}
diff --git a/DungeonShooting_Godot/src/game/role/Role.cs b/DungeonShooting_Godot/src/game/role/Role.cs
index 6d8e632..90c1cfc 100644
--- a/DungeonShooting_Godot/src/game/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/role/Role.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using Godot;
@@ -63,16 +62,6 @@
private FaceDirection _face;
///
- /// 是否启用角色移动, 如果禁用, 那么调用 CalcMove() 将不再有任何效果
- ///
- public bool EnableMove { get; set; } = true;
-
- ///
- /// 移动速度, 通过调用 CalcMove() 函数来移动
- ///
- public Vector2 Velocity { get; set; } = Vector2.Zero;
-
- ///
/// 是否死亡
///
public bool IsDie { get; private set; }
@@ -245,10 +234,8 @@
InteractiveArea.Connect("area_exited", this, nameof(_OnPropsExit));
}
- public override void _Process(float delta)
+ protected override void Process(float delta)
{
- base._Process(delta);
-
//看向目标
if (LookTarget != null)
{
@@ -348,17 +335,6 @@
}
///
- /// 计算角色移动
- ///
- public virtual void CalcMove(float delta)
- {
- if (EnableMove && Velocity != Vector2.Zero)
- {
- Velocity = MoveAndSlide(Velocity);
- }
- }
-
- ///
/// 返回所有武器是否弹药都打光了
///
public bool IsAllWeaponTotalAmmoEmpty()
diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
index e2e3143..2e547fc 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
@@ -136,10 +136,9 @@
Destroy();
}
- public override void _PhysicsProcess(float delta)
+ protected override void PhysicsProcess(float delta)
{
- base._PhysicsProcess(delta);
-
+ base.PhysicsProcess(delta);
_enemyAttackTimer -= delta;
EnemyPickUpWeapon();
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs
index 9199909..4d507e6 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs
@@ -108,10 +108,9 @@
//计算移动
var nextPos = Master.NavigationAgent2D.GetNextLocation();
Master.AnimatedSprite.Animation = AnimatorNames.Run;
- Master.Velocity =
+ Master.BasisVelocity =
(nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
Master.MoveSpeed;
- Master.CalcMove(delta);
}
}
}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs
index f4a8371..bb6e82f 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs
@@ -75,9 +75,8 @@
//计算移动
var nextPos = Master.NavigationAgent2D.GetNextLocation();
Master.AnimatedSprite.Animation = AnimatorNames.Run;
- Master.Velocity = (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() *
+ Master.BasisVelocity = (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() *
Master.MoveSpeed;
- Master.CalcMove(delta);
}
//检测玩家是否在视野内
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs
index 96babc1..d0901ab 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs
@@ -67,9 +67,8 @@
var nextPos = Master.NavigationAgent2D.GetNextLocation();
Master.LookTargetPosition(Enemy.FindTargetPosition);
Master.AnimatedSprite.Animation = AnimatorNames.Run;
- Master.Velocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+ Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
Master.MoveSpeed;
- Master.CalcMove(delta);
}
var playerPos = GameApplication.Instance.Room.Player.GetCenterPosition();
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs
index 8260a7e..0683d8d 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs
@@ -78,9 +78,8 @@
//计算移动
var nextPos = Master.NavigationAgent2D.GetNextLocation();
Master.AnimatedSprite.Animation = AnimatorNames.Run;
- Master.Velocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+ Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
Master.MoveSpeed;
- Master.CalcMove(delta);
if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
{
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs
index 36c6594..5995c35 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs
@@ -80,9 +80,8 @@
//计算移动
var nextPos = Master.NavigationAgent2D.GetNextLocation();
Master.AnimatedSprite.Animation = AnimatorNames.Run;
- Master.Velocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+ Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
Master.MoveSpeed;
- Master.CalcMove(delta);
if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
{
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs
index 7a094e7..d766cd2 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs
@@ -68,9 +68,8 @@
//计算移动
var nextPos = Master.NavigationAgent2D.GetNextLocation();
Master.AnimatedSprite.Animation = AnimatorNames.Run;
- Master.Velocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+ Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
Master.MoveSpeed;
- Master.CalcMove(delta);
}
//检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
if (Master.IsInTailAfterViewRange(playerPos))