diff --git a/DungeonShooting_Godot/prefab/ui/PauseMenu.tscn b/DungeonShooting_Godot/prefab/ui/PauseMenu.tscn
new file mode 100644
index 0000000..421dd01
--- /dev/null
+++ b/DungeonShooting_Godot/prefab/ui/PauseMenu.tscn
@@ -0,0 +1,59 @@
+[gd_scene load_steps=3 format=3 uid="uid://bkq1wl66w3ais"]
+
+[ext_resource type="Script" path="res://src/game/ui/pauseMenu/PauseMenuPanel.cs" id="1_ef73i"]
+[ext_resource type="Theme" uid="uid://drb1ajgvcih7p" path="res://resource/theme/theme1.tres" id="2_x1py5"]
+
+[node name="PauseMenu" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+script = ExtResource("1_ef73i")
+Layer = 2
+
+[node name="ColorRect" type="ColorRect" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+color = Color(0, 0, 0, 0.54902)
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -64.0
+offset_top = -79.0
+offset_right = 64.0
+offset_bottom = 79.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Continue" type="Button" parent="VBoxContainer"]
+custom_minimum_size = Vector2(0, 50)
+layout_mode = 2
+focus_neighbor_top = NodePath("../Exit")
+focus_neighbor_bottom = NodePath("../Setting")
+theme = ExtResource("2_x1py5")
+text = "继续"
+
+[node name="Restart" type="Button" parent="VBoxContainer"]
+custom_minimum_size = Vector2(0, 50)
+layout_mode = 2
+focus_neighbor_top = NodePath("../Exit")
+focus_neighbor_bottom = NodePath("../Setting")
+theme = ExtResource("2_x1py5")
+text = "重新开始"
+
+[node name="Exit" type="Button" parent="VBoxContainer"]
+custom_minimum_size = Vector2(0, 50)
+layout_mode = 2
+focus_neighbor_top = NodePath("../Exit")
+focus_neighbor_bottom = NodePath("../Setting")
+theme = ExtResource("2_x1py5")
+text = "退出游戏"
diff --git a/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs b/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
index c00452d..37575bb 100644
--- a/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
+++ b/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
@@ -251,7 +251,7 @@
if (_currWaveIndex < WaveList.Count)
{
GD.Print($"执行第{_currWaveIndex}波");
- _coroutineId = GameApplication.Instance.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
+ _coroutineId = GameApplication.Instance.World.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
_currWaveIndex++;
}
}
@@ -268,7 +268,7 @@
}
GD.Print($"执行第{_currWaveIndex}波");
- _coroutineId = GameApplication.Instance.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
+ _coroutineId = GameApplication.Instance.World.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
_currWaveIndex++;
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
index 4600a54..1696169 100644
--- a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
@@ -254,6 +254,11 @@
GameCamera.Main.SetFollowTarget(null);
BasisVelocity = Vector2.Zero;
MoveController.ClearForce();
+
+ //暂停游戏
+ GameApplication.Instance.World.Pause = true;
+ //弹出结算面板
+ GameApplication.Instance.Cursor.SetGuiMode(true);
UiManager.Open_Settlement();
}
diff --git a/DungeonShooting_Godot/src/game/manager/ResourcePath.cs b/DungeonShooting_Godot/src/game/manager/ResourcePath.cs
index 26f4baa..e44024d 100644
--- a/DungeonShooting_Godot/src/game/manager/ResourcePath.cs
+++ b/DungeonShooting_Godot/src/game/manager/ResourcePath.cs
@@ -9,7 +9,6 @@
public const string excel_DungeonShooting_ExcelTool_deps_json = "res://excel/DungeonShooting_ExcelTool.deps.json";
public const string excel_DungeonShooting_ExcelTool_runtimeconfig_json = "res://excel/DungeonShooting_ExcelTool.runtimeconfig.json";
public const string prefab_Cursor_tscn = "res://prefab/Cursor.tscn";
- public const string prefab_FanCollisionShape_tscn = "res://prefab/FanCollisionShape.tscn";
public const string prefab_bullet_Bullet0001_tscn = "res://prefab/bullet/Bullet0001.tscn";
public const string prefab_bullet_Bullet0002_tscn = "res://prefab/bullet/Bullet0002.tscn";
public const string prefab_bullet_Bullet0003_tscn = "res://prefab/bullet/Bullet0003.tscn";
@@ -21,6 +20,7 @@
public const string prefab_effect_weapon_BulletSmoke_tscn = "res://prefab/effect/weapon/BulletSmoke.tscn";
public const string prefab_effect_weapon_FirePart_tscn = "res://prefab/effect/weapon/FirePart.tscn";
public const string prefab_effect_weapon_MeleeAttack1_tscn = "res://prefab/effect/weapon/MeleeAttack1.tscn";
+ public const string prefab_effect_weapon_MeleeAttack2_tscn = "res://prefab/effect/weapon/MeleeAttack2.tscn";
public const string prefab_effect_weapon_ShotFire_tscn = "res://prefab/effect/weapon/ShotFire.tscn";
public const string prefab_map_RoomDoor_E_tscn = "res://prefab/map/RoomDoor_E.tscn";
public const string prefab_map_RoomDoor_N_tscn = "res://prefab/map/RoomDoor_N.tscn";
@@ -63,6 +63,7 @@
public const string prefab_ui_MapEditorProject_tscn = "res://prefab/ui/MapEditorProject.tscn";
public const string prefab_ui_MapEditorSelectObject_tscn = "res://prefab/ui/MapEditorSelectObject.tscn";
public const string prefab_ui_MapEditorTools_tscn = "res://prefab/ui/MapEditorTools.tscn";
+ public const string prefab_ui_PauseMenu_tscn = "res://prefab/ui/PauseMenu.tscn";
public const string prefab_ui_RoomUI_tscn = "res://prefab/ui/RoomUI.tscn";
public const string prefab_ui_Settlement_tscn = "res://prefab/ui/Settlement.tscn";
public const string prefab_weapon_Weapon0001_tscn = "res://prefab/weapon/Weapon0001.tscn";
@@ -303,6 +304,7 @@
public const string scene_Main_tscn = "res://scene/Main.tscn";
public const string scene_World_tscn = "res://scene/World.tscn";
public const string scene_test_TestCommpont_tscn = "res://scene/test/TestCommpont.tscn";
+ public const string scene_test_TestCreateSector_tscn = "res://scene/test/TestCreateSector.tscn";
public const string scene_test_TestExpression_tscn = "res://scene/test/TestExpression.tscn";
public const string scene_test_TestGenerateDungeon_tscn = "res://scene/test/TestGenerateDungeon.tscn";
public const string scene_test_TestNavigation2_tscn = "res://scene/test/TestNavigation2.tscn";
diff --git a/DungeonShooting_Godot/src/game/manager/UiManager_Methods.cs b/DungeonShooting_Godot/src/game/manager/UiManager_Methods.cs
index 738391c..c64b660 100644
--- a/DungeonShooting_Godot/src/game/manager/UiManager_Methods.cs
+++ b/DungeonShooting_Godot/src/game/manager/UiManager_Methods.cs
@@ -22,6 +22,7 @@
public const string MapEditorProject = "MapEditorProject";
public const string MapEditorSelectObject = "MapEditorSelectObject";
public const string MapEditorTools = "MapEditorTools";
+ public const string PauseMenu = "PauseMenu";
public const string RoomUI = "RoomUI";
public const string Settlement = "Settlement";
}
@@ -795,6 +796,54 @@
}
///
+ /// 创建 PauseMenu, 并返回UI实例, 该函数不会打开 Ui
+ ///
+ public static UI.PauseMenu.PauseMenuPanel Create_PauseMenu()
+ {
+ return CreateUi(UiName.PauseMenu);
+ }
+
+ ///
+ /// 打开 PauseMenu, 并返回UI实例
+ ///
+ public static UI.PauseMenu.PauseMenuPanel Open_PauseMenu()
+ {
+ return OpenUi(UiName.PauseMenu);
+ }
+
+ ///
+ /// 隐藏 PauseMenu 的所有实例
+ ///
+ public static void Hide_PauseMenu()
+ {
+ var uiInstance = Get_PauseMenu_Instance();
+ foreach (var uiPanel in uiInstance)
+ {
+ uiPanel.HideUi();
+ }
+ }
+
+ ///
+ /// 销毁 PauseMenu 的所有实例
+ ///
+ public static void Destroy_PauseMenu()
+ {
+ var uiInstance = Get_PauseMenu_Instance();
+ foreach (var uiPanel in uiInstance)
+ {
+ uiPanel.Destroy();
+ }
+ }
+
+ ///
+ /// 获取所有 PauseMenu 的实例, 如果没有实例, 则返回一个空数组
+ ///
+ public static UI.PauseMenu.PauseMenuPanel[] Get_PauseMenu_Instance()
+ {
+ return GetUiInstance(nameof(UI.PauseMenu.PauseMenu));
+ }
+
+ ///
/// 创建 RoomUI, 并返回UI实例, 该函数不会打开 Ui
///
public static UI.RoomUI.RoomUIPanel Create_RoomUI()
diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs
index f0b1bd7..c0b9834 100644
--- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs
+++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs
@@ -72,7 +72,6 @@
GameApplication.Instance.StartCoroutine(RunLoadDungeonCoroutine(finish));
}
-
///
/// 重启地牢
///
@@ -152,6 +151,21 @@
{
if (IsInDungeon)
{
+ if (World.Pause) //已经暂停
+ {
+ return;
+ }
+
+ //暂停游戏
+ if (Input.IsActionJustPressed("ui_cancel"))
+ {
+ World.Pause = true;
+ //鼠标改为Ui鼠标
+ GameApplication.Instance.Cursor.SetGuiMode(true);
+ //打开暂停Ui
+ UiManager.Open_PauseMenu();
+ }
+
_checkEnemyTimer += (float)delta;
if (_checkEnemyTimer >= 1)
{
diff --git a/DungeonShooting_Godot/src/game/room/World.cs b/DungeonShooting_Godot/src/game/room/World.cs
index 622803c..a11e2fd 100644
--- a/DungeonShooting_Godot/src/game/room/World.cs
+++ b/DungeonShooting_Godot/src/game/room/World.cs
@@ -1,10 +1,11 @@
+using System.Collections;
using System.Collections.Generic;
using Godot;
///
/// 游戏世界
///
-public partial class World : Node2D
+public partial class World : Node2D, ICoroutine
{
///
/// //对象根节点
@@ -73,12 +74,22 @@
public Vector2 Enemy_FindTargetPosition { get; set; }
private bool _pause = false;
-
+ private List _coroutineList;
+
public override void _Ready()
{
TileRoot.YSortEnabled = false;
}
+ public override void _Process(double delta)
+ {
+ //协程更新
+ if (_coroutineList != null)
+ {
+ ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, (float)delta);
+ }
+ }
+
///
/// 获取指定层级根节点
///
@@ -95,4 +106,23 @@
return null;
}
+ public long StartCoroutine(IEnumerator able)
+ {
+ return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
+ }
+
+ public void StopCoroutine(long coroutineId)
+ {
+ ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
+ }
+
+ public bool IsCoroutineOver(long coroutineId)
+ {
+ return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
+ }
+
+ public void StopAllCoroutine()
+ {
+ ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
+ }
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/ui/pauseMenu/PauseMenu.cs b/DungeonShooting_Godot/src/game/ui/pauseMenu/PauseMenu.cs
new file mode 100644
index 0000000..256a892
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/ui/pauseMenu/PauseMenu.cs
@@ -0,0 +1,154 @@
+namespace UI.PauseMenu;
+
+///
+/// Ui代码, 该类是根据ui场景自动生成的, 请不要手动编辑该类, 以免造成代码丢失
+///
+public abstract partial class PauseMenu : UiBase
+{
+ ///
+ /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: PauseMenu.ColorRect
+ ///
+ public ColorRect L_ColorRect
+ {
+ get
+ {
+ if (_L_ColorRect == null) _L_ColorRect = new ColorRect((PauseMenuPanel)this, GetNode("ColorRect"));
+ return _L_ColorRect;
+ }
+ }
+ private ColorRect _L_ColorRect;
+
+ ///
+ /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: PauseMenu.VBoxContainer
+ ///
+ public VBoxContainer L_VBoxContainer
+ {
+ get
+ {
+ if (_L_VBoxContainer == null) _L_VBoxContainer = new VBoxContainer((PauseMenuPanel)this, GetNode("VBoxContainer"));
+ return _L_VBoxContainer;
+ }
+ }
+ private VBoxContainer _L_VBoxContainer;
+
+
+ public PauseMenu() : base(nameof(PauseMenu))
+ {
+ }
+
+ public sealed override void OnInitNestedUi()
+ {
+
+ }
+
+ ///
+ /// 类型: , 路径: PauseMenu.ColorRect
+ ///
+ public class ColorRect : UiNode
+ {
+ public ColorRect(PauseMenuPanel uiPanel, Godot.ColorRect node) : base(uiPanel, node) { }
+ public override ColorRect Clone() => new (UiPanel, (Godot.ColorRect)Instance.Duplicate());
+ }
+
+ ///
+ /// 类型: , 路径: PauseMenu.VBoxContainer.Continue
+ ///
+ public class Continue : UiNode
+ {
+ public Continue(PauseMenuPanel uiPanel, Godot.Button node) : base(uiPanel, node) { }
+ public override Continue Clone() => new (UiPanel, (Godot.Button)Instance.Duplicate());
+ }
+
+ ///
+ /// 类型: , 路径: PauseMenu.VBoxContainer.Restart
+ ///
+ public class Restart : UiNode
+ {
+ public Restart(PauseMenuPanel uiPanel, Godot.Button node) : base(uiPanel, node) { }
+ public override Restart Clone() => new (UiPanel, (Godot.Button)Instance.Duplicate());
+ }
+
+ ///
+ /// 类型: , 路径: PauseMenu.VBoxContainer.Exit
+ ///
+ public class Exit : UiNode
+ {
+ public Exit(PauseMenuPanel uiPanel, Godot.Button node) : base(uiPanel, node) { }
+ public override Exit Clone() => new (UiPanel, (Godot.Button)Instance.Duplicate());
+ }
+
+ ///
+ /// 类型: , 路径: PauseMenu.VBoxContainer
+ ///
+ public class VBoxContainer : UiNode
+ {
+ ///
+ /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: PauseMenu.Continue
+ ///
+ public Continue L_Continue
+ {
+ get
+ {
+ if (_L_Continue == null) _L_Continue = new Continue(UiPanel, Instance.GetNode("Continue"));
+ return _L_Continue;
+ }
+ }
+ private Continue _L_Continue;
+
+ ///
+ /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: PauseMenu.Restart
+ ///
+ public Restart L_Restart
+ {
+ get
+ {
+ if (_L_Restart == null) _L_Restart = new Restart(UiPanel, Instance.GetNode("Restart"));
+ return _L_Restart;
+ }
+ }
+ private Restart _L_Restart;
+
+ ///
+ /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: PauseMenu.Exit
+ ///
+ public Exit L_Exit
+ {
+ get
+ {
+ if (_L_Exit == null) _L_Exit = new Exit(UiPanel, Instance.GetNode("Exit"));
+ return _L_Exit;
+ }
+ }
+ private Exit _L_Exit;
+
+ public VBoxContainer(PauseMenuPanel uiPanel, Godot.VBoxContainer node) : base(uiPanel, node) { }
+ public override VBoxContainer Clone() => new (UiPanel, (Godot.VBoxContainer)Instance.Duplicate());
+ }
+
+
+ ///
+ /// 场景中唯一名称的节点, 节点类型: , 节点路径: PauseMenu.ColorRect
+ ///
+ public ColorRect S_ColorRect => L_ColorRect;
+
+ ///
+ /// 场景中唯一名称的节点, 节点类型: , 节点路径: PauseMenu.VBoxContainer.Continue
+ ///
+ public Continue S_Continue => L_VBoxContainer.L_Continue;
+
+ ///
+ /// 场景中唯一名称的节点, 节点类型: , 节点路径: PauseMenu.VBoxContainer.Restart
+ ///
+ public Restart S_Restart => L_VBoxContainer.L_Restart;
+
+ ///
+ /// 场景中唯一名称的节点, 节点类型: , 节点路径: PauseMenu.VBoxContainer.Exit
+ ///
+ public Exit S_Exit => L_VBoxContainer.L_Exit;
+
+ ///
+ /// 场景中唯一名称的节点, 节点类型: , 节点路径: PauseMenu.VBoxContainer
+ ///
+ public VBoxContainer S_VBoxContainer => L_VBoxContainer;
+
+}
diff --git a/DungeonShooting_Godot/src/game/ui/pauseMenu/PauseMenuPanel.cs b/DungeonShooting_Godot/src/game/ui/pauseMenu/PauseMenuPanel.cs
new file mode 100644
index 0000000..19e06a1
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/ui/pauseMenu/PauseMenuPanel.cs
@@ -0,0 +1,66 @@
+using Godot;
+
+namespace UI.PauseMenu;
+
+public partial class PauseMenuPanel : PauseMenu
+{
+
+ public override void OnCreateUi()
+ {
+ S_Continue.Instance.Pressed += OnContinueClick;
+ S_Restart.Instance.Pressed += OnRestartClick;
+ S_Exit.Instance.Pressed += OnExitClick;
+
+ if (GameApplication.Instance.DungeonManager.IsEditorMode) //在编辑器模式下打开的Ui
+ {
+ S_Exit.Instance.Text = "返回编辑器";
+ }
+ }
+
+ public override void Process(float delta)
+ {
+ if (Input.IsActionJustPressed("ui_cancel")) //返回游戏
+ {
+ OnContinueClick();
+ }
+ }
+
+ //继续游戏
+ private void OnContinueClick()
+ {
+ GameApplication.Instance.World.Pause = false;
+ GameApplication.Instance.Cursor.SetGuiMode(false);
+ Destroy();
+ }
+
+ //重新开始
+ private void OnRestartClick()
+ {
+ Destroy();
+ if (GameApplication.Instance.DungeonManager.IsEditorMode) //在编辑器模式下打开的Ui
+ {
+ EditorPlayManager.Restart();
+ }
+ else //正常重新开始
+ {
+ GameApplication.Instance.DungeonManager.RestartDungeon(GameApplication.Instance.DungeonConfig);
+ }
+ }
+
+ //退出地牢
+ private void OnExitClick()
+ {
+ Destroy();
+ if (GameApplication.Instance.DungeonManager.IsEditorMode) //在编辑器模式下打开的Ui
+ {
+ EditorPlayManager.Exit();
+ }
+ else //正常关闭Ui
+ {
+ GameApplication.Instance.DungeonManager.ExitDungeon(() =>
+ {
+ UiManager.Open_Main();
+ });
+ }
+ }
+}