Compare commits
8 Commits
abc3df086d
...
e3f047de2b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3f047de2b | ||
|
|
0bfcfa3038 | ||
|
|
b4e0cb0530 | ||
|
|
f81a17e1f5 | ||
|
|
64b383fe6e | ||
|
|
46b5bcc978 | ||
|
|
28f431f26a | ||
|
|
d3cc23a1ce |
7
.idea/.idea.Colorbook/.idea/discord.xml
generated
Normal file
7
.idea/.idea.Colorbook/.idea/discord.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
<androidPackage spec="com.appsflyer:af-android-sdk:6.17.6"></androidPackage>
|
<androidPackage spec="com.appsflyer:af-android-sdk:6.17.6"></androidPackage>
|
||||||
<androidPackage spec="com.appsflyer:unity-wrapper:6.17.91"></androidPackage>
|
<androidPackage spec="com.appsflyer:unity-wrapper:6.17.91"></androidPackage>
|
||||||
<androidPackage spec="com.android.installreferrer:installreferrer:2.1"></androidPackage>
|
<androidPackage spec="com.android.installreferrer:installreferrer:2.1"></androidPackage>
|
||||||
<androidPackage spec="com.appsflyer:purchase-connector:2.2.0"></androidPackage>
|
|
||||||
</androidPackages>
|
</androidPackages>
|
||||||
|
|
||||||
<iosPods>
|
<iosPods>
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public interface IColoringController
|
|||||||
void PaintRegion(string regionId, Color color);
|
void PaintRegion(string regionId, Color color);
|
||||||
IReadOnlyDictionary<string, Color> GetCurrentColors();
|
IReadOnlyDictionary<string, Color> GetCurrentColors();
|
||||||
UniTask PlayCompletionAnimationAsync(CancellationToken ct);
|
UniTask PlayCompletionAnimationAsync(CancellationToken ct);
|
||||||
|
|
||||||
|
// True while the completion celebration is on screen (the real drawing is hidden).
|
||||||
|
// Capture must skip these frames so it never grabs the animation instead of the art.
|
||||||
|
bool IsPlayingCompletionAnimation { get; }
|
||||||
|
|
||||||
bool HasNonAuthoredColors { get; }
|
bool HasNonAuthoredColors { get; }
|
||||||
void ResetAll();
|
void ResetAll();
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: d63726aaa9398f341a1a923bc039c446
|
guid: fac6898f446df4a8e994fa47eed10068
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Darkmatter.Core.Contracts.Features.Tutorial
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Decides whether the one-time tutorial should run, and records that it has been completed.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITutorialGate
|
||||||
|
{
|
||||||
|
/// <summary>True only for a genuine first-time player who has not finished the tutorial.</summary>
|
||||||
|
bool ShouldRun { get; }
|
||||||
|
|
||||||
|
/// <summary>Persist that the tutorial is done so it never runs again.</summary>
|
||||||
|
void MarkCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e7c2fc9f6a9354a068fdc7d9ed5aa4ad
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Darkmatter.Core.Contracts.Features.Tutorial
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Full-screen guidance overlay: a dim frame with a cut-out "hole" over a target element,
|
||||||
|
/// an animated hand + halo, and an instruction bubble. Lives on a persistent root-scoped
|
||||||
|
/// Canvas so it survives scene swaps (mirrors the loading screen).
|
||||||
|
/// </summary>
|
||||||
|
public interface ITutorialOverlay
|
||||||
|
{
|
||||||
|
/// <summary>True once the view is initialised and safe to drive.</summary>
|
||||||
|
bool IsReady { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spotlight a single tap target. When <paramref name="target"/> is null the dim/hole are
|
||||||
|
/// skipped and only a centered bubble is shown (a non-blocking hint).
|
||||||
|
/// When <paramref name="blockInput"/> is true every touch outside the hole is swallowed.
|
||||||
|
/// </summary>
|
||||||
|
void ShowTap(RectTransform target, string message, bool blockInput);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spotlight a drag gesture from <paramref name="from"/> to <paramref name="to"/>. Input is
|
||||||
|
/// never blocked here, so the dragged piece can render above the dim.
|
||||||
|
/// </summary>
|
||||||
|
void ShowDrag(RectTransform from, RectTransform to, string message);
|
||||||
|
|
||||||
|
/// <summary>Hide everything immediately (used across scene swaps).</summary>
|
||||||
|
void HideInstant();
|
||||||
|
|
||||||
|
/// <summary>Show a centered celebratory bubble for a short beat, then hide.</summary>
|
||||||
|
UniTask ShowToastAsync(string message, CancellationToken ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1fae7a22d89c64857af91268a55bd564
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Darkmatter.Core.Data.Signals.Features.Coloring
|
||||||
|
{
|
||||||
|
public record struct ColorSelectedSignal(int Index, Color Color);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: df1823d5d5df7469781b42466c308ecc
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Darkmatter.Core
|
||||||
|
{
|
||||||
|
// Published by the catalog presenter once the drawing grid is populated and on screen.
|
||||||
|
// Namespace matches the sibling OpenColorBookSignal so existing catalog code needs no new using.
|
||||||
|
public record struct DrawingCatalogReadySignal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e71fd9bc94a644ced8b0a141f058291b
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 8f948c844c48b42479fbc2aea5142bc1
|
guid: 3aee861659cfe43c4b48d513479c2d7d
|
||||||
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Darkmatter.Core.Data.Signals.Features.Tutorial
|
||||||
|
{
|
||||||
|
public record struct TutorialCompletedSignal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e3b50d1afc8134a0f8ae92b6c0590bdb
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Darkmatter.Core.Data.Signals.Features.Tutorial
|
||||||
|
{
|
||||||
|
public record struct TutorialStartedSignal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3aeb975bb1d6a45aca5c86ddf72bee22
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Darkmatter.Core.Data.Signals.Features.Tutorial
|
||||||
|
{
|
||||||
|
public record struct TutorialStepCompletedSignal(string StepId, int StepIndex);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 11b2e1b23836f4664be3a84389c1c364
|
||||||
@@ -16,6 +16,7 @@ namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder
|
|||||||
|
|
||||||
[Header("Drag")]
|
[Header("Drag")]
|
||||||
[SerializeField, Range(1f, 2f)] private float dragScale = 1.15f;
|
[SerializeField, Range(1f, 2f)] private float dragScale = 1.15f;
|
||||||
|
[SerializeField, Range(0f, 1f)] private float dragAlpha = 0.7f;
|
||||||
|
|
||||||
[Header("Preview easing")]
|
[Header("Preview easing")]
|
||||||
[SerializeField] private AnimationCurve previewCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
[SerializeField] private AnimationCurve previewCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||||
@@ -25,6 +26,7 @@ namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder
|
|||||||
public float SnapDuration => snapDuration;
|
public float SnapDuration => snapDuration;
|
||||||
public float ReturnDuration => returnDuration;
|
public float ReturnDuration => returnDuration;
|
||||||
public float DragScale => dragScale;
|
public float DragScale => dragScale;
|
||||||
|
public float DragAlpha => dragAlpha;
|
||||||
public AnimationCurve PreviewCurve => previewCurve;
|
public AnimationCurve PreviewCurve => previewCurve;
|
||||||
|
|
||||||
public Vector2 DragSizeDelta(ShapeSO shape) =>
|
public Vector2 DragSizeDelta(ShapeSO shape) =>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1cda3e3840cbd4eccbe7ad810dee920d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Darkmatter.Core.Data.Static.Features.Tutorial
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Designer-tunable copy and timing for the one-time onboarding tutorial. The step *sequence*
|
||||||
|
/// is fixed in TutorialDirector; only the wording, the spotlight padding and the per-step
|
||||||
|
/// watchdog timeout live here.
|
||||||
|
/// </summary>
|
||||||
|
[CreateAssetMenu(fileName = "TutorialStepsConfig",
|
||||||
|
menuName = "Darkmatter/Tutorial/Steps Config")]
|
||||||
|
public sealed class TutorialStepsConfig : ScriptableObject
|
||||||
|
{
|
||||||
|
[Header("Step copy (kept short for young readers)")]
|
||||||
|
[SerializeField] private string pickText = "Pick a picture to start!";
|
||||||
|
[SerializeField] private string dragText = "Drag the piece to its spot!";
|
||||||
|
[SerializeField] private string finishText = "Now finish the puzzle!";
|
||||||
|
[SerializeField] private string colorText = "Choose a color!";
|
||||||
|
[SerializeField] private string paintText = "Tap the picture to color it!";
|
||||||
|
[SerializeField] private string nextText = "Tap Next when you're done!";
|
||||||
|
[SerializeField] private string doneText = "Yay! You did it!";
|
||||||
|
|
||||||
|
[Header("Watchdog")]
|
||||||
|
[Tooltip("Timeout (s) while waiting for a SYSTEM precondition (scene/catalog/regions ready). If it " +
|
||||||
|
"doesn't arrive the tutorial fails open so the player is never trapped.")]
|
||||||
|
[SerializeField] private float stepTimeoutSeconds = 45f;
|
||||||
|
|
||||||
|
[Tooltip("Timeout (s) while waiting for the CHILD's own action (drag/tap/paint). 0 = no timeout: " +
|
||||||
|
"the hint stays until they do it. Set a large value if you want a safety net instead.")]
|
||||||
|
[SerializeField] private float actionTimeoutSeconds;
|
||||||
|
|
||||||
|
public string PickText => pickText;
|
||||||
|
public string DragText => dragText;
|
||||||
|
public string FinishText => finishText;
|
||||||
|
public string ColorText => colorText;
|
||||||
|
public string PaintText => paintText;
|
||||||
|
public string NextText => nextText;
|
||||||
|
public string DoneText => doneText;
|
||||||
|
|
||||||
|
public float StepTimeoutSeconds => stepTimeoutSeconds;
|
||||||
|
public float ActionTimeoutSeconds => actionTimeoutSeconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5c513430cc85f4357b3df1da019bf554
|
||||||
@@ -30,6 +30,7 @@ namespace Darkmatter.Features.AppBoot.Flow
|
|||||||
|
|
||||||
public async UniTask StartAsync(CancellationToken cancellation = default)
|
public async UniTask StartAsync(CancellationToken cancellation = default)
|
||||||
{
|
{
|
||||||
|
Screen.sleepTimeout = SleepTimeout.NeverSleep;
|
||||||
await _progression.LoadAsync();
|
await _progression.LoadAsync();
|
||||||
|
|
||||||
var tcs = new UniTaskCompletionSource();
|
var tcs = new UniTaskCompletionSource();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using Darkmatter.Core.Contracts.Features.Capture;
|
using Darkmatter.Core.Contracts.Features.Capture;
|
||||||
|
using Darkmatter.Core.Contracts.Features.Coloring;
|
||||||
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
|
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
|
||||||
using Darkmatter.Core.Contracts.Features.GameplayFlow;
|
using Darkmatter.Core.Contracts.Features.GameplayFlow;
|
||||||
using Darkmatter.Core.Contracts.Features.Progression;
|
using Darkmatter.Core.Contracts.Features.Progression;
|
||||||
@@ -21,6 +22,7 @@ namespace Darkmatter.Features.Capture
|
|||||||
private readonly CaptureConfig _config;
|
private readonly CaptureConfig _config;
|
||||||
private readonly IProgressionSystem _progression;
|
private readonly IProgressionSystem _progression;
|
||||||
private readonly IDrawingTemplateCatalog _catalog;
|
private readonly IDrawingTemplateCatalog _catalog;
|
||||||
|
private readonly IColoringController _coloring;
|
||||||
|
|
||||||
public CaptureSystem(
|
public CaptureSystem(
|
||||||
ICaptureService captureService,
|
ICaptureService captureService,
|
||||||
@@ -29,7 +31,8 @@ namespace Darkmatter.Features.Capture
|
|||||||
IEventBus bus,
|
IEventBus bus,
|
||||||
CaptureConfig config,
|
CaptureConfig config,
|
||||||
IProgressionSystem progression,
|
IProgressionSystem progression,
|
||||||
IDrawingTemplateCatalog catalog)
|
IDrawingTemplateCatalog catalog,
|
||||||
|
IColoringController coloring)
|
||||||
{
|
{
|
||||||
_captureService = captureService;
|
_captureService = captureService;
|
||||||
_galleryService = galleryService;
|
_galleryService = galleryService;
|
||||||
@@ -38,10 +41,16 @@ namespace Darkmatter.Features.Capture
|
|||||||
_config = config;
|
_config = config;
|
||||||
_progression = progression;
|
_progression = progression;
|
||||||
_catalog = catalog;
|
_catalog = catalog;
|
||||||
|
_coloring = coloring;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async UniTask<byte[]> CapturePngAsync(bool saveToGallery = false, CancellationToken ct = default)
|
public async UniTask<byte[]> CapturePngAsync(bool saveToGallery = false, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
// The completion celebration hides the real drawing and shows an animation object
|
||||||
|
// under PaperRoot. Capturing then would grab the animation, not the art, so skip.
|
||||||
|
// A null result keeps the existing thumbnail and skips the gallery write (both no-op on null).
|
||||||
|
if (_coloring.IsPlayingCompletionAnimation) return null;
|
||||||
|
|
||||||
var png = await _captureService.CapturePngAsync(_refs.PaperRoot.gameObject, _config.CaptureScale, ct);
|
var png = await _captureService.CapturePngAsync(_refs.PaperRoot.gameObject, _config.CaptureScale, ct);
|
||||||
if (!saveToGallery || png == null || png.Length == 0) return png;
|
if (!saveToGallery || png == null || png.Length == 0) return png;
|
||||||
|
|
||||||
|
|||||||
@@ -50,12 +50,21 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
|
|||||||
public async UniTask StartAsync(CancellationToken cancellation = new CancellationToken())
|
public async UniTask StartAsync(CancellationToken cancellation = new CancellationToken())
|
||||||
{
|
{
|
||||||
_scopeCts = CancellationTokenSource.CreateLinkedTokenSource(cancellation);
|
_scopeCts = CancellationTokenSource.CreateLinkedTokenSource(cancellation);
|
||||||
|
// Grab the token value up front. If the scope is torn down (scene unload) while the
|
||||||
|
// init below is in flight, the await resumes during disposal — when _scopeCts is already
|
||||||
|
// disposed and its .Token getter would throw ObjectDisposedException. The captured struct
|
||||||
|
// stays safe to read.
|
||||||
|
var ct = _scopeCts.Token;
|
||||||
_returnToMainMenuSubscription = _bus.Subscribe<ReturnToMainMenuSignal>(OnReturnToMainMenu);
|
_returnToMainMenuSubscription = _bus.Subscribe<ReturnToMainMenuSignal>(OnReturnToMainMenu);
|
||||||
_loadingScreen.SetProgress(1f);
|
_loadingScreen.SetProgress(1f);
|
||||||
await _drawingCatalog.InitializeAsync(cancellation);
|
await _drawingCatalog.InitializeAsync(ct);
|
||||||
|
// scope disposed mid-init; nothing left to do. Check the external token too — it's the
|
||||||
|
// one VContainer cancels on teardown, and the linked _scopeCts may lag the callback order.
|
||||||
|
if (cancellation.IsCancellationRequested || ct.IsCancellationRequested) return;
|
||||||
|
|
||||||
if (!_navigatingToGameplay) _loadingScreen.Hide();
|
if (!_navigatingToGameplay) _loadingScreen.Hide();
|
||||||
|
|
||||||
PrewarmInterstitialAdAsync(_scopeCts.Token).Forget();
|
PrewarmInterstitialAdAsync(ct).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async UniTaskVoid PrewarmInterstitialAdAsync(CancellationToken ct)
|
private async UniTaskVoid PrewarmInterstitialAdAsync(CancellationToken ct)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public class ColoringController : IColoringController, IDisposable
|
|||||||
private GameObject _colorButtonPrefab;
|
private GameObject _colorButtonPrefab;
|
||||||
private GameObject _completionAnimationInstance;
|
private GameObject _completionAnimationInstance;
|
||||||
private CompletionAnimationView _completionAnimationView;
|
private CompletionAnimationView _completionAnimationView;
|
||||||
|
private bool _isPlayingCompletionAnimation;
|
||||||
private readonly List<ColorRegionView> _regions = new();
|
private readonly List<ColorRegionView> _regions = new();
|
||||||
private readonly List<ColorButton> _buttons = new();
|
private readonly List<ColorButton> _buttons = new();
|
||||||
private readonly Dictionary<string, Color> _authoredColors = new();
|
private readonly Dictionary<string, Color> _authoredColors = new();
|
||||||
@@ -88,17 +89,21 @@ public class ColoringController : IColoringController, IDisposable
|
|||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsPlayingCompletionAnimation => _isPlayingCompletionAnimation;
|
||||||
|
|
||||||
public async UniTask PlayCompletionAnimationAsync(CancellationToken ct)
|
public async UniTask PlayCompletionAnimationAsync(CancellationToken ct)
|
||||||
{
|
{
|
||||||
if (_completionAnimationInstance == null || _completionAnimationView == null) return;
|
if (_completionAnimationInstance == null || _completionAnimationView == null) return;
|
||||||
if (_colorInstance != null) _colorInstance.SetActive(false);
|
if (_colorInstance != null) _colorInstance.SetActive(false);
|
||||||
_completionAnimationInstance.SetActive(true);
|
_completionAnimationInstance.SetActive(true);
|
||||||
|
_isPlayingCompletionAnimation = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _completionAnimationView.PlayAsync(ct);
|
await _completionAnimationView.PlayAsync(ct);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
_isPlayingCompletionAnimation = false;
|
||||||
if (_completionAnimationInstance != null)
|
if (_completionAnimationInstance != null)
|
||||||
_completionAnimationInstance.SetActive(false);
|
_completionAnimationInstance.SetActive(false);
|
||||||
}
|
}
|
||||||
@@ -133,6 +138,7 @@ public class ColoringController : IColoringController, IDisposable
|
|||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_history.Drop();
|
_history.Drop();
|
||||||
|
_isPlayingCompletionAnimation = false;
|
||||||
|
|
||||||
foreach (var button in _buttons)
|
foreach (var button in _buttons)
|
||||||
if (button != null)
|
if (button != null)
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
using Darkmatter.Core.Contracts.Features.Coloring;
|
using Darkmatter.Core.Contracts.Features.Coloring;
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.Coloring;
|
||||||
|
using Darkmatter.Libs.Observer;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Darkmatter.Features.Coloring.Systems;
|
namespace Darkmatter.Features.Coloring.Systems;
|
||||||
|
|
||||||
public class ColoringStateRepository
|
public class ColoringStateRepository
|
||||||
{
|
{
|
||||||
|
private readonly IEventBus _bus;
|
||||||
|
|
||||||
|
public ColoringStateRepository(IEventBus bus)
|
||||||
|
{
|
||||||
|
_bus = bus;
|
||||||
|
}
|
||||||
|
|
||||||
public IColorPalette SelectedPalette { get; private set; }
|
public IColorPalette SelectedPalette { get; private set; }
|
||||||
public int SelectedIndex { get; private set; }
|
public int SelectedIndex { get; private set; }
|
||||||
public Color SelectedColor =>
|
public Color SelectedColor =>
|
||||||
@@ -29,5 +38,9 @@ public class ColoringStateRepository
|
|||||||
if (idx < 0) return;
|
if (idx < 0) return;
|
||||||
SelectedIndex = idx;
|
SelectedIndex = idx;
|
||||||
SelectedIndexChanged?.Invoke();
|
SelectedIndexChanged?.Invoke();
|
||||||
|
// Surface the user's colour pick on the bus so the tutorial (a root-scoped service that
|
||||||
|
// can't reach this scene-scoped repository directly) can detect it. Only fires on an actual
|
||||||
|
// SelectColor — not on the default selection made in SetPalette.
|
||||||
|
_bus.Publish(new ColorSelectedSignal(idx, color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ namespace Darkmatter.Features.DrawingCatalog
|
|||||||
|
|
||||||
// Unblock InitializeAsync: items are now on screen, so the loading screen can hide.
|
// Unblock InitializeAsync: items are now on screen, so the loading screen can hide.
|
||||||
_controller.NotifyPopulated();
|
_controller.NotifyPopulated();
|
||||||
|
|
||||||
|
// Cue the first-run tutorial that the catalog grid is on screen and tappable.
|
||||||
|
_eventBus.Publish(new DrawingCatalogReadySignal());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ namespace Darkmatter.Features.GameplayFlow.Systems
|
|||||||
|
|
||||||
public async UniTask NextAsync(CancellationToken ct)
|
public async UniTask NextAsync(CancellationToken ct)
|
||||||
{
|
{
|
||||||
|
// Drop any debounced autosave so it can't fire during/after the completion
|
||||||
|
// animation and capture the animation (or an empty paper) into the thumbnail.
|
||||||
|
_autosaveCts?.Cancel();
|
||||||
|
_autosaveCts?.Dispose();
|
||||||
|
_autosaveCts = null;
|
||||||
|
|
||||||
await SaveCurrentAsync(ct);
|
await SaveCurrentAsync(ct);
|
||||||
_refs.Confetti.Play();
|
_refs.Confetti.Play();
|
||||||
_sfx.Play(SfxId.FireWorkLaunch);
|
_sfx.Play(SfxId.FireWorkLaunch);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
private Vector2 _origAnchorMax;
|
private Vector2 _origAnchorMax;
|
||||||
private Vector2 _origPivot;
|
private Vector2 _origPivot;
|
||||||
private bool _origPreserveAspect;
|
private bool _origPreserveAspect;
|
||||||
|
private Vector3 _homeScale = Vector3.one;
|
||||||
|
|
||||||
// Per-drag state
|
// Per-drag state
|
||||||
private RectTransform _rt;
|
private RectTransform _rt;
|
||||||
@@ -45,6 +46,8 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
private Vector2 _trayPosInDragRoot;
|
private Vector2 _trayPosInDragRoot;
|
||||||
private Vector2 _dragSizeDelta;
|
private Vector2 _dragSizeDelta;
|
||||||
private Vector3 _dragLocalScale;
|
private Vector3 _dragLocalScale;
|
||||||
|
private float _dragOrigAlpha;
|
||||||
|
private Tween _dragScaleTween;
|
||||||
private Sequence _previewSeq;
|
private Sequence _previewSeq;
|
||||||
private Sequence _snapSettle;
|
private Sequence _snapSettle;
|
||||||
private bool _locked;
|
private bool _locked;
|
||||||
@@ -68,6 +71,14 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
if (image != null) image.color = color;
|
if (image != null) image.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetAlpha(float a)
|
||||||
|
{
|
||||||
|
if (image == null) return;
|
||||||
|
var c = image.color;
|
||||||
|
c.a = a;
|
||||||
|
image.color = c;
|
||||||
|
}
|
||||||
|
|
||||||
public void Setup(
|
public void Setup(
|
||||||
ShapeSO shape,
|
ShapeSO shape,
|
||||||
SlotMarker[] candidateSlots,
|
SlotMarker[] candidateSlots,
|
||||||
@@ -95,6 +106,7 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
_origAnchorMax = RectTransform.anchorMax;
|
_origAnchorMax = RectTransform.anchorMax;
|
||||||
_origPivot = RectTransform.pivot;
|
_origPivot = RectTransform.pivot;
|
||||||
_origPreserveAspect = image != null && image.preserveAspect;
|
_origPreserveAspect = image != null && image.preserveAspect;
|
||||||
|
_homeScale = RectTransform.localScale;
|
||||||
|
|
||||||
image.sprite = shape.Sprite;
|
image.sprite = shape.Sprite;
|
||||||
ApplyTrayPose();
|
ApplyTrayPose();
|
||||||
@@ -104,6 +116,10 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
{
|
{
|
||||||
if (_locked) return;
|
if (_locked) return;
|
||||||
|
|
||||||
|
// Kill any tweens still running on this piece (e.g. a return/preview from a
|
||||||
|
// re-grab mid-animation) so the new drag starts from a clean, known pose.
|
||||||
|
Tween.StopAll(onTarget: RectTransform);
|
||||||
|
|
||||||
if (_dragRoot != null && RectTransform.parent != _dragRoot)
|
if (_dragRoot != null && RectTransform.parent != _dragRoot)
|
||||||
{
|
{
|
||||||
RectTransform.SetParent(_dragRoot, worldPositionStays: true);
|
RectTransform.SetParent(_dragRoot, worldPositionStays: true);
|
||||||
@@ -114,11 +130,20 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
_eventCam = e.pressEventCamera;
|
_eventCam = e.pressEventCamera;
|
||||||
_trayPosInDragRoot = RectTransform.anchoredPosition;
|
_trayPosInDragRoot = RectTransform.anchoredPosition;
|
||||||
_dragSizeDelta = RectTransform.sizeDelta;
|
_dragSizeDelta = RectTransform.sizeDelta;
|
||||||
_dragLocalScale = RectTransform.localScale;
|
// Use the canonical resting scale, not the live value, so a re-grab mid-tween
|
||||||
|
// can't bake a drifted scale into the drag base.
|
||||||
|
_dragLocalScale = _homeScale;
|
||||||
|
RectTransform.localScale = _homeScale;
|
||||||
_grabOffset = RectTransform.anchoredPosition - ScreenToLocal(e.position);
|
_grabOffset = RectTransform.anchoredPosition - ScreenToLocal(e.position);
|
||||||
_inPreview = false;
|
_inPreview = false;
|
||||||
|
|
||||||
Tween.LocalScale(RectTransform, _dragLocalScale * _cfg.DragScale, _cfg.SnapDuration, Ease.OutQuad);
|
if (image != null)
|
||||||
|
{
|
||||||
|
_dragOrigAlpha = image.color.a;
|
||||||
|
SetAlpha(_cfg.DragAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dragScaleTween = Tween.Scale(RectTransform, _dragLocalScale * _cfg.DragScale, _cfg.SnapDuration, Ease.OutQuad);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDrag(PointerEventData e)
|
public void OnDrag(PointerEventData e)
|
||||||
@@ -156,6 +181,12 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
{
|
{
|
||||||
if (_locked) return;
|
if (_locked) return;
|
||||||
|
|
||||||
|
// Stop the begin-drag scale-up so it can't fight the return/snap pose.
|
||||||
|
// Leave _previewSeq alive — the snap path lets it settle.
|
||||||
|
if (_dragScaleTween.isAlive) _dragScaleTween.Stop();
|
||||||
|
|
||||||
|
SetAlpha(_dragOrigAlpha);
|
||||||
|
|
||||||
var target = FindSlotUnder(e.position);
|
var target = FindSlotUnder(e.position);
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
@@ -184,16 +215,18 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
|
|
||||||
private void AnimatePreviewPose(bool toSlot)
|
private void AnimatePreviewPose(bool toSlot)
|
||||||
{
|
{
|
||||||
|
if (_dragScaleTween.isAlive) _dragScaleTween.Stop();
|
||||||
if (_previewSeq.isAlive) _previewSeq.Stop();
|
if (_previewSeq.isAlive) _previewSeq.Stop();
|
||||||
|
|
||||||
if (toSlot && _activeSlot != null)
|
if (toSlot && _activeSlot != null)
|
||||||
{
|
{
|
||||||
var slot = _activeSlot.RectTransform;
|
var slot = _activeSlot.RectTransform;
|
||||||
|
SlotPoseInDragSpace(out var slotRot, out var slotScale);
|
||||||
if (image != null) image.preserveAspect = false;
|
if (image != null) image.preserveAspect = false;
|
||||||
_previewSeq = Sequence.Create()
|
_previewSeq = Sequence.Create()
|
||||||
.Group(Tween.UIAnchoredPosition(RectTransform, SlotPosInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
|
.Group(Tween.UIAnchoredPosition(RectTransform, SlotPosInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
|
||||||
.Group(Tween.LocalScale(RectTransform, SlotScaleInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
|
.Group(Tween.LocalScale(RectTransform, slotScale, _cfg.SnapDuration, Ease.OutQuad))
|
||||||
.Group(Tween.LocalRotation(RectTransform, SlotRotInDragSpace(), _cfg.SnapDuration, Ease.OutQuad))
|
.Group(Tween.LocalRotation(RectTransform, slotRot, _cfg.SnapDuration, Ease.OutQuad))
|
||||||
.Group(Tween.UISizeDelta(RectTransform, slot.rect.size, _cfg.SnapDuration, Ease.OutQuad));
|
.Group(Tween.UISizeDelta(RectTransform, slot.rect.size, _cfg.SnapDuration, Ease.OutQuad));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -222,19 +255,25 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
_inPreview = false;
|
_inPreview = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Quaternion SlotRotInDragSpace()
|
// Rotation + signed scale that make the piece (a child of the drag root) match the pose
|
||||||
|
// it will have once parented into the slot. Derived from the slot's local X/Y axes
|
||||||
|
// expressed in drag-root space: their angle gives the rotation, their lengths the scale,
|
||||||
|
// and their handedness the mirror. A quaternion + lossyScale pair can't encode a negative
|
||||||
|
// (mirrored) scale, which is why flipped slots previewed at the wrong orientation while the
|
||||||
|
// snapped piece — which inherits the slot's real transform — looked correct.
|
||||||
|
private void SlotPoseInDragSpace(out Quaternion rot, out Vector3 scale)
|
||||||
{
|
{
|
||||||
return Quaternion.Inverse(_parentRect.rotation) * _activeSlot.RectTransform.rotation;
|
var slot = _activeSlot.RectTransform;
|
||||||
}
|
Vector3 r = _parentRect.InverseTransformVector(slot.TransformVector(Vector3.right));
|
||||||
|
Vector3 u = _parentRect.InverseTransformVector(slot.TransformVector(Vector3.up));
|
||||||
|
|
||||||
private Vector3 SlotScaleInDragSpace()
|
float angle = Mathf.Atan2(r.y, r.x) * Mathf.Rad2Deg;
|
||||||
{
|
float sx = new Vector2(r.x, r.y).magnitude;
|
||||||
Vector3 parentLossy = _parentRect.lossyScale;
|
float sy = new Vector2(u.x, u.y).magnitude;
|
||||||
Vector3 slotLossy = _activeSlot.RectTransform.lossyScale;
|
if (r.x * u.y - r.y * u.x < 0f) sy = -sy; // mirrored hierarchy -> flip one axis
|
||||||
return new Vector3(
|
|
||||||
slotLossy.x / Mathf.Max(0.0001f, parentLossy.x),
|
rot = Quaternion.Euler(0f, 0f, angle);
|
||||||
slotLossy.y / Mathf.Max(0.0001f, parentLossy.y),
|
scale = new Vector3(sx, sy, 1f);
|
||||||
slotLossy.z / Mathf.Max(0.0001f, parentLossy.z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SnapInternal()
|
internal void SnapInternal()
|
||||||
@@ -361,6 +400,7 @@ namespace Darkmatter.Features.ShapeBuilder.UI
|
|||||||
{
|
{
|
||||||
RectTransform.sizeDelta = _traySize;
|
RectTransform.sizeDelta = _traySize;
|
||||||
RectTransform.localRotation = Quaternion.identity;
|
RectTransform.localRotation = Quaternion.identity;
|
||||||
|
RectTransform.localScale = _homeScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 ScreenToLocal(Vector2 screenPos)
|
private Vector2 ScreenToLocal(Vector2 screenPos)
|
||||||
|
|||||||
8
Assets/Darkmatter/Code/Features/Tutorial.meta
Normal file
8
Assets/Darkmatter/Code/Features/Tutorial.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5913ea683733a4597b3cf6b3903811a0
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Darkmatter/Code/Features/Tutorial/Editor.meta
Normal file
8
Assets/Darkmatter/Code/Features/Tutorial/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d69b43c419c8d4f13b930f1dc30359ff
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using Darkmatter.Features.Tutorial.Systems;
|
||||||
|
using Darkmatter.Libs.PlayerPrefs;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Darkmatter.Features.Tutorial.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// QA helpers for the forced-once tutorial (editor only — stripped from player builds).
|
||||||
|
/// </summary>
|
||||||
|
public static class TutorialDebugMenu
|
||||||
|
{
|
||||||
|
[MenuItem("Tools/Darkmatter/Tutorial/Reset (run again next launch)")]
|
||||||
|
public static void Reset()
|
||||||
|
{
|
||||||
|
ProtectedPlayerPrefs.SetBool(TutorialGateService.CompletedKey, false);
|
||||||
|
ProtectedPlayerPrefs.Save();
|
||||||
|
Debug.Log("[Tutorial] Reset. Note: it also requires zero completed drawings to run.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Tools/Darkmatter/Tutorial/Mark Completed (skip)")]
|
||||||
|
public static void MarkCompleted()
|
||||||
|
{
|
||||||
|
ProtectedPlayerPrefs.SetBool(TutorialGateService.CompletedKey, true);
|
||||||
|
ProtectedPlayerPrefs.Save();
|
||||||
|
Debug.Log("[Tutorial] Marked completed — it will not run.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9a54326b3914a43ffa206b427980908e
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "Features.Tutorial",
|
||||||
|
"rootNamespace": "Darkmatter.Features.Tutorial",
|
||||||
|
"references": [
|
||||||
|
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
|
||||||
|
"GUID:b4c9f7fbf1e144933a1797dc208ece5f",
|
||||||
|
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
|
||||||
|
"GUID:564d11c0820a9455c8821cd85e9d0fd1",
|
||||||
|
"GUID:2ca8c3a66565544118d3d52d3922933b",
|
||||||
|
"GUID:4cede189a43c349069c614e305683720",
|
||||||
|
"GUID:eb9b7ee4936ff42bebd83ca110182103",
|
||||||
|
"GUID:995166e584dda4ff98501f62b07aa9cb",
|
||||||
|
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
|
||||||
|
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||||
|
"GUID:80ecb87cae9c44d19824e70ea7229748",
|
||||||
|
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||||
|
],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a6beea6626ba14397b6be37b16032fb5
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Darkmatter/Code/Features/Tutorial/Installers.meta
Normal file
8
Assets/Darkmatter/Code/Features/Tutorial/Installers.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ed3d9a0f27b0a486ab8dfe44d39ce2f9
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using Darkmatter.Core.Contracts.Features.Tutorial;
|
||||||
|
using Darkmatter.Core.Data.Static.Features.Tutorial;
|
||||||
|
using Darkmatter.Features.Tutorial.Systems;
|
||||||
|
using Darkmatter.Features.Tutorial.UI;
|
||||||
|
using Darkmatter.Libs.Installers;
|
||||||
|
using UnityEngine;
|
||||||
|
using VContainer;
|
||||||
|
using VContainer.Unity;
|
||||||
|
|
||||||
|
namespace Darkmatter.Features.Tutorial.Installers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the tutorial in the Boot scene's RootLifetimeScope so the director, overlay and
|
||||||
|
/// gate are single instances that survive every Colorbook -> Gameplay scene swap (same pattern
|
||||||
|
/// as the loading screen). Drop this component on a GameObject in the Boot scene and add it to
|
||||||
|
/// RootLifetimeScope.serviceModules.
|
||||||
|
/// </summary>
|
||||||
|
public class TutorialFeatureModule : MonoBehaviour, IModule
|
||||||
|
{
|
||||||
|
[SerializeField] private TutorialOverlayView overlayView;
|
||||||
|
[SerializeField] private TutorialStepsConfig config;
|
||||||
|
|
||||||
|
public void Register(IContainerBuilder builder)
|
||||||
|
{
|
||||||
|
if (overlayView != null)
|
||||||
|
builder.RegisterComponent<ITutorialOverlay>(overlayView);
|
||||||
|
if (config != null)
|
||||||
|
builder.RegisterInstance(config);
|
||||||
|
|
||||||
|
builder.Register<ITutorialGate, TutorialGateService>(Lifetime.Singleton);
|
||||||
|
builder.RegisterEntryPoint<TutorialDirector>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 97ce2c486cc8541d1ab1d83fda7f8eda
|
||||||
69
Assets/Darkmatter/Code/Features/Tutorial/SETUP.md
Normal file
69
Assets/Darkmatter/Code/Features/Tutorial/SETUP.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Tutorial — Unity Editor setup
|
||||||
|
|
||||||
|
All C# is in place. These steps are the GUI wiring the code can't do. The tutorial is **forced
|
||||||
|
once**: a first-time player (no completed drawings, flag unset) is guided through pick → drag →
|
||||||
|
finish → pick colour → paint → Next, with a watchdog that fails open if anything stalls.
|
||||||
|
|
||||||
|
## 1. Create the config asset
|
||||||
|
- Project window → right-click → **Create ▸ Darkmatter ▸ Tutorial ▸ Steps Config**.
|
||||||
|
- Save as `Assets/Darkmatter/Data/Settings/Tutorial/TutorialStepsConfig.asset`.
|
||||||
|
- Edit the step copy / watchdog timeout if desired.
|
||||||
|
|
||||||
|
## 2. Overlay prefab — single-image circular cutout
|
||||||
|
`Assets/Darkmatter/Content/Colorbook UI/Prefabs/UI/TutorialOverlayCanvas.prefab`. Target hierarchy:
|
||||||
|
|
||||||
|
```
|
||||||
|
TutorialOverlayCanvas Canvas (Overlay, Sort Order 5000) + CanvasScaler + GraphicRaycaster
|
||||||
|
+ CanvasGroup + TutorialFeatureModule (overlayView + config assigned)
|
||||||
|
Area full-stretch RectTransform (pivot 0.5) + TutorialOverlayView
|
||||||
|
Dim ONE full-stretch black Image, raycast ON, + TutorialCutoutDim component
|
||||||
|
Halo ring sprite, raycast OFF
|
||||||
|
Hand hand sprite, raycast OFF
|
||||||
|
BubbleRoot
|
||||||
|
BubbleBg bubble sprite, raycast OFF
|
||||||
|
Text TMP_Text (Fredoka SemiBold), raycast OFF
|
||||||
|
```
|
||||||
|
|
||||||
|
The dim is a **single full-screen Image**; the `TutorialCutoutDim` component drives the
|
||||||
|
`Darkmatter/TutorialCutout` shader to punch a soft **circular hole** over the target, and acts as a
|
||||||
|
raycast filter so taps inside the hole reach the real button while everything else is blocked.
|
||||||
|
|
||||||
|
`TutorialCutoutDim` fields: **Cutout Shader** = `Darkmatter/TutorialCutout`, **Dim Image** = the
|
||||||
|
Dim's own Image. (It builds a material instance at runtime — no material asset needed.)
|
||||||
|
|
||||||
|
`TutorialOverlayView` fields: Canvas, RootGroup (root CanvasGroup), **Cutout** (the Dim's
|
||||||
|
TutorialCutoutDim), Halo, Hand, BubbleRoot, BubbleText.
|
||||||
|
|
||||||
|
Sprites (optional polish) under `Assets/Darkmatter/Content/Colorbook UI/Sprites/Tutorial/`:
|
||||||
|
ring for Halo, finger for Hand (turn **Preserve Aspect** on), bubble for BubbleBg.
|
||||||
|
|
||||||
|
## 3. Put it in the Boot scene
|
||||||
|
Open `Assets/Darkmatter/Scenes/Boot.unity`:
|
||||||
|
1. Drag the **TutorialOverlayCanvas** prefab into the scene (persistent — Boot is never unloaded,
|
||||||
|
like the loading screen).
|
||||||
|
2. Make sure its `TutorialFeatureModule` **Config** field points at `TutorialStepsConfig.asset`.
|
||||||
|
3. Select the **RootLifetimeScope** GameObject and add the prefab's root (it carries the
|
||||||
|
`TutorialFeatureModule`) to the **Service Modules** array — same as every other root module.
|
||||||
|
|
||||||
|
That's the whole wiring: assign config + drop in Boot + add to serviceModules.
|
||||||
|
|
||||||
|
## 4. (Optional) register the prefs key for documentation
|
||||||
|
The flag is stored via `ProtectedPlayerPrefs` under the key `Tutorial.Completed` (hashed, no
|
||||||
|
registry validation — it already works). To list it in the editor for clarity, add it via
|
||||||
|
**Tools ▸ Darkmatter ▸ PlayerPrefs Editor** (type Bool).
|
||||||
|
|
||||||
|
## 5. Test
|
||||||
|
- **Tools ▸ Darkmatter ▸ Tutorial ▸ Reset**, and clear progression (so there are no completed
|
||||||
|
drawings), then Play from **Boot**.
|
||||||
|
- After the intro you should be guided through the whole loop. Relaunch → it must NOT reappear.
|
||||||
|
- See the verification checklist in `/Users/darkmatter/.claude/plans/help-me-design-a-splendid-hearth.md`.
|
||||||
|
|
||||||
|
## How it hooks in (no gameplay prefab changes needed)
|
||||||
|
- The director (root singleton) arms on `IntroCompletedSignal`, then awaits existing gameplay
|
||||||
|
signals one per step. Spawned targets (catalog cell, piece, colour button, region, Next) are
|
||||||
|
found at runtime with `FindObjectsByType`, so no scene wiring of targets is required.
|
||||||
|
- Two tiny signals were added for things Find can't observe: `DrawingCatalogReadySignal`
|
||||||
|
(catalog presenter) and `ColorSelectedSignal` (coloring state repository).
|
||||||
|
- Input gating is the overlay CanvasGroup's `blocksRaycasts`: ON for blocking tap steps (dim
|
||||||
|
swallows touches, the empty hole passes through to the real button), OFF for the drag step so the
|
||||||
|
piece stays visible and draggable.
|
||||||
7
Assets/Darkmatter/Code/Features/Tutorial/SETUP.md.meta
Normal file
7
Assets/Darkmatter/Code/Features/Tutorial/SETUP.md.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c9fcf6edd0d00433bb41f63ff3b4b1b7
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Darkmatter/Code/Features/Tutorial/Systems.meta
Normal file
8
Assets/Darkmatter/Code/Features/Tutorial/Systems.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc34be257ded14eacbf3059d20b0c758
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Darkmatter.Core; // DrawingCatalogReadySignal, OpenArtBook/ColorBook, ReturnToMainMenu
|
||||||
|
using Darkmatter.Core.Contracts.Features.Tutorial;
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.AppBoot; // IntroCompletedSignal
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.Coloring; // ColorApplied/ColorSelected/RegionsInitialized
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.Drawing; // DrawingSelectedSignal
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.GameplayFlow; // DrawingCompletedSignal
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.ShapeBuilder; // ShapeBuilderStarted/PieceSnapped/ShapeAssembled
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.Tutorial;
|
||||||
|
using Darkmatter.Core.Data.Static.Features.Tutorial;
|
||||||
|
using Darkmatter.Features.Coloring.UI; // ColorButton, ColorRegionView
|
||||||
|
using Darkmatter.Features.DrawingCatalog; // DrawingCatalogButton
|
||||||
|
using Darkmatter.Features.GameplayFlow.UI; // NextButtonView
|
||||||
|
using Darkmatter.Features.ShapeBuilder.UI; // ShapePiece, SlotMarker
|
||||||
|
using Darkmatter.Libs.Observer;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using VContainer.Unity;
|
||||||
|
|
||||||
|
namespace Darkmatter.Features.Tutorial.Systems
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Drives the one-time, forced guided tutorial. A single root-scoped singleton that arms on
|
||||||
|
/// <see cref="IntroCompletedSignal"/> and walks a fixed, linear sequence by awaiting one gameplay
|
||||||
|
/// signal per step. Watchdog timeouts make every wait fail open so a child is never trapped.
|
||||||
|
///
|
||||||
|
/// Navigation is handled so the overlay never gets stranded: opening the ArtBook or leaving to
|
||||||
|
/// the menu hides it (and re-shows the current step on return), and going Back to the catalog
|
||||||
|
/// mid-gameplay restarts the tutorial from step 1. A generation counter keeps a restarted run
|
||||||
|
/// from racing the cancelled one. Targets are found at runtime via FindObjectsByType.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TutorialDirector : IStartable, IDisposable
|
||||||
|
{
|
||||||
|
private readonly IEventBus _bus;
|
||||||
|
private readonly ITutorialOverlay _overlay;
|
||||||
|
private readonly ITutorialGate _gate;
|
||||||
|
private readonly TutorialStepsConfig _config;
|
||||||
|
|
||||||
|
private IDisposable _introSub;
|
||||||
|
private readonly List<IDisposable> _navSubs = new();
|
||||||
|
private CancellationTokenSource _runCts;
|
||||||
|
private CancellationToken _ct;
|
||||||
|
private bool _completed;
|
||||||
|
private bool _suspended;
|
||||||
|
private Action _reshow;
|
||||||
|
private int _stepIndex;
|
||||||
|
private int _gen;
|
||||||
|
|
||||||
|
public TutorialDirector(IEventBus bus, ITutorialOverlay overlay, ITutorialGate gate, TutorialStepsConfig config)
|
||||||
|
{
|
||||||
|
_bus = bus;
|
||||||
|
_overlay = overlay;
|
||||||
|
_gate = gate;
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_introSub = _bus.Subscribe<IntroCompletedSignal>(OnIntroCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnIntroCompleted(IntroCompletedSignal _)
|
||||||
|
{
|
||||||
|
_introSub?.Dispose();
|
||||||
|
_introSub = null;
|
||||||
|
|
||||||
|
if (!_gate.ShouldRun) return;
|
||||||
|
|
||||||
|
// Run-lifetime navigation handling (persists across restarts).
|
||||||
|
_navSubs.Add(_bus.Subscribe<OpenArtBookSignal>(_ => Suspend()));
|
||||||
|
_navSubs.Add(_bus.Subscribe<ReturnToMainMenuSignal>(_ => Suspend()));
|
||||||
|
_navSubs.Add(_bus.Subscribe<OpenColorBookSignal>(_ => Resume()));
|
||||||
|
_navSubs.Add(_bus.Subscribe<DrawingCatalogReadySignal>(OnCatalogReadyGlobal));
|
||||||
|
|
||||||
|
StartRun(skipCatalogWait: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartRun(bool skipCatalogWait)
|
||||||
|
{
|
||||||
|
_runCts?.Cancel();
|
||||||
|
_runCts?.Dispose();
|
||||||
|
_runCts = new CancellationTokenSource();
|
||||||
|
_ct = _runCts.Token;
|
||||||
|
_gen++;
|
||||||
|
_suspended = false;
|
||||||
|
_reshow = null;
|
||||||
|
_stepIndex = 0;
|
||||||
|
_overlay.HideInstant();
|
||||||
|
RunAsync(_gen, skipCatalogWait).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opening the ArtBook / leaving to menu: hide the overlay but keep awaiting the current step.
|
||||||
|
private void Suspend()
|
||||||
|
{
|
||||||
|
_suspended = true;
|
||||||
|
_overlay.HideInstant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returning to the colour book (ArtBook closed): re-show the current step.
|
||||||
|
private void Resume()
|
||||||
|
{
|
||||||
|
if (!_suspended) return;
|
||||||
|
_suspended = false;
|
||||||
|
_reshow?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The catalog re-appeared while we were mid-gameplay -> the player went Back. Restart from
|
||||||
|
// step 1 (the catalog is already on screen, so skip the wait). Excludes step 6+, whose own
|
||||||
|
// completion loads the catalog.
|
||||||
|
private void OnCatalogReadyGlobal(DrawingCatalogReadySignal _)
|
||||||
|
{
|
||||||
|
if (!_completed && _stepIndex >= 2 && _stepIndex <= 5)
|
||||||
|
StartRun(skipCatalogWait: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowStep(Action show)
|
||||||
|
{
|
||||||
|
_reshow = show;
|
||||||
|
if (!_suspended) show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async UniTaskVoid RunAsync(int gen, bool skipCatalogWait)
|
||||||
|
{
|
||||||
|
if (gen == _gen) _bus.Publish(new TutorialStartedSignal());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await StepsAsync(skipCatalogWait);
|
||||||
|
if (gen == _gen) Complete();
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// Cancelled by a restart or app shutdown — the newer run (if any) owns the overlay.
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[Tutorial] Aborted with error, failing open: {e}");
|
||||||
|
if (gen == _gen) Complete();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gen == _gen) _overlay.HideInstant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async UniTask StepsAsync(bool skipCatalogWait)
|
||||||
|
{
|
||||||
|
// Step 1 — pick a drawing (Colorbook scene).
|
||||||
|
_stepIndex = 1;
|
||||||
|
if (!skipCatalogWait)
|
||||||
|
{
|
||||||
|
if (!await WaitForSignalAsync<DrawingCatalogReadySignal>()) return;
|
||||||
|
}
|
||||||
|
await UniTask.NextFrame(_ct);
|
||||||
|
ShowStep(() => ShowBlockingTap(FindFirstCatalogCell(), _config.PickText));
|
||||||
|
if (!await WaitForActionAsync<DrawingSelectedSignal>()) return;
|
||||||
|
EndStep("pick", 1);
|
||||||
|
|
||||||
|
// Step 2 — drag the first piece (Gameplay scene).
|
||||||
|
_stepIndex = 2;
|
||||||
|
if (!await WaitForSignalAsync<ShapeBuilderStartedSignal>()) return;
|
||||||
|
await UniTask.NextFrame(_ct);
|
||||||
|
ShowStep(() =>
|
||||||
|
{
|
||||||
|
var (pieceRect, slotRect) = FindFirstPieceAndSlot();
|
||||||
|
if (pieceRect != null) _overlay.ShowDrag(pieceRect, slotRect, _config.DragText);
|
||||||
|
else Debug.LogWarning("[Tutorial] No draggable piece found for the drag step.");
|
||||||
|
});
|
||||||
|
if (!await WaitForActionAsync<PieceSnappedSignal>()) return; // any snap teaches the gesture
|
||||||
|
EndStep("drag", 2);
|
||||||
|
|
||||||
|
// Step 3 — finish the rest of the puzzle freely (non-blocking hint).
|
||||||
|
_stepIndex = 3;
|
||||||
|
ShowStep(() => _overlay.ShowTap(null, _config.FinishText, blockInput: false));
|
||||||
|
if (!await WaitForActionAsync<ShapeAssembledSignal>()) return;
|
||||||
|
EndStep("finish", 3);
|
||||||
|
|
||||||
|
// Step 4 — pick a colour.
|
||||||
|
_stepIndex = 4;
|
||||||
|
if (!await WaitForSignalAsync<RegionsInitializedSignal>()) return;
|
||||||
|
await UniTask.NextFrame(_ct);
|
||||||
|
ShowStep(() => ShowBlockingTap(FindFirstColorButton(), _config.ColorText));
|
||||||
|
if (!await WaitForActionAsync<ColorSelectedSignal>()) return;
|
||||||
|
EndStep("color", 4);
|
||||||
|
|
||||||
|
// Step 5 — paint a region.
|
||||||
|
_stepIndex = 5;
|
||||||
|
ShowStep(() => ShowBlockingTap(FindLargestRegion(), _config.PaintText));
|
||||||
|
if (!await WaitForActionAsync<ColorAppliedSignal>()) return;
|
||||||
|
EndStep("paint", 5);
|
||||||
|
|
||||||
|
// Step 6 — press Next.
|
||||||
|
_stepIndex = 6;
|
||||||
|
await UniTask.NextFrame(_ct);
|
||||||
|
ShowStep(() => ShowBlockingTap(FindNextButton(), _config.NextText));
|
||||||
|
if (!await WaitForActionAsync<DrawingCompletedSignal>()) return;
|
||||||
|
EndStep("next", 6);
|
||||||
|
|
||||||
|
// Step 7 — celebrate.
|
||||||
|
_stepIndex = 7;
|
||||||
|
await _overlay.ShowToastAsync(_config.DoneText, _ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowBlockingTap(RectTransform target, string message)
|
||||||
|
{
|
||||||
|
if (target == null) Debug.LogWarning($"[Tutorial] No target found for step: \"{message}\"");
|
||||||
|
_overlay.ShowTap(target, message, blockInput: target != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndStep(string id, int index)
|
||||||
|
{
|
||||||
|
_reshow = null;
|
||||||
|
_bus.Publish(new TutorialStepCompletedSignal(id, index));
|
||||||
|
_overlay.HideInstant();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Complete()
|
||||||
|
{
|
||||||
|
if (_completed) return;
|
||||||
|
_completed = true;
|
||||||
|
_gate.MarkCompleted();
|
||||||
|
_bus.Publish(new TutorialCompletedSignal());
|
||||||
|
DisposeNav();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preconditions (a system/scene must become ready): time out so a stalled load fails open.
|
||||||
|
private UniTask<bool> WaitForSignalAsync<T>(Func<T, bool> predicate = null) where T : struct =>
|
||||||
|
WaitCoreAsync(_config.StepTimeoutSeconds, predicate);
|
||||||
|
|
||||||
|
// The child's own action (drag/tap/paint): defaults to no timeout (ActionTimeoutSeconds = 0) so
|
||||||
|
// the hint stays put until they do it; a positive value re-enables a safety net.
|
||||||
|
private UniTask<bool> WaitForActionAsync<T>(Func<T, bool> predicate = null) where T : struct =>
|
||||||
|
WaitCoreAsync(_config.ActionTimeoutSeconds, predicate);
|
||||||
|
|
||||||
|
private async UniTask<bool> WaitCoreAsync<T>(float timeoutSeconds, Func<T, bool> predicate) where T : struct
|
||||||
|
{
|
||||||
|
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(_ct);
|
||||||
|
var tcs = new UniTaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
var sub = _bus.Subscribe<T>(evt =>
|
||||||
|
{
|
||||||
|
if (predicate == null || predicate(evt)) tcs.TrySetResult(true);
|
||||||
|
});
|
||||||
|
if (timeoutSeconds > 0f) TimeoutAsync(timeoutSeconds, timeoutCts.Token, tcs).Forget();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (_ct.Register(() => tcs.TrySetCanceled(_ct)))
|
||||||
|
return await tcs.Task;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
sub.Dispose();
|
||||||
|
timeoutCts.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async UniTaskVoid TimeoutAsync(float seconds, CancellationToken ct, UniTaskCompletionSource<bool> tcs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await UniTask.Delay(TimeSpan.FromSeconds(seconds), DelayType.UnscaledDeltaTime, cancellationToken: ct);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcs.TrySetResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Runtime target discovery ─────────────────────────────────────────
|
||||||
|
|
||||||
|
private static RectTransform FindFirstCatalogCell()
|
||||||
|
{
|
||||||
|
var buttons = UnityEngine.Object.FindObjectsByType<DrawingCatalogButton>(FindObjectsSortMode.None);
|
||||||
|
var cell = LowestSiblingActive(buttons);
|
||||||
|
ScrollToStart(cell); // catalog may be on another page — bring the first item into view
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (RectTransform piece, RectTransform slot) FindFirstPieceAndSlot()
|
||||||
|
{
|
||||||
|
var pieces = UnityEngine.Object.FindObjectsByType<ShapePiece>(FindObjectsSortMode.None);
|
||||||
|
ShapePiece piece = null;
|
||||||
|
foreach (var p in pieces)
|
||||||
|
{
|
||||||
|
if (p == null || p.IsLocked || !p.gameObject.activeInHierarchy) continue;
|
||||||
|
piece = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (piece == null) return (null, null);
|
||||||
|
|
||||||
|
RectTransform slotRect = null;
|
||||||
|
var slots = UnityEngine.Object.FindObjectsByType<SlotMarker>(FindObjectsSortMode.None);
|
||||||
|
foreach (var s in slots)
|
||||||
|
{
|
||||||
|
if (s == null || s.IsOccupied) continue;
|
||||||
|
if (s.SlotId == piece.PieceId) { slotRect = s.RectTransform; break; }
|
||||||
|
}
|
||||||
|
return (piece.RectTransform, slotRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RectTransform FindFirstColorButton()
|
||||||
|
{
|
||||||
|
var buttons = UnityEngine.Object.FindObjectsByType<ColorButton>(FindObjectsSortMode.None);
|
||||||
|
return LowestSiblingActive(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RectTransform FindLargestRegion()
|
||||||
|
{
|
||||||
|
var regions = UnityEngine.Object.FindObjectsByType<ColorRegionView>(FindObjectsSortMode.None);
|
||||||
|
ColorRegionView best = null;
|
||||||
|
float bestArea = -1f;
|
||||||
|
foreach (var r in regions)
|
||||||
|
{
|
||||||
|
if (r == null || !r.gameObject.activeInHierarchy) continue;
|
||||||
|
var size = ((RectTransform)r.transform).rect.size;
|
||||||
|
var area = Mathf.Abs(size.x * size.y);
|
||||||
|
if (area > bestArea) { bestArea = area; best = r; }
|
||||||
|
}
|
||||||
|
return best != null ? (RectTransform)best.transform : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RectTransform FindNextButton()
|
||||||
|
{
|
||||||
|
var view = UnityEngine.Object.FindFirstObjectByType<NextButtonView>();
|
||||||
|
return view != null ? (RectTransform)view.transform : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first item = lowest sibling index. Cells are instantiated in data order under a layout
|
||||||
|
// group, so sibling 0 is the leftmost/first; visibility is handled by scrolling it into view.
|
||||||
|
private static RectTransform LowestSiblingActive<T>(T[] components) where T : Component
|
||||||
|
{
|
||||||
|
T best = null;
|
||||||
|
var bestIndex = int.MaxValue;
|
||||||
|
foreach (var c in components)
|
||||||
|
{
|
||||||
|
if (c == null || !c.gameObject.activeInHierarchy) continue;
|
||||||
|
var index = c.transform.GetSiblingIndex();
|
||||||
|
if (index < bestIndex) { bestIndex = index; best = c; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return best != null ? (RectTransform)best.transform : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scrolls the target's ScrollRect to the start so a paged-off first item becomes visible.
|
||||||
|
private static void ScrollToStart(RectTransform cell)
|
||||||
|
{
|
||||||
|
if (cell == null) return;
|
||||||
|
var scroll = cell.GetComponentInParent<ScrollRect>();
|
||||||
|
if (scroll == null) return;
|
||||||
|
scroll.StopMovement();
|
||||||
|
if (scroll.horizontal) scroll.horizontalNormalizedPosition = 0f;
|
||||||
|
if (scroll.vertical) scroll.verticalNormalizedPosition = 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisposeNav()
|
||||||
|
{
|
||||||
|
foreach (var s in _navSubs) s?.Dispose();
|
||||||
|
_navSubs.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_introSub?.Dispose();
|
||||||
|
DisposeNav();
|
||||||
|
_runCts?.Cancel();
|
||||||
|
_runCts?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d96038ffc4ea74bca8143d84655e8b4a
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Darkmatter.Core.Contracts.Features.Progression;
|
||||||
|
using Darkmatter.Core.Contracts.Features.Tutorial;
|
||||||
|
using Darkmatter.Libs.PlayerPrefs;
|
||||||
|
|
||||||
|
namespace Darkmatter.Features.Tutorial.Systems
|
||||||
|
{
|
||||||
|
public sealed class TutorialGateService : ITutorialGate
|
||||||
|
{
|
||||||
|
// Stored through ProtectedPlayerPrefs (keys are hashed, not validated against the registry,
|
||||||
|
// so a local constant is safe). Optionally register it in Tools > Darkmatter > PlayerPrefs
|
||||||
|
// Editor for documentation.
|
||||||
|
public const string CompletedKey = "Tutorial.Completed";
|
||||||
|
|
||||||
|
private readonly IProgressionSystem _progression;
|
||||||
|
|
||||||
|
public TutorialGateService(IProgressionSystem progression)
|
||||||
|
{
|
||||||
|
_progression = progression;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Belt-and-suspenders: a player who cleared prefs but already has finished drawings is not a
|
||||||
|
// first-timer, so don't re-tutorialize them.
|
||||||
|
public bool ShouldRun =>
|
||||||
|
!ProtectedPlayerPrefs.GetBool(CompletedKey, false)
|
||||||
|
&& _progression.CompletedTemplateIds.Count == 0;
|
||||||
|
|
||||||
|
public void MarkCompleted()
|
||||||
|
{
|
||||||
|
ProtectedPlayerPrefs.SetBool(CompletedKey, true);
|
||||||
|
ProtectedPlayerPrefs.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3ee1f88d72ddf4d99bf5669a36cc52bc
|
||||||
8
Assets/Darkmatter/Code/Features/Tutorial/UI.meta
Normal file
8
Assets/Darkmatter/Code/Features/Tutorial/UI.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 98ae3bd636ac84b648d602de444dbf89
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Darkmatter.Features.Tutorial.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A single full-screen dim Image with a soft circular hole driven by the TutorialCutout shader.
|
||||||
|
/// Also an <see cref="ICanvasRaycastFilter"/>: when the dim is blocking, taps inside the hole
|
||||||
|
/// fall through to the real button underneath, taps outside are swallowed.
|
||||||
|
/// </summary>
|
||||||
|
[RequireComponent(typeof(Image))]
|
||||||
|
public sealed class TutorialCutoutDim : MonoBehaviour, ICanvasRaycastFilter
|
||||||
|
{
|
||||||
|
[SerializeField] private Shader cutoutShader;
|
||||||
|
[SerializeField] private Image dimImage;
|
||||||
|
|
||||||
|
private Material _material;
|
||||||
|
private Vector2 _centerScreen;
|
||||||
|
private float _radiusScreen;
|
||||||
|
private bool _holeActive;
|
||||||
|
|
||||||
|
private static readonly int CenterId = Shader.PropertyToID("_Center");
|
||||||
|
private static readonly int RadiusId = Shader.PropertyToID("_Radius");
|
||||||
|
private static readonly int AspectId = Shader.PropertyToID("_Aspect");
|
||||||
|
private static readonly int SoftnessId = Shader.PropertyToID("_Softness");
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (dimImage == null) dimImage = GetComponent<Image>();
|
||||||
|
if (cutoutShader != null && dimImage != null)
|
||||||
|
{
|
||||||
|
_material = new Material(cutoutShader); // instance — never mutate the asset
|
||||||
|
dimImage.material = _material;
|
||||||
|
}
|
||||||
|
SetVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Show/hide the dim. Hidden = the Graphic is disabled, so it neither draws nor blocks.</summary>
|
||||||
|
public void SetVisible(bool visible)
|
||||||
|
{
|
||||||
|
if (dimImage != null) dimImage.enabled = visible;
|
||||||
|
if (!visible) ClearHole();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetHole(Vector2 centerScreen, float radiusScreen, float screenWidth, float screenHeight)
|
||||||
|
{
|
||||||
|
_centerScreen = centerScreen;
|
||||||
|
_radiusScreen = radiusScreen;
|
||||||
|
_holeActive = radiusScreen > 0f && screenHeight > 0f;
|
||||||
|
if (_material == null || screenHeight <= 0f) return;
|
||||||
|
|
||||||
|
_material.SetVector(CenterId, new Vector4(centerScreen.x / screenWidth, centerScreen.y / screenHeight, 0f, 0f));
|
||||||
|
_material.SetFloat(RadiusId, radiusScreen / screenHeight);
|
||||||
|
_material.SetFloat(AspectId, screenWidth / screenHeight);
|
||||||
|
_material.SetFloat(SoftnessId, 0.004f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearHole()
|
||||||
|
{
|
||||||
|
_holeActive = false;
|
||||||
|
if (_material != null) _material.SetFloat(RadiusId, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consulted only when the graphic actually participates in raycasting (parent CanvasGroup
|
||||||
|
// blocksRaycasts == true). Outside the hole -> block; inside -> pass to whatever's beneath.
|
||||||
|
public bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
|
||||||
|
{
|
||||||
|
if (!_holeActive) return true;
|
||||||
|
return Vector2.Distance(screenPoint, _centerScreen) > _radiusScreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 29c836b3d2ed343e6a810f6e7548f487
|
||||||
@@ -0,0 +1,449 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Darkmatter.Core.Contracts.Features.Tutorial;
|
||||||
|
using PrimeTween;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Darkmatter.Features.Tutorial.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Persistent guidance overlay. A single full-screen dim with a soft circular hole (see
|
||||||
|
/// <see cref="TutorialCutoutDim"/>) spotlights the target; an animated hand + halo point at it
|
||||||
|
/// and an instruction bubble sits above/below. Lives on a high-sortingOrder Canvas in the Boot
|
||||||
|
/// scene so it renders over — and outlives — every additive gameplay scene.
|
||||||
|
///
|
||||||
|
/// Input gating is the whole-overlay CanvasGroup.blocksRaycasts master switch: ON for blocking
|
||||||
|
/// tap steps; OFF for drag steps, hints and toasts. All targets are tracked live in LateUpdate
|
||||||
|
/// (catalog cells scroll, pieces are dragged); if a target is destroyed (scene swap) the overlay
|
||||||
|
/// hides itself. All animation uses unscaled time.
|
||||||
|
/// </summary>
|
||||||
|
[RequireComponent(typeof(CanvasGroup))]
|
||||||
|
public sealed class TutorialOverlayView : MonoBehaviour, ITutorialOverlay
|
||||||
|
{
|
||||||
|
private enum Mode { Hidden, Tap, Drag, Centered }
|
||||||
|
|
||||||
|
[Header("Canvas")]
|
||||||
|
[SerializeField] private Canvas canvas;
|
||||||
|
[SerializeField] private CanvasGroup rootGroup;
|
||||||
|
|
||||||
|
[Header("Dim (single image + circular cutout)")]
|
||||||
|
[SerializeField] private TutorialCutoutDim cutout;
|
||||||
|
|
||||||
|
[Header("Pointer")]
|
||||||
|
[SerializeField] private RectTransform halo;
|
||||||
|
[SerializeField] private RectTransform hand;
|
||||||
|
|
||||||
|
[Header("Bubble")]
|
||||||
|
[SerializeField] private RectTransform bubbleRoot;
|
||||||
|
[SerializeField] private TMP_Text bubbleText;
|
||||||
|
|
||||||
|
[Header("Tuning")]
|
||||||
|
[Tooltip("Extra screen pixels added to the spotlight circle radius around the target.")]
|
||||||
|
[SerializeField] private float holePadding = 44f;
|
||||||
|
[SerializeField] private float fadeDuration = 0.25f;
|
||||||
|
[SerializeField] private float toastSeconds = 1.6f;
|
||||||
|
[SerializeField] private float bubbleGap = 60f;
|
||||||
|
[SerializeField] private float haloPulseScale = 1.18f;
|
||||||
|
[SerializeField] private float pulseDuration = 0.6f;
|
||||||
|
[SerializeField] private float dragHandDuration = 1.1f;
|
||||||
|
|
||||||
|
[Header("Drag step")]
|
||||||
|
[Tooltip("Offset (px) from the hand's pivot to its visible fingertip. The tip is placed on the target so it points accurately; a positive Y drops the hand body below the spot.")]
|
||||||
|
[SerializeField] private Vector2 dragHandTipOffset = new(0f, 70f);
|
||||||
|
[Tooltip("Pin the drag bubble to the top (true) or bottom (false) edge so it never covers the play area.")]
|
||||||
|
[SerializeField] private bool dragBubbleAtTop = true;
|
||||||
|
[Tooltip("Margin (px) from that edge for the drag bubble.")]
|
||||||
|
[SerializeField] private float dragBubbleEdgeMargin = 150f;
|
||||||
|
|
||||||
|
private RectTransform _area;
|
||||||
|
private Camera _overlayCam;
|
||||||
|
private Mode _mode = Mode.Hidden;
|
||||||
|
private RectTransform _target; // tap target
|
||||||
|
private RectTransform _dragFrom; // the piece (drag start)
|
||||||
|
private RectTransform _dragTo; // the slot (drag destination)
|
||||||
|
private float _dragT;
|
||||||
|
private Sequence _haloSeq;
|
||||||
|
private Sequence _handSeq;
|
||||||
|
private readonly Vector3[] _corners = new Vector3[4];
|
||||||
|
private bool _ready;
|
||||||
|
|
||||||
|
public bool IsReady => _ready && this != null;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
CacheRefs();
|
||||||
|
ApplyHiddenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheRefs()
|
||||||
|
{
|
||||||
|
if (_ready) return;
|
||||||
|
_area = (RectTransform)transform;
|
||||||
|
if (canvas == null) canvas = GetComponentInParent<Canvas>();
|
||||||
|
if (rootGroup == null) rootGroup = GetComponent<CanvasGroup>();
|
||||||
|
_overlayCam = canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay
|
||||||
|
? canvas.worldCamera
|
||||||
|
: null;
|
||||||
|
_ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── ITutorialOverlay ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
public void ShowTap(RectTransform target, string message, bool blockInput)
|
||||||
|
{
|
||||||
|
CacheRefs();
|
||||||
|
KillAnims();
|
||||||
|
SetText(message);
|
||||||
|
_dragFrom = null;
|
||||||
|
_dragTo = null;
|
||||||
|
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
_mode = Mode.Tap;
|
||||||
|
_target = target;
|
||||||
|
if (cutout != null) cutout.SetVisible(true);
|
||||||
|
SetPointerVisible(true);
|
||||||
|
rootGroup.blocksRaycasts = blockInput;
|
||||||
|
StartHaloPulse();
|
||||||
|
StartHandTap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_mode = Mode.Centered;
|
||||||
|
_target = null;
|
||||||
|
if (cutout != null) cutout.SetVisible(false);
|
||||||
|
SetPointerVisible(false);
|
||||||
|
rootGroup.blocksRaycasts = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutNow();
|
||||||
|
FadeInQuick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowDrag(RectTransform from, RectTransform to, string message)
|
||||||
|
{
|
||||||
|
CacheRefs();
|
||||||
|
KillAnims();
|
||||||
|
SetText(message);
|
||||||
|
|
||||||
|
// No dim and no blocking — the piece lives under the overlay and must stay visible and
|
||||||
|
// draggable. Halo + hand travel together along the piece -> slot path, recomputed live.
|
||||||
|
if (cutout != null) cutout.SetVisible(false);
|
||||||
|
rootGroup.blocksRaycasts = false;
|
||||||
|
_target = null;
|
||||||
|
_dragFrom = from;
|
||||||
|
_dragTo = to;
|
||||||
|
_dragT = 0f;
|
||||||
|
|
||||||
|
if (from != null)
|
||||||
|
{
|
||||||
|
_mode = Mode.Drag;
|
||||||
|
SetPointerVisible(true);
|
||||||
|
StartHaloPulse();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_mode = Mode.Centered;
|
||||||
|
SetPointerVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutNow();
|
||||||
|
FadeInQuick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask ShowToastAsync(string message, CancellationToken ct)
|
||||||
|
{
|
||||||
|
CacheRefs();
|
||||||
|
KillAnims();
|
||||||
|
SetText(message);
|
||||||
|
|
||||||
|
_mode = Mode.Centered;
|
||||||
|
_target = null;
|
||||||
|
_dragFrom = null;
|
||||||
|
_dragTo = null;
|
||||||
|
if (cutout != null) cutout.SetVisible(false);
|
||||||
|
SetPointerVisible(false);
|
||||||
|
rootGroup.blocksRaycasts = false;
|
||||||
|
LayoutNow();
|
||||||
|
|
||||||
|
await FadeAsync(0f, 1f, fadeDuration, ct);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await UniTask.Delay(TimeSpan.FromSeconds(toastSeconds), DelayType.UnscaledDeltaTime, cancellationToken: ct);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
HideInstant();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
await FadeAsync(1f, 0f, fadeDuration, CancellationToken.None);
|
||||||
|
HideInstant();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideInstant()
|
||||||
|
{
|
||||||
|
CacheRefs();
|
||||||
|
KillAnims();
|
||||||
|
ApplyHiddenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Per-frame layout ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private void LateUpdate()
|
||||||
|
{
|
||||||
|
if (_mode == Mode.Hidden) return;
|
||||||
|
LayoutNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LayoutNow()
|
||||||
|
{
|
||||||
|
switch (_mode)
|
||||||
|
{
|
||||||
|
case Mode.Tap:
|
||||||
|
if (_target == null) { HideInstant(); return; } // destroyed (scene swap) -> self-hide
|
||||||
|
PlaceSpotlight(_target);
|
||||||
|
break;
|
||||||
|
case Mode.Drag:
|
||||||
|
if (_dragFrom == null) { HideInstant(); return; }
|
||||||
|
LayoutDrag();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LayoutCentered();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tap: cutout + halo + resting hand + bubble around a static target.
|
||||||
|
private void PlaceSpotlight(RectTransform target)
|
||||||
|
{
|
||||||
|
if (!TryToScreenBounds(target, out var min, out var max)) return;
|
||||||
|
|
||||||
|
var centerScreen = (min + max) * 0.5f;
|
||||||
|
var radiusScreen = (max - min).magnitude * 0.5f + holePadding;
|
||||||
|
|
||||||
|
if (cutout != null) cutout.SetHole(centerScreen, radiusScreen, Screen.width, Screen.height);
|
||||||
|
|
||||||
|
if (!ScreenToLocal(centerScreen, out var centerLocal)) return;
|
||||||
|
|
||||||
|
float scale = Screen.height > 0 ? _area.rect.height / Screen.height : 1f;
|
||||||
|
float radiusLocal = radiusScreen * scale;
|
||||||
|
|
||||||
|
if (halo != null)
|
||||||
|
{
|
||||||
|
halo.anchoredPosition = centerLocal;
|
||||||
|
halo.sizeDelta = Vector2.one * (radiusLocal * 2f);
|
||||||
|
}
|
||||||
|
if (hand != null)
|
||||||
|
hand.anchoredPosition = centerLocal + new Vector2(0f, -radiusLocal * 0.5f);
|
||||||
|
|
||||||
|
PositionBubble(centerLocal.y, centerLocal.y + radiusLocal, centerLocal.y - radiusLocal,
|
||||||
|
_area.rect.height * 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drag: halo + hand glide piece -> slot, recomputed live so it tracks the real positions.
|
||||||
|
private void LayoutDrag()
|
||||||
|
{
|
||||||
|
if (!TryToLocalCenter(_dragFrom, out var a)) return;
|
||||||
|
Vector2 b = _dragTo != null && TryToLocalCenter(_dragTo, out var bc) ? bc : a;
|
||||||
|
|
||||||
|
const float pressT = 0.25f;
|
||||||
|
const float holdT = 0.5f;
|
||||||
|
float move = Mathf.Max(0.3f, dragHandDuration);
|
||||||
|
float period = pressT + move + holdT;
|
||||||
|
_dragT += Time.unscaledDeltaTime;
|
||||||
|
if (_dragT >= period) _dragT -= period;
|
||||||
|
|
||||||
|
float frac, pressScale;
|
||||||
|
if (_dragT < pressT) { frac = 0f; pressScale = Mathf.Lerp(1f, 0.8f, _dragT / pressT); }
|
||||||
|
else if (_dragT < pressT + move) { frac = Mathf.SmoothStep(0f, 1f, (_dragT - pressT) / move); pressScale = 0.8f; }
|
||||||
|
else { frac = 1f; pressScale = Mathf.Lerp(0.8f, 1f, (_dragT - pressT - move) / holdT); }
|
||||||
|
|
||||||
|
Vector2 pos = Vector2.Lerp(a, b, frac);
|
||||||
|
|
||||||
|
float scale = Screen.height > 0 ? _area.rect.height / Screen.height : 1f;
|
||||||
|
float radiusScreen = 120f;
|
||||||
|
if (TryToScreenBounds(_dragFrom, out var min, out var max))
|
||||||
|
radiusScreen = (max - min).magnitude * 0.5f + holePadding;
|
||||||
|
float radiusLocal = radiusScreen * scale;
|
||||||
|
|
||||||
|
if (halo != null)
|
||||||
|
{
|
||||||
|
halo.anchoredPosition = pos;
|
||||||
|
halo.sizeDelta = Vector2.one * (radiusLocal * 2f);
|
||||||
|
}
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
// Put the visible fingertip on the target point (halo centre) so it points accurately,
|
||||||
|
// with the hand body hanging below it.
|
||||||
|
hand.anchoredPosition = pos - dragHandTipOffset;
|
||||||
|
hand.localScale = Vector3.one * pressScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The drag path spans the play area, so pin the bubble to a screen edge instead of hugging
|
||||||
|
// the piece — keeps it off the shapes.
|
||||||
|
PositionBubbleAtEdge(dragBubbleAtTop, dragBubbleEdgeMargin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LayoutCentered()
|
||||||
|
{
|
||||||
|
if (bubbleRoot == null) return;
|
||||||
|
float halfH = _area.rect.height * 0.5f;
|
||||||
|
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
|
||||||
|
bubbleRoot.anchoredPosition =
|
||||||
|
new Vector2(0f, Mathf.Clamp(halfH * 0.45f, -halfH + bubbleHalf, halfH - bubbleHalf));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PositionBubble(float holeCenterY, float holeTopY, float holeBottomY, float halfH)
|
||||||
|
{
|
||||||
|
if (bubbleRoot == null) return;
|
||||||
|
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
|
||||||
|
float y = holeCenterY <= 0f
|
||||||
|
? holeTopY + bubbleGap + bubbleHalf
|
||||||
|
: holeBottomY - bubbleGap - bubbleHalf;
|
||||||
|
y = Mathf.Clamp(y, -halfH + bubbleHalf, halfH - bubbleHalf);
|
||||||
|
bubbleRoot.anchoredPosition = new Vector2(0f, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pins the bubble to the top or bottom edge (used for the drag step, whose target spans the
|
||||||
|
// play area). Centred horizontally so it clears the shapes.
|
||||||
|
private void PositionBubbleAtEdge(bool top, float margin)
|
||||||
|
{
|
||||||
|
if (bubbleRoot == null) return;
|
||||||
|
float halfH = _area.rect.height * 0.5f;
|
||||||
|
float bubbleHalf = bubbleRoot.rect.height * 0.5f;
|
||||||
|
float y = top ? halfH - bubbleHalf - margin : -halfH + bubbleHalf + margin;
|
||||||
|
y = Mathf.Clamp(y, -halfH + bubbleHalf, halfH - bubbleHalf);
|
||||||
|
bubbleRoot.anchoredPosition = new Vector2(0f, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Coordinate conversion (camera-agnostic) ──────────────────────────
|
||||||
|
|
||||||
|
private bool TryToScreenBounds(RectTransform target, out Vector2 min, out Vector2 max)
|
||||||
|
{
|
||||||
|
min = new Vector2(float.MaxValue, float.MaxValue);
|
||||||
|
max = new Vector2(float.MinValue, float.MinValue);
|
||||||
|
if (target == null) return false;
|
||||||
|
|
||||||
|
var cam = ResolveCamera(target);
|
||||||
|
target.GetWorldCorners(_corners);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
var sp = RectTransformUtility.WorldToScreenPoint(cam, _corners[i]);
|
||||||
|
min = Vector2.Min(min, sp);
|
||||||
|
max = Vector2.Max(max, sp);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryToLocalCenter(RectTransform target, out Vector2 local)
|
||||||
|
{
|
||||||
|
local = default;
|
||||||
|
if (!TryToScreenBounds(target, out var min, out var max)) return false;
|
||||||
|
return ScreenToLocal((min + max) * 0.5f, out local);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ScreenToLocal(Vector2 screen, out Vector2 local) =>
|
||||||
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(_area, screen, _overlayCam, out local);
|
||||||
|
|
||||||
|
private static Camera ResolveCamera(RectTransform target)
|
||||||
|
{
|
||||||
|
var c = target.GetComponentInParent<Canvas>();
|
||||||
|
if (c == null) return null;
|
||||||
|
c = c.rootCanvas;
|
||||||
|
return c.renderMode == RenderMode.ScreenSpaceOverlay ? null : c.worldCamera;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Animation ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private void StartHaloPulse()
|
||||||
|
{
|
||||||
|
if (halo == null) return;
|
||||||
|
halo.localScale = Vector3.one;
|
||||||
|
_haloSeq = Sequence.Create(useUnscaledTime: true, cycles: -1)
|
||||||
|
.Chain(Tween.Scale(halo, Vector3.one * haloPulseScale, pulseDuration, Ease.InOutSine))
|
||||||
|
.Chain(Tween.Scale(halo, Vector3.one, pulseDuration, Ease.InOutSine));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartHandTap()
|
||||||
|
{
|
||||||
|
if (hand == null) return;
|
||||||
|
hand.localScale = Vector3.one;
|
||||||
|
_handSeq = Sequence.Create(useUnscaledTime: true, cycles: -1)
|
||||||
|
.Chain(Tween.Scale(hand, Vector3.one * 0.82f, 0.35f, Ease.OutQuad))
|
||||||
|
.Chain(Tween.Scale(hand, Vector3.one, 0.35f, Ease.OutQuad))
|
||||||
|
.ChainDelay(0.35f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FadeInQuick()
|
||||||
|
{
|
||||||
|
if (rootGroup == null) return;
|
||||||
|
Tween.StopAll(onTarget: rootGroup);
|
||||||
|
rootGroup.alpha = 0f;
|
||||||
|
Sequence.Create(useUnscaledTime: true).Chain(Tween.Alpha(rootGroup, 1f, fadeDuration, Ease.OutQuad));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async UniTask FadeAsync(float from, float to, float duration, CancellationToken ct)
|
||||||
|
{
|
||||||
|
if (rootGroup == null) return;
|
||||||
|
Tween.StopAll(onTarget: rootGroup);
|
||||||
|
rootGroup.alpha = from;
|
||||||
|
float t = 0f;
|
||||||
|
while (t < duration)
|
||||||
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
t += Time.unscaledDeltaTime;
|
||||||
|
rootGroup.alpha = Mathf.Lerp(from, to, duration > 0f ? t / duration : 1f);
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.Update);
|
||||||
|
}
|
||||||
|
rootGroup.alpha = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── State helpers ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private void ApplyHiddenState()
|
||||||
|
{
|
||||||
|
_mode = Mode.Hidden;
|
||||||
|
_target = null;
|
||||||
|
_dragFrom = null;
|
||||||
|
_dragTo = null;
|
||||||
|
if (cutout != null) cutout.SetVisible(false);
|
||||||
|
if (rootGroup != null)
|
||||||
|
{
|
||||||
|
rootGroup.alpha = 0f;
|
||||||
|
rootGroup.blocksRaycasts = false;
|
||||||
|
rootGroup.interactable = false;
|
||||||
|
}
|
||||||
|
SetPointerVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetText(string message)
|
||||||
|
{
|
||||||
|
if (bubbleText != null) bubbleText.text = message;
|
||||||
|
if (bubbleRoot != null) bubbleRoot.gameObject.SetActive(!string.IsNullOrEmpty(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPointerVisible(bool visible)
|
||||||
|
{
|
||||||
|
if (halo != null) halo.gameObject.SetActive(visible);
|
||||||
|
if (hand != null) hand.gameObject.SetActive(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void KillAnims()
|
||||||
|
{
|
||||||
|
if (_haloSeq.isAlive) _haloSeq.Stop();
|
||||||
|
if (_handSeq.isAlive) _handSeq.Stop();
|
||||||
|
_haloSeq = default;
|
||||||
|
_handSeq = default;
|
||||||
|
if (halo != null) { Tween.StopAll(onTarget: halo); halo.localScale = Vector3.one; }
|
||||||
|
if (hand != null) { Tween.StopAll(onTarget: hand); hand.localScale = Vector3.one; }
|
||||||
|
if (rootGroup != null) Tween.StopAll(onTarget: rootGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
KillAnims();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ecf127118699405ebcd0e0712d7373d
|
||||||
@@ -8,6 +8,7 @@ using Darkmatter.Core.Data.Signals.Features.Drawing;
|
|||||||
using Darkmatter.Core.Data.Signals.Features.GameplayFlow;
|
using Darkmatter.Core.Data.Signals.Features.GameplayFlow;
|
||||||
using Darkmatter.Core.Data.Signals.Features.MainMenu;
|
using Darkmatter.Core.Data.Signals.Features.MainMenu;
|
||||||
using Darkmatter.Core.Data.Signals.Features.ShapeBuilder;
|
using Darkmatter.Core.Data.Signals.Features.ShapeBuilder;
|
||||||
|
using Darkmatter.Core.Data.Signals.Features.Tutorial;
|
||||||
using Darkmatter.Libs.Observer;
|
using Darkmatter.Libs.Observer;
|
||||||
using VContainer.Unity;
|
using VContainer.Unity;
|
||||||
|
|
||||||
@@ -52,6 +53,15 @@ namespace Darkmatter.Services.Analytics
|
|||||||
_subs.Add(_bus.Subscribe<GallerySaveStartedSignal>(_ => _analytics.LogEvent("gallery_save_started")));
|
_subs.Add(_bus.Subscribe<GallerySaveStartedSignal>(_ => _analytics.LogEvent("gallery_save_started")));
|
||||||
_subs.Add(_bus.Subscribe<GallerySaveCompletedSignal>(s =>
|
_subs.Add(_bus.Subscribe<GallerySaveCompletedSignal>(s =>
|
||||||
_analytics.LogEvent("gallery_save_completed", "success", s.Success ? "true" : "false")));
|
_analytics.LogEvent("gallery_save_completed", "success", s.Success ? "true" : "false")));
|
||||||
|
|
||||||
|
_subs.Add(_bus.Subscribe<TutorialStartedSignal>(_ => _analytics.LogEvent("tutorial_started")));
|
||||||
|
_subs.Add(_bus.Subscribe<TutorialStepCompletedSignal>(s => _analytics.LogEvent("tutorial_step_completed",
|
||||||
|
new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["step_id"] = s.StepId,
|
||||||
|
["step_index"] = s.StepIndex,
|
||||||
|
})));
|
||||||
|
_subs.Add(_bus.Subscribe<TutorialCompletedSignal>(_ => _analytics.LogEvent("tutorial_completed")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
BIN
Assets/Darkmatter/Content/.DS_Store
vendored
BIN
Assets/Darkmatter/Content/.DS_Store
vendored
Binary file not shown.
BIN
Assets/Darkmatter/Content/Colorbook UI/.DS_Store
vendored
BIN
Assets/Darkmatter/Content/Colorbook UI/.DS_Store
vendored
Binary file not shown.
@@ -281,8 +281,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 2018849806684805117}
|
m_GameObject: {fileID: 2018849806684805117}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.4066, y: 1.4066, z: 1.4066}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 86201234489763977}
|
- {fileID: 86201234489763977}
|
||||||
- {fileID: 109331856778429183}
|
- {fileID: 109331856778429183}
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 970882496690282873}
|
m_GameObject: {fileID: 970882496690282873}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.1503, y: 1.1503, z: 1.1503}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 4862617518150298184}
|
- {fileID: 4862617518150298184}
|
||||||
- {fileID: 1927978426257304632}
|
- {fileID: 1927978426257304632}
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 6408485857370138169}
|
m_GameObject: {fileID: 6408485857370138169}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.2033, y: 1.2033, z: 1.2033}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1214920657407418962}
|
- {fileID: 1214920657407418962}
|
||||||
- {fileID: 6162131388587199005}
|
- {fileID: 6162131388587199005}
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 830151417515138702}
|
m_GameObject: {fileID: 830151417515138702}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.2121, y: 1.2121, z: 1.2121}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1060224653914720711}
|
- {fileID: 1060224653914720711}
|
||||||
- {fileID: 3409973025274235484}
|
- {fileID: 3409973025274235484}
|
||||||
|
|||||||
@@ -930,7 +930,7 @@ GameObject:
|
|||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
m_IsActive: 1
|
m_IsActive: 0
|
||||||
--- !u!224 &3765577967584406493
|
--- !u!224 &3765577967584406493
|
||||||
RectTransform:
|
RectTransform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2013,8 +2013,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 6684381930794325998}
|
m_GameObject: {fileID: 6684381930794325998}
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.2563, y: 1.2563, z: 1.2563}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 4001251692510412888}
|
- {fileID: 4001251692510412888}
|
||||||
- {fileID: 9065922355177954181}
|
- {fileID: 9065922355177954181}
|
||||||
@@ -2022,7 +2022,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
m_AnchoredPosition: {x: 0, y: -324.28992}
|
m_AnchoredPosition: {x: 18, y: -324.28992}
|
||||||
m_SizeDelta: {x: 484.2721, y: 79.242615}
|
m_SizeDelta: {x: 484.2721, y: 79.242615}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!1 &6720628983119242459
|
--- !u!1 &6720628983119242459
|
||||||
@@ -3192,8 +3192,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 8914662876087302500}
|
m_GameObject: {fileID: 8914662876087302500}
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.2563, y: 1.2563, z: 1.2563}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 4452683220369286777}
|
- {fileID: 4452683220369286777}
|
||||||
- {fileID: 1884834246100035824}
|
- {fileID: 1884834246100035824}
|
||||||
@@ -3201,7 +3201,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0}
|
m_AnchorMin: {x: 0.5, y: 0}
|
||||||
m_AnchorMax: {x: 0.5, y: 0}
|
m_AnchorMax: {x: 0.5, y: 0}
|
||||||
m_AnchoredPosition: {x: -0.000030517578, y: 39.621277}
|
m_AnchoredPosition: {x: -33, y: 39.621277}
|
||||||
m_SizeDelta: {x: 484.27228, y: 79.242615}
|
m_SizeDelta: {x: 484.27228, y: 79.242615}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!1 &9047034408538749912
|
--- !u!1 &9047034408538749912
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 8269026611177622940}
|
m_GameObject: {fileID: 8269026611177622940}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.1414, y: 1.1414, z: 1.1414}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 1
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
|||||||
@@ -0,0 +1,761 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &100100
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100101}
|
||||||
|
- component: {fileID: 100102}
|
||||||
|
- component: {fileID: 100103}
|
||||||
|
- component: {fileID: 100104}
|
||||||
|
- component: {fileID: 100105}
|
||||||
|
- component: {fileID: 100107}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: TutorialOverlayCanvas
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100101
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100100}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 100111}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0, y: 0}
|
||||||
|
--- !u!223 &100102
|
||||||
|
Canvas:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100100}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_Camera: {fileID: 0}
|
||||||
|
m_PlaneDistance: 100
|
||||||
|
m_PixelPerfect: 0
|
||||||
|
m_ReceivesEvents: 1
|
||||||
|
m_OverrideSorting: 0
|
||||||
|
m_OverridePixelPerfect: 0
|
||||||
|
m_SortingBucketNormalizedSize: 0
|
||||||
|
m_VertexColorAlwaysGammaSpace: 1
|
||||||
|
m_UseReflectionProbes: 0
|
||||||
|
m_AdditionalShaderChannelsFlag: 25
|
||||||
|
m_UpdateRectTransformForStandalone: 0
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingOrder: 5000
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
--- !u!114 &100103
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100100}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_UiScaleMode: 1
|
||||||
|
m_ReferencePixelsPerUnit: 100
|
||||||
|
m_ScaleFactor: 1
|
||||||
|
m_ReferenceResolution: {x: 1080, y: 1920}
|
||||||
|
m_ScreenMatchMode: 0
|
||||||
|
m_MatchWidthOrHeight: 0.5
|
||||||
|
m_PhysicalUnit: 3
|
||||||
|
m_FallbackScreenDPI: 96
|
||||||
|
m_DefaultSpriteDPI: 96
|
||||||
|
m_DynamicPixelsPerUnit: 1
|
||||||
|
m_PresetInfoIsWorld: 0
|
||||||
|
--- !u!114 &100104
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100100}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_IgnoreReversedGraphics: 1
|
||||||
|
m_BlockingObjects: 0
|
||||||
|
m_BlockingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
--- !u!225 &100105
|
||||||
|
CanvasGroup:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100100}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_Alpha: 0
|
||||||
|
m_Interactable: 0
|
||||||
|
m_BlocksRaycasts: 0
|
||||||
|
m_IgnoreParentGroups: 0
|
||||||
|
--- !u!114 &100107
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100100}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 97ce2c486cc8541d1ab1d83fda7f8eda, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
overlayView: {fileID: 100106}
|
||||||
|
config: {fileID: 11400000, guid: 71357eb1222bb4151ab4e5697a1decd3, type: 2}
|
||||||
|
--- !u!1 &100110
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100111}
|
||||||
|
- component: {fileID: 100106}
|
||||||
|
- component: {fileID: 6008915593776814208}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Area
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100111
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100110}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 100201}
|
||||||
|
- {fileID: 100601}
|
||||||
|
- {fileID: 100701}
|
||||||
|
- {fileID: 100801}
|
||||||
|
m_Father: {fileID: 100101}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!114 &100106
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100110}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 4ecf127118699405ebcd0e0712d7373d, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
canvas: {fileID: 100102}
|
||||||
|
rootGroup: {fileID: 100105}
|
||||||
|
cutout: {fileID: 100204}
|
||||||
|
halo: {fileID: 100601}
|
||||||
|
hand: {fileID: 100701}
|
||||||
|
bubbleRoot: {fileID: 100801}
|
||||||
|
bubbleText: {fileID: 101003}
|
||||||
|
holePadding: 44
|
||||||
|
fadeDuration: 0.25
|
||||||
|
toastSeconds: 1.6
|
||||||
|
bubbleGap: 60
|
||||||
|
haloPulseScale: 1.18
|
||||||
|
pulseDuration: 0.6
|
||||||
|
dragHandDuration: 1.1
|
||||||
|
--- !u!225 &6008915593776814208
|
||||||
|
CanvasGroup:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100110}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_Alpha: 1
|
||||||
|
m_Interactable: 1
|
||||||
|
m_BlocksRaycasts: 1
|
||||||
|
m_IgnoreParentGroups: 0
|
||||||
|
--- !u!1 &100200
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100201}
|
||||||
|
- component: {fileID: 100202}
|
||||||
|
- component: {fileID: 100203}
|
||||||
|
- component: {fileID: 100204}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Dim
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100201
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100200}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 100111}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &100202
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100200}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &100203
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100200}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 0, g: 0, b: 0, a: 0.72}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 0}
|
||||||
|
m_Type: 0
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!114 &100204
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100200}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 29c836b3d2ed343e6a810f6e7548f487, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
cutoutShader: {fileID: 4800000, guid: 57d1ed1c62afa45db97a7c8e9ace795c, type: 3}
|
||||||
|
dimImage: {fileID: 100203}
|
||||||
|
--- !u!1 &100600
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100601}
|
||||||
|
- component: {fileID: 100602}
|
||||||
|
- component: {fileID: 100603}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Halo
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100601
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100600}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 100111}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 240, y: 240}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &100602
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100600}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &100603
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100600}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 0.9}
|
||||||
|
m_RaycastTarget: 0
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 21300000, guid: 17078a4ce7e7d450e85816637b6b6bbe, type: 3}
|
||||||
|
m_Type: 0
|
||||||
|
m_PreserveAspect: 1
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!1 &100700
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100701}
|
||||||
|
- component: {fileID: 100702}
|
||||||
|
- component: {fileID: 100703}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Hand
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100701
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100700}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 100111}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 130, y: 130}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &100702
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100700}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &100703
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100700}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 0
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 5357005990035746724, guid: edf2d0d62497c37488be3b7304708f09, type: 3}
|
||||||
|
m_Type: 0
|
||||||
|
m_PreserveAspect: 1
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!1 &100800
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100801}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: BubbleRoot
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100801
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100800}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 100901}
|
||||||
|
m_Father: {fileID: 100111}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 350}
|
||||||
|
m_SizeDelta: {x: 760, y: 180}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!1 &100900
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 100901}
|
||||||
|
- component: {fileID: 100902}
|
||||||
|
- component: {fileID: 100903}
|
||||||
|
- component: {fileID: 6057957808347567821}
|
||||||
|
- component: {fileID: 3730188213376167672}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: BubbleBg
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &100901
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100900}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 101001}
|
||||||
|
m_Father: {fileID: 100801}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 91}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &100902
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100900}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &100903
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100900}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 0.96}
|
||||||
|
m_RaycastTarget: 0
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 21300000, guid: 392a0995832130344b5e8918edc0052f, type: 3}
|
||||||
|
m_Type: 1
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!114 &6057957808347567821
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100900}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||||
|
m_HorizontalFit: 2
|
||||||
|
m_VerticalFit: 0
|
||||||
|
--- !u!114 &3730188213376167672
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 100900}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||||
|
m_Padding:
|
||||||
|
m_Left: 100
|
||||||
|
m_Right: 100
|
||||||
|
m_Top: -80
|
||||||
|
m_Bottom: 0
|
||||||
|
m_ChildAlignment: 3
|
||||||
|
m_Spacing: 0
|
||||||
|
m_ChildForceExpandWidth: 0
|
||||||
|
m_ChildForceExpandHeight: 0
|
||||||
|
m_ChildControlWidth: 0
|
||||||
|
m_ChildControlHeight: 0
|
||||||
|
m_ChildScaleWidth: 1
|
||||||
|
m_ChildScaleHeight: 1
|
||||||
|
m_ReverseArrangement: 0
|
||||||
|
--- !u!1 &101000
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 101001}
|
||||||
|
- component: {fileID: 101002}
|
||||||
|
- component: {fileID: 101003}
|
||||||
|
- component: {fileID: 8870904446750593947}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Text
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &101001
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 101000}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 100901}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 1}
|
||||||
|
m_AnchorMax: {x: 0, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 463.445, y: -95.50001}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &101002
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 101000}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &101003
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 101000}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 0
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_text: Tutorial
|
||||||
|
m_isRightToLeft: 0
|
||||||
|
m_fontAsset: {fileID: 11400000, guid: dde468a43b0440f4a9d121fb1d8f290e, type: 2}
|
||||||
|
m_sharedMaterial: {fileID: -1548830327015913602, guid: dde468a43b0440f4a9d121fb1d8f290e, type: 2}
|
||||||
|
m_fontSharedMaterials: []
|
||||||
|
m_fontMaterial: {fileID: 0}
|
||||||
|
m_fontMaterials: []
|
||||||
|
m_fontColor32:
|
||||||
|
serializedVersion: 2
|
||||||
|
rgba: 4281542953
|
||||||
|
m_fontColor: {r: 0.16, g: 0.16, b: 0.2, a: 1}
|
||||||
|
m_enableVertexGradient: 0
|
||||||
|
m_colorMode: 3
|
||||||
|
m_fontColorGradient:
|
||||||
|
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_fontColorGradientPreset: {fileID: 0}
|
||||||
|
m_spriteAsset: {fileID: 0}
|
||||||
|
m_tintAllSprites: 0
|
||||||
|
m_StyleSheet: {fileID: 0}
|
||||||
|
m_TextStyleHashCode: -1183493901
|
||||||
|
m_overrideHtmlColors: 0
|
||||||
|
m_faceColor:
|
||||||
|
serializedVersion: 2
|
||||||
|
rgba: 4294967295
|
||||||
|
m_fontSize: 60
|
||||||
|
m_fontSizeBase: 46
|
||||||
|
m_fontWeight: 400
|
||||||
|
m_enableAutoSizing: 1
|
||||||
|
m_fontSizeMin: 24
|
||||||
|
m_fontSizeMax: 60
|
||||||
|
m_fontStyle: 0
|
||||||
|
m_HorizontalAlignment: 2
|
||||||
|
m_VerticalAlignment: 512
|
||||||
|
m_textAlignment: 65535
|
||||||
|
m_characterSpacing: 0
|
||||||
|
m_characterHorizontalScale: 1
|
||||||
|
m_wordSpacing: 0
|
||||||
|
m_lineSpacing: 0
|
||||||
|
m_lineSpacingMax: 0
|
||||||
|
m_paragraphSpacing: 0
|
||||||
|
m_charWidthMaxAdj: 0
|
||||||
|
m_TextWrappingMode: 0
|
||||||
|
m_wordWrappingRatios: 0.4
|
||||||
|
m_overflowMode: 0
|
||||||
|
m_linkedTextComponent: {fileID: 0}
|
||||||
|
parentLinkedComponent: {fileID: 0}
|
||||||
|
m_enableKerning: 0
|
||||||
|
m_ActiveFontFeatures: 6e72656b
|
||||||
|
m_enableExtraPadding: 0
|
||||||
|
checkPaddingRequired: 0
|
||||||
|
m_isRichText: 1
|
||||||
|
m_EmojiFallbackSupport: 1
|
||||||
|
m_parseCtrlCharacters: 1
|
||||||
|
m_isOrthographic: 1
|
||||||
|
m_isCullingEnabled: 0
|
||||||
|
m_horizontalMapping: 0
|
||||||
|
m_verticalMapping: 0
|
||||||
|
m_uvLineOffset: 0
|
||||||
|
m_geometrySortingOrder: 0
|
||||||
|
m_IsTextObjectScaleStatic: 0
|
||||||
|
m_VertexBufferAutoSizeReduction: 0
|
||||||
|
m_useMaxVisibleDescender: 1
|
||||||
|
m_pageToDisplay: 1
|
||||||
|
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_isUsingLegacyAnimationComponent: 0
|
||||||
|
m_isVolumetricText: 0
|
||||||
|
m_hasFontAssetChanged: 0
|
||||||
|
m_baseMaterial: {fileID: 0}
|
||||||
|
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
--- !u!114 &8870904446750593947
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 101000}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 3e37e2b5f1962004c8f10779a2fcf23a, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: uLayout::Poke.UI.LayoutText
|
||||||
|
m_log: 0
|
||||||
|
m_ignoreLayout: 0
|
||||||
|
m_sizing:
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Darkmatter/Content/Colorbook UI/Shaders.meta
Normal file
8
Assets/Darkmatter/Content/Colorbook UI/Shaders.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ea8eac2c3ee646718ebb2b13b40f661
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
Shader "Darkmatter/TutorialCutout"
|
||||||
|
{
|
||||||
|
// Full-screen UI dim with a soft circular hole punched out. The hole centre/radius are driven
|
||||||
|
// from script in UV space (0..1 across the image, which covers the screen). Radius 0 = solid dim.
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
|
||||||
|
_Color ("Tint", Color) = (1,1,1,1)
|
||||||
|
_Center ("Hole Center (UV)", Vector) = (0.5, 0.5, 0, 0)
|
||||||
|
_Radius ("Hole Radius", Float) = 0
|
||||||
|
_Softness ("Edge Softness", Float) = 0.004
|
||||||
|
_Aspect ("Aspect (w/h)", Float) = 1
|
||||||
|
|
||||||
|
_StencilComp ("Stencil Comparison", Float) = 8
|
||||||
|
_Stencil ("Stencil ID", Float) = 0
|
||||||
|
_StencilOp ("Stencil Operation", Float) = 0
|
||||||
|
_StencilWriteMask ("Stencil Write Mask", Float) = 255
|
||||||
|
_StencilReadMask ("Stencil Read Mask", Float) = 255
|
||||||
|
_ColorMask ("Color Mask", Float) = 15
|
||||||
|
}
|
||||||
|
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Tags
|
||||||
|
{
|
||||||
|
"Queue"="Transparent"
|
||||||
|
"IgnoreProjector"="True"
|
||||||
|
"RenderType"="Transparent"
|
||||||
|
"PreviewType"="Plane"
|
||||||
|
"CanUseSpriteAtlas"="True"
|
||||||
|
}
|
||||||
|
|
||||||
|
Stencil
|
||||||
|
{
|
||||||
|
Ref [_Stencil]
|
||||||
|
Comp [_StencilComp]
|
||||||
|
Pass [_StencilOp]
|
||||||
|
ReadMask [_StencilReadMask]
|
||||||
|
WriteMask [_StencilWriteMask]
|
||||||
|
}
|
||||||
|
|
||||||
|
Cull Off
|
||||||
|
Lighting Off
|
||||||
|
ZWrite Off
|
||||||
|
ZTest [unity_GUIZTestMode]
|
||||||
|
Blend SrcAlpha OneMinusSrcAlpha
|
||||||
|
ColorMask [_ColorMask]
|
||||||
|
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
CGPROGRAM
|
||||||
|
#pragma vertex vert
|
||||||
|
#pragma fragment frag
|
||||||
|
#include "UnityCG.cginc"
|
||||||
|
|
||||||
|
struct appdata_t
|
||||||
|
{
|
||||||
|
float4 vertex : POSITION;
|
||||||
|
float4 color : COLOR;
|
||||||
|
float2 texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct v2f
|
||||||
|
{
|
||||||
|
float4 vertex : SV_POSITION;
|
||||||
|
fixed4 color : COLOR;
|
||||||
|
float2 texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
sampler2D _MainTex;
|
||||||
|
fixed4 _Color;
|
||||||
|
float4 _Center;
|
||||||
|
float _Radius;
|
||||||
|
float _Softness;
|
||||||
|
float _Aspect;
|
||||||
|
|
||||||
|
v2f vert(appdata_t v)
|
||||||
|
{
|
||||||
|
v2f o;
|
||||||
|
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||||
|
o.texcoord = v.texcoord;
|
||||||
|
o.color = v.color * _Color;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed4 frag(v2f i) : SV_Target
|
||||||
|
{
|
||||||
|
fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
|
||||||
|
|
||||||
|
float2 d = i.texcoord - _Center.xy;
|
||||||
|
d.x *= _Aspect; // keep the hole round on non-square screens
|
||||||
|
float dist = length(d);
|
||||||
|
// 0 inside the hole -> fully transparent, 1 outside -> full dim.
|
||||||
|
float cut = smoothstep(_Radius - _Softness, _Radius + _Softness, dist);
|
||||||
|
col.a *= cut;
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
ENDCG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 57d1ed1c62afa45db97a7c8e9ace795c
|
||||||
|
ShaderImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
defaultTextures: []
|
||||||
|
nonModifiableTextures: []
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -49,7 +49,7 @@ TextureImporter:
|
|||||||
alignment: 0
|
alignment: 0
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
spritePixelsToUnits: 100
|
spritePixelsToUnits: 100
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
spriteBorder: {x: 270, y: 191, z: 255, w: 110}
|
||||||
spriteGenerateFallbackPhysicsShape: 1
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
alphaUsage: 1
|
alphaUsage: 1
|
||||||
alphaIsTransparency: 1
|
alphaIsTransparency: 1
|
||||||
@@ -119,6 +119,19 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: iOS
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
@@ -127,7 +140,7 @@ TextureImporter:
|
|||||||
physicsShape: []
|
physicsShape: []
|
||||||
bones: []
|
bones: []
|
||||||
spriteID: 5e97eb03825dee720800000000000000
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
internalID: 0
|
internalID: 1537655665
|
||||||
vertices: []
|
vertices: []
|
||||||
indices:
|
indices:
|
||||||
edges: []
|
edges: []
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: Core::Darkmatter.Core.Data.Static.Services.Ads.AdUnitCatalogSO
|
m_EditorClassIdentifier: Core::Darkmatter.Core.Data.Static.Services.Ads.AdUnitCatalogSO
|
||||||
androidAppId: ca-app-pub-3940256099942544~3347511713
|
androidAppId: ca-app-pub-3940256099942544~3347511713
|
||||||
iosAppId: ca-app-pub-3940256099942544~1458002511
|
iosAppId: ca-app-pub-3940256099942544~1458002511
|
||||||
useTestUnits: 1
|
useTestUnits: 0
|
||||||
testDeviceIds: []
|
testDeviceIds: []
|
||||||
entries: []
|
entries: []
|
||||||
|
|||||||
8
Assets/Darkmatter/Data/Tutorial.meta
Normal file
8
Assets/Darkmatter/Data/Tutorial.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bf4c00fda65d94d4da204b00409759ed
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
22
Assets/Darkmatter/Data/Tutorial/TutorialStepsConfig.asset
Normal file
22
Assets/Darkmatter/Data/Tutorial/TutorialStepsConfig.asset
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5c513430cc85f4357b3df1da019bf554, type: 3}
|
||||||
|
m_Name: TutorialStepsConfig
|
||||||
|
m_EditorClassIdentifier: Core::Darkmatter.Core.Data.Static.Features.Tutorial.TutorialStepsConfig
|
||||||
|
pickText: Pick a picture to start!
|
||||||
|
dragText: Drag the piece to its spot!
|
||||||
|
finishText: Now finish the puzzle!
|
||||||
|
colorText: Choose a color!
|
||||||
|
paintText: Tap the picture to color it!
|
||||||
|
nextText: Tap Next when you're done!
|
||||||
|
doneText: Yay! You did it!
|
||||||
|
stepTimeoutSeconds: 45
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 71357eb1222bb4151ab4e5697a1decd3
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1526,8 +1526,55 @@ Transform:
|
|||||||
- {fileID: 1043308346}
|
- {fileID: 1043308346}
|
||||||
- {fileID: 610419919}
|
- {fileID: 610419919}
|
||||||
- {fileID: 789049882}
|
- {fileID: 789049882}
|
||||||
|
- {fileID: 777749261}
|
||||||
m_Father: {fileID: 1798580248}
|
m_Father: {fileID: 1798580248}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &777749260
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 777749261}
|
||||||
|
- component: {fileID: 777749262}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Tutorial Feature Module
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &777749261
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 777749260}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 752713007}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &777749262
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 777749260}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 97ce2c486cc8541d1ab1d83fda7f8eda, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Features.Tutorial::Darkmatter.Features.Tutorial.Installers.TutorialFeatureModule
|
||||||
|
overlayView: {fileID: 1976259501}
|
||||||
|
config: {fileID: 11400000, guid: 71357eb1222bb4151ab4e5697a1decd3, type: 2}
|
||||||
--- !u!1 &789049881
|
--- !u!1 &789049881
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2319,6 +2366,7 @@ MonoBehaviour:
|
|||||||
- {fileID: 361052052}
|
- {fileID: 361052052}
|
||||||
- {fileID: 1707278034}
|
- {fileID: 1707278034}
|
||||||
- {fileID: 164240471}
|
- {fileID: 164240471}
|
||||||
|
- {fileID: 777749262}
|
||||||
--- !u!1 &1890425864
|
--- !u!1 &1890425864
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2365,6 +2413,158 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: Features.AppBoot::Darkmatter.Features.AppBoot.SceneRefs.AppBootSceneRefs
|
m_EditorClassIdentifier: Features.AppBoot::Darkmatter.Features.AppBoot.SceneRefs.AppBootSceneRefs
|
||||||
<IntroVideoPlayer>k__BackingField: {fileID: 2122267604}
|
<IntroVideoPlayer>k__BackingField: {fileID: 2122267604}
|
||||||
<IntroCanvas>k__BackingField: {fileID: 2133561494}
|
<IntroCanvas>k__BackingField: {fileID: 2133561494}
|
||||||
|
--- !u!1001 &1976259500
|
||||||
|
PrefabInstance:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Modification:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransformParent: {fileID: 0}
|
||||||
|
m_Modifications:
|
||||||
|
- target: {fileID: 100100, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_Name
|
||||||
|
value: TutorialOverlayCanvas
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_Pivot.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_Pivot.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.w
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100101, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100603, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_Enabled
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100701, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.x
|
||||||
|
value: 200
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100701, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.y
|
||||||
|
value: 200
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 100901, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.y
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.y
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.x
|
||||||
|
value: 207.45999
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101001, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.y
|
||||||
|
value: -95.50001
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 101003, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
propertyPath: m_fontSize
|
||||||
|
value: 60
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
m_RemovedComponents: []
|
||||||
|
m_RemovedGameObjects: []
|
||||||
|
m_AddedGameObjects: []
|
||||||
|
m_AddedComponents: []
|
||||||
|
m_SourcePrefab: {fileID: 100100000, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
--- !u!114 &1976259501 stripped
|
||||||
|
MonoBehaviour:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 100106, guid: 7d10b17c0a1e4e7d9b2f8c6a5d4e3f22, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 1976259500}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 4ecf127118699405ebcd0e0712d7373d, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
--- !u!1 &2122267603
|
--- !u!1 &2122267603
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2553,3 +2753,4 @@ SceneRoots:
|
|||||||
- {fileID: 673724413}
|
- {fileID: 673724413}
|
||||||
- {fileID: 1156238481}
|
- {fileID: 1156238481}
|
||||||
- {fileID: 680382929}
|
- {fileID: 680382929}
|
||||||
|
- {fileID: 1976259500}
|
||||||
|
|||||||
@@ -164,7 +164,6 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: Features.Capture::Darkmatter.Features.Capture.CaptureFeatureModule
|
m_EditorClassIdentifier: Features.Capture::Darkmatter.Features.Capture.CaptureFeatureModule
|
||||||
captureScale: 1
|
captureScale: 1
|
||||||
galleryBackground: {fileID: 2800000, guid: 0c8e208e83531f84cb2b842025cdd232, type: 3}
|
|
||||||
captureButtonView: {fileID: 376589371}
|
captureButtonView: {fileID: 376589371}
|
||||||
gallerySaveView: {fileID: 0}
|
gallerySaveView: {fileID: 0}
|
||||||
--- !u!1 &64614225
|
--- !u!1 &64614225
|
||||||
@@ -551,7 +550,7 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 259035377}
|
m_GameObject: {fileID: 259035377}
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1.4399601, y: 1.4399601, z: 1.4399601}
|
m_LocalScale: {x: 1.8345093, y: 1.8345093, z: 1.8345093}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1176170784}
|
- {fileID: 1176170784}
|
||||||
@@ -559,7 +558,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 1, y: 0}
|
m_AnchorMin: {x: 1, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 0}
|
m_AnchorMax: {x: 1, y: 0}
|
||||||
m_AnchoredPosition: {x: -622.2647, y: 212}
|
m_AnchoredPosition: {x: -718, y: 244}
|
||||||
m_SizeDelta: {x: 407.377, y: 163}
|
m_SizeDelta: {x: 407.377, y: 163}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!114 &259035379
|
--- !u!114 &259035379
|
||||||
@@ -821,7 +820,7 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 376589366}
|
m_GameObject: {fileID: 376589366}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1.2278218, y: 1.2278218, z: 1.2278218}
|
m_LocalScale: {x: 1.3688985, y: 1.3688985, z: 1.3688985}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 153461769}
|
m_Father: {fileID: 153461769}
|
||||||
@@ -2437,7 +2436,7 @@ RectTransform:
|
|||||||
m_GameObject: {fileID: 1310839948}
|
m_GameObject: {fileID: 1310839948}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1.1945, y: 1.1945, z: 1.1945}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 2058063738}
|
- {fileID: 2058063738}
|
||||||
@@ -2446,7 +2445,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
m_AnchoredPosition: {x: 505.82385, y: 200.40308}
|
m_AnchoredPosition: {x: 505.82385, y: 257}
|
||||||
m_SizeDelta: {x: 660.4729, y: 319.02832}
|
m_SizeDelta: {x: 660.4729, y: 319.02832}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!114 &1310839950
|
--- !u!114 &1310839950
|
||||||
@@ -3360,10 +3359,6 @@ PrefabInstance:
|
|||||||
propertyPath: m_Name
|
propertyPath: m_Name
|
||||||
value: ArtBookView
|
value: ArtBookView
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 3521470624751981147, guid: 4dd2a1cb2754a410f9f807f563a55e7c, type: 3}
|
|
||||||
propertyPath: m_IsActive
|
|
||||||
value: 0
|
|
||||||
objectReference: {fileID: 0}
|
|
||||||
- target: {fileID: 3765577967584406493, guid: 4dd2a1cb2754a410f9f807f563a55e7c, type: 3}
|
- target: {fileID: 3765577967584406493, guid: 4dd2a1cb2754a410f9f807f563a55e7c, type: 3}
|
||||||
propertyPath: m_Pivot.x
|
propertyPath: m_Pivot.x
|
||||||
value: 0.5
|
value: 0.5
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
|
|
||||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.google.firebase</groupId>
|
<groupId>com.google.firebase</groupId>
|
||||||
<artifactId>firebase-analytics-unity</artifactId>
|
<artifactId>firebase-analytics-unity</artifactId>
|
||||||
<version>13.11.0</version>
|
<version>13.11.0</version>
|
||||||
<packaging>aar</packaging>
|
<packaging>srcaar</packaging>
|
||||||
<dependencies>
|
<dependencies></dependencies>
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
|
|
||||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.google.firebase</groupId>
|
<groupId>com.google.firebase</groupId>
|
||||||
<artifactId>firebase-app-unity</artifactId>
|
<artifactId>firebase-app-unity</artifactId>
|
||||||
<version>13.11.0</version>
|
<version>13.11.0</version>
|
||||||
<packaging>aar</packaging>
|
<packaging>srcaar</packaging>
|
||||||
<dependencies>
|
<dependencies></dependencies>
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
|
|
||||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.google.firebase</groupId>
|
<groupId>com.google.firebase</groupId>
|
||||||
<artifactId>firebase-crashlytics-unity</artifactId>
|
<artifactId>firebase-crashlytics-unity</artifactId>
|
||||||
<version>13.11.0</version>
|
<version>13.11.0</version>
|
||||||
<packaging>aar</packaging>
|
<packaging>srcaar</packaging>
|
||||||
<dependencies>
|
<dependencies></dependencies>
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
8
Assets/GeneratedLocalRepo.meta
Normal file
8
Assets/GeneratedLocalRepo.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 83732855be18646128164c8d644d01bd
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/GeneratedLocalRepo/Firebase.meta
Normal file
8
Assets/GeneratedLocalRepo/Firebase.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2451496f684c848beb22b71b81903a15
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/GeneratedLocalRepo/Firebase/m2repository.meta
Normal file
8
Assets/GeneratedLocalRepo/Firebase/m2repository.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 54010902c78a941509e897823321d35e
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/GeneratedLocalRepo/Firebase/m2repository/com.meta
Normal file
8
Assets/GeneratedLocalRepo/Firebase/m2repository/com.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c648d2de1050c479b87d888a0ac24ee1
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2fe52c66d427049abbcab20b07c64623
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 03d5972fac263492a8178b6868e96fef
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eb03e879ecfd84fa5a561c4ed17d3a52
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 488e722f615c144958f0882c5ba8f292
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 29951eef4f9054aa88743cf6c4efbaae
|
||||||
|
labels:
|
||||||
|
- gpsr
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 3
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
Android:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
Any:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
Editor:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.google.firebase</groupId>
|
||||||
|
<artifactId>firebase-analytics-unity</artifactId>
|
||||||
|
<version>13.11.0</version>
|
||||||
|
<packaging>aar</packaging>
|
||||||
|
<dependencies></dependencies>
|
||||||
|
</project>
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 95b36b0e05811724fa9ff82f0e1b72ed
|
guid: 07873cfa577e34134a09d460a78b614c
|
||||||
|
labels:
|
||||||
|
- gpsr
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 727b3d8e3d42849fdbef83b22b5d58eb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ad53f7df8726c45d2a1b9908d33aeb29
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f6c1d3b42f439488c86ed09c55566281
|
||||||
|
labels:
|
||||||
|
- gpsr
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 3
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
Android:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
Any:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
Editor:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.google.firebase</groupId>
|
||||||
|
<artifactId>firebase-app-unity</artifactId>
|
||||||
|
<version>13.11.0</version>
|
||||||
|
<packaging>aar</packaging>
|
||||||
|
<dependencies></dependencies>
|
||||||
|
</project>
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3509e33d6780510448b1f27a6ad6b84f
|
guid: bcd4da93c567b4aa19035656e33aaf4b
|
||||||
|
labels:
|
||||||
|
- gpsr
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0c1c59c3e31b246b49b12204516afeeb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user