初始化仓库
This commit is contained in:
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
Reference in New Issue
Block a user