初始化仓库

This commit is contained in:
SepComet
2026-02-08 17:08:52 +08:00
commit 8763955323
1132 changed files with 285326 additions and 0 deletions
@@ -0,0 +1,82 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UI
{
public class CommonButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
private const float FadeTime = 0.3f;
private const float OnHoverAlpha = 0.7f;
private const float OnClickAlpha = 0.6f;
[SerializeField]
private UnityEvent m_OnHover = null;
[SerializeField]
private UnityEvent m_OnClick = null;
private CanvasGroup m_CanvasGroup = null;
private void Awake()
{
m_CanvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
}
private void OnDisable()
{
m_CanvasGroup.alpha = 1f;
}
public void OnPointerEnter(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
{
return;
}
StopAllCoroutines();
StartCoroutine(m_CanvasGroup.FadeToAlpha(OnHoverAlpha, FadeTime));
m_OnHover.Invoke();
}
public void OnPointerExit(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
{
return;
}
StopAllCoroutines();
StartCoroutine(m_CanvasGroup.FadeToAlpha(1f, FadeTime));
}
public void OnPointerDown(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
{
return;
}
m_CanvasGroup.alpha = OnClickAlpha;
m_OnClick.Invoke();
}
public void OnPointerUp(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
{
return;
}
m_CanvasGroup.alpha = OnHoverAlpha;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a5079836f95c2a44b96fa331487ebb70
timeCreated: 1528026160
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+189
View File
@@ -0,0 +1,189 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using GameFramework;
using TMPro;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
public class DialogForm : UGuiForm
{
[SerializeField] private TMP_Text _titleText = null;
[SerializeField] private TMP_Text _messageText = null;
[SerializeField] private GameObject[] _modeObjects = null;
[SerializeField] private TMP_Text[] _confirmTexts = null;
[SerializeField] private TMP_Text[] _cancelTexts = null;
[SerializeField] private TMP_Text[] _otherTexts = null;
private int _dialogMode = 1;
private bool _pauseGame = false;
private object _userData = null;
private GameFrameworkAction<object> _onClickConfirmGFAction = null;
private GameFrameworkAction<object> _onClickCancelGFAction = null;
private GameFrameworkAction<object> _onClickOtherGFAction = null;
public int DialogMode => _dialogMode;
public bool PauseGame => _pauseGame;
public object UserData => _userData;
public void OnConfirmButtonClick()
{
Close();
if (_onClickConfirmGFAction != null)
{
_onClickConfirmGFAction(_userData);
}
}
public void OnCancelButtonClick()
{
Close();
if (_onClickCancelGFAction != null)
{
_onClickCancelGFAction(_userData);
}
}
public void OnOtherButtonClick()
{
Close();
if (_onClickOtherGFAction != null)
{
_onClickOtherGFAction(_userData);
}
}
#if UNITY_2017_3_OR_NEWER
protected override void OnOpen(object userData)
#else
protected internal override void OnOpen(object userData)
#endif
{
base.OnOpen(userData);
DialogParams dialogParams = (DialogParams)userData;
if (dialogParams == null)
{
Log.Warning("DialogParams is invalid.");
return;
}
_dialogMode = dialogParams.Mode;
RefreshDialogMode();
_titleText.text = dialogParams.Title;
_messageText.text = dialogParams.Message;
_pauseGame = dialogParams.PauseGame;
RefreshPauseGame();
_userData = dialogParams.UserData;
RefreshConfirmText(dialogParams.ConfirmText);
_onClickConfirmGFAction = dialogParams.OnClickConfirm;
RefreshCancelText(dialogParams.CancelText);
_onClickCancelGFAction = dialogParams.OnClickCancel;
RefreshOtherText(dialogParams.OtherText);
_onClickOtherGFAction = dialogParams.OnClickOther;
}
#if UNITY_2017_3_OR_NEWER
protected override void OnClose(bool isShutdown, object userData)
#else
protected internal override void OnClose(bool isShutdown, object userData)
#endif
{
if (_pauseGame)
{
GameEntry.Base.ResumeGame();
}
_dialogMode = 1;
_titleText.text = string.Empty;
_messageText.text = string.Empty;
_pauseGame = false;
_userData = null;
RefreshConfirmText(string.Empty);
_onClickConfirmGFAction = null;
RefreshCancelText(string.Empty);
_onClickCancelGFAction = null;
RefreshOtherText(string.Empty);
_onClickOtherGFAction = null;
base.OnClose(isShutdown, userData);
}
private void RefreshDialogMode()
{
for (int i = 1; i <= _modeObjects.Length; i++)
{
_modeObjects[i - 1].SetActive(i == _dialogMode);
}
}
private void RefreshPauseGame()
{
if (_pauseGame)
{
GameEntry.Base.PauseGame();
}
}
private void RefreshConfirmText(string confirmText)
{
if (string.IsNullOrEmpty(confirmText))
{
confirmText = GameEntry.Localization.GetString("Dialog.ConfirmButton");
}
for (int i = 0; i < _confirmTexts.Length; i++)
{
_confirmTexts[i].text = confirmText;
}
}
private void RefreshCancelText(string cancelText)
{
if (string.IsNullOrEmpty(cancelText))
{
cancelText = GameEntry.Localization.GetString("Dialog.CancelButton");
}
for (int i = 0; i < _cancelTexts.Length; i++)
{
_cancelTexts[i].text = cancelText;
}
}
private void RefreshOtherText(string otherText)
{
if (string.IsNullOrEmpty(otherText))
{
otherText = GameEntry.Localization.GetString("Dialog.OtherButton");
}
for (int i = 0; i < _otherTexts.Length; i++)
{
_otherTexts[i].text = otherText;
}
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c04f3be6bab0c7748bc236f9023e47f9
timeCreated: 1528026160
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+116
View File
@@ -0,0 +1,116 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using GameFramework;
namespace UI
{
/// <summary>
/// 对话框显示数据。
/// </summary>
public class DialogParams
{
/// <summary>
/// 模式,即按钮数量。取值 1、2、3。
/// </summary>
public int Mode
{
get;
set;
}
/// <summary>
/// 标题。
/// </summary>
public string Title
{
get;
set;
}
/// <summary>
/// 消息内容。
/// </summary>
public string Message
{
get;
set;
}
/// <summary>
/// 弹出窗口时是否暂停游戏。
/// </summary>
public bool PauseGame
{
get;
set;
}
/// <summary>
/// 确认按钮文本。
/// </summary>
public string ConfirmText
{
get;
set;
}
/// <summary>
/// 确定按钮回调。
/// </summary>
public GameFrameworkAction<object> OnClickConfirm
{
get;
set;
}
/// <summary>
/// 取消按钮文本。
/// </summary>
public string CancelText
{
get;
set;
}
/// <summary>
/// 取消按钮回调。
/// </summary>
public GameFrameworkAction<object> OnClickCancel
{
get;
set;
}
/// <summary>
/// 中立按钮文本。
/// </summary>
public string OtherText
{
get;
set;
}
/// <summary>
/// 其它按钮回调。
/// </summary>
public GameFrameworkAction<object> OnClickOther
{
get;
set;
}
/// <summary>
/// 用户自定义数据。
/// </summary>
public string UserData
{
get;
set;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ad9ca3c36c52b0a4e8b25c8b451966da
timeCreated: 1528026160
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ea2618629fd6bbd40a9dda07b40a0094
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 797dee361a842bf4a826e018725f327a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UI
{
/// <summary>
/// Open data for MVC-based GameplayA form.
/// </summary>
public sealed class CombineFormContext : UIContext
{
/// <summary>
/// Slot definitions. Position and order are provided externally.
/// </summary>
public List<CombineSlotContext> Slots;
/// <summary>
/// Optional part definitions. When null/empty, parts are derived from slots.
/// </summary>
public List<CombinePartContext> Parts;
/// <summary>
/// Auto start puzzle after runtime nodes are generated.
/// </summary>
public bool AutoStart = true;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d8c5c616c000704fb2d7d94a8d22c84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
using System;
using Definition.Enum;
using UnityEngine;
namespace UI
{
/// <summary>
/// Runtime part data passed from external system.
/// </summary>
[Serializable]
public sealed class CombinePartContext
{
public CombinePartType PartType = CombinePartType.Dou;
public string PartDisplayName = "Dou";
public string MechanicsExplanation = string.Empty;
public bool LockAfterPlaced = true;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 82f303529f5b4b040845223f97a66cfa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,28 @@
using System;
using Definition.Enum;
using UnityEngine;
namespace UI
{
/// <summary>
/// Runtime slot data passed from external system.
/// </summary>
[Serializable]
public sealed class CombineSlotContext
{
public CombinePartType RequiredPartType = CombinePartType.Dou;
public int BuildOrder = 0;
public bool RequireStrictOrder = true;
public Vector2 AnchoredPosition = Vector2.zero;
public Vector2 SizeDelta = new Vector2(120f, 120f);
public string MechanicsExplanation = string.Empty;
public string MismatchHint = string.Empty;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 03894567063ea7d42a417545043e32c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f5e3a76d06305a244a21a9ecabe635bc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,96 @@
using CustomComponent;
using GameFramework.Event;
using UnityGameFramework.Runtime;
namespace UI
{
public class CombineFormController : IFormController<CombineFormContext>
{
private CombineComponent _controller;
private CombineForm _combineForm;
private int? _formSerialId;
private CombineFormContext _context;
public CombineFormController(CombineComponent controller)
{
_controller = controller;
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
GameEntry.Event.Subscribe(CloseUIFormCompleteEventArgs.EventId, CloseUIFormComplete);
}
public int? OpenUI(CombineFormContext context)
{
if (_controller == null)
{
_controller = GameEntry.Combine;
}
if (_controller == null)
{
Log.Warning("CombineFormController open failed. Controller is null.");
return null;
}
if (context != null)
{
_controller.SetFormContext(context);
}
_context = _controller.GetFormContext();
if (_context == null)
{
Log.Warning("CombineFormController open failed. Form context is null.");
return null;
}
_formSerialId = GameEntry.UI.OpenUIForm(UIFormId.CombineForm, _context);
return _formSerialId;
}
public void CloseUI()
{
if (_formSerialId.HasValue)
{
GameEntry.UI.CloseUIForm(_formSerialId.Value);
return;
}
if (_combineForm != null)
{
_combineForm.Close();
}
}
~CombineFormController()
{
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
GameEntry.Event.Unsubscribe(CloseUIFormCompleteEventArgs.EventId, CloseUIFormComplete);
}
private void OpenUIFormSuccess(object sender, GameEventArgs e)
{
if (!(e is OpenUIFormSuccessEventArgs args)) return;
if (args.UserData == _context)
{
_combineForm = args.UIForm.Logic as CombineForm;
}
}
private void CloseUIFormComplete(object sender, GameEventArgs e)
{
if (!(e is CloseUIFormCompleteEventArgs args)) return;
if (args.SerialId == _formSerialId)
{
_combineForm = null;
_formSerialId = null;
_context = null;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff5681c108fbc6c4680287e385ddaa12
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2bb96e9f3ec659447838d79b7b33db97
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,254 @@
using CustomComponent;
using Definition.Enum;
using UnityEngine;
using UnityEngine.EventSystems;
namespace UI
{
/// <summary>
/// 可拖拽拼装部件:负责拖拽交互、出生点回退与放置到槽位。
/// </summary>
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class CombineDraggablePart : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
#region Inspector Config
[SerializeField] private CombinePartType _partType = CombinePartType.Dou;
[SerializeField] private string _partDisplayName = "Dou";
[SerializeField] [TextArea(2, 4)] private string _mechanicsExplanation = string.Empty;
[SerializeField] private bool _lockAfterPlaced = true;
[SerializeField] private RectTransform _rectTransform;
[SerializeField] private CanvasGroup _canvasGroup;
#endregion
#region Spawn State
private bool _spawnStateCached;
private Transform _spawnParent;
private Vector3 _spawnWorldPosition = Vector3.zero;
private Quaternion _spawnWorldRotation = Quaternion.identity;
private Vector3 _spawnWorldScale = Vector3.one;
private int _spawnSiblingIndex;
#endregion
#region Runtime State
private CombineComponent _controller;
private CombineSlot _currentSlot;
private bool _isPlaced;
private bool _isLocked;
#endregion
#region Public Query
public CombinePartType PartType => _partType;
public string MechanicsExplanation => _mechanicsExplanation;
#endregion
#region Setup
/// <summary>
/// 绑定玩法控制器。
/// </summary>
public void BindController(CombineComponent controller)
{
_controller = controller;
}
/// <summary>
/// 使用运行时数据初始化部件配置。
/// </summary>
public void Initialize(CombinePartContext data)
{
_partType = data.PartType;
_partDisplayName = string.IsNullOrEmpty(data.PartDisplayName)
? data.PartType.ToString()
: data.PartDisplayName;
_mechanicsExplanation = data.MechanicsExplanation ?? string.Empty;
_lockAfterPlaced = data.LockAfterPlaced;
}
/// <summary>
/// 缓存出生点状态(仅首次缓存)。
/// </summary>
public void CacheSpawnState()
{
if (_spawnStateCached)
{
return;
}
_spawnStateCached = true;
_spawnParent = _rectTransform.parent;
_spawnWorldPosition = _rectTransform.position;
_spawnWorldRotation = _rectTransform.rotation;
_spawnWorldScale = _rectTransform.localScale;
_spawnSiblingIndex = _rectTransform.GetSiblingIndex();
}
/// <summary>
/// 重置部件到出生点,并清理槽位占用状态。
/// </summary>
public void ResetToSpawn()
{
ClearSlotOccupancy();
_isPlaced = false;
_isLocked = false;
ReturnToSpawn();
}
#endregion
#region Drag Flow
/// <summary>
/// 开始拖拽:关闭射线阻挡并切到拖拽层级。
/// </summary>
public void OnBeginDrag(PointerEventData eventData)
{
if (!CanStartDrag())
{
return;
}
_canvasGroup.blocksRaycasts = false;
MoveToDragRoot();
_rectTransform.SetAsLastSibling();
}
/// <summary>
/// 拖拽中:按指针增量更新锚点位置。
/// </summary>
public void OnDrag(PointerEventData eventData)
{
if (!CanDrag(eventData))
{
return;
}
_rectTransform.anchoredPosition += eventData.delta;
}
/// <summary>
/// 结束拖拽:恢复射线阻挡;未成功放置则回到出生点。
/// </summary>
public void OnEndDrag(PointerEventData eventData)
{
if (_isLocked)
{
return;
}
_canvasGroup.blocksRaycasts = true;
if (!_isPlaced)
{
ReturnToSpawn();
}
}
/// <summary>
/// 校验是否允许开始拖拽。
/// </summary>
private bool CanStartDrag()
{
return !_isLocked && !_isPlaced;
}
/// <summary>
/// 校验拖拽中是否可更新位置。
/// </summary>
private bool CanDrag(PointerEventData eventData)
{
return !_isLocked && !_isPlaced && eventData != null;
}
/// <summary>
/// 将部件切到控制器提供的拖拽根节点。
/// </summary>
private void MoveToDragRoot()
{
if (_controller == null)
{
return;
}
Transform dragRoot = _controller.GetDragRoot();
if (dragRoot != null)
{
_rectTransform.SetParent(dragRoot, true);
}
}
#endregion
#region Placement
/// <summary>
/// 将部件恢复到出生点状态。
/// </summary>
public void ReturnToSpawn()
{
if (_spawnParent == null)
{
return;
}
_rectTransform.SetParent(_spawnParent, true);
_rectTransform.position = _spawnWorldPosition;
_rectTransform.rotation = _spawnWorldRotation;
_rectTransform.localScale = _spawnWorldScale;
_rectTransform.SetSiblingIndex(_spawnSiblingIndex);
}
/// <summary>
/// 应用成功放置到槽位后的表现与状态。
/// </summary>
internal void PlaceToSlot(CombineSlot slot)
{
_currentSlot = slot;
_isPlaced = true;
_isLocked = _lockAfterPlaced;
RectTransform snapPoint = slot.SnapPoint;
_rectTransform.SetParent(snapPoint != null ? snapPoint : slot.transform, false);
_rectTransform.anchoredPosition = Vector2.zero;
_rectTransform.localRotation = Quaternion.identity;
_rectTransform.localScale = Vector3.one;
_canvasGroup.blocksRaycasts = !_isLocked;
}
/// <summary>
/// 清理当前槽位占用记录。
/// </summary>
private void ClearSlotOccupancy()
{
if (_currentSlot != null)
{
_currentSlot.ClearOccupiedPart(this);
_currentSlot = null;
}
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c019085f31e649a88e99eb655ed94b15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,247 @@
using System.Collections.Generic;
using CustomComponent;
using Event;
using GameFramework.Event;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
/// <summary>
/// MVC UI form for GameplayA. It builds slots and draggable parts from external data.
/// </summary>
[DisallowMultipleComponent]
public class CombineForm : UGuiForm
{
#region Property
[SerializeField] private CombineComponent _controller;
[SerializeField] private RectTransform _slotRoot;
[SerializeField] private RectTransform _partRoot;
[SerializeField] private CombineSlot _slotPrefab;
[SerializeField] private CombineDraggablePart _partPrefab;
[SerializeField] private TMP_Text _guideText;
[SerializeField] private TMP_Text _explanationText;
[SerializeField] private TMP_Text _progressText;
[SerializeField] private string _progressFormat = "{0}/{1}";
[SerializeField] private Vector2 _partStartAnchoredPosition = new(0f, -40f);
[SerializeField] private float _partVerticalSpacing = 120f;
private readonly List<GameObject> _runtimeNodes = new();
#endregion
#region FSM
protected override void OnInit(object userData)
{
base.OnInit(userData);
if (_controller == null)
{
_controller = GameEntry.Combine;
}
ResetTexts();
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (_controller == null)
{
_controller = GameEntry.Combine;
}
if (userData is CombineFormContext context)
{
if (context.Slots.Count == 0)
{
Log.Warning("CombineMvcForm open failed. Slot model is empty.");
return;
}
Build(context);
_controller.BindRuntimeContext(_slotRoot, _partRoot);
GameEntry.Event.Subscribe(CombineGuideMessageEventArgs.EventId, OnGuideMessageChanged);
GameEntry.Event.Subscribe(CombinePartMessageEventArgs.EventId, OnPartExplained);
GameEntry.Event.Subscribe(CombineProgressEventArgs.EventId, OnProgressChanged);
GameEntry.Event.Subscribe(CombineCompletedEventArgs.EventId, OnPuzzleCompleted);
if (context.AutoStart)
{
_controller.StartPuzzle();
}
else
{
GameEntry.Event.Fire(this,
CombineProgressEventArgs.Create(_controller.CurrentStep, _controller.TotalStep));
}
}
else
{
Log.Error("CombineMvcForm open failed. userData is invalid.");
}
}
protected override void OnClose(bool isShutdown, object userData)
{
GameEntry.Event.Unsubscribe(CombineGuideMessageEventArgs.EventId, OnGuideMessageChanged);
GameEntry.Event.Unsubscribe(CombinePartMessageEventArgs.EventId, OnPartExplained);
GameEntry.Event.Unsubscribe(CombineProgressEventArgs.EventId, OnProgressChanged);
GameEntry.Event.Unsubscribe(CombineCompletedEventArgs.EventId, OnPuzzleCompleted);
if (_controller != null)
{
_controller.ClearRuntimeContext();
}
ClearRuntimeNodes();
ResetTexts();
base.OnClose(isShutdown, userData);
}
protected override void OnPause()
{
base.OnPause();
if (_controller != null)
{
_controller.PausePuzzle();
}
}
protected override void OnResume()
{
base.OnResume();
if (_controller != null)
{
_controller.ResumePuzzle();
}
}
protected override void OnCover()
{
base.OnCover();
if (_controller != null)
{
_controller.PausePuzzle();
}
}
protected override void OnReveal()
{
base.OnReveal();
if (_controller != null)
{
_controller.ResumePuzzle();
}
}
#endregion
#region Other Methods
private void ClearRuntimeNodes()
{
for (int i = _runtimeNodes.Count - 1; i >= 0; i--)
{
GameObject node = _runtimeNodes[i];
if (node != null)
{
GameObject.Destroy(node);
}
}
_runtimeNodes.Clear();
}
private void ResetTexts()
{
GameEntry.Event.Fire(this, CombineGuideMessageEventArgs.Create(string.Empty));
GameEntry.Event.Fire(this, CombinePartMessageEventArgs.Create(string.Empty));
GameEntry.Event.Fire(this, CombineProgressEventArgs.Create(0, 0));
}
private void Build(CombineFormContext context)
{
ClearRuntimeNodes();
foreach (var slotData in context.Slots)
{
CombineSlot slot = Instantiate(_slotPrefab, _slotRoot, false);
slot.Initialize(slotData);
slot.SetSnapPoint(slot.transform as RectTransform);
_runtimeNodes.Add(slot.gameObject);
}
foreach (var partData in context.Parts)
{
CombineDraggablePart part = Instantiate(_partPrefab, _partRoot, false);
part.Initialize(partData);
_runtimeNodes.Add(part.gameObject);
}
}
#endregion
#region Event Handlers
private void OnGuideMessageChanged(object sender, GameEventArgs e)
{
if (!(e is CombineGuideMessageEventArgs args)) return;
if (_guideText != null)
{
_guideText.text = args.Message;
}
}
private void OnPartExplained(object sender, GameEventArgs e)
{
if (!(e is CombinePartMessageEventArgs args)) return;
if (_explanationText != null)
{
_explanationText.text = args.Message;
}
}
private void OnProgressChanged(object sender, GameEventArgs e)
{
if (!(e is CombineProgressEventArgs args)) return;
if (_progressText != null)
{
_progressText.text = string.Format(_progressFormat, args.CurrentStep, args.TotalSteps);
}
}
private void OnPuzzleCompleted(object sender, GameEventArgs e)
{
if (!(e is CombineCompletedEventArgs args)) return;
if (_progressText != null)
{
_progressText.text = string.Format(_progressFormat, _controller.TotalStep, _controller.TotalStep);
}
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 004eb70514fd9064ca990769ebe97043
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,195 @@
using CustomComponent;
using Definition.Enum;
using UnityEngine;
using UnityEngine.EventSystems;
namespace UI
{
/// <summary>
/// 拼装槽位:接收拖拽部件并转发给玩法控制器做规则校验。
/// </summary>
[DisallowMultipleComponent]
public class CombineSlot : MonoBehaviour, IDropHandler
{
#region Inspector Config
/// <summary>
/// 槽位要求的部件类型。
/// </summary>
[SerializeField] private CombinePartType _requiredPartType = CombinePartType.Dou;
/// <summary>
/// 槽位在拼装流程中的顺序值。
/// </summary>
[SerializeField] private int _buildOrder;
/// <summary>
/// 是否要求严格按顺序放置。
/// </summary>
[SerializeField] private bool _requireStrictOrder = true;
/// <summary>
/// 部件吸附点;为空时使用自身 RectTransform。
/// </summary>
[SerializeField] private RectTransform _snapPoint;
/// <summary>
/// 放置成功后的力学说明文案。
/// </summary>
[SerializeField] [TextArea(2, 4)] private string _mechanicsExplanation = string.Empty;
/// <summary>
/// 部件不匹配时的自定义提示文案。
/// </summary>
[SerializeField] [TextArea(2, 4)] private string _mismatchHint = string.Empty;
#endregion
#region Runtime State
/// <summary>
/// 玩法控制器引用。
/// </summary>
private CombineComponent _controller;
/// <summary>
/// 当前占用该槽位的部件。
/// </summary>
private CombineDraggablePart _occupiedPart;
#endregion
#region Public Query
/// <summary>
/// 获取槽位要求的部件类型。
/// </summary>
public CombinePartType RequiredPartType => _requiredPartType;
/// <summary>
/// 获取槽位顺序值。
/// </summary>
public int BuildOrder => _buildOrder;
/// <summary>
/// 获取槽位是否要求严格顺序。
/// </summary>
public bool RequireStrictOrder => _requireStrictOrder;
/// <summary>
/// 获取槽位是否已被占用。
/// </summary>
public bool IsOccupied => _occupiedPart != null;
/// <summary>
/// 获取槽位的力学说明文案。
/// </summary>
public string MechanicsExplanation => _mechanicsExplanation;
/// <summary>
/// 获取槽位不匹配提示文案。
/// </summary>
public string MismatchHint => _mismatchHint;
/// <summary>
/// 获取槽位吸附点。
/// </summary>
public RectTransform SnapPoint => _snapPoint != null ? _snapPoint : transform as RectTransform;
#endregion
#region Setup
/// <summary>
/// 绑定玩法控制器。
/// </summary>
public void BindController(CombineComponent controller)
{
_controller = controller;
}
/// <summary>
/// 使用运行时数据初始化槽位配置。
/// </summary>
public void Initialize(CombineSlotContext data)
{
_requiredPartType = data.RequiredPartType;
_buildOrder = data.BuildOrder;
_requireStrictOrder = data.RequireStrictOrder;
_mechanicsExplanation = data.MechanicsExplanation ?? string.Empty;
_mismatchHint = data.MismatchHint ?? string.Empty;
}
/// <summary>
/// 设置槽位吸附点,为空时回退到槽位自身。
/// </summary>
public void SetSnapPoint(RectTransform snapPoint)
{
_snapPoint = snapPoint;
}
/// <summary>
/// 重置槽位占用状态。
/// </summary>
public void ResetSlot()
{
_occupiedPart = null;
}
#endregion
#region Drop Handling
/// <summary>
/// 拖拽放下回调:识别部件并交给控制器校验放置。
/// </summary>
public void OnDrop(PointerEventData eventData)
{
if (!CanHandleDrop(eventData))
{
return;
}
CombineDraggablePart part = eventData.pointerDrag.GetComponent<CombineDraggablePart>();
if (part == null)
{
return;
}
_controller.TryPlacePart(part, this);
}
/// <summary>
/// 校验是否满足处理放下事件的前置条件。
/// </summary>
private bool CanHandleDrop(PointerEventData eventData)
{
return _controller != null && eventData != null && eventData.pointerDrag != null;
}
#endregion
#region Occupancy
/// <summary>
/// 标记当前槽位被指定部件占用。
/// </summary>
internal void SetOccupiedPart(CombineDraggablePart part)
{
_occupiedPart = part;
}
/// <summary>
/// 清理槽位占用,仅在占用者与传入部件一致时生效。
/// </summary>
internal void ClearOccupiedPart(CombineDraggablePart part)
{
if (_occupiedPart == part)
{
_occupiedPart = null;
}
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5986fde954b3467b96ccc5d2d741297a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
namespace UI
{
public interface IFormController<T> where T : UIContext
{
int? OpenUI(T context);
void CloseUI();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7754184093b2d14cb03dd9c8e6bbe03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+250
View File
@@ -0,0 +1,250 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using StarForce;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
public abstract class UGuiForm : UIFormLogic
{
public const int DepthFactor = 100;
private const float FadeTime = 0.3f;
private static Font _mainFont = null;
private static TMP_FontAsset _mainTMPFont = null;
private Canvas _cachedCanvas = null;
private CanvasGroup _canvasGroup = null;
private List<Canvas> _cachedCanvasContainer = new List<Canvas>();
public int OriginalDepth { get; private set; }
public int Depth => _cachedCanvas.sortingOrder;
public void Close()
{
Close(false);
}
public void Close(bool ignoreFade)
{
StopAllCoroutines();
if (ignoreFade)
{
GameEntry.UI.CloseUIForm(this);
}
else
{
StartCoroutine(CloseCo(FadeTime));
}
}
public void PlayUISound(int uiSoundId)
{
GameEntry.Sound.PlayUISound(uiSoundId);
}
public static void SetMainFont(Font mainFont)
{
if (mainFont == null)
{
Log.Error("Main font is invalid.");
return;
}
_mainFont = mainFont;
}
public static void SetMainTMPFont(TMP_FontAsset mainTMPFont)
{
if (mainTMPFont == null)
{
Log.Error("Main font is invalid.");
return;
}
_mainTMPFont = mainTMPFont;
}
#if UNITY_2017_3_OR_NEWER
protected override void OnInit(object userData)
#else
protected internal override void OnInit(object userData)
#endif
{
base.OnInit(userData);
_cachedCanvas = gameObject.GetOrAddComponent<Canvas>();
_cachedCanvas.overrideSorting = true;
OriginalDepth = _cachedCanvas.sortingOrder;
_canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
RectTransform rect = GetComponent<RectTransform>();
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.anchoredPosition = Vector2.zero;
rect.sizeDelta = Vector2.zero;
gameObject.GetOrAddComponent<GraphicRaycaster>();
if (_mainTMPFont == null)
{
Log.Warning("Main TMP font isn't set.");
}
else
{
var tmp_texts = GetComponentsInChildren<TMP_Text>(true);
foreach (var text in tmp_texts)
{
text.font = _mainTMPFont;
if (!string.IsNullOrEmpty(text.text))
{
text.text = GameEntry.Localization.GetString(text.text);
}
}
}
if (_mainFont == null)
{
Log.Warning("Main font isn't set.");
}
else
{
var texts = GetComponentsInChildren<Text>(true);
foreach (var text in texts)
{
text.font = _mainFont;
if (!string.IsNullOrEmpty(text.text))
{
text.text = GameEntry.Localization.GetString(text.text);
}
}
}
}
#if UNITY_2017_3_OR_NEWER
protected override void OnRecycle()
#else
protected internal override void OnRecycle()
#endif
{
base.OnRecycle();
}
#if UNITY_2017_3_OR_NEWER
protected override void OnOpen(object userData)
#else
protected internal override void OnOpen(object userData)
#endif
{
base.OnOpen(userData);
_canvasGroup.alpha = 0f;
StopAllCoroutines();
StartCoroutine(_canvasGroup.FadeToAlpha(1f, FadeTime));
}
#if UNITY_2017_3_OR_NEWER
protected override void OnClose(bool isShutdown, object userData)
#else
protected internal override void OnClose(bool isShutdown, object userData)
#endif
{
base.OnClose(isShutdown, userData);
}
#if UNITY_2017_3_OR_NEWER
protected override void OnPause()
#else
protected internal override void OnPause()
#endif
{
base.OnPause();
}
#if UNITY_2017_3_OR_NEWER
protected override void OnResume()
#else
protected internal override void OnResume()
#endif
{
base.OnResume();
_canvasGroup.alpha = 0f;
StopAllCoroutines();
StartCoroutine(_canvasGroup.FadeToAlpha(1f, FadeTime));
}
#if UNITY_2017_3_OR_NEWER
protected override void OnCover()
#else
protected internal override void OnCover()
#endif
{
base.OnCover();
}
#if UNITY_2017_3_OR_NEWER
protected override void OnReveal()
#else
protected internal override void OnReveal()
#endif
{
base.OnReveal();
}
#if UNITY_2017_3_OR_NEWER
protected override void OnRefocus(object userData)
#else
protected internal override void OnRefocus(object userData)
#endif
{
base.OnRefocus(userData);
}
#if UNITY_2017_3_OR_NEWER
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
#else
protected internal override void OnUpdate(float elapseSeconds, float realElapseSeconds)
#endif
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
}
#if UNITY_2017_3_OR_NEWER
protected override void OnDepthChanged(int uiGroupDepth, int depthInUIGroup)
#else
protected internal override void OnDepthChanged(int uiGroupDepth, int depthInUIGroup)
#endif
{
int oldDepth = Depth;
base.OnDepthChanged(uiGroupDepth, depthInUIGroup);
int deltaDepth = UGuiGroupHelper.DepthFactor * uiGroupDepth + DepthFactor * depthInUIGroup - oldDepth +
OriginalDepth;
GetComponentsInChildren(true, _cachedCanvasContainer);
for (int i = 0; i < _cachedCanvasContainer.Count; i++)
{
_cachedCanvasContainer[i].sortingOrder += deltaDepth;
}
_cachedCanvasContainer.Clear();
}
private IEnumerator CloseCo(float duration)
{
yield return _canvasGroup.FadeToAlpha(0f, duration);
GameEntry.UI.CloseUIForm(this);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0b92f84dc56dc764a9c261fe47df5520
timeCreated: 1528026161
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
/// <summary>
/// uGUI 界面组辅助器。
/// </summary>
public class UGuiGroupHelper : UIGroupHelperBase
{
public const int DepthFactor = 10000;
private int m_Depth = 0;
private Canvas m_CachedCanvas = null;
/// <summary>
/// 设置界面组深度。
/// </summary>
/// <param name="depth">界面组深度。</param>
public override void SetDepth(int depth)
{
m_Depth = depth;
m_CachedCanvas.overrideSorting = true;
m_CachedCanvas.sortingOrder = DepthFactor * depth;
}
private void Awake()
{
m_CachedCanvas = gameObject.GetOrAddComponent<Canvas>();
gameObject.GetOrAddComponent<GraphicRaycaster>();
}
private void Start()
{
m_CachedCanvas.overrideSorting = true;
m_CachedCanvas.sortingOrder = DepthFactor * m_Depth;
RectTransform transform = GetComponent<RectTransform>();
transform.anchorMin = Vector2.zero;
transform.anchorMax = Vector2.one;
transform.anchoredPosition = Vector2.zero;
transform.sizeDelta = Vector2.zero;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 05a35a4a1f7dd5646a70cb1a73348780
timeCreated: 1528026161
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+6
View File
@@ -0,0 +1,6 @@
namespace UI
{
public class UIContext
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 960a1d4c81cf9824682c47b744bba74c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+178
View File
@@ -0,0 +1,178 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using GameFramework.DataTable;
using GameFramework.UI;
using System.Collections;
using Procedure;
using StarForce;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
public static class UIExtension
{
public static IEnumerator FadeToAlpha(this CanvasGroup canvasGroup, float alpha, float duration)
{
float time = 0f;
float originalAlpha = canvasGroup.alpha;
while (time < duration)
{
time += Time.deltaTime;
canvasGroup.alpha = Mathf.Lerp(originalAlpha, alpha, time / duration);
yield return new WaitForEndOfFrame();
}
canvasGroup.alpha = alpha;
}
public static IEnumerator SmoothValue(this Slider slider, float value, float duration)
{
float time = 0f;
float originalValue = slider.value;
while (time < duration)
{
time += Time.deltaTime;
slider.value = Mathf.Lerp(originalValue, value, time / duration);
yield return new WaitForEndOfFrame();
}
slider.value = value;
}
public static bool HasUIForm(this UIComponent uiComponent, UIFormId uiFormId, string uiGroupName = null)
{
return uiComponent.HasUIForm((int)uiFormId, uiGroupName);
}
public static bool HasUIForm(this UIComponent uiComponent, int uiFormId, string uiGroupName = null)
{
IDataTable<DRUIForm> dtUIForm = GameEntry.DataTable.GetDataTable<DRUIForm>();
DRUIForm drUIForm = dtUIForm.GetDataRow(uiFormId);
if (drUIForm == null)
{
return false;
}
string assetName = AssetUtility.GetUIFormAsset(drUIForm.AssetName);
if (string.IsNullOrEmpty(uiGroupName))
{
return uiComponent.HasUIForm(assetName);
}
IUIGroup uiGroup = uiComponent.GetUIGroup(uiGroupName);
if (uiGroup == null)
{
return false;
}
return uiGroup.HasUIForm(assetName);
}
public static UGuiForm GetUIForm(this UIComponent uiComponent, UIFormId uiFormId, string uiGroupName = null)
{
return uiComponent.GetUIForm((int)uiFormId, uiGroupName);
}
public static UGuiForm GetUIForm(this UIComponent uiComponent, int uiFormId, string uiGroupName = null)
{
IDataTable<DRUIForm> dtUIForm = GameEntry.DataTable.GetDataTable<DRUIForm>();
DRUIForm drUIForm = dtUIForm.GetDataRow(uiFormId);
if (drUIForm == null)
{
return null;
}
string assetName = AssetUtility.GetUIFormAsset(drUIForm.AssetName);
UIForm uiForm = null;
if (string.IsNullOrEmpty(uiGroupName))
{
uiForm = uiComponent.GetUIForm(assetName);
if (uiForm == null)
{
return null;
}
return (UGuiForm)uiForm.Logic;
}
IUIGroup uiGroup = uiComponent.GetUIGroup(uiGroupName);
if (uiGroup == null)
{
return null;
}
uiForm = (UIForm)uiGroup.GetUIForm(assetName);
if (uiForm == null)
{
return null;
}
return (UGuiForm)uiForm.Logic;
}
public static void CloseUIForm(this UIComponent uiComponent, UGuiForm uiForm)
{
uiComponent.CloseUIForm(uiForm.UIForm);
}
public static int? OpenUIForm(this UIComponent uiComponent, UIFormId uiFormId, object userData = null)
{
return uiComponent.OpenUIForm((int)uiFormId, userData);
}
public static int? OpenUIForm(this UIComponent uiComponent, int uiFormId, object userData = null)
{
IDataTable<DRUIForm> dtUIForm = GameEntry.DataTable.GetDataTable<DRUIForm>();
DRUIForm drUIForm = dtUIForm.GetDataRow(uiFormId);
if (drUIForm == null)
{
Log.Warning("Can not load UI form '{0}' from data table.", uiFormId.ToString());
return null;
}
string assetName = AssetUtility.GetUIFormAsset(drUIForm.AssetName);
if (!drUIForm.AllowMultiInstance)
{
if (uiComponent.IsLoadingUIForm(assetName))
{
return null;
}
if (uiComponent.HasUIForm(assetName))
{
return null;
}
}
return uiComponent.OpenUIForm(assetName, drUIForm.UIGroupName, Constant.AssetPriority.UIFormAsset, drUIForm.PauseCoveredUIForm, userData);
}
public static void OpenDialog(this UIComponent uiComponent, DialogParams dialogParams)
{
if (((ProcedureBase)GameEntry.Procedure.CurrentProcedure).UseNativeDialog)
{
OpenNativeDialog(dialogParams);
}
else
{
uiComponent.OpenUIForm(UIFormId.DialogForm, dialogParams);
}
}
private static void OpenNativeDialog(DialogParams dialogParams)
{
// TODO:这里应该弹出原生对话框,先简化实现为直接按确认按钮
if (dialogParams.OnClickConfirm != null)
{
dialogParams.OnClickConfirm(dialogParams.UserData);
}
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9cfc2c881ce240349901812c61f4476b
timeCreated: 1528026162
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+42
View File
@@ -0,0 +1,42 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
namespace UI
{
/// <summary>
/// 界面编号。
/// </summary>
public enum UIFormId : byte
{
Undefined = 0,
/// <summary>
/// 弹出框。
/// </summary>
DialogForm = 1,
/// <summary>
/// 主菜单。
/// </summary>
MenuForm = 100,
/// <summary>
/// 设置。
/// </summary>
SettingForm = 101,
/// <summary>
/// 关于。
/// </summary>
AboutForm = 102,
/// <summary>
/// 核心玩法A MVC测试界面。
/// </summary>
CombineForm = 103,
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 75fd10c7585513846ab25372be0590b7
timeCreated: 1528026162
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
using UnityEngine;
using UnityEngine.UI;
namespace UI
{
public class UpdateResourceForm : MonoBehaviour
{
[SerializeField]
private Text m_DescriptionText = null;
[SerializeField]
private Slider m_ProgressSlider = null;
private void Start()
{
}
private void Update()
{
}
public void SetProgress(float progress, string description)
{
m_ProgressSlider.value = progress;
m_DescriptionText.text = description;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3d8946ea9933b16499cd11174ad3c410
timeCreated: 1504077253
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: