diff --git a/DungeonShooting_Godot/prefab/role/Enemy0001.tscn b/DungeonShooting_Godot/prefab/role/Enemy0001.tscn
index 5f153c2..6d6eeaf 100644
--- a/DungeonShooting_Godot/prefab/role/Enemy0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/Enemy0001.tscn
@@ -25,14 +25,16 @@
shader_parameter/outline_color = Color(0, 0, 0, 1)
shader_parameter/outline_rainbow = false
-[node name="Enemy0001" node_paths=PackedStringArray("HurtArea", "MountPoint", "BackMountPoint", "InteractiveArea", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_5po38")]
+[node name="Enemy0001" node_paths=PackedStringArray("HurtArea", "HurtCollision", "MountPoint", "BackMountPoint", "InteractiveArea", "InteractiveCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_5po38")]
collision_layer = 16
collision_mask = 25
script = ExtResource("2_1plrq")
HurtArea = NodePath("HurtArea")
+HurtCollision = NodePath("HurtArea/HurtCollision")
MountPoint = NodePath("MountPoint")
BackMountPoint = NodePath("BackMountPoint")
InteractiveArea = NodePath("InteractiveArea")
+InteractiveCollision = NodePath("InteractiveArea/InteractiveCollision")
ShadowSprite = NodePath("ShadowSprite")
AnimatedSprite = NodePath("AnimatedSprite")
Collision = NodePath("Collision")
diff --git a/DungeonShooting_Godot/prefab/role/Role0001.tscn b/DungeonShooting_Godot/prefab/role/Role0001.tscn
index 4560a76..196f400 100644
--- a/DungeonShooting_Godot/prefab/role/Role0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/Role0001.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=7 format=3 uid="uid://cxhrcytrx0kcf"]
[ext_resource type="PackedScene" uid="uid://cyrcv2jdgr8cf" path="res://prefab/role/RoleTemplate.tscn" id="1_10c2n"]
-[ext_resource type="Script" path="res://src/game/activity/role/Player.cs" id="2_i08u4"]
+[ext_resource type="Script" path="res://src/game/activity/role/player/Player.cs" id="2_6xwnt"]
[ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="3_rk4gg"]
[ext_resource type="SpriteFrames" uid="uid://n11thtali6es" path="res://resource/spriteFrames/role/Role0001.tres" id="4_galcc"]
@@ -25,13 +25,15 @@
shader_parameter/outline_color = Color(0, 0, 0, 1)
shader_parameter/outline_rainbow = false
-[node name="Role0001" node_paths=PackedStringArray("HurtArea", "MountPoint", "BackMountPoint", "InteractiveArea", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_10c2n")]
+[node name="Role0001" node_paths=PackedStringArray("HurtArea", "HurtCollision", "MountPoint", "BackMountPoint", "InteractiveArea", "InteractiveCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_10c2n")]
collision_layer = 8
-script = ExtResource("2_i08u4")
+script = ExtResource("2_6xwnt")
HurtArea = NodePath("HurtArea")
+HurtCollision = NodePath("HurtArea/HurtCollision")
MountPoint = NodePath("MountPoint")
BackMountPoint = NodePath("BackMountPoint")
InteractiveArea = NodePath("InteractiveArea")
+InteractiveCollision = NodePath("InteractiveArea/InteractiveCollision")
ShadowSprite = NodePath("ShadowSprite")
AnimatedSprite = NodePath("AnimatedSprite")
Collision = NodePath("Collision")
@@ -42,10 +44,6 @@
[node name="AnimatedSprite" parent="." index="2"]
material = SubResource("ShaderMaterial_8hgu2")
sprite_frames = ExtResource("4_galcc")
-frame_progress = 0.0995217
-
-[node name="CollisionShape2D" parent="HurtArea" index="0"]
-position = Vector2(0, -12)
[node name="MountPoint" parent="." index="6"]
position = Vector2(2, -8)
diff --git a/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn b/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn
index fde7ce1..d55de02 100644
--- a/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn
+++ b/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn
@@ -8,7 +8,7 @@
shader = ExtResource("1_xk5yk")
shader_parameter/blend = Color(0, 0, 0, 0.470588)
shader_parameter/schedule = 0.0
-shader_parameter/alpha = 1.0
+shader_parameter/modulate = Color(1, 1, 1, 1)
shader_parameter/show_outline = true
shader_parameter/outline_color = Color(0, 0, 0, 1)
shader_parameter/outline_rainbow = false
@@ -18,7 +18,7 @@
shader = ExtResource("1_xk5yk")
shader_parameter/blend = Color(1, 1, 1, 1)
shader_parameter/schedule = 0.0
-shader_parameter/alpha = 1.0
+shader_parameter/modulate = Color(1, 1, 1, 1)
shader_parameter/show_outline = true
shader_parameter/outline_color = Color(0, 0, 0, 1)
shader_parameter/outline_rainbow = false
@@ -54,7 +54,7 @@
collision_mask = 0
monitoring = false
-[node name="CollisionShape2D" type="CollisionShape2D" parent="HurtArea"]
+[node name="HurtCollision" type="CollisionShape2D" parent="HurtArea"]
position = Vector2(0, -9)
shape = SubResource("RectangleShape2D_1eja2")
@@ -64,7 +64,7 @@
collision_mask = 4
monitorable = false
-[node name="Collision" type="CollisionShape2D" parent="InteractiveArea"]
+[node name="InteractiveCollision" type="CollisionShape2D" parent="InteractiveArea"]
position = Vector2(0, -5)
shape = SubResource("RectangleShape2D_n68nu")
diff --git a/DungeonShooting_Godot/resource/spriteFrames/role/Role0001.tres b/DungeonShooting_Godot/resource/spriteFrames/role/Role0001.tres
index e262de5..8205354 100644
--- a/DungeonShooting_Godot/resource/spriteFrames/role/Role0001.tres
+++ b/DungeonShooting_Godot/resource/spriteFrames/role/Role0001.tres
@@ -1,4 +1,4 @@
-[gd_resource type="SpriteFrames" load_steps=15 format=3 uid="uid://n11thtali6es"]
+[gd_resource type="SpriteFrames" load_steps=21 format=3 uid="uid://n11thtali6es"]
[ext_resource type="Texture2D" uid="uid://ekas4lqprrml" path="res://resource/sprite/role/role0001/idle/Sprite-0002.png" id="1_le6bk"]
[ext_resource type="Texture2D" uid="uid://b81k08ofpf2oo" path="res://resource/sprite/role/role0001/idle/Sprite-0003.png" id="2_whsc2"]
@@ -14,6 +14,12 @@
[ext_resource type="Texture2D" uid="uid://d32g0f5vk68sj" path="res://resource/sprite/role/role0001/run/Sprite-0004.png" id="12_cbabh"]
[ext_resource type="Texture2D" uid="uid://cw83liyy6gnln" path="res://resource/sprite/role/role0001/run/Sprite-0003.png" id="13_u0cmp"]
[ext_resource type="Texture2D" uid="uid://b1gh481w2xvsl" path="res://resource/sprite/role/role0001/run/Sprite-0002.png" id="14_nlfq5"]
+[ext_resource type="Texture2D" uid="uid://sknj4eflhbvc" path="res://resource/sprite/role/role0001/roll/Sprite-0004.png" id="17_xnddk"]
+[ext_resource type="Texture2D" uid="uid://c8ijooj30lvpw" path="res://resource/sprite/role/role0001/roll/Sprite-0005.png" id="18_1doii"]
+[ext_resource type="Texture2D" uid="uid://blqx76rvx6c34" path="res://resource/sprite/role/role0001/roll/Sprite-0006.png" id="19_ilt25"]
+[ext_resource type="Texture2D" uid="uid://48qebkjqggub" path="res://resource/sprite/role/role0001/roll/Sprite-0007.png" id="20_tp03g"]
+[ext_resource type="Texture2D" uid="uid://dvrxriqd6dk1d" path="res://resource/sprite/role/role0001/roll/Sprite-0008.png" id="21_oocqa"]
+[ext_resource type="Texture2D" uid="uid://ceqi6d4vhbpt" path="res://resource/sprite/role/role0001/roll/Sprite-0009.png" id="22_yc5ek"]
[resource]
animations = [{
@@ -53,9 +59,6 @@
}, {
"frames": [{
"duration": 1.0,
-"texture": ExtResource("8_scwvl")
-}, {
-"duration": 1.0,
"texture": ExtResource("9_yjs5f")
}, {
"duration": 1.0,
@@ -72,6 +75,9 @@
}, {
"duration": 1.0,
"texture": ExtResource("14_nlfq5")
+}, {
+"duration": 1.0,
+"texture": ExtResource("8_scwvl")
}],
"loop": true,
"name": &"reverseRun",
@@ -79,6 +85,29 @@
}, {
"frames": [{
"duration": 1.0,
+"texture": ExtResource("17_xnddk")
+}, {
+"duration": 1.0,
+"texture": ExtResource("18_1doii")
+}, {
+"duration": 1.0,
+"texture": ExtResource("19_ilt25")
+}, {
+"duration": 1.0,
+"texture": ExtResource("20_tp03g")
+}, {
+"duration": 1.0,
+"texture": ExtResource("21_oocqa")
+}, {
+"duration": 1.0,
+"texture": ExtResource("22_yc5ek")
+}],
+"loop": false,
+"name": &"roll",
+"speed": 15.0
+}, {
+"frames": [{
+"duration": 1.0,
"texture": ExtResource("14_nlfq5")
}, {
"duration": 1.0,
diff --git a/DungeonShooting_Godot/resource/spriteFrames/role/Role1001.tres b/DungeonShooting_Godot/resource/spriteFrames/role/Role1001.tres
index dd4a35a..600ba06 100644
--- a/DungeonShooting_Godot/resource/spriteFrames/role/Role1001.tres
+++ b/DungeonShooting_Godot/resource/spriteFrames/role/Role1001.tres
@@ -1,6 +1,6 @@
[gd_resource type="SpriteFrames" load_steps=15 format=3 uid="uid://cnctpyrn02rhd"]
-[ext_resource type="Texture2D" path="res://resource/sprite/role/enemy0001/enemy0001.png" id="1_xi6qw"]
+[ext_resource type="Texture2D" uid="uid://ddhkhfaos2w1g" path="res://resource/sprite/role/enemy0001/enemy0001.png" id="1_xi6qw"]
[sub_resource type="AtlasTexture" id="AtlasTexture_jttte"]
atlas = ExtResource("1_xi6qw")
diff --git a/DungeonShooting_Godot/src/framework/activity/Component.cs b/DungeonShooting_Godot/src/framework/activity/Component.cs
index f96b8dd..ec1897d 100644
--- a/DungeonShooting_Godot/src/framework/activity/Component.cs
+++ b/DungeonShooting_Godot/src/framework/activity/Component.cs
@@ -1,10 +1,11 @@
+using System.Collections;
using Godot;
///
/// 组件基类, 用于挂载到游戏物体上, 相比于原生 Node 更加轻量化, 实例化 Component 不会创建额外的 Node, 可以大量添加组件
///
-public abstract class Component : IProcess, IDestroy
+public abstract class Component : IProcess, IDestroy, ICoroutine
{
///
/// 当前组件所挂载的游戏对象
@@ -212,4 +213,24 @@
ActivityInstance.RemoveComponent(this);
OnDestroy();
}
+
+ public long StartCoroutine(IEnumerator able)
+ {
+ return ActivityInstance.StartCoroutine(able);
+ }
+
+ public void StopCoroutine(long coroutineId)
+ {
+ ActivityInstance.StopCoroutine(coroutineId);
+ }
+
+ public bool IsCoroutineOver(long coroutineId)
+ {
+ return ActivityInstance.IsCoroutineOver(coroutineId);
+ }
+
+ public void StopAllCoroutine()
+ {
+ ActivityInstance.StopAllCoroutine();
+ }
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs
index 743708a..124220e 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/Bullet.cs
@@ -74,11 +74,11 @@
BasisVelocity = new Vector2(FlySpeed, 0).Rotated(Rotation);
//如果子弹会对玩家造成伤害, 则显示红色描边
- if (Player.Current.CollisionWithMask(targetLayer))
- {
- ShowOutline = true;
- OutlineColor = new Color(1, 0, 0, 0.9f);
- }
+ // if (Player.Current.CollisionWithMask(targetLayer))
+ // {
+ // ShowOutline = true;
+ // OutlineColor = new Color(1, 0, 0, 0.9f);
+ // }
}
protected override void PhysicsProcessOver(float delta)
diff --git a/DungeonShooting_Godot/src/game/activity/role/Player.cs b/DungeonShooting_Godot/src/game/activity/role/Player.cs
deleted file mode 100644
index a4f3640..0000000
--- a/DungeonShooting_Godot/src/game/activity/role/Player.cs
+++ /dev/null
@@ -1,287 +0,0 @@
-using Godot;
-
-
-///
-/// 玩家角色基类, 所有角色都必须继承该类
-///
-[Tool]
-public partial class Player : Role
-{
- ///
- /// 获取当前操作的角色
- ///
- public static Player Current { get; private set; }
-
- ///
- /// 设置当前操作的玩家对象
- ///
- public static void SetCurrentPlayer(Player player)
- {
- Current = player;
- //设置相机和鼠标跟随玩家
- GameCamera.Main.SetFollowTarget(player);
- GameApplication.Instance.Cursor.SetMountRole(player);
- }
-
- public override void OnInit()
- {
- base.OnInit();
-
- AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Prop | PhysicsLayer.Enemy;
- Camp = CampEnum.Camp1;
-
- MaxHp = 6;
- Hp = 6;
- MaxShield = 0;
- Shield = 0;
-
- // debug用
- // RoleState.Acceleration = 3000;
- // RoleState.Friction = 3000;
- // RoleState.MoveSpeed = 500;
- // CollisionLayer = 0;
- // CollisionMask = 0;
- // GameCamera.Main.Zoom = new Vector2(0.2f, 0.2f);
- // //GameCamera.Main.Zoom = new Vector2(0.5f, 0.5f);
- }
-
- protected override void Process(float delta)
- {
- if (IsDie)
- {
- return;
- }
- base.Process(delta);
- //脸的朝向
- if (LookTarget == null)
- {
- var gPos = GlobalPosition;
- Vector2 mousePos = InputManager.CursorPosition;
- if (mousePos.X > gPos.X && Face == FaceDirection.Left)
- {
- Face = FaceDirection.Right;
- }
- else if (mousePos.X < gPos.X && Face == FaceDirection.Right)
- {
- Face = FaceDirection.Left;
- }
- //枪口跟随鼠标
- MountPoint.SetLookAt(mousePos);
- }
-
- if (InputManager.ExchangeWeapon) //切换武器
- {
- ExchangeNextWeapon();
- }
- else if (InputManager.ThrowWeapon) //扔掉武器
- {
- ThrowWeapon();
-
- // //测试用的, 所有敌人也扔掉武器
- // if (Affiliation != null)
- // {
- // var enemies = Affiliation.FindIncludeItems(o =>
- // {
- // return o.CollisionWithMask(PhysicsLayer.Enemy);
- // });
- // foreach (var activityObject in enemies)
- // {
- // if (activityObject is Enemy enemy)
- // {
- // enemy.ThrowWeapon();
- // }
- // }
- // }
- }
- else if (InputManager.Interactive) //互动物体
- {
- TriggerInteractive();
- }
- else if (InputManager.Reload) //换弹
- {
- Reload();
- }
-
- if (InputManager.Fire) //开火
- {
- Attack();
- // var weaponArray = AffiliationArea.FindEnterItems(o => o is Weapon);
- // foreach (Weapon activityObject in weaponArray)
- // {
- // activityObject.Trigger(this);
- // }
- }
-
- if (InputManager.UseActiveProp) //使用道具
- {
- UseActiveProp();
- }
- else if (InputManager.RemoveProp) //扔掉道具
- {
- ThrowActiveProp();
- }
-
- if (Input.IsKeyPressed(Key.P))
- {
- //Hurt(1000, 0);
- Hp = 0;
- Hurt(1000, 0);
- }
- }
-
- protected override void PhysicsProcess(float delta)
- {
- if (IsDie)
- {
- return;
- }
-
- base.PhysicsProcess(delta);
- HandleMoveInput(delta);
- //播放动画
- PlayAnim();
- }
-
- protected override void OnPickUpWeapon(Weapon weapon)
- {
- EventManager.EmitEvent(EventEnum.OnPlayerPickUpWeapon, weapon);
- }
-
- protected override void OnThrowWeapon(Weapon weapon)
- {
- EventManager.EmitEvent(EventEnum.OnPlayerRemoveWeapon, weapon);
- }
-
- protected override int OnHandlerHurt(int damage)
- {
- //修改受到的伤害, 每次只受到1点伤害
- return 1;
- }
-
- protected override void OnHit(int damage, bool realHarm)
- {
- //进入无敌状态
- if (realHarm) //真实伤害
- {
- PlayInvincibleFlashing(RoleState.WoundedInvincibleTime);
- }
- else //护盾抵消掉的
- {
- PlayInvincibleFlashing(RoleState.ShieldInvincibleTime);
- }
- }
-
- protected override void OnChangeHp(int hp)
- {
- //GameApplication.Instance.Ui.SetHp(hp);
- EventManager.EmitEvent(EventEnum.OnPlayerHpChange, hp);
- }
-
- protected override void OnChangeMaxHp(int maxHp)
- {
- //GameApplication.Instance.Ui.SetMaxHp(maxHp);
- EventManager.EmitEvent(EventEnum.OnPlayerMaxHpChange, maxHp);
- }
-
- protected override void ChangeInteractiveItem(CheckInteractiveResult prev, CheckInteractiveResult result)
- {
- if (prev != null && prev.Target.ShowOutline)
- {
- prev.Target.OutlineColor = Colors.Black;
- }
- if (result != null && result.Target.ShowOutline)
- {
- result.Target.OutlineColor = Colors.White;
- }
- //派发互动对象改变事件
- EventManager.EmitEvent(EventEnum.OnPlayerChangeInteractiveItem, result);
- }
-
- protected override void OnChangeShield(int shield)
- {
- //GameApplication.Instance.Ui.SetShield(shield);
- EventManager.EmitEvent(EventEnum.OnPlayerShieldChange, shield);
- }
-
- protected override void OnChangeMaxShield(int maxShield)
- {
- //GameApplication.Instance.Ui.SetMaxShield(maxShield);
- EventManager.EmitEvent(EventEnum.OnPlayerMaxShieldChange, maxShield);
- }
-
- protected override void OnDie()
- {
- GameCamera.Main.SetFollowTarget(null);
- BasisVelocity = Vector2.Zero;
- MoveController.ClearForce();
- UiManager.Open_Settlement();
- }
-
- protected override void OnPickUpActiveProp(ActiveProp activeProp)
- {
- EventManager.EmitEvent(EventEnum.OnPlayerPickUpProp, activeProp);
- }
-
- protected override void OnRemoveActiveProp(ActiveProp activeProp)
- {
- EventManager.EmitEvent(EventEnum.OnPlayerRemoveProp, activeProp);
- }
-
- protected override void OnPickUpBuffProp(BuffProp buffProp)
- {
- EventManager.EmitEvent(EventEnum.OnPlayerPickUpProp, buffProp);
- }
-
- protected override void OnRemoveBuffProp(BuffProp buffProp)
- {
- EventManager.EmitEvent(EventEnum.OnPlayerRemoveProp, buffProp);
- }
-
- //处理角色移动的输入
- private void HandleMoveInput(float delta)
- {
- //角色移动
- Vector2 dir = InputManager.MoveAxis;
- // 移动. 如果移动的数值接近0(是用 摇杆可能出现 方向 可能会出现浮点),就friction的值 插值 到 0
- // 如果 有输入 就以当前速度,用acceleration 插值到 对应方向 * 最大速度
- if (Mathf.IsZeroApprox(dir.X))
- {
- BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, 0, RoleState.Friction * delta), BasisVelocity.Y);
- }
- else
- {
- BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, dir.X * RoleState.MoveSpeed, RoleState.Acceleration * delta),
- BasisVelocity.Y);
- }
-
- if (Mathf.IsZeroApprox(dir.Y))
- {
- BasisVelocity = new Vector2(BasisVelocity.X, Mathf.MoveToward(BasisVelocity.Y, 0, RoleState.Friction * delta));
- }
- else
- {
- BasisVelocity = new Vector2(BasisVelocity.X,
- Mathf.MoveToward(BasisVelocity.Y, dir.Y * RoleState.MoveSpeed, RoleState.Acceleration * delta));
- }
- }
-
- // 播放动画
- private void PlayAnim()
- {
- if (BasisVelocity != Vector2.Zero)
- {
- if ((Face == FaceDirection.Right && BasisVelocity.X >= 0) || Face == FaceDirection.Left && BasisVelocity.X <= 0) //向前走
- {
- AnimatedSprite.Play(AnimatorNames.Run);
- }
- else if ((Face == FaceDirection.Right && BasisVelocity.X < 0) || Face == FaceDirection.Left && BasisVelocity.X > 0) //向后走
- {
- AnimatedSprite.Play(AnimatorNames.ReverseRun);
- }
- }
- else
- {
- AnimatedSprite.Play(AnimatorNames.Idle);
- }
- }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs
index 1221d33..f910803 100644
--- a/DungeonShooting_Godot/src/game/activity/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs
@@ -27,6 +27,12 @@
///
[Export, ExportFillNode]
public Area2D HurtArea { get; set; }
+
+ ///
+ /// 伤害区域碰撞器
+ ///
+ [Export, ExportFillNode]
+ public CollisionShape2D HurtCollision { get; set; }
///
/// 所属阵营
@@ -71,6 +77,12 @@
public Area2D InteractiveArea { get; set; }
///
+ /// 互动区域碰撞器
+ ///
+ [Export, ExportFillNode]
+ public CollisionShape2D InteractiveCollision { get; set; }
+
+ ///
/// 脸的朝向
///
public FaceDirection Face { get => _face; set => SetFace(value); }
diff --git a/DungeonShooting_Godot/src/game/activity/role/RoleState.cs b/DungeonShooting_Godot/src/game/activity/role/RoleState.cs
index 0585f25..835d741 100644
--- a/DungeonShooting_Godot/src/game/activity/role/RoleState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/RoleState.cs
@@ -15,6 +15,11 @@
/// 移动加速度
///
public float Acceleration = 1500f;
+
+ ///
+ /// 翻滚速度
+ ///
+ public float RollSpeed = 180f;
///
/// 移动摩擦力
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
new file mode 100644
index 0000000..89e806c
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
@@ -0,0 +1,290 @@
+using Godot;
+
+
+///
+/// 玩家角色基类, 所有角色都必须继承该类
+///
+[Tool]
+public partial class Player : Role
+{
+ ///
+ /// 获取当前操作的角色
+ ///
+ public static Player Current { get; private set; }
+
+ ///
+ /// 玩家身上的状态机控制器
+ ///
+ public StateController StateController { get; private set; }
+
+ ///
+ /// 是否翻滚中
+ ///
+ public bool IsRolling { get; private set; }
+
+ ///
+ /// 设置当前操作的玩家对象
+ ///
+ public static void SetCurrentPlayer(Player player)
+ {
+ Current = player;
+ //设置相机和鼠标跟随玩家
+ GameCamera.Main.SetFollowTarget(player);
+ GameApplication.Instance.Cursor.SetMountRole(player);
+ }
+
+ public override void OnInit()
+ {
+ base.OnInit();
+
+ IsAi = false;
+ StateController = AddComponent>();
+ AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Prop | PhysicsLayer.Enemy;
+ Camp = CampEnum.Camp1;
+
+ MaxHp = 6;
+ Hp = 6;
+ MaxShield = 0;
+ Shield = 0;
+
+ // debug用
+ // RoleState.Acceleration = 3000;
+ // RoleState.Friction = 3000;
+ // RoleState.MoveSpeed = 500;
+ // CollisionLayer = 0;
+ // CollisionMask = 0;
+ // GameCamera.Main.Zoom = new Vector2(0.2f, 0.2f);
+ // //GameCamera.Main.Zoom = new Vector2(0.5f, 0.5f);
+
+ //注册状态机
+ StateController.Register(new PlayerIdleState());
+ StateController.Register(new PlayerMoveState());
+ StateController.Register(new PlayerRollState());
+ //默认状态
+ StateController.ChangeStateInstant(PlayerStateEnum.Idle);
+ }
+
+ protected override void Process(float delta)
+ {
+ if (IsDie)
+ {
+ return;
+ }
+ base.Process(delta);
+ //脸的朝向
+ if (LookTarget == null)
+ {
+ var gPos = GlobalPosition;
+ Vector2 mousePos = InputManager.CursorPosition;
+ if (mousePos.X > gPos.X && Face == FaceDirection.Left)
+ {
+ Face = FaceDirection.Right;
+ }
+ else if (mousePos.X < gPos.X && Face == FaceDirection.Right)
+ {
+ Face = FaceDirection.Left;
+ }
+ //枪口跟随鼠标
+ MountPoint.SetLookAt(mousePos);
+ }
+
+ if (InputManager.ExchangeWeapon) //切换武器
+ {
+ ExchangeNextWeapon();
+ }
+ else if (InputManager.ThrowWeapon) //扔掉武器
+ {
+ ThrowWeapon();
+
+ // //测试用的, 所有敌人也扔掉武器
+ // if (Affiliation != null)
+ // {
+ // var enemies = Affiliation.FindIncludeItems(o =>
+ // {
+ // return o.CollisionWithMask(PhysicsLayer.Enemy);
+ // });
+ // foreach (var activityObject in enemies)
+ // {
+ // if (activityObject is Enemy enemy)
+ // {
+ // enemy.ThrowWeapon();
+ // }
+ // }
+ // }
+ }
+ else if (InputManager.Interactive) //互动物体
+ {
+ TriggerInteractive();
+ }
+ else if (InputManager.Reload) //换弹
+ {
+ Reload();
+ }
+
+ if (InputManager.Fire) //开火
+ {
+ if (StateController.CurrState != PlayerStateEnum.Roll) //不能是翻滚状态
+ {
+ Attack();
+ // var weaponArray = AffiliationArea.FindEnterItems(o => o is Weapon);
+ // foreach (Weapon activityObject in weaponArray)
+ // {
+ // activityObject.Trigger(this);
+ // }
+ }
+ }
+
+ if (InputManager.UseActiveProp) //使用道具
+ {
+ UseActiveProp();
+ }
+ else if (InputManager.RemoveProp) //扔掉道具
+ {
+ ThrowActiveProp();
+ }
+
+ if (Input.IsKeyPressed(Key.P)) //测试用, 自杀
+ {
+ //Hurt(1000, 0);
+ Hp = 0;
+ Hurt(1000, 0);
+ }
+ }
+
+ // protected override void PhysicsProcess(float delta)
+ // {
+ // if (IsDie)
+ // {
+ // return;
+ // }
+ //
+ // base.PhysicsProcess(delta);
+ // //处理移动
+ // HandleMoveInput(delta);
+ // //播放动画
+ // PlayAnim();
+ // }
+
+ protected override void OnPickUpWeapon(Weapon weapon)
+ {
+ EventManager.EmitEvent(EventEnum.OnPlayerPickUpWeapon, weapon);
+ }
+
+ protected override void OnThrowWeapon(Weapon weapon)
+ {
+ EventManager.EmitEvent(EventEnum.OnPlayerRemoveWeapon, weapon);
+ }
+
+ protected override int OnHandlerHurt(int damage)
+ {
+ //修改受到的伤害, 每次只受到1点伤害
+ return 1;
+ }
+
+ protected override void OnHit(int damage, bool realHarm)
+ {
+ //进入无敌状态
+ if (realHarm) //真实伤害
+ {
+ PlayInvincibleFlashing(RoleState.WoundedInvincibleTime);
+ }
+ else //护盾抵消掉的
+ {
+ PlayInvincibleFlashing(RoleState.ShieldInvincibleTime);
+ }
+ }
+
+ protected override void OnChangeHp(int hp)
+ {
+ //GameApplication.Instance.Ui.SetHp(hp);
+ EventManager.EmitEvent(EventEnum.OnPlayerHpChange, hp);
+ }
+
+ protected override void OnChangeMaxHp(int maxHp)
+ {
+ //GameApplication.Instance.Ui.SetMaxHp(maxHp);
+ EventManager.EmitEvent(EventEnum.OnPlayerMaxHpChange, maxHp);
+ }
+
+ protected override void ChangeInteractiveItem(CheckInteractiveResult prev, CheckInteractiveResult result)
+ {
+ if (prev != null && prev.Target.ShowOutline)
+ {
+ prev.Target.OutlineColor = Colors.Black;
+ }
+ if (result != null && result.Target.ShowOutline)
+ {
+ result.Target.OutlineColor = Colors.White;
+ }
+ //派发互动对象改变事件
+ EventManager.EmitEvent(EventEnum.OnPlayerChangeInteractiveItem, result);
+ }
+
+ protected override void OnChangeShield(int shield)
+ {
+ //GameApplication.Instance.Ui.SetShield(shield);
+ EventManager.EmitEvent(EventEnum.OnPlayerShieldChange, shield);
+ }
+
+ protected override void OnChangeMaxShield(int maxShield)
+ {
+ //GameApplication.Instance.Ui.SetMaxShield(maxShield);
+ EventManager.EmitEvent(EventEnum.OnPlayerMaxShieldChange, maxShield);
+ }
+
+ protected override void OnDie()
+ {
+ StateController.Enable = false;
+ GameCamera.Main.SetFollowTarget(null);
+ BasisVelocity = Vector2.Zero;
+ MoveController.ClearForce();
+ UiManager.Open_Settlement();
+ }
+
+ protected override void OnPickUpActiveProp(ActiveProp activeProp)
+ {
+ EventManager.EmitEvent(EventEnum.OnPlayerPickUpProp, activeProp);
+ }
+
+ protected override void OnRemoveActiveProp(ActiveProp activeProp)
+ {
+ EventManager.EmitEvent(EventEnum.OnPlayerRemoveProp, activeProp);
+ }
+
+ protected override void OnPickUpBuffProp(BuffProp buffProp)
+ {
+ EventManager.EmitEvent(EventEnum.OnPlayerPickUpProp, buffProp);
+ }
+
+ protected override void OnRemoveBuffProp(BuffProp buffProp)
+ {
+ EventManager.EmitEvent(EventEnum.OnPlayerRemoveProp, buffProp);
+ }
+
+ ///
+ /// 处理角色移动的输入
+ ///
+ public void HandleMoveInput(float delta)
+ {
+ var dir = InputManager.MoveAxis;
+ // 移动. 如果移动的数值接近0(是用 摇杆可能出现 方向 可能会出现浮点),就friction的值 插值 到 0
+ // 如果 有输入 就以当前速度,用acceleration 插值到 对应方向 * 最大速度
+ if (Mathf.IsZeroApprox(dir.X))
+ {
+ BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, 0, RoleState.Friction * delta), BasisVelocity.Y);
+ }
+ else
+ {
+ BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, dir.X * RoleState.MoveSpeed, RoleState.Acceleration * delta), BasisVelocity.Y);
+ }
+
+ if (Mathf.IsZeroApprox(dir.Y))
+ {
+ BasisVelocity = new Vector2(BasisVelocity.X, Mathf.MoveToward(BasisVelocity.Y, 0, RoleState.Friction * delta));
+ }
+ else
+ {
+ BasisVelocity = new Vector2(BasisVelocity.X, Mathf.MoveToward(BasisVelocity.Y, dir.Y * RoleState.MoveSpeed, RoleState.Acceleration * delta));
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerIdleState.cs b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerIdleState.cs
new file mode 100644
index 0000000..fb3c530
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerIdleState.cs
@@ -0,0 +1,38 @@
+
+using Godot;
+
+///
+/// 空闲状态
+///
+public class PlayerIdleState : StateBase
+{
+ public PlayerIdleState() : base(PlayerStateEnum.Idle)
+ {
+ }
+
+ public override void Enter(PlayerStateEnum prev, params object[] args)
+ {
+ Master.HandleMoveInput((float)Master.GetProcessDeltaTime());
+ Master.AnimatedSprite.Play(AnimatorNames.Idle);
+ }
+
+ public override void Process(float delta)
+ {
+ var dir = InputManager.MoveAxis;
+ if (dir != Vector2.Zero)
+ {
+ if (InputManager.Roll) //按下翻滚
+ {
+ ChangeState(PlayerStateEnum.Roll);
+ }
+ else //移动
+ {
+ ChangeState(PlayerStateEnum.Move);
+ }
+ }
+ else
+ {
+ Master.HandleMoveInput(delta);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerMoveState.cs b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerMoveState.cs
new file mode 100644
index 0000000..a3953f1
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerMoveState.cs
@@ -0,0 +1,51 @@
+
+using Godot;
+
+///
+/// 移动状态
+///
+public class PlayerMoveState : StateBase
+{
+ public PlayerMoveState() : base(PlayerStateEnum.Move)
+ {
+ }
+
+ public override void Enter(PlayerStateEnum prev, params object[] args)
+ {
+ Master.HandleMoveInput((float)Master.GetProcessDeltaTime());
+ PlayAnim();
+ }
+
+ public override void Process(float delta)
+ {
+ if (InputManager.MoveAxis == Vector2.Zero) //停止移动
+ {
+ ChangeState(PlayerStateEnum.Idle);
+ }
+ else
+ {
+ if (InputManager.Roll) //翻滚
+ {
+ ChangeState(PlayerStateEnum.Roll);
+ }
+ else //执行移动
+ {
+ Master.HandleMoveInput(delta);
+ PlayAnim();
+ }
+ }
+ }
+
+ // 播放动画
+ private void PlayAnim()
+ {
+ if ((Master.Face == FaceDirection.Right && Master.BasisVelocity.X >= 0) || Master.Face == FaceDirection.Left && Master.BasisVelocity.X <= 0) //向前走
+ {
+ Master.AnimatedSprite.Play(AnimatorNames.Run);
+ }
+ else if ((Master.Face == FaceDirection.Right && Master.BasisVelocity.X < 0) || Master.Face == FaceDirection.Left && Master.BasisVelocity.X > 0) //向后走
+ {
+ Master.AnimatedSprite.Play(AnimatorNames.ReverseRun);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerRollState.cs b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerRollState.cs
new file mode 100644
index 0000000..badde0e
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerRollState.cs
@@ -0,0 +1,66 @@
+
+using System.Collections;
+using Godot;
+
+///
+/// 翻滚状态
+///
+public class PlayerRollState : StateBase
+{
+ private long _coroutineId = -1;
+ private Vector2 _moveDir;
+
+ public PlayerRollState() : base(PlayerStateEnum.Roll)
+ {
+ }
+
+ public override void Enter(PlayerStateEnum prev, params object[] args)
+ {
+ if (_coroutineId >= 0)
+ {
+ Master.StopCoroutine(_coroutineId);
+ }
+
+ _coroutineId = Master.StartCoroutine(RunRoll());
+ Master.AnimatedSprite.Play(AnimatorNames.Roll);
+
+ //隐藏武器
+ Master.BackMountPoint.Visible = false;
+ Master.MountPoint.Visible = false;
+ //禁用伤害碰撞
+ Master.HurtCollision.Disabled = true;
+
+ //翻滚移动方向
+ _moveDir = InputManager.MoveAxis;
+ Master.BasisVelocity = _moveDir * Master.RoleState.RollSpeed;
+ }
+
+ public override void Exit(PlayerStateEnum next)
+ {
+ //显示武器
+ Master.BackMountPoint.Visible = true;
+ Master.MountPoint.Visible = true;
+ //启用伤害碰撞
+ Master.HurtCollision.Disabled = false;
+ }
+
+ public override void Process(float delta)
+ {
+ Master.BasisVelocity = _moveDir * Master.RoleState.RollSpeed;
+ }
+
+ //翻滚逻辑处理
+ private IEnumerator RunRoll()
+ {
+ yield return Master.AnimatedSprite.ToSignal(Master.AnimatedSprite, AnimatedSprite2D.SignalName.AnimationFinished);
+ _coroutineId = -1;
+ if (InputManager.MoveAxis != Vector2.Zero) //切换到移动状态
+ {
+ ChangeState(PlayerStateEnum.Move);
+ }
+ else //切换空闲状态
+ {
+ ChangeState(PlayerStateEnum.Idle);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerStateEnum.cs
new file mode 100644
index 0000000..5bbd421
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/player/state/PlayerStateEnum.cs
@@ -0,0 +1,16 @@
+
+public enum PlayerStateEnum
+{
+ ///
+ /// 待机状态
+ ///
+ Idle,
+ ///
+ /// 移动状态
+ ///
+ Move,
+ ///
+ /// 翻滚状态
+ ///
+ Roll
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/manager/InputManager.cs b/DungeonShooting_Godot/src/game/manager/InputManager.cs
index 9ebf832..01512d6 100644
--- a/DungeonShooting_Godot/src/game/manager/InputManager.cs
+++ b/DungeonShooting_Godot/src/game/manager/InputManager.cs
@@ -7,7 +7,7 @@
public static class InputManager
{
///
- /// 移动方向, 键鼠: 键盘WASD
+ /// 移动方向, 已经归一化, 键鼠: 键盘WASD
///
public static Vector2 MoveAxis { get; private set; }