gameplay refine
1. 优化 ResolutionAdapter 的分辨率适配问题 2. 调整 SpriteCache 的资源路径拼接 3. 引入 StoryDirector 做各玩法的胶水 4. 导入和改名资源便于代码查询路径
This commit is contained in:
@@ -377,6 +377,7 @@ namespace CustomComponent
|
||||
GameEntry.Event.Fire(this, CombineGuideMessageEventArgs.Create(_completeHint));
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, CombineCompletedEventArgs.Create());
|
||||
_onPuzzleCompleted.Invoke();
|
||||
}
|
||||
|
||||
|
||||
@@ -338,11 +338,20 @@ namespace CustomComponent
|
||||
|
||||
private void EndDialogInternal()
|
||||
{
|
||||
int chapterId = _formContext != null ? _formContext.ChapterId : _currentChapterId;
|
||||
int dialogId = _formContext != null ? _formContext.DialogId : 0;
|
||||
int lineId = _formContext != null ? _formContext.CurrentLineId : 0;
|
||||
|
||||
_isPlaying = false;
|
||||
_currentLineIndex = -1;
|
||||
|
||||
_formController.OnDialogEnded(_formContext);
|
||||
_formController.CloseUI();
|
||||
|
||||
if (dialogId > 0)
|
||||
{
|
||||
GameEntry.Event.Fire(this, DialogCompletedEventArgs.Create(chapterId, dialogId, lineId));
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyLineToContext(DRDialogLine lineRow, int lineIndex, int totalLines)
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace GeometryTD.CustomComponent
|
||||
[SerializeField] private Vector2 _referenceResolution = new Vector2(2560f, 1600f);
|
||||
[SerializeField] private bool _adaptUiCanvasToViewport = true;
|
||||
[SerializeField] private bool _enableBlackMask = true;
|
||||
[SerializeField] private bool _autoCollectSceneCanvases = true;
|
||||
[SerializeField] private List<Transform> _uiRoots = new List<Transform>();
|
||||
|
||||
private readonly List<Canvas> _canvasBuffer = new List<Canvas>(32);
|
||||
@@ -29,6 +30,7 @@ namespace GeometryTD.CustomComponent
|
||||
|
||||
private bool _canvasCacheDirty = true;
|
||||
private bool _uiEventSubscribed;
|
||||
private bool _sceneEventSubscribed;
|
||||
private bool _missingRootWarned;
|
||||
|
||||
private Canvas _maskCanvas;
|
||||
@@ -163,18 +165,6 @@ namespace GeometryTD.CustomComponent
|
||||
return;
|
||||
}
|
||||
|
||||
if (_uiRoots == null || _uiRoots.Count == 0)
|
||||
{
|
||||
if (!_missingRootWarned)
|
||||
{
|
||||
_missingRootWarned = true;
|
||||
Log.Warning(
|
||||
"ResolutionAdapterComponent missing injected roots. Assign UI/HPBar root transforms in scene.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_canvasCacheDirty)
|
||||
{
|
||||
RebuildCanvasCache();
|
||||
@@ -200,9 +190,49 @@ namespace GeometryTD.CustomComponent
|
||||
_trackedCanvases.Clear();
|
||||
_trackedCanvasSet.Clear();
|
||||
|
||||
foreach (var root in _uiRoots)
|
||||
bool hasValidRoot = false;
|
||||
if (_uiRoots != null)
|
||||
{
|
||||
CollectCanvases(root);
|
||||
foreach (var root in _uiRoots)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hasValidRoot = true;
|
||||
CollectCanvases(root);
|
||||
}
|
||||
}
|
||||
|
||||
if (_autoCollectSceneCanvases || !hasValidRoot)
|
||||
{
|
||||
Canvas[] canvases = Resources.FindObjectsOfTypeAll<Canvas>();
|
||||
foreach (Canvas canvas in canvases)
|
||||
{
|
||||
if (canvas == null || canvas == _maskCanvas || canvas.renderMode == RenderMode.WorldSpace)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject gameObject = canvas.gameObject;
|
||||
if (!gameObject.scene.IsValid() || !gameObject.scene.isLoaded)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_trackedCanvasSet.Add(canvas))
|
||||
{
|
||||
_trackedCanvases.Add(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidRoot && !_autoCollectSceneCanvases && !_missingRootWarned)
|
||||
{
|
||||
_missingRootWarned = true;
|
||||
Log.Warning(
|
||||
"ResolutionAdapterComponent missing injected roots. Assign UI/HPBar root transforms in scene or enable auto collection.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,27 +300,46 @@ namespace GeometryTD.CustomComponent
|
||||
|
||||
private void TryEnsureUiEventSubscribed()
|
||||
{
|
||||
if (_uiEventSubscribed || GameEntry.Event == null)
|
||||
if (GameEntry.Event == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnUIFormChanged);
|
||||
GameEntry.Event.Subscribe(CloseUIFormCompleteEventArgs.EventId, OnUIFormChanged);
|
||||
_uiEventSubscribed = true;
|
||||
_canvasCacheDirty = true;
|
||||
if (!_uiEventSubscribed)
|
||||
{
|
||||
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnUIFormChanged);
|
||||
GameEntry.Event.Subscribe(CloseUIFormCompleteEventArgs.EventId, OnUIFormChanged);
|
||||
_uiEventSubscribed = true;
|
||||
_canvasCacheDirty = true;
|
||||
}
|
||||
|
||||
if (!_sceneEventSubscribed)
|
||||
{
|
||||
GameEntry.Event.Subscribe(LoadSceneSuccessEventArgs.EventId, OnSceneChanged);
|
||||
_sceneEventSubscribed = true;
|
||||
_canvasCacheDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnsubscribeUiEvents()
|
||||
{
|
||||
if (!_uiEventSubscribed || GameEntry.Event == null)
|
||||
if (GameEntry.Event == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OnUIFormChanged);
|
||||
GameEntry.Event.Unsubscribe(CloseUIFormCompleteEventArgs.EventId, OnUIFormChanged);
|
||||
_uiEventSubscribed = false;
|
||||
if (_uiEventSubscribed)
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OnUIFormChanged);
|
||||
GameEntry.Event.Unsubscribe(CloseUIFormCompleteEventArgs.EventId, OnUIFormChanged);
|
||||
_uiEventSubscribed = false;
|
||||
}
|
||||
|
||||
if (_sceneEventSubscribed)
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(LoadSceneSuccessEventArgs.EventId, OnSceneChanged);
|
||||
_sceneEventSubscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUIFormChanged(object sender, GameEventArgs e)
|
||||
@@ -298,6 +347,12 @@ namespace GeometryTD.CustomComponent
|
||||
_canvasCacheDirty = true;
|
||||
}
|
||||
|
||||
private void OnSceneChanged(object sender, GameEventArgs e)
|
||||
{
|
||||
_canvasCacheDirty = true;
|
||||
_missingRootWarned = false;
|
||||
}
|
||||
|
||||
private void UpdateMaskLayout()
|
||||
{
|
||||
if (!_enableBlackMask)
|
||||
@@ -442,4 +497,4 @@ namespace GeometryTD.CustomComponent
|
||||
maskRect.sizeDelta = new Vector2(0f, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace CustomComponent
|
||||
{
|
||||
_resource.LoadAsset
|
||||
(
|
||||
AssetUtility.GetUIDialogAsset(assetName),
|
||||
AssetUtility.GetUISpriteAsset(assetName),
|
||||
Constant.AssetPriority.UIFormAsset,
|
||||
new LoadAssetCallbacks(
|
||||
(resourcePath, asset, duration, userData) =>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99c1d60910f24e37ba0cbd8109e63bd7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Story/Directive/Change Background", fileName = "Directive_ChangeBackground")]
|
||||
public sealed class StoryChangeBackgroundDirectiveAsset : StoryDirectiveAsset
|
||||
{
|
||||
[SerializeField] private string _backgroundAssetName = string.Empty;
|
||||
|
||||
public override string ActionName => "ChangeBackground";
|
||||
|
||||
public override void Execute(StoryDirectorComponent director)
|
||||
{
|
||||
if (director == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
director.ExecuteChangeBackground(_backgroundAssetName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d4b16a5d76140a1b952ad48774dd89a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UI;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class StoryCombineConfig
|
||||
{
|
||||
public bool AutoStart = true;
|
||||
public List<CombineSlotContext> Slots = new List<CombineSlotContext>();
|
||||
public List<CombinePartContext> Parts = new List<CombinePartContext>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c53bd314c194677b10a2e7fa754fdbb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
public abstract class StoryDirectiveAsset : ScriptableObject
|
||||
{
|
||||
[SerializeField] private bool _enabled = true;
|
||||
|
||||
[SerializeField] private StoryTriggerType _triggerType = StoryTriggerType.DialogCompleted;
|
||||
|
||||
[SerializeField] [Tooltip("DialogCompleted 时为对话 Id;<=0 表示该触发类型下的任意 Id。")]
|
||||
private int _triggerId = 0;
|
||||
|
||||
public bool IsEnabled => _enabled;
|
||||
|
||||
public StoryTriggerType TriggerType => _triggerType;
|
||||
|
||||
public int TriggerId => _triggerId;
|
||||
|
||||
public virtual string ActionName => GetType().Name;
|
||||
|
||||
public bool IsMatch(StoryTriggerType triggerType, int triggerId)
|
||||
{
|
||||
if (!_enabled || _triggerType != triggerType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (triggerType == StoryTriggerType.DialogCompleted && _triggerId > 0 && _triggerId != triggerId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void Execute(StoryDirectorComponent director);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2deed2f965a04cbab1c18d2e9b5d5845
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Story/Directive/End Chapter", fileName = "Directive_EndChapter")]
|
||||
public sealed class StoryEndChapterDirectiveAsset : StoryDirectiveAsset
|
||||
{
|
||||
[SerializeField] [Tooltip("<=0 则使用当前章节。")] private int _chapterId = 0;
|
||||
|
||||
public override string ActionName => "EndChapter";
|
||||
|
||||
public override void Execute(StoryDirectorComponent director)
|
||||
{
|
||||
if (director == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
director.ExecuteEndChapter(_chapterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b63fb6eb96e4d3193dd26b443f856c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Story/Directive/Start Combine", fileName = "Directive_StartCombine")]
|
||||
public sealed class StoryStartCombineDirectiveAsset : StoryDirectiveAsset
|
||||
{
|
||||
[SerializeField] private bool _useDefaultConfig = true;
|
||||
|
||||
[SerializeField] private StoryCombineConfig _combineConfig = new StoryCombineConfig();
|
||||
|
||||
public override string ActionName => "StartCombine";
|
||||
|
||||
public override void Execute(StoryDirectorComponent director)
|
||||
{
|
||||
if (director == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StoryCombineConfig config = _useDefaultConfig ? null : _combineConfig;
|
||||
director.ExecuteStartCombine(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19a1150cd0fb4b648ad8232de4e38baa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Story/Directive/Start Dialog", fileName = "Directive_StartDialog")]
|
||||
public sealed class StoryStartDialogDirectiveAsset : StoryDirectiveAsset
|
||||
{
|
||||
[SerializeField] private int _dialogId = 0;
|
||||
|
||||
public override string ActionName => "StartDialog";
|
||||
|
||||
public override void Execute(StoryDirectorComponent director)
|
||||
{
|
||||
if (director == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
director.ExecuteStartDialog(_dialogId);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e4367863f5042e1b5b0b3b3b7f62f5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CustomComponent
|
||||
{
|
||||
public enum StoryTriggerType
|
||||
{
|
||||
DialogCompleted = 0,
|
||||
CombineCompleted = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b9d79013962410681f2f29343902599
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,358 @@
|
||||
using System.Collections.Generic;
|
||||
using Definition.Enum;
|
||||
using Event;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace CustomComponent
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class StoryDirectorComponent : GameFrameworkComponent
|
||||
{
|
||||
[SerializeField] [Tooltip("按顺序执行。每个元素是一个 StoryDirectiveAsset 资产引用。")]
|
||||
private List<StoryDirectiveAsset> _directives = new List<StoryDirectiveAsset>();
|
||||
|
||||
[SerializeField] private bool _allowRepeatTrigger = false;
|
||||
|
||||
[SerializeField] private bool _verboseLog = true;
|
||||
|
||||
[SerializeField] private string _backgroundAssetNamePrefix = string.Empty;
|
||||
|
||||
private readonly HashSet<string> _consumedDirectiveTokens = new HashSet<string>();
|
||||
|
||||
private BgFormController _bgFormController;
|
||||
private int _bgRequestVersion;
|
||||
private bool _isExecuting;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GameEntry.Event.Subscribe(DialogCompletedEventArgs.EventId, OnDialogCompleted);
|
||||
GameEntry.Event.Subscribe(CombineCompletedEventArgs.EventId, OnCombineCompleted);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(DialogCompletedEventArgs.EventId, OnDialogCompleted);
|
||||
GameEntry.Event.Unsubscribe(CombineCompletedEventArgs.EventId, OnCombineCompleted);
|
||||
|
||||
_bgFormController?.CloseUI();
|
||||
_bgFormController = null;
|
||||
}
|
||||
|
||||
public void ResetConsumedDirectives()
|
||||
{
|
||||
_consumedDirectiveTokens.Clear();
|
||||
}
|
||||
|
||||
private void OnDialogCompleted(object sender, GameFramework.Event.GameEventArgs e)
|
||||
{
|
||||
if (!(e is DialogCompletedEventArgs args))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ExecuteDirectives(StoryTriggerType.DialogCompleted, args.DialogId);
|
||||
}
|
||||
|
||||
private void OnCombineCompleted(object sender, GameFramework.Event.GameEventArgs e)
|
||||
{
|
||||
if (!(e is CombineCompletedEventArgs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ExecuteDirectives(StoryTriggerType.CombineCompleted, 0);
|
||||
}
|
||||
|
||||
private void ExecuteDirectives(StoryTriggerType triggerType, int triggerId)
|
||||
{
|
||||
if (_isExecuting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isExecuting = true;
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < _directives.Count; i++)
|
||||
{
|
||||
StoryDirectiveAsset directive = _directives[i];
|
||||
if (directive == null || !directive.IsMatch(triggerType, triggerId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string directiveToken = BuildDirectiveToken(directive, i);
|
||||
if (!_allowRepeatTrigger && _consumedDirectiveTokens.Contains(directiveToken))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ExecuteDirective(directive, triggerType, triggerId);
|
||||
|
||||
if (!_allowRepeatTrigger)
|
||||
{
|
||||
_consumedDirectiveTokens.Add(directiveToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isExecuting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildDirectiveToken(StoryDirectiveAsset directive, int directiveIndex)
|
||||
{
|
||||
return $"{directive.GetInstanceID()}:{directiveIndex}";
|
||||
}
|
||||
|
||||
private void ExecuteDirective(StoryDirectiveAsset directive, StoryTriggerType triggerType, int triggerId)
|
||||
{
|
||||
directive.Execute(this);
|
||||
|
||||
if (_verboseLog)
|
||||
{
|
||||
Log.Info("StoryDirector executed action '{0}' by trigger '{1}' ({2}).",
|
||||
directive.ActionName, triggerType.ToString(), triggerId.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteStartDialog(int dialogId)
|
||||
{
|
||||
if (dialogId <= 0)
|
||||
{
|
||||
Log.Warning("StoryDirector start dialog skipped. dialogId must be positive.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameEntry.Dialog == null)
|
||||
{
|
||||
Log.Warning("StoryDirector start dialog failed. Dialog component is missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Dialog.StartDialog(dialogId);
|
||||
}
|
||||
|
||||
public void ExecuteStartCombine(StoryCombineConfig config)
|
||||
{
|
||||
if (GameEntry.Combine == null)
|
||||
{
|
||||
Log.Warning("StoryDirector start combine failed. Combine component is missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
CombineFormContext context = BuildCombineFormContext(config);
|
||||
int? formSerialId = GameEntry.Combine.StartLevel(context);
|
||||
if (!formSerialId.HasValue)
|
||||
{
|
||||
Log.Warning("StoryDirector start combine failed. Open combine UI failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteChangeBackground(string backgroundAssetName)
|
||||
{
|
||||
string assetName = string.IsNullOrWhiteSpace(backgroundAssetName)
|
||||
? string.Empty
|
||||
: backgroundAssetName.Trim();
|
||||
if (string.IsNullOrEmpty(assetName))
|
||||
{
|
||||
Log.Warning("StoryDirector change background skipped. assetName is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameEntry.SpriteCache == null)
|
||||
{
|
||||
Log.Warning("StoryDirector change background failed. SpriteCache component is missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
int requestVersion = ++_bgRequestVersion;
|
||||
GameEntry.SpriteCache.GetSprite(_backgroundAssetNamePrefix + assetName,
|
||||
sprite => { OnBackgroundLoaded(requestVersion, assetName, sprite); });
|
||||
}
|
||||
|
||||
private void OnBackgroundLoaded(int requestVersion, string assetName, Sprite sprite)
|
||||
{
|
||||
if (requestVersion != _bgRequestVersion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sprite == null)
|
||||
{
|
||||
Log.Warning("StoryDirector change background failed. Loaded sprite is null for '{0}'.", assetName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_bgFormController == null)
|
||||
{
|
||||
_bgFormController = new BgFormController();
|
||||
}
|
||||
|
||||
_bgFormController.OpenUI(new BgFormContext
|
||||
{
|
||||
Sprite = sprite
|
||||
});
|
||||
}
|
||||
|
||||
public void ExecuteEndChapter(int chapterId)
|
||||
{
|
||||
int finalChapterId = chapterId > 0
|
||||
? chapterId
|
||||
: (GameEntry.Dialog != null ? GameEntry.Dialog.CurrentChapterId : 0);
|
||||
|
||||
GameEntry.Event.Fire(this, StoryChapterEndedEventArgs.Create(finalChapterId));
|
||||
}
|
||||
|
||||
private static CombineFormContext BuildCombineFormContext(StoryCombineConfig config)
|
||||
{
|
||||
if (config != null && config.Slots != null && config.Slots.Count > 0)
|
||||
{
|
||||
return new CombineFormContext
|
||||
{
|
||||
Slots = CloneSlots(config.Slots),
|
||||
Parts = CloneParts(config.Parts),
|
||||
AutoStart = config.AutoStart
|
||||
};
|
||||
}
|
||||
|
||||
return BuildDefaultCombineContext();
|
||||
}
|
||||
|
||||
private static List<CombineSlotContext> CloneSlots(List<CombineSlotContext> source)
|
||||
{
|
||||
var result = new List<CombineSlotContext>();
|
||||
if (source == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
CombineSlotContext slot = source[i];
|
||||
if (slot == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = slot.RequiredPartType,
|
||||
BuildOrder = slot.BuildOrder,
|
||||
RequireStrictOrder = slot.RequireStrictOrder,
|
||||
AnchoredPosition = slot.AnchoredPosition,
|
||||
SizeDelta = slot.SizeDelta,
|
||||
MechanicsExplanation = slot.MechanicsExplanation,
|
||||
MismatchHint = slot.MismatchHint
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<CombinePartContext> CloneParts(List<CombinePartContext> source)
|
||||
{
|
||||
var result = new List<CombinePartContext>();
|
||||
if (source == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
CombinePartContext part = source[i];
|
||||
if (part == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(new CombinePartContext
|
||||
{
|
||||
PartType = part.PartType,
|
||||
PartDisplayName = part.PartDisplayName,
|
||||
MechanicsExplanation = part.MechanicsExplanation,
|
||||
LockAfterPlaced = part.LockAfterPlaced
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static CombineFormContext BuildDefaultCombineContext()
|
||||
{
|
||||
List<CombineSlotContext> slots = new List<CombineSlotContext>
|
||||
{
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Dou,
|
||||
BuildOrder = 0,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-320f, -160f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Dou transfers upper load and works as the base node."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Sheng,
|
||||
BuildOrder = 1,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-320f, -20f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Sheng raises layer height to form the bracket hierarchy."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Gong,
|
||||
BuildOrder = 2,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-320f, 120f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Gong spreads force laterally through overhang."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Qiao,
|
||||
BuildOrder = 3,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-160f, 120f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Qiao continues force transfer to the outer side."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Ang,
|
||||
BuildOrder = 4,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(0f, 120f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Ang uses leverage to redirect eave load inward."
|
||||
}
|
||||
};
|
||||
|
||||
List<CombinePartContext> parts = new List<CombinePartContext>
|
||||
{
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Dou, PartDisplayName = "Dou", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Sheng, PartDisplayName = "Sheng", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Gong, PartDisplayName = "Gong", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Qiao, PartDisplayName = "Qiao", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Ang, PartDisplayName = "Ang", LockAfterPlaced = true }
|
||||
};
|
||||
|
||||
return new CombineFormContext
|
||||
{
|
||||
Slots = slots,
|
||||
Parts = parts,
|
||||
AutoStart = true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d899fa8b1598c1846bc3a03d11c83d04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user