创建开始菜单面板和设置面板

- 添加 MenuForm 与 SettingForm
- 为带左右按钮的水平选择界面添加HorizonSelectGroup预制件。
- 添加游戏核心可配置项
This commit is contained in:
SepComet 2026-02-10 15:10:31 +08:00
parent 7ac832f74b
commit 13583354f9
111 changed files with 11247 additions and 755 deletions

View File

@ -4,5 +4,4 @@
# 场景编号 备注 资源名称 背景音乐编号 # 场景编号 备注 资源名称 背景音乐编号
1 菜单场景 Menu 1 1 菜单场景 Menu 1
2 战斗场景 Main 2 2 战斗场景 Main 2
3 压力测试场景 StressTest 0 3 GameplayA 0
4 GameplayA 0

View File

@ -132,8 +132,8 @@ Material:
- _Stencil: 0 - _Stencil: 0
- _StencilComp: 8 - _StencilComp: 8
- _StencilOp: 0 - _StencilOp: 0
- _StencilReadMask: 255 - _StencilReadMask: 1
- _StencilWriteMask: 255 - _StencilWriteMask: 0
- _TextureHeight: 4096 - _TextureHeight: 4096
- _TextureWidth: 4096 - _TextureWidth: 4096
- _UnderlayDilate: 0 - _UnderlayDilate: 0
@ -168,9 +168,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04, type: 3} m_Script: {fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04, type: 3}
m_Name: MainTMPFont m_Name: MainTMPFont
m_EditorClassIdentifier: m_EditorClassIdentifier:
hashCode: -1438885570 hashCode: 1106704785
material: {fileID: -1106088975554028259} material: {fileID: -1106088975554028259}
materialHashCode: -1897074850 materialHashCode: -1461255791
m_Version: 1.1.0 m_Version: 1.1.0
m_SourceFontFileGUID: 376d7b8f751da3646930f65eab02a204 m_SourceFontFileGUID: 376d7b8f751da3646930f65eab02a204
m_SourceFontFile_EditorRef: {fileID: 12800000, guid: 376d7b8f751da3646930f65eab02a204, m_SourceFontFile_EditorRef: {fileID: 12800000, guid: 376d7b8f751da3646930f65eab02a204,

View File

@ -5,6 +5,7 @@
// Feedback: mailto:ellan@gameframework.cn // Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------ //------------------------------------------------------------
using Definition.DataStruct;
using GameFramework; using GameFramework;
using StarForce; using StarForce;
using UI; using UI;

View File

@ -5,7 +5,7 @@
// Feedback: mailto:ellan@gameframework.cn // Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------ //------------------------------------------------------------
namespace StarForce namespace Definition.DataStruct
{ {
public class BuildInfo public class BuildInfo
{ {

View File

@ -0,0 +1,69 @@
using Definition.Enum;
namespace Definition.DataStruct
{
public struct GameSetting
{
#region SoundConfig
/// <summary>
/// 音乐音量
/// </summary>
public float BGMVolume { get; set; }
/// <summary>
/// 音效音量
/// </summary>
public float SEVolume { get; set; }
#endregion
#region GameConfig
/// <summary>
/// 允许画面震动
/// </summary>
public bool AllowShake { get; set; }
/// <summary>
/// 允许画面闪光
/// </summary>
public bool AllowBlink { get; set; }
/// <summary>
/// 对话窗口透明度
/// </summary>
public DialogWindowAlpha DialogWindowAlpha { get; set; }
/// <summary>
/// 对话播放速度
/// </summary>
public DialogPlayingSpeed PlayingSpeed { get; set; }
#endregion
#region ScreenConfig
/// <summary>
/// 屏幕分辨率
/// </summary>
public ScreenSolutionType ScreenSolution { get; set; }
/// <summary>
/// 屏幕窗口模式
/// </summary>
public ScreenWindowType ScreenWindow { get; set; }
/// <summary>
/// 垂直同步
/// </summary>
public bool VSync { get; set; }
/// <summary>
/// 抗锯齿
/// </summary>
public bool AntiAliasing { get; set; }
#endregion
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fca4b405240141ae845bc6cbf5f7f9d2
timeCreated: 1770692998

View File

@ -5,7 +5,7 @@
// Feedback: mailto:ellan@gameframework.cn // Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------ //------------------------------------------------------------
namespace StarForce namespace Definition.DataStruct
{ {
public class VersionInfo public class VersionInfo
{ {

View File

@ -1,4 +1,4 @@
namespace Scene namespace Definition.Enum
{ {
public enum SceneId : byte public enum SceneId : byte
{ {
@ -6,8 +6,6 @@ namespace Scene
Menu = 1, Menu = 1,
Main = 2, Main = 2,
StressTest = 3, GameplayA = 3
GameplayA = 4
} }
} }

View File

@ -0,0 +1,28 @@
namespace Definition.Enum
{
public enum DialogPlayingSpeed: byte
{
Slow,
Medium,
Fast,
}
public enum DialogWindowAlpha : byte
{
None,
Low,
Medium,
High
}
public enum ScreenSolutionType : byte
{
}
public enum ScreenWindowType : byte
{
NoneBoard,
Window,
FullScreen
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2f0f253e843b439ea057d9c2fac08bee
timeCreated: 1770691231

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: ea2618629fd6bbd40a9dda07b40a0094 guid: f8a21bc21c2e2c9499f273702a5ee70d
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: d81d2a322c2e93948b4d5aa7e36c99f2 guid: 2fb9e4e2d5a6060459c5cc2eccd01021
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 3c721a41db518484e9a1771952725489 guid: 73d2bbb90d12eb640a9c31f53f797f63
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -0,0 +1,25 @@
using GameFramework;
using GameFramework.Event;
namespace Event
{
public class MenuContinueEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(MenuContinueEventArgs).GetHashCode();
public override int Id => EventId;
public MenuContinueEventArgs()
{
}
public static MenuContinueEventArgs Create()
{
return ReferencePool.Acquire<MenuContinueEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a104dcc8130e0c448ae99e6e3b54f289
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
using GameFramework;
using GameFramework.Event;
namespace Event
{
public class MenuExitEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(MenuExitEventArgs).GetHashCode();
public override int Id => EventId;
public MenuExitEventArgs()
{
}
public static MenuExitEventArgs Create()
{
return ReferencePool.Acquire<MenuExitEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b795b7493e19a03488a29937318df5e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
using GameFramework;
using GameFramework.Event;
namespace Event
{
public class MenuSettingEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(MenuSettingEventArgs).GetHashCode();
public override int Id => EventId;
public MenuSettingEventArgs()
{
}
public static MenuSettingEventArgs Create()
{
return ReferencePool.Acquire<MenuSettingEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04ec642391ce9de45bea3806a121fd76
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
using GameFramework;
using GameFramework.Event;
namespace Event
{
public class MenuStartEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(MenuStartEventArgs).GetHashCode();
public override int Id => EventId;
public MenuStartEventArgs()
{
}
public static MenuStartEventArgs Create()
{
return ReferencePool.Acquire<MenuStartEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de3b954ecd2a5b649944ca31f0c80b94
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,32 @@
using Definition.DataStruct;
using GameFramework;
using GameFramework.Event;
namespace Event
{
public class SettingSaveEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(SettingSaveEventArgs).GetHashCode();
public override int Id => EventId;
public GameSetting? GameSettings;
public SettingSaveEventArgs()
{
}
public static SettingSaveEventArgs Create(GameSetting gameSetting)
{
var args = ReferencePool.Acquire<SettingSaveEventArgs>();
args.GameSettings = gameSetting;
return args;
}
public override void Clear()
{
GameSettings = null;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f6cbbeb839bda744b56d83cd6ccde75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 3c1a6b69591248579f9cade5744deae0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 3232d5f1486b49029ab0a7f5db041bd0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,9 +1,9 @@
using CustomUtility; using CustomUtility;
using DataTable; using DataTable;
using Definition; using Definition;
using Definition.Enum;
using GameFramework.DataTable; using GameFramework.DataTable;
using GameFramework.Event; using GameFramework.Event;
using Scene;
using StarForce; using StarForce;
using UnityGameFramework.Runtime; using UnityGameFramework.Runtime;
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>; using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;

View File

@ -5,6 +5,7 @@
// Feedback: mailto:ellan@gameframework.cn // Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------ //------------------------------------------------------------
using Definition.DataStruct;
using GameFramework; using GameFramework;
using GameFramework.Event; using GameFramework.Event;
using GameFramework.Resource; using GameFramework.Resource;

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using CustomUtility; using CustomUtility;
using DataTable; using DataTable;
using Definition; using Definition;
using Definition.Enum;
using TMPro; using TMPro;
using UI; using UI;
using UnityEngine; using UnityEngine;
@ -71,7 +72,7 @@ namespace Procedure
} }
} }
procedureOwner.SetData<VarInt32>("NextSceneId", GameEntry.Config.GetInt("Scene.GameplayA")); procedureOwner.SetData<VarInt32>("NextSceneId", (int)SceneId.Main);
ChangeState<ProcedureChangeScene>(procedureOwner); ChangeState<ProcedureChangeScene>(procedureOwner);
} }
@ -118,34 +119,36 @@ namespace Procedure
private void LoadFont(string fontName) private void LoadFont(string fontName)
{ {
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false); _loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks( GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset,
new LoadAssetCallbacks(
(assetName, asset, duration, userData) => (assetName, asset, duration, userData) =>
{ {
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true; _loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
UGuiForm.SetMainFont((Font)asset); UGuiForm.SetMainFont((Font)asset);
Log.Info("Load font '{0}' OK.", fontName); Log.Info("Load font '{0}' OK.", fontName);
}, },
(assetName, status, errorMessage, userData) => (assetName, status, errorMessage, userData) =>
{ {
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage); Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName,
errorMessage);
})); }));
} }
private void LoadTMPFont(string fontName) private void LoadTMPFont(string fontName)
{ {
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false); _loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks( GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset,
new LoadAssetCallbacks(
(assetName, asset, duration, userData) => (assetName, asset, duration, userData) =>
{ {
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true; _loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
UGuiForm.SetMainTMPFont((TMP_FontAsset)asset); UGuiForm.SetMainTMPFont((TMP_FontAsset)asset);
Log.Info("Load font '{0}' OK.", fontName); Log.Info("Load font '{0}' OK.", fontName);
}, },
(assetName, status, errorMessage, userData) => (assetName, status, errorMessage, userData) =>
{ {
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage); Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName,
errorMessage);
})); }));
} }
@ -169,7 +172,8 @@ namespace Procedure
return; return;
} }
Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName, ne.ConfigAssetName, ne.ErrorMessage); Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName,
ne.ConfigAssetName, ne.ErrorMessage);
} }
private void OnLoadDataTableSuccess(object sender, GameEventArgs e) private void OnLoadDataTableSuccess(object sender, GameEventArgs e)
@ -192,7 +196,8 @@ namespace Procedure
return; return;
} }
Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName, ne.DataTableAssetName, ne.ErrorMessage); Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName,
ne.DataTableAssetName, ne.ErrorMessage);
} }
private void OnLoadDictionarySuccess(object sender, GameEventArgs e) private void OnLoadDictionarySuccess(object sender, GameEventArgs e)
@ -215,7 +220,8 @@ namespace Procedure
return; return;
} }
Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName, ne.DictionaryAssetName, ne.ErrorMessage); Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName,
ne.DictionaryAssetName, ne.ErrorMessage);
} }
} }
} }

View File

@ -1,7 +1,6 @@
using Scene; using Definition.Enum;
using System.Collections.Generic; using System.Collections.Generic;
using CustomComponent; using CustomComponent;
using Definition.Enum;
using Event; using Event;
using GameFramework.Event; using GameFramework.Event;
using UI; using UI;

View File

@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProcedureMain : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b86c72387528b8e4993ed9c395825d0a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
using GameFramework.Fsm;
using GameFramework.Procedure;
using UI;
namespace Procedure
{
public class ProcedureMenu : ProcedureBase
{
public override bool UseNativeDialog => false;
private MenuFormController _menuFormController;
#region FSM
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
_menuFormController = new MenuFormController();
_menuFormController.OpenUI(new MenuFormContext());
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8c39c93ba7eab0478a50fc0b1370458
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
namespace UI
{
public class MenuFormContext : UIContext
{
public bool HasGameData = false;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8cdd22c948028246b9d1d7afd80f08c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
using System.Collections;
using System.Collections.Generic;
using Definition.DataStruct;
using UnityEngine;
namespace UI
{
public class SettingFormContext : UIContext
{
public SettingFormController Controller;
public GameSetting Setting;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c2754dbcd65873f4b9d3f579c12cef58
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,132 @@
using GameFramework.Event;
using UnityGameFramework.Runtime;
namespace UI
{
public class MenuFormController : IFormController<MenuFormContext>
{
private MenuFormContext _context;
private MenuForm _menuForm;
private int? _menuFormSerialId;
private bool _pendingRefresh;
public MenuFormController()
{
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
GameEntry.Event.Subscribe(CloseUIFormCompleteEventArgs.EventId, CloseUIFormComplete);
}
public int? OpenUI(MenuFormContext context)
{
if (context == null)
{
Log.Warning("MenuFormController open failed. context is null.");
return null;
}
_context = context;
if (_menuForm != null)
{
_menuForm.RefreshUI(_context);
return _menuFormSerialId;
}
CloseUI();
_pendingRefresh = true;
_menuFormSerialId = GameEntry.UI.OpenUIForm(UIFormId.MenuForm, context);
return _menuFormSerialId;
}
public void CloseUI()
{
_pendingRefresh = false;
if (_menuFormSerialId.HasValue)
{
GameEntry.UI.CloseUIForm(_menuFormSerialId.Value);
return;
}
if (_menuForm != null)
{
_menuForm.Close();
}
}
private void TryRefreshUI()
{
if (_context == null)
{
return;
}
if (_menuForm == null)
{
_pendingRefresh = true;
return;
}
_menuForm.RefreshUI(_context);
_pendingRefresh = false;
}
~MenuFormController()
{
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
GameEntry.Event.Unsubscribe(CloseUIFormCompleteEventArgs.EventId, CloseUIFormComplete);
}
#region EventHanlders
private void OpenUIFormSuccess(object sender, GameEventArgs e)
{
if (!(e is OpenUIFormSuccessEventArgs args))
{
return;
}
if (!_menuFormSerialId.HasValue)
{
return;
}
if (args.UIForm == null || args.UIForm.SerialId != _menuFormSerialId.Value || args.UserData != _context)
{
return;
}
_menuForm = args.UIForm.Logic as MenuForm;
if (_menuForm == null)
{
Log.Warning("DialogFormController open success but form logic is invalid.");
return;
}
if (_pendingRefresh)
{
TryRefreshUI();
}
}
private void CloseUIFormComplete(object sender, GameEventArgs e)
{
if (!(e is CloseUIFormCompleteEventArgs args))
{
return;
}
if (args.SerialId != _menuFormSerialId)
{
return;
}
_menuForm = null;
_menuFormSerialId = null;
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38fe84430afbe554f8f8c81e3f6ac47b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,129 @@
using System;
using GameFramework.Event;
using UnityGameFramework.Runtime;
namespace UI
{
public class SettingFormController : IFormController<SettingFormContext>
{
private SettingFormContext _context;
private SettingForm _settingForm;
private int? _formSerialId;
private bool _pendingRefresh;
public SettingFormController()
{
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess);
GameEntry.Event.Subscribe(CloseUIFormCompleteEventArgs.EventId, OnCloseUIFormComplete);
}
public int? OpenUI(SettingFormContext context)
{
if (context == null)
{
Log.Warning("SettingFormController open failed. context is null.");
return null;
}
_context = context;
if (_settingForm != null)
{
_settingForm.RefreshUI(context);
return _formSerialId;
}
CloseUI();
_pendingRefresh = true;
_formSerialId = GameEntry.UI.OpenUIForm(UIFormId.SettingForm, context);
return _formSerialId;
}
public void CloseUI()
{
_pendingRefresh = false;
if (_formSerialId.HasValue)
{
GameEntry.UI.CloseUIForm(_formSerialId.Value);
return;
}
if (_settingForm != null)
{
_settingForm.Close();
}
}
~SettingFormController()
{
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess);
GameEntry.Event.Unsubscribe(CloseUIFormCompleteEventArgs.EventId, OnCloseUIFormComplete);
}
private void TryRefreshUI()
{
if (_context == null)
{
return;
}
if (_settingForm == null)
{
_pendingRefresh = true;
return;
}
_settingForm.RefreshUI(_context);
_pendingRefresh = false;
}
private void OnOpenUIFormSuccess(object sender, GameEventArgs e)
{
if (!(e is OpenUIFormSuccessEventArgs args))
{
return;
}
if (!_formSerialId.HasValue)
{
return;
}
if (args.UIForm == null || args.UIForm.SerialId != _formSerialId.Value || args.UserData != _context)
{
return;
}
_settingForm = args.UIForm.Logic as SettingForm;
if (_settingForm == null)
{
Log.Warning("SettingFormController open success but form logic is invalid.");
return;
}
if (_pendingRefresh)
{
TryRefreshUI();
}
}
private void OnCloseUIFormComplete(object sender, GameEventArgs e)
{
if (!(e is CloseUIFormCompleteEventArgs args))
{
return;
}
if (args.SerialId != _formSerialId)
{
return;
}
_settingForm = null;
_formSerialId = null;
_pendingRefresh = false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe89c33ff996c344a911bcee3293f439
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -16,11 +16,14 @@ namespace UI
{ {
public class DialogForm : UGuiForm public class DialogForm : UGuiForm
{ {
[SerializeField] private TMP_Text _titleText = null;
[SerializeField] private TMP_Text _messageText = null; [SerializeField] private TMP_Text _messageText = null;
[SerializeField] private GameObject[] _modeObjects = null; [SerializeField] private GameObject[] _modeObjects = null;
[SerializeField] private TMP_Text[] _confirmTexts = null; [SerializeField] private TMP_Text[] _confirmTexts = null;
[SerializeField] private TMP_Text[] _cancelTexts = null; [SerializeField] private TMP_Text[] _cancelTexts = null;
[SerializeField] private TMP_Text[] _otherTexts = null; [SerializeField] private TMP_Text[] _otherTexts = null;
private int _dialogMode = 1; private int _dialogMode = 1;
@ -84,7 +87,6 @@ namespace UI
_dialogMode = dialogParams.Mode; _dialogMode = dialogParams.Mode;
RefreshDialogMode(); RefreshDialogMode();
_titleText.text = dialogParams.Title;
_messageText.text = dialogParams.Message; _messageText.text = dialogParams.Message;
_pauseGame = dialogParams.PauseGame; _pauseGame = dialogParams.PauseGame;
@ -114,7 +116,6 @@ namespace UI
} }
_dialogMode = 1; _dialogMode = 1;
_titleText.text = string.Empty;
_messageText.text = string.Empty; _messageText.text = string.Empty;
_pauseGame = false; _pauseGame = false;
_userData = null; _userData = null;

View File

@ -45,7 +45,7 @@ namespace UI
_context = context; _context = context;
string speakerName = context.SpeakerName; string speakerName = _context.SpeakerName;
if (_speakerArea != null) if (_speakerArea != null)
{ {
@ -57,7 +57,7 @@ namespace UI
_speakerNameText.text = speakerName; _speakerNameText.text = speakerName;
} }
PlayTypewriter(_contentText, context.Text, context.PlayingSpeed); PlayTypewriter(_contentText, _context.Text, _context.PlayingSpeed);
if (string.IsNullOrEmpty(speakerName)) if (string.IsNullOrEmpty(speakerName))
{ {

View File

@ -0,0 +1,82 @@
using System;
using TMPro;
using UnityEngine;
namespace UI
{
public class HorizonSelectGroup : MonoBehaviour
{
[SerializeField] private TMP_Text _showText;
[SerializeField] private GameObject _leftButton;
[SerializeField] private GameObject _rightButton;
[SerializeField] private int _currentValue;
[SerializeField] private string[] _showTexts;
private int LeftBound = 0;
private int RightBound => _showTexts.Length - 1;
private void Start()
{
SetValue(_currentValue);
_leftButton.SetActive(false);
_rightButton.SetActive(false);
}
public void OnLeftClick()
{
_currentValue--;
_showText.text = _showTexts[_currentValue];
UpdateButtonState();
}
public void OnRightClick()
{
_currentValue++;
_showText.text = _showTexts[_currentValue];
UpdateButtonState();
}
public void SetValue(int value)
{
if (value < 0 || value >= _showTexts.Length)
{
throw new IndexOutOfRangeException();
}
_currentValue = value;
_showText.text = _showTexts[_currentValue];
UpdateButtonState();
}
public void SetValue(bool value)
{
_currentValue = value ? 1 : 0;
_showText.text = _showTexts[_currentValue];
UpdateButtonState();
}
public void UpdateButtonState()
{
_leftButton.SetActive(_currentValue != LeftBound);
_rightButton.SetActive(_currentValue != RightBound);
}
public void HideButtons()
{
_leftButton.SetActive(false);
_rightButton.SetActive(false);
}
public int GetIntValue() => _currentValue;
public bool GetBoolValue() => _currentValue == 1;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3ad474ed1648574f984d626f3d9726a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,49 @@
using Event;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace UI
{
public class MenuForm : UGuiForm
{
[SerializeField] private GameObject _continueButton;
public void RefreshUI(MenuFormContext context)
{
_continueButton.SetActive(context.HasGameData);
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (!(userData is MenuFormContext context))
{
Log.Error("MenuFormContext is invalid.");
return;
}
RefreshUI(context);
}
public void OnContinueButtonClick()
{
GameEntry.Event.Fire(this, MenuContinueEventArgs.Create());
}
public void OnStartButtonClick()
{
GameEntry.Event.Fire(this, MenuStartEventArgs.Create());
}
public void OnSettingButtonClick()
{
GameEntry.Event.Fire(this, MenuSettingEventArgs.Create());
}
public void OnExitButtonClick()
{
GameEntry.Event.Fire(this, MenuExitEventArgs.Create());
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81cd82e6a7856b148bcffd790e5e5ed8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
using DG.Tweening;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace UI
{
public class SelectableItem : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] private Image _bgImage;
[SerializeField] private float _fadeDuration;
private Sequence _fadeSequence;
public UnityEvent _onSelect;
public UnityEvent _onDeselect;
public void OnPointerEnter(PointerEventData eventData)
{
_fadeSequence.Kill();
_fadeSequence = DOTween.Sequence();
_fadeSequence.Append(_bgImage.DOFade(1, _fadeDuration));
_onSelect.Invoke();
}
public void OnPointerExit(PointerEventData eventData)
{
_fadeSequence.Kill();
_fadeSequence = DOTween.Sequence();
_fadeSequence.Append(_bgImage.DOFade(0, _fadeDuration));
_onDeselect.Invoke();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74ad2e39e0d4fc546ab11cf446143f44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,134 @@
using Definition.DataStruct;
using Definition.Enum;
using Event;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
public class SettingForm : UGuiForm
{
[SerializeField] private Image[] _navigateButtonImages;
[SerializeField] private TMP_Text[] _navigateButtonTexts;
[SerializeField] private Color _darkColor;
[SerializeField] private Color _brightColor;
[SerializeField] private Slider _bgmVolumeSlider;
[SerializeField] private Slider _seVolumeSlider;
[SerializeField] private HorizonSelectGroup _allowShakeGroup;
[SerializeField] private HorizonSelectGroup _allowBlinkGroup;
[SerializeField] private HorizonSelectGroup _dialogWindowAlpha;
[SerializeField] private HorizonSelectGroup _playingSpeed;
[SerializeField] private HorizonSelectGroup _screenSolution;
[SerializeField] private HorizonSelectGroup _screenWindow;
[SerializeField] private HorizonSelectGroup _vSyncGroup;
[SerializeField] private HorizonSelectGroup _antiAliasingGroup;
private SettingFormController _controller;
public void RefreshUI(SettingFormContext context)
{
_controller = context.Controller;
var setting = context.Setting;
_bgmVolumeSlider.value = setting.BGMVolume;
_seVolumeSlider.value = setting.SEVolume;
_allowBlinkGroup.SetValue(setting.AllowBlink);
_allowShakeGroup.SetValue(setting.AllowShake);
_dialogWindowAlpha.SetValue((int)setting.DialogWindowAlpha);
_playingSpeed.SetValue((int)setting.PlayingSpeed);
_screenSolution.SetValue((int)setting.ScreenSolution);
_screenWindow.SetValue((int)setting.ScreenWindow);
_vSyncGroup.SetValue(setting.VSync);
_antiAliasingGroup.SetValue(setting.AntiAliasing);
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (!(userData is SettingFormContext context))
{
Log.Error("SettingFormContext is invalid.");
return;
}
RefreshUI(context);
}
private GameSetting CollectSetting()
{
var setting = new GameSetting
{
BGMVolume = _bgmVolumeSlider.value,
SEVolume = _seVolumeSlider.value,
AllowShake = _allowShakeGroup.GetBoolValue(),
AllowBlink = _allowBlinkGroup.GetBoolValue(),
DialogWindowAlpha = (DialogWindowAlpha)_dialogWindowAlpha.GetIntValue(),
PlayingSpeed = (DialogPlayingSpeed)_playingSpeed.GetIntValue(),
ScreenSolution = (ScreenSolutionType)_screenSolution.GetIntValue(),
ScreenWindow = (ScreenWindowType)_screenWindow.GetIntValue(),
VSync = _vSyncGroup.GetBoolValue(),
AntiAliasing = _antiAliasingGroup.GetBoolValue()
};
return setting;
}
public void OnNavigateButtonClick(int index)
{
if (index < 0 || index >= _navigateButtonImages.Length)
{
Log.Error("NavigateButtonClick index is out of range.");
}
for (int i = 0; i < _navigateButtonImages.Length; i++)
{
_navigateButtonImages[i].color = i != index ? _brightColor : _darkColor;
_navigateButtonTexts[i].color = i != index ? _darkColor : _brightColor;
}
}
public void OnReturnButtonClick()
{
var dialogParams = new DialogParams
{
Title = "确认是否返回",
Message = "是否保存更改?",
ConfirmText = "保存并返回",
CancelText = "直接返回",
OtherText = "取消",
Mode = 3,
};
dialogParams.OnClickConfirm += SaveSettingAndReturn;
dialogParams.OnClickCancel += _ => _controller.CloseUI();
GameEntry.UI.OpenUIForm(UIFormId.DialogForm, dialogParams);
}
private void SaveSettingAndReturn(object userData)
{
var setting = CollectSetting();
GameEntry.Event.Fire(this, SettingSaveEventArgs.Create(setting));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cbbc5660f5b30714183f047355830159
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -612,7 +612,6 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 4703471767818675053} - component: {fileID: 4703471767818675053}
- component: {fileID: 4643264964412212504}
- component: {fileID: 2327325990879817607} - component: {fileID: 2327325990879817607}
m_Layer: 5 m_Layer: 5
m_Name: BottomBoxDialogForm m_Name: BottomBoxDialogForm
@ -633,6 +632,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 4565999398500957528}
- {fileID: 6089528910385973127} - {fileID: 6089528910385973127}
- {fileID: 2330152971407905255} - {fileID: 2330152971407905255}
- {fileID: 478704929657922221} - {fileID: 478704929657922221}
@ -643,29 +643,6 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!223 &4643264964412212504
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4995567450066526950}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 25
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!114 &2327325990879817607 --- !u!114 &2327325990879817607
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -678,7 +655,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ea6f55294a4cd2946a83649e7be82314, type: 3} m_Script: {fileID: 11500000, guid: ea6f55294a4cd2946a83649e7be82314, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_playSpeed: 0
_speakerArea: {fileID: 3736358320082617150} _speakerArea: {fileID: 3736358320082617150}
_speakerNameText: {fileID: 2470970474825277305} _speakerNameText: {fileID: 2470970474825277305}
_contentText: {fileID: 6431296888118130931} _contentText: {fileID: 6431296888118130931}
@ -688,6 +664,81 @@ MonoBehaviour:
_rightSpritePosition: -450 _rightSpritePosition: -450
_moveDuration: 0.25 _moveDuration: 0.25
_moveEase: 9 _moveEase: 9
--- !u!1 &6371466324854950042
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4565999398500957528}
- component: {fileID: 7444848871740763634}
- component: {fileID: 7250237685065880628}
m_Layer: 5
m_Name: raycast
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4565999398500957528
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6371466324854950042}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4703471767818675053}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7444848871740763634
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6371466324854950042}
m_CullTransparentMesh: 1
--- !u!114 &7250237685065880628
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6371466324854950042}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &7381337123922490182 --- !u!1 &7381337123922490182
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -338,6 +338,81 @@ MonoBehaviour:
m_hasFontAssetChanged: 0 m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0} m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &4110659048894178401
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4526989310283327243}
- component: {fileID: 2420282737750769956}
- component: {fileID: 457794338423505963}
m_Layer: 5
m_Name: raycast
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4526989310283327243
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4110659048894178401}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4910643681303047144}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2420282737750769956
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4110659048894178401}
m_CullTransparentMesh: 1
--- !u!114 &457794338423505963
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4110659048894178401}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &5084888560994457996 --- !u!1 &5084888560994457996
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -367,6 +442,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 4526989310283327243}
- {fileID: 7190008853478101747} - {fileID: 7190008853478101747}
- {fileID: 1061474815361198294} - {fileID: 1061474815361198294}
- {fileID: 7767208163422656795} - {fileID: 7767208163422656795}
@ -404,8 +480,10 @@ MonoBehaviour:
_progressFormat: '{0}/{1}' _progressFormat: '{0}/{1}'
_partStartAnchoredPosition: {x: 0, y: -40} _partStartAnchoredPosition: {x: 0, y: -40}
_partVerticalSpacing: 120 _partVerticalSpacing: 120
_defaultSlots: [] _partSpawnMinXNormalized: 0.55
_defaultParts: [] _partSpawnMaxXNormalized: 0.95
_partSpawnMinYNormalized: 0.1
_partSpawnMaxYNormalized: 0.9
--- !u!1 &5518555242189156955 --- !u!1 &5518555242189156955
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

Some files were not shown because too many files have changed in this diff Show More