Complete persistence boundaries and free-play supply with device verification
This commit is contained in:
@@ -16,10 +16,19 @@ namespace MagnetismHeroes.Core
|
||||
public BoardRules Board { get; private set; }
|
||||
public CameraState Camera { get; private set; } = DefaultCamera();
|
||||
public string LastSaveError { get; private set; }
|
||||
public event Action<string> SaveFinished;
|
||||
public bool HasFreePlay => _progress.latestFreePlay != null;
|
||||
public int[] CompletedStageIds => (int[])_progress.completedStageIds.Clone();
|
||||
public IReadOnlyList<StageDefinition> Definitions => Array.AsReadOnly(_definitions);
|
||||
public bool HasUnfinishedStage(int stageId) => _progress.puzzleStates.Any(state => state.stageId == stageId);
|
||||
public bool HasSeenTutorial(string id) => _progress.seenTutorialIds.Contains(id);
|
||||
|
||||
public bool MarkTutorialSeen(string id)
|
||||
{
|
||||
if ((id != "merge" && id != "split") || HasSeenTutorial(id)) return false;
|
||||
_progress.seenTutorialIds = _progress.seenTutorialIds.Concat(new[] { id }).ToArray();
|
||||
SaveCurrent(); return true;
|
||||
}
|
||||
|
||||
public GameSession(IEnumerable<StageDefinition> definitions, IProgressStore store)
|
||||
{
|
||||
@@ -67,6 +76,14 @@ namespace MagnetismHeroes.Core
|
||||
public RuleResult SplitAndMove(string groupId, IReadOnlyList<string> selectedIds, string newGroupId, Position3 delta) =>
|
||||
Commit(() => Board.TrySplitAndMove(groupId, selectedIds, newGroupId, delta));
|
||||
public RuleResult Count(string ballId) => Commit(() => Board.TryCount(ballId));
|
||||
public RuleResult ReturnGroup(string groupId) => Commit(() => Board.TryReturn(groupId));
|
||||
public RuleResult Spawn(Position3 position)
|
||||
{
|
||||
if (Board == null) return RuleResult.Reject(RejectionReason.InvalidGroup);
|
||||
int index = 1;
|
||||
while (Board.Balls.Any(ball => ball.id == $"free-b{index:D2}") || Board.Groups.Any(group => group.id == $"free-g{index:D2}")) index++;
|
||||
return Commit(() => Board.TrySpawn($"free-b{index:D2}", $"free-g{index:D2}", position));
|
||||
}
|
||||
|
||||
public void CommitCamera(CameraState camera)
|
||||
{
|
||||
@@ -104,6 +121,7 @@ namespace MagnetismHeroes.Core
|
||||
}
|
||||
var success = _store.TrySave(_progress, out var error);
|
||||
LastSaveError = error;
|
||||
SaveFinished?.Invoke(error);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using MagnetismHeroes.Core;
|
||||
using MagnetismHeroes.UnityRuntime.Bootstrap;
|
||||
using MagnetismHeroes.UnityRuntime.StageAssets;
|
||||
using TMPro;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MagnetismHeroes.Editor
|
||||
{
|
||||
public static class PersistenceAssets
|
||||
{
|
||||
private const string Presentation = "Assets/MagnetismHeroes/UnityRuntime/Presentation/";
|
||||
[MenuItem("Magnetism Heroes/Build Persistence Assets")]
|
||||
public static void Build()
|
||||
{
|
||||
var font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(Presentation + "Fonts/NotoSansCJKkr-FirstSlice.asset");
|
||||
const string glyphs = "2 하나 꺼내기 친구 반납 지금은 저장하지 못했어요. 다시 해볼게요. 빈 곳이 보이도록 화면을 움직여 볼까?";
|
||||
if (glyphs.Any(character => !font.HasCharacter(character)))
|
||||
{
|
||||
typeof(TMP_FontAsset).GetProperty("SourceFont_EditorRef", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
.SetValue(font, AssetDatabase.LoadAssetAtPath<Font>(Presentation + "Fonts/NotoSansCJKkr-Regular.otf"));
|
||||
font.atlasPopulationMode = AtlasPopulationMode.Dynamic;
|
||||
try { if (!font.TryAddCharacters(glyphs, out var missing)) throw new InvalidOperationException("Missing persistence glyphs: " + missing); }
|
||||
finally { font.atlasPopulationMode = AtlasPopulationMode.Static; }
|
||||
EditorUtility.SetDirty(font);
|
||||
}
|
||||
const string stagePath = "Assets/MagnetismHeroes/UnityRuntime/StageAssets/Stage02.asset";
|
||||
var stage = AssetDatabase.LoadAssetAtPath<StageAsset>(stagePath);
|
||||
if (stage == null) { stage = ScriptableObject.CreateInstance<StageAsset>(); AssetDatabase.CreateAsset(stage, stagePath); }
|
||||
var stageFields = new SerializedObject(stage); stageFields.FindProperty("_stageId").intValue = 2;
|
||||
stageFields.FindProperty("_kind").enumValueIndex = (int)StageKind.Counting;
|
||||
var initial = stageFields.FindProperty("_initialGroups"); initial.arraySize = 2;
|
||||
initial.GetArrayElementAtIndex(0).intValue = initial.GetArrayElementAtIndex(1).intValue = 1;
|
||||
var target = stageFields.FindProperty("_targetGroups"); target.arraySize = 1; target.GetArrayElementAtIndex(0).intValue = 2;
|
||||
var positions = stageFields.FindProperty("_ballPositions"); positions.arraySize = 2;
|
||||
positions.GetArrayElementAtIndex(0).vector3Value = new Vector3(-1.2f, .8f, 0);
|
||||
positions.GetArrayElementAtIndex(1).vector3Value = new Vector3(1.2f, .8f, 0); stageFields.ApplyModifiedPropertiesWithoutUndo();
|
||||
var root = PrefabUtility.LoadPrefabContents(FirstSliceAssets.AppPrefabPath);
|
||||
try
|
||||
{
|
||||
var app = new SerializedObject(root.GetComponent<GameApp>());
|
||||
var stages = app.FindProperty("_stages"); var catalog = Enumerable.Range(0, stages.arraySize)
|
||||
.Select(index => (StageAsset)stages.GetArrayElementAtIndex(index).objectReferenceValue).Where(value => value.StageId != 2)
|
||||
.Concat(new[] { stage }).OrderBy(value => value.StageId).ToArray(); stages.arraySize = catalog.Length;
|
||||
for (int index = 0; index < catalog.Length; index++) stages.GetArrayElementAtIndex(index).objectReferenceValue = catalog[index];
|
||||
var safe = root.transform.Find("Interface/SafeArea"); var selection = safe.Find("StageSelection");
|
||||
var template = selection.Find("Stage01Button").gameObject;
|
||||
var stageButton = Button(selection, template, "Stage02Button", "2 친구 찾기", new Vector2(.5f, .36f), new Vector2(280, 72));
|
||||
app.FindProperty("_stageTwoButton").objectReferenceValue = stageButton;
|
||||
var play = safe.Find("Play"); var playTemplate = play.Find("HomeButton").gameObject;
|
||||
app.FindProperty("_spawnButton").objectReferenceValue = Button(play, playTemplate, "SpawnButton", "하나 꺼내기", new Vector2(.86f, .3f), new Vector2(240, 62));
|
||||
app.FindProperty("_returnButton").objectReferenceValue = Button(play, playTemplate, "ReturnButton", "친구 반납", new Vector2(.86f, .2f), new Vector2(240, 62));
|
||||
var notice = (TMP_Text)app.FindProperty("_saveNotice").objectReferenceValue;
|
||||
notice.transform.SetParent(safe, false); notice.transform.SetAsLastSibling();
|
||||
notice.rectTransform.anchorMin = notice.rectTransform.anchorMax = new Vector2(.5f, .07f);
|
||||
notice.rectTransform.anchoredPosition = Vector2.zero;
|
||||
app.ApplyModifiedPropertiesWithoutUndo(); PrefabUtility.SaveAsPrefabAsset(root, FirstSliceAssets.AppPrefabPath);
|
||||
}
|
||||
finally { PrefabUtility.UnloadPrefabContents(root); }
|
||||
AssetDatabase.SaveAssets(); Debug.Log("[Persistence] Stage02, locked selection, free supply/whole-friend return and shared save notice wired. Main unchanged.");
|
||||
}
|
||||
private static UnityEngine.UI.Button Button(Transform parent, GameObject template, string name, string label, Vector2 anchor, Vector2 size)
|
||||
{
|
||||
var existing = parent.Find(name); var button = existing == null ? UnityEngine.Object.Instantiate(template, parent) : existing.gameObject;
|
||||
button.name = name; var rect = (RectTransform)button.transform; rect.anchorMin = rect.anchorMax = anchor;
|
||||
rect.anchoredPosition = Vector2.zero; rect.sizeDelta = size;
|
||||
var text = button.GetComponentInChildren<TMP_Text>(); text.text = label; text.rectTransform.sizeDelta = size;
|
||||
return button.GetComponent<UnityEngine.UI.Button>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60c8eab85ee35ad40884c25ab21276c9
|
||||
@@ -26,9 +26,9 @@ namespace MagnetismHeroes.Tests
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/MagnetismHeroes/UnityRuntime/Presentation/Prefabs/GameApp.prefab");
|
||||
var serialized = new SerializedObject(prefab.GetComponent<GameApp>()); var stages = serialized.FindProperty("_stages");
|
||||
Assert.That(stages.arraySize, Is.EqualTo(4)); var definitions = Enumerable.Range(0, stages.arraySize)
|
||||
Assert.That(stages.arraySize, Is.EqualTo(5)); var definitions = Enumerable.Range(0, stages.arraySize)
|
||||
.Select(index => ((StageAsset)stages.GetArrayElementAtIndex(index).objectReferenceValue).ToDefinition()).ToArray();
|
||||
Assert.That(definitions.Select(stage => stage.Id), Is.EqualTo(new[] { 1, 6, 10, 14 }));
|
||||
Assert.That(definitions.Select(stage => stage.Id), Is.EqualTo(new[] { 1, 2, 6, 10, 14 }));
|
||||
var session = new GameSession(definitions, new EmptyStore()); Assert.That(session.IsUnlocked(6), Is.False);
|
||||
Assert.That(session.StartStage(6), Is.False); Assert.That(session.IsUnlocked(10), Is.False); Assert.That(session.IsUnlocked(14), Is.False);
|
||||
Assert.That(serialized.FindProperty("_compositionButtons").arraySize, Is.EqualTo(3));
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace MagnetismHeroes.Tests
|
||||
Assert.That(File.ReadAllText(_path), Is.EqualTo("broken-primary"));
|
||||
Assert.That(store.TrySave(new ProgressSave(), out var error), Is.True, error);
|
||||
Assert.That(Directory.GetFiles(_directory, "*.damaged-*").Select(File.ReadAllText), Does.Contain("broken-primary"));
|
||||
Assert.That(File.ReadAllText(_path + ".bak"), Is.EqualTo("broken-backup"));
|
||||
}
|
||||
[Test] public void InvalidGroupMembershipDoesNotReplaceAValidSave()
|
||||
{
|
||||
@@ -99,5 +100,23 @@ namespace MagnetismHeroes.Tests
|
||||
Assert.That(Store().TrySave(Puzzle(), out _), Is.True);
|
||||
Assert.That(File.ReadAllText(_path), Does.Not.Contain("IsValid"));
|
||||
}
|
||||
[Test] public void LockedTemporaryFileReportsFailureAndKeepsTheLastValidSave()
|
||||
{
|
||||
var store = Store(); Assert.That(store.TrySave(Puzzle(), out _), Is.True);
|
||||
Assert.That(store.TrySave(Puzzle(), out _), Is.True);
|
||||
var before = File.ReadAllBytes(_path);
|
||||
var backupBefore = File.ReadAllBytes(_path + ".bak");
|
||||
using (var locked = new FileStream(_path + ".tmp", FileMode.Create, FileAccess.ReadWrite, FileShare.None))
|
||||
{
|
||||
string error = null; bool saved = true;
|
||||
Assert.DoesNotThrow(() => saved = store.TrySave(Puzzle(), out error));
|
||||
Assert.That(saved, Is.False); Assert.That(error, Is.Not.Empty);
|
||||
Assert.That(File.ReadAllBytes(_path), Is.EqualTo(before));
|
||||
Assert.That(File.ReadAllBytes(_path + ".bak"), Is.EqualTo(backupBefore));
|
||||
}
|
||||
Assert.That(store.TryLoad(out var restored, out _), Is.True);
|
||||
Assert.That(restored.puzzleStates.Length, Is.EqualTo(1));
|
||||
Assert.That(store.TrySave(Puzzle(), out var recoveredError), Is.True, recoveredError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MagnetismHeroes.Core;
|
||||
using MagnetismHeroes.UnityRuntime.Persistence;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace MagnetismHeroes.Tests
|
||||
{
|
||||
public sealed class PersistenceSessionTests
|
||||
{
|
||||
private string _directory, _path;
|
||||
private static readonly StageDefinition[] Definitions = {
|
||||
new StageDefinition(1, StageKind.Counting, new[] { 1 }, new[] { 1 }),
|
||||
new StageDefinition(2, StageKind.Counting, new[] { 1, 1 }, new[] { 2 }),
|
||||
new StageDefinition(6, StageKind.Composition, new[] { 1, 1 }, new[] { 2 }) };
|
||||
private sealed class RecordedStore : IProgressStore
|
||||
{
|
||||
private readonly LocalProgressStore _store;
|
||||
public int Writes;
|
||||
public RecordedStore(string path) { _store = new LocalProgressStore(path, Definitions); }
|
||||
public bool TryLoad(out ProgressSave save, out string error) => _store.TryLoad(out save, out error);
|
||||
public bool TrySave(ProgressSave save, out string error) { Writes++; return _store.TrySave(save, out error); }
|
||||
}
|
||||
[SetUp] public void SetUp()
|
||||
{ _directory = Path.Combine(Path.GetTempPath(), "MagnetismHeroes-persistence-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(_directory); _path = Path.Combine(_directory, "progress.json"); }
|
||||
[TearDown] public void TearDown() => Directory.Delete(_directory, true);
|
||||
private ProgressSave Load()
|
||||
{ Assert.That(new LocalProgressStore(_path, Definitions).TryLoad(out var save, out var error), Is.True, error); return save; }
|
||||
private static CameraState Camera(float distance) => new CameraState {
|
||||
target = new Position3(1, .8f, -2), rotation = new Rotation4(0, .6f, 0, .8f), distance = distance };
|
||||
private static void CompleteOne(GameSession session)
|
||||
{ session.StartStage(1); session.MoveGroup(session.Board.Groups.Single().id, new Position3(.5f, .8f, 0)); session.Count(session.Board.Balls.Single().id); }
|
||||
|
||||
[Test] public void ActualFileAlternatesTwoUnfinishedBoardsAndLatestFreeWithoutLosingAnyField()
|
||||
{
|
||||
var store = new RecordedStore(_path); var session = new GameSession(Definitions, store); CompleteOne(session);
|
||||
session.Spawn(new Position3(-2, .8f, 0)); session.CommitCamera(Camera(9)); session.ShowHome();
|
||||
session.StartStage(2); var groups = session.Board.Groups;
|
||||
session.MoveAndMerge(groups[0].id, new Position3(.6f, 1.1f, -2), groups[1].id);
|
||||
session.Count(session.Board.Balls[0].id); session.CommitCamera(Camera(11)); session.ShowHome();
|
||||
var fixture = Load(); fixture.completedStageIds = new[] { 1, 2, 3, 4, 5 };
|
||||
Assert.That(new LocalProgressStore(_path, Definitions).TrySave(fixture, out var error), Is.True, error);
|
||||
session = new GameSession(Definitions, new RecordedStore(_path)); session.StartStage(6);
|
||||
session.MoveGroup(session.Board.Groups[0].id, new Position3(-1, .8f, 2)); session.CommitCamera(Camera(7)); session.ShowHome();
|
||||
var before = File.ReadAllBytes(_path); var saved = Load();
|
||||
Assert.That(saved.puzzleStates.Length, Is.EqualTo(2));
|
||||
Assert.That(saved.puzzleStates.Single(state => state.stageId == 2).countedBallIds.Length, Is.EqualTo(1));
|
||||
foreach (int id in new[] { 2, 6, 2, 6 })
|
||||
{
|
||||
session = new GameSession(Definitions, new RecordedStore(_path)); Assert.That(session.Screen, Is.EqualTo(SessionScreen.Home));
|
||||
Assert.That(session.StartStage(id), Is.True); var expected = saved.puzzleStates.Single(state => state.stageId == id);
|
||||
AssertBoard(session.Board, expected.balls, expected.groups); AssertCamera(session.Camera, expected.camera);
|
||||
Assert.That(session.Board.CollectedBallIds, Is.EqualTo(expected.collectedBallIds));
|
||||
Assert.That(session.Board.CountedBallIds, Is.EqualTo(expected.countedBallIds)); session.ShowHome();
|
||||
Assert.That(session.ContinueFreePlay(), Is.True); AssertBoard(session.Board, saved.latestFreePlay.balls, saved.latestFreePlay.groups);
|
||||
AssertCamera(session.Camera, saved.latestFreePlay.camera); session.ShowHome();
|
||||
Assert.That(File.ReadAllBytes(_path), Is.EqualTo(before), "Exact deterministic JSON bytes retain both unfinished plus global Free.");
|
||||
}
|
||||
}
|
||||
[Test] public void CompletionIsOneWriteReplacesOnlyLatestFreeAndReplayKeepsProgress()
|
||||
{
|
||||
var store = new RecordedStore(_path); var session = new GameSession(Definitions, store); CompleteOne(session);
|
||||
session.StartStage(2); session.MoveAndMerge(session.Board.Groups[0].id, new Position3(.5f, 0, 0), session.Board.Groups[1].id);
|
||||
session.Count(session.Board.Balls[0].id); int before = store.Writes;
|
||||
session.Count(session.Board.Balls[1].id); Assert.That(store.Writes, Is.EqualTo(before + 1));
|
||||
var completed = Load(); Assert.That(completed.completedStageIds, Is.EqualTo(new[] { 1, 2 }));
|
||||
Assert.That(completed.puzzleStates, Is.Empty); Assert.That(completed.latestFreePlay.sourceStageId, Is.EqualTo(2));
|
||||
session.StartStage(1); session.MoveGroup(session.Board.Groups[0].id, new Position3(.2f, 0, 0));
|
||||
var replay = Load(); Assert.That(replay.completedStageIds, Is.EqualTo(new[] { 1, 2 }));
|
||||
Assert.That(replay.puzzleStates.Single().stageId, Is.EqualTo(1)); Assert.That(replay.latestFreePlay.sourceStageId, Is.EqualTo(2));
|
||||
session.Count(session.Board.Balls.Single().id); Assert.That(Load().latestFreePlay.sourceStageId, Is.EqualTo(1));
|
||||
Assert.That(Load().completedStageIds, Is.EqualTo(new[] { 1, 2 }));
|
||||
}
|
||||
[Test] public void TutorialRecordsAreUniqueValidatedAndPersistAcrossFreeAndPuzzleTransitions()
|
||||
{
|
||||
var store = new RecordedStore(_path); var session = new GameSession(Definitions, store);
|
||||
Assert.That(session.MarkTutorialSeen("merge"), Is.True); int before = store.Writes;
|
||||
Assert.That(session.MarkTutorialSeen("merge"), Is.False); Assert.That(session.MarkTutorialSeen("unknown"), Is.False);
|
||||
Assert.That(store.Writes, Is.EqualTo(before)); CompleteOne(session); Assert.That(session.MarkTutorialSeen("split"), Is.True);
|
||||
session.StartStage(1); session.ShowHome(); session = new GameSession(Definitions, new RecordedStore(_path));
|
||||
Assert.That(session.HasSeenTutorial("merge"), Is.True); Assert.That(session.HasSeenTutorial("split"), Is.True);
|
||||
Assert.That(Load().seenTutorialIds, Is.EqualTo(new[] { "merge", "split" }));
|
||||
}
|
||||
private static void AssertBoard(BoardRules board, BallState[] balls, GroupState[] groups)
|
||||
{
|
||||
Assert.That(board.Balls.Select(ball => ball.id), Is.EqualTo(balls.Select(ball => ball.id)));
|
||||
Assert.That(board.Balls.Select(ball => ball.position), Is.EqualTo(balls.Select(ball => ball.position)));
|
||||
Assert.That(board.Groups.Select(group => group.id), Is.EqualTo(groups.Select(group => group.id)));
|
||||
for (int index = 0; index < groups.Length; index++) Assert.That(board.Groups[index].ballIds, Is.EqualTo(groups[index].ballIds));
|
||||
}
|
||||
private static void AssertCamera(CameraState actual, CameraState expected)
|
||||
{ Assert.That(actual.target, Is.EqualTo(expected.target)); Assert.That(actual.rotation, Is.EqualTo(expected.rotation)); Assert.That(actual.distance, Is.EqualTo(expected.distance)); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8666ab89be2e7ab4a96f90ee79122b2f
|
||||
@@ -20,8 +20,16 @@ namespace MagnetismHeroes.Tests
|
||||
private sealed class MemoryStore : IProgressStore
|
||||
{
|
||||
public ProgressSave Saved = new ProgressSave();
|
||||
public bool TryLoad(out ProgressSave save, out string error) { save = Saved; error = null; return true; }
|
||||
public bool TrySave(ProgressSave save, out string error) { Saved = save; error = null; return true; }
|
||||
public bool FailWrites;
|
||||
private static ProgressSave Copy(ProgressSave save)
|
||||
{ var copy = JsonUtility.FromJson<ProgressSave>(JsonUtility.ToJson(save)); if (save.latestFreePlay == null) copy.latestFreePlay = null; return copy; }
|
||||
public bool TryLoad(out ProgressSave save, out string error) { save = Copy(Saved); error = null; return true; }
|
||||
public bool TrySave(ProgressSave save, out string error)
|
||||
{
|
||||
error = FailWrites ? "Disk full during committed save" : null;
|
||||
if (FailWrites) return false;
|
||||
Saved = Copy(save); return true;
|
||||
}
|
||||
}
|
||||
private GameApp _app; private MemoryStore _store; private Touchscreen _touchscreen;
|
||||
private InputSettings _originalInputSettings, _testInputSettings;
|
||||
@@ -63,6 +71,75 @@ namespace MagnetismHeroes.Tests
|
||||
private void QueueTouch(int id, UnityEngine.InputSystem.TouchPhase phase, Vector2 position) =>
|
||||
InputSystem.QueueStateEvent(_touchscreen, new TouchState { touchId = id, phase = phase, position = position });
|
||||
|
||||
[UnityTest] public IEnumerator FailedMoveCameraAndPauseSavesShowAVisibleNoticeAndRecoveryClearsIt()
|
||||
{
|
||||
_app.StartStage(1); yield return null;
|
||||
var before = JsonUtility.ToJson(_store.Saved); _store.FailWrites = true;
|
||||
_app.CommitMove(_app.Session.Board.Groups.Single().id, new Position3(.2f, 0, 0));
|
||||
var notice = _app.GetComponentsInChildren<TMP_Text>(true).Single(text => text.name == "SaveNotice");
|
||||
Assert.That(notice.text, Does.Contain("저장")); Assert.That(notice.gameObject.activeInHierarchy, Is.True);
|
||||
Assert.That(JsonUtility.ToJson(_store.Saved), Is.EqualTo(before));
|
||||
_store.FailWrites = false; _app.Session.SaveCurrent(); Assert.That(notice.text, Is.Empty);
|
||||
_store.FailWrites = true; _app.Input.Begin(new Vector2(Screen.width - 30, Screen.height / 2), false);
|
||||
_app.Input.Move(new Vector2(Screen.width - 80, Screen.height / 2)); _app.Input.End(new Vector2(Screen.width - 80, Screen.height / 2));
|
||||
Assert.That(notice.text, Does.Contain("저장"));
|
||||
_store.FailWrites = false; _app.Session.SaveCurrent(); Assert.That(notice.text, Is.Empty);
|
||||
_store.FailWrites = true; _app.gameObject.SendMessage("OnApplicationPause", true);
|
||||
Assert.That(notice.text, Does.Contain("저장"));
|
||||
_store.FailWrites = false; _app.gameObject.SendMessage("OnApplicationPause", true);
|
||||
Assert.That(notice.text, Is.Empty);
|
||||
}
|
||||
|
||||
[UnityTest] public IEnumerator FreeSupplyButtonsCanReachTenRejectMoreReturnAWholeFriendAndRespawnEmptyBoard()
|
||||
{
|
||||
_app.StartStage(1); yield return null; Physics.SyncTransforms();
|
||||
var point = BallPoint(); Drag(point, point + new Vector2(60, 0)); yield return null; Physics.SyncTransforms(); Tap(BallPoint()); yield return null;
|
||||
var spawnObject = _app.transform.Find("Interface/SafeArea/Play/SpawnButton");
|
||||
Assert.That(spawnObject, Is.Not.Null, "Free play needs its real supply button.");
|
||||
var spawn = spawnObject.GetComponent<UnityEngine.UI.Button>();
|
||||
var giveBack = _app.transform.Find("Interface/SafeArea/Play/ReturnButton").GetComponent<UnityEngine.UI.Button>();
|
||||
for (int index = 0; index < 9; index++) { spawn.onClick.Invoke(); yield return null; }
|
||||
Assert.That(_app.Session.Board.BallCount, Is.EqualTo(10)); var full = JsonUtility.ToJson(_store.Saved);
|
||||
Assert.That(spawn.interactable, Is.False); spawn.onClick.Invoke(); Assert.That(JsonUtility.ToJson(_store.Saved), Is.EqualTo(full));
|
||||
while (_app.Session.Board.BallCount > 0)
|
||||
{
|
||||
var ball = _app.Presenter.Balls.Values.First(); Vector2 location = _app.Presenter.Camera.WorldToScreenPoint(ball.transform.position);
|
||||
int before = _app.Session.Board.BallCount; Tap(location); giveBack.onClick.Invoke(); yield return null; Physics.SyncTransforms();
|
||||
Assert.That(_app.Session.Board.BallCount, Is.LessThan(before));
|
||||
}
|
||||
Assert.That(_app.Session.Board.Groups, Is.Empty); Assert.That(_store.Saved.completedStageIds, Is.EqualTo(new[] { 1 }));
|
||||
spawn.onClick.Invoke(); yield return null; Assert.That(_app.Session.Board.BallCount, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[UnityTest] public IEnumerator SuccessfulTwoCountKeepsItsFinalNumbersDuringFreeSplitCancelAndCommit()
|
||||
{
|
||||
_store.Saved.completedStageIds = new[] { 1 }; _app.Initialize(_store);
|
||||
foreach (bool cancel in new[] { true, false })
|
||||
{
|
||||
_app.StartStage(2); yield return null; Physics.SyncTransforms();
|
||||
var groups = _app.Session.Board.Groups;
|
||||
_app.CommitMove(groups[0].id, new Position3(.6f, 0, 0), groups[1].id);
|
||||
var ids = _app.Session.Board.Balls.Select(ball => ball.id).ToArray();
|
||||
foreach (string id in ids)
|
||||
{
|
||||
Vector2 point = _app.Presenter.Camera.WorldToScreenPoint(_app.Presenter.Balls[id].transform.position);
|
||||
Tap(point);
|
||||
}
|
||||
Assert.That(_app.Session.Screen, Is.EqualTo(SessionScreen.FreePlay)); Assert.That(_app.Voice.PendingCount, Is.EqualTo(2));
|
||||
Assert.That(_app.GetComponent<AudioSource>().clip.name, Is.EqualTo("count_01"));
|
||||
Vector2 firstPoint = _app.Presenter.Camera.WorldToScreenPoint(_app.Presenter.Balls[ids[0]].transform.position); Tap(firstPoint);
|
||||
_app.transform.Find("Interface/SafeArea/Play/SplitButton").GetComponent<UnityEngine.UI.Button>().onClick.Invoke();
|
||||
if (cancel) _app.transform.Find("Interface/SafeArea/Play/CancelSplitButton").GetComponent<UnityEngine.UI.Button>().onClick.Invoke();
|
||||
else { Tap(firstPoint); Drag(firstPoint, firstPoint - new Vector2(120, 0)); }
|
||||
Assert.That(_app.Voice.PendingCount, Is.EqualTo(2), cancel ? "Cancel split must keep count FIFO." : "Committed split must keep count FIFO.");
|
||||
float deadline = Time.realtimeSinceStartup + 5;
|
||||
while (_app.Voice.CurrentClipId == "count_01" && Time.realtimeSinceStartup < deadline) yield return null;
|
||||
Assert.That(_app.Voice.CurrentClipId, Is.EqualTo("count_02")); Assert.That(_app.GetComponent<AudioSource>().isPlaying, Is.True);
|
||||
while (_app.Voice.PendingCount > 0 && Time.realtimeSinceStartup < deadline) yield return null;
|
||||
Assert.That(_app.Voice.PendingCount, Is.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest] public IEnumerator SameUpdateShortTapRespondsBeforeCollectionAndCountsOnceAfterCollection()
|
||||
{
|
||||
_touchscreen = InputSystem.AddDevice<Touchscreen>(); _app.StartStage(1); yield return null; Physics.SyncTransforms();
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
|
||||
[SerializeField] private UnityEngine.UI.Button _playButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _continueButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _stageOneButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _stageTwoButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _spawnButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _returnButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _homeButton;
|
||||
[SerializeField] private UnityEngine.UI.Button _selectionHomeButton;
|
||||
[SerializeField] private UnityEngine.UI.Button[] _compositionButtons = Array.Empty<UnityEngine.UI.Button>();
|
||||
@@ -47,12 +50,15 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
|
||||
_playButton.onClick.AddListener(ShowSelection);
|
||||
_continueButton.onClick.AddListener(ContinueFreePlay);
|
||||
_stageOneButton.onClick.AddListener(() => StartStage(1));
|
||||
if (_stageTwoButton != null) _stageTwoButton.onClick.AddListener(() => StartStage(2));
|
||||
if (_spawnButton != null) _spawnButton.onClick.AddListener(SpawnFriend);
|
||||
if (_returnButton != null) _returnButton.onClick.AddListener(ReturnSelectedFriend);
|
||||
_homeButton.onClick.AddListener(ShowHome);
|
||||
_selectionHomeButton.onClick.AddListener(ShowHome);
|
||||
for (int index = 0; index < _compositionButtons.Length; index++)
|
||||
{ int stageId = _stages[index + 1].StageId; _compositionButtons[index].onClick.AddListener(() => StartStage(stageId)); }
|
||||
{ int stageId = _stages.Where(stage => stage.ToDefinition().Kind == StageKind.Composition).ElementAt(index).StageId; _compositionButtons[index].onClick.AddListener(() => StartStage(stageId)); }
|
||||
if (_splitButton != null) _splitButton.onClick.AddListener(() => { _input.BeginSplit(); if (_input.IsSplitting) _voice.Guide("guide_split"); });
|
||||
if (_cancelSplitButton != null) _cancelSplitButton.onClick.AddListener(() => { _input.CancelSplit(); _voice.Clear(); });
|
||||
if (_cancelSplitButton != null) _cancelSplitButton.onClick.AddListener(() => { _input.CancelSplit(); _voice.CancelGuide(); });
|
||||
}
|
||||
private void Start()
|
||||
{
|
||||
@@ -62,11 +68,30 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
|
||||
public void Initialize(IProgressStore store)
|
||||
{
|
||||
Session = new GameSession(_stages.Select(stage => stage.ToDefinition()), store);
|
||||
Session.SaveFinished += ShowSaveResult;
|
||||
_saveNotice.text = Session.LastSaveError == null ? "" : Session.LastSaveError.StartsWith("Recovered", StringComparison.Ordinal)
|
||||
? "이전 기록으로 이어서 시작할게요." : "기록을 읽지 못해 처음부터 시작할게요.";
|
||||
if (Session.LastSaveError != null) Debug.LogWarning("[ProgressLoad] " + Session.LastSaveError);
|
||||
Refresh(true);
|
||||
}
|
||||
private void ShowSaveResult(string error)
|
||||
{
|
||||
_saveNotice.text = error == null ? "" : "지금은 저장하지 못했어요. 다시 해볼게요.";
|
||||
if (error != null) Debug.LogWarning("[ProgressSave] " + error);
|
||||
}
|
||||
public void SpawnFriend()
|
||||
{
|
||||
if (Session.Screen != SessionScreen.FreePlay || Session.Board.BallCount >= 10) return;
|
||||
_input.CancelSplit();
|
||||
if (!_presenter.TryFindSpawnPosition(out var position)) { _instruction.text = "빈 곳이 보이도록 화면을 움직여 볼까?"; return; }
|
||||
if (Session.Spawn(position).Accepted) Refresh(false);
|
||||
}
|
||||
public void ReturnSelectedFriend()
|
||||
{
|
||||
if (Session.Screen != SessionScreen.FreePlay || _input.SelectedGroup == null) return;
|
||||
string groupId = _input.SelectedGroup; _input.CancelSplit();
|
||||
if (Session.ReturnGroup(groupId).Accepted) Refresh(false);
|
||||
}
|
||||
public void ShowSelection()
|
||||
{ _input.CancelSplit(); _voice.Clear(); Session.ShowSelection(); Refresh(true); }
|
||||
public void ShowHome()
|
||||
@@ -93,7 +118,7 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
|
||||
string newId = groupId + "-split";
|
||||
while (Session.Board.Groups.Any(group => group.id == newId)) newId += "-split";
|
||||
var result = Session.SplitAndMove(groupId, selected, newId, delta);
|
||||
if (result.Accepted) { _voice.Clear(); Refresh(false); }
|
||||
if (result.Accepted) { _voice.CancelGuide(); Refresh(false); }
|
||||
return result.Accepted;
|
||||
}
|
||||
public void CountBall(string ballId)
|
||||
@@ -116,7 +141,10 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
|
||||
bool playing = screen == SessionScreen.Puzzle || screen == SessionScreen.FreePlay;
|
||||
_playPanel.SetActive(playing); _world.SetActive(playing);
|
||||
_continueButton.gameObject.SetActive(Session.HasFreePlay);
|
||||
for (int index = 0; index < _compositionButtons.Length; index++) _compositionButtons[index].interactable = Session.IsUnlocked(_stages[index + 1].StageId);
|
||||
if (_stageTwoButton != null) _stageTwoButton.interactable = Session.IsUnlocked(2);
|
||||
for (int index = 0; index < _compositionButtons.Length; index++) _compositionButtons[index].interactable = Session.IsUnlocked(_stages.Where(stage => stage.ToDefinition().Kind == StageKind.Composition).ElementAt(index).StageId);
|
||||
if (_spawnButton != null) { _spawnButton.gameObject.SetActive(screen == SessionScreen.FreePlay); _spawnButton.interactable = Session.Board != null && Session.Board.BallCount < 10; }
|
||||
if (_returnButton != null) _returnButton.gameObject.SetActive(screen == SessionScreen.FreePlay);
|
||||
if (applyCamera) _orbit.Apply(Session.Camera);
|
||||
_presenter.Render(Session.Board);
|
||||
if (!playing) return;
|
||||
@@ -137,6 +165,7 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
|
||||
{
|
||||
if (Session == null || _splitButton == null) return;
|
||||
var group = Session.Board?.Groups.FirstOrDefault(value => value.id == _input.SelectedGroup);
|
||||
if (_returnButton != null) _returnButton.interactable = Session.Screen == SessionScreen.FreePlay && group != null && !_input.IsSplitting;
|
||||
_splitButton.gameObject.SetActive(!_input.IsSplitting);
|
||||
_splitButton.interactable = group != null && group.ballIds.Length > 1;
|
||||
_cancelSplitButton.gameObject.SetActive(_input.IsSplitting);
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace MagnetismHeroes.UnityRuntime.Interaction
|
||||
_splitting = true; _selected.Clear(); _app.RefreshSelection();
|
||||
}
|
||||
public void CancelSplit()
|
||||
{ Cancel(); if (_splitting) _app.Voice.Clear(); _splitting = false; _selected.Clear(); _selectedGroup = null; _presenter.ShowSelection(_selected); _app.RefreshSelection(); }
|
||||
{ Cancel(); if (_splitting) _app.Voice.CancelGuide(); _splitting = false; _selected.Clear(); _selectedGroup = null; _presenter.ShowSelection(_selected); _app.RefreshSelection(); }
|
||||
|
||||
public void Begin(Vector2 point, bool uiBlocked)
|
||||
{
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace MagnetismHeroes.UnityRuntime.Persistence
|
||||
{
|
||||
if (!SaveValidator.TryValidate(save, _definitions, out error)) return false;
|
||||
string temporary = _path + ".tmp";
|
||||
bool createdTemporary = false;
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(_path)));
|
||||
@@ -106,7 +107,7 @@ namespace MagnetismHeroes.UnityRuntime.Persistence
|
||||
}
|
||||
using (var stream = new FileStream(temporary, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
using (var writer = new StreamWriter(stream))
|
||||
{ writer.Write(JsonConvert.SerializeObject(save, Formatting.Indented, SerializerSettings)); writer.Flush(); stream.Flush(true); }
|
||||
{ createdTemporary = true; writer.Write(JsonConvert.SerializeObject(save, Formatting.Indented, SerializerSettings)); writer.Flush(); stream.Flush(true); }
|
||||
if (File.Exists(_path))
|
||||
{
|
||||
// Never replace a valid recovered backup with the invalid primary.
|
||||
@@ -118,7 +119,7 @@ namespace MagnetismHeroes.UnityRuntime.Persistence
|
||||
}
|
||||
catch (Exception exception) when (exception is IOException || exception is UnauthorizedAccessException)
|
||||
{ error = exception.Message; return false; }
|
||||
finally { if (File.Exists(temporary)) File.Delete(temporary); }
|
||||
finally { if (createdTemporary && File.Exists(temporary)) File.Delete(temporary); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,23 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryFindSpawnPosition(out Position3 position)
|
||||
{
|
||||
Physics.SyncTransforms();
|
||||
// Search visible space at the same unit size, away from friends and background props.
|
||||
for (int row = 0; row < 5; row++)
|
||||
for (int column = 0; column < 7; column++)
|
||||
{
|
||||
var point = new Vector3((column - 3) * 1.2f, .8f + row * 1.2f, 0);
|
||||
var viewport = _camera.WorldToViewportPoint(point);
|
||||
if (viewport.z <= 0 || viewport.x < .08f || viewport.x > .92f || viewport.y < .3f || viewport.y > .78f) continue;
|
||||
if (_board.Balls.Any(ball => Vector3.Distance(ToVector(ball.position), point) < 1.1f)) continue;
|
||||
if (Physics.OverlapSphere(point, .55f, ~0, QueryTriggerInteraction.Ignore).Any(collider => !collider.transform.IsChildOf(transform))) continue;
|
||||
position = ToPosition(point); return true;
|
||||
}
|
||||
position = default; return false;
|
||||
}
|
||||
|
||||
private void PositionBadges()
|
||||
{
|
||||
if (_board == null) return;
|
||||
|
||||
+416
-81
File diff suppressed because one or more lines are too long
@@ -35,6 +35,8 @@ RectTransform:
|
||||
- {fileID: 947662399340529430}
|
||||
- {fileID: 8104365176756033704}
|
||||
- {fileID: 8364979175126307048}
|
||||
- {fileID: 2329883891830714780}
|
||||
- {fileID: 5090946158136759876}
|
||||
m_Father: {fileID: 3999613752604275916}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -289,6 +291,7 @@ RectTransform:
|
||||
- {fileID: 6801798374945474417}
|
||||
- {fileID: 4774970796337304695}
|
||||
- {fileID: 7868283166943063582}
|
||||
- {fileID: 2650272815419196348}
|
||||
m_Father: {fileID: 3999613752604275916}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -803,6 +806,401 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &1328309431493275319
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5049519322727858860}
|
||||
- component: {fileID: 7493142574714255270}
|
||||
- component: {fileID: 8396089032746231139}
|
||||
m_Layer: 0
|
||||
m_Name: Label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5049519322727858860
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1328309431493275319}
|
||||
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: 2329883891830714780}
|
||||
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: 62}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7493142574714255270
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1328309431493275319}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8396089032746231139
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1328309431493275319}
|
||||
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: "\uD558\uB098 \uAEBC\uB0B4\uAE30"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a5bc77ef7ce7c7e4d85ac578cfcd6646, type: 2}
|
||||
m_sharedMaterial: {fileID: 8207275579423446409, guid: a5bc77ef7ce7c7e4d85ac578cfcd6646, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 0.12, g: 0.2, b: 0.31, 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: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 28
|
||||
m_fontSizeBase: 28
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
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: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656bu
|
||||
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!1 &1458915873150721834
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2650272815419196348}
|
||||
- component: {fileID: 1467687443961635546}
|
||||
- component: {fileID: 6572129107923074595}
|
||||
- component: {fileID: 4131456494785851528}
|
||||
m_Layer: 0
|
||||
m_Name: Stage02Button
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2650272815419196348
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1458915873150721834}
|
||||
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: 5651594774981243508}
|
||||
m_Father: {fileID: 2361705476825752074}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.36}
|
||||
m_AnchorMax: {x: 0.5, y: 0.36}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 280, y: 72}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &1467687443961635546
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1458915873150721834}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &6572129107923074595
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1458915873150721834}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 0.8, b: 0.3, a: 1}
|
||||
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 &4131456494785851528
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1458915873150721834}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 6572129107923074595}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &1467268788090281726
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5651594774981243508}
|
||||
- component: {fileID: 6040077154455259841}
|
||||
- component: {fileID: 3093407653909830820}
|
||||
m_Layer: 0
|
||||
m_Name: Label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5651594774981243508
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1467268788090281726}
|
||||
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: 2650272815419196348}
|
||||
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: 280, y: 72}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6040077154455259841
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1467268788090281726}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &3093407653909830820
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1467268788090281726}
|
||||
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: "2 \uCE5C\uAD6C \uCC3E\uAE30"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a5bc77ef7ce7c7e4d85ac578cfcd6646, type: 2}
|
||||
m_sharedMaterial: {fileID: 8207275579423446409, guid: a5bc77ef7ce7c7e4d85ac578cfcd6646, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 0.12, g: 0.2, b: 0.31, 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: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 34
|
||||
m_fontSizeBase: 34
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
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: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656bu
|
||||
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!1 &1734378736986617752
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -972,7 +1370,6 @@ RectTransform:
|
||||
- {fileID: 3194082258746179425}
|
||||
- {fileID: 4532829656532669174}
|
||||
- {fileID: 5317872834923726274}
|
||||
- {fileID: 983150840242648897}
|
||||
m_Father: {fileID: 3999613752604275916}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -1136,6 +1533,127 @@ Transform:
|
||||
- {fileID: 4847436933123184085}
|
||||
m_Father: {fileID: 6696913924934804788}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3130945442339227461
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5090946158136759876}
|
||||
- component: {fileID: 9219190355672231004}
|
||||
- component: {fileID: 665966907793119626}
|
||||
- component: {fileID: 4435257573578294946}
|
||||
m_Layer: 0
|
||||
m_Name: ReturnButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5090946158136759876
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3130945442339227461}
|
||||
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: 4450401086215199481}
|
||||
m_Father: {fileID: 2530971626885568150}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.86, y: 0.2}
|
||||
m_AnchorMax: {x: 0.86, y: 0.2}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 240, y: 62}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &9219190355672231004
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3130945442339227461}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &665966907793119626
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3130945442339227461}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 0.8, b: 0.3, a: 1}
|
||||
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 &4435257573578294946
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3130945442339227461}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 665966907793119626}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &3169550458985797308
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -2716,6 +3234,143 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &5066269170581119357
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4450401086215199481}
|
||||
- component: {fileID: 6172297422653075404}
|
||||
- component: {fileID: 1778027915619506758}
|
||||
m_Layer: 0
|
||||
m_Name: Label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4450401086215199481
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5066269170581119357}
|
||||
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: 5090946158136759876}
|
||||
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: 62}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6172297422653075404
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5066269170581119357}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1778027915619506758
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5066269170581119357}
|
||||
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: "\uCE5C\uAD6C \uBC18\uB0A9"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a5bc77ef7ce7c7e4d85ac578cfcd6646, type: 2}
|
||||
m_sharedMaterial: {fileID: 8207275579423446409, guid: a5bc77ef7ce7c7e4d85ac578cfcd6646, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 0.12, g: 0.2, b: 0.31, 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: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 28
|
||||
m_fontSizeBase: 28
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
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: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656bu
|
||||
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!1 &5310382666504661114
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -3256,6 +3911,7 @@ RectTransform:
|
||||
- {fileID: 3237793279449092937}
|
||||
- {fileID: 2361705476825752074}
|
||||
- {fileID: 2530971626885568150}
|
||||
- {fileID: 983150840242648897}
|
||||
m_Father: {fileID: 4274269384354727046}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -3958,7 +4614,7 @@ RectTransform:
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 3237793279449092937}
|
||||
m_Father: {fileID: 3999613752604275916}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.07}
|
||||
m_AnchorMax: {x: 0.5, y: 0.07}
|
||||
@@ -4065,6 +4721,127 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &7061760651837010790
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2329883891830714780}
|
||||
- component: {fileID: 5573057991149697080}
|
||||
- component: {fileID: 4086799282263640400}
|
||||
- component: {fileID: 3013192724825968427}
|
||||
m_Layer: 0
|
||||
m_Name: SpawnButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2329883891830714780
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7061760651837010790}
|
||||
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: 5049519322727858860}
|
||||
m_Father: {fileID: 2530971626885568150}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.86, y: 0.3}
|
||||
m_AnchorMax: {x: 0.86, y: 0.3}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 240, y: 62}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5573057991149697080
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7061760651837010790}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4086799282263640400
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7061760651837010790}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 0.8, b: 0.3, a: 1}
|
||||
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 &3013192724825968427
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7061760651837010790}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 4086799282263640400}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &7158186905691569963
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -4120,6 +4897,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier: MagnetismHeroes.UnityRuntime::MagnetismHeroes.UnityRuntime.Bootstrap.GameApp
|
||||
_stages:
|
||||
- {fileID: 11400000, guid: 1bd91d4fcb826e54e861dc2275fcbdee, type: 2}
|
||||
- {fileID: 11400000, guid: 74d68861704a8b541bb8ac1d37613620, type: 2}
|
||||
- {fileID: 11400000, guid: 6e1df3aeda3cea54b8441c528e7f503a, type: 2}
|
||||
- {fileID: 11400000, guid: 65683957e8f990649a840e8648fd470a, type: 2}
|
||||
- {fileID: 11400000, guid: a8fae6d8bb4a24246b5cfc1e89d7075f, type: 2}
|
||||
@@ -4134,6 +4912,9 @@ MonoBehaviour:
|
||||
_playButton: {fileID: 8869707931174415660}
|
||||
_continueButton: {fileID: 428650618540010171}
|
||||
_stageOneButton: {fileID: 227025040056778259}
|
||||
_stageTwoButton: {fileID: 4131456494785851528}
|
||||
_spawnButton: {fileID: 3013192724825968427}
|
||||
_returnButton: {fileID: 4435257573578294946}
|
||||
_homeButton: {fileID: 1767103786293493516}
|
||||
_selectionHomeButton: {fileID: 5673944335554824576}
|
||||
_compositionButtons:
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
|
||||
{ _guide = Find(id); if (!_playingCount) { _source.Stop(); Advance(); } }
|
||||
public void Clear()
|
||||
{ _counts.Clear(); _guide = null; _playingCount = false; _source.Stop(); _source.clip = null; }
|
||||
public void CancelGuide()
|
||||
{ _guide = null; if (!_playingCount) { _source.Stop(); _source.clip = null; } }
|
||||
private AudioClip Find(string id) { foreach (var voice in _clips) if (voice.id == id) return voice.clip; return null; }
|
||||
private void Advance()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
%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: 25d91ab5f7c987840910f7a3683c8d3f, type: 3}
|
||||
m_Name: Stage02
|
||||
m_EditorClassIdentifier: MagnetismHeroes.UnityRuntime::MagnetismHeroes.UnityRuntime.StageAssets.StageAsset
|
||||
_stageId: 2
|
||||
_kind: 0
|
||||
_initialGroups: 0100000001000000i
|
||||
_targetGroups: 02000000i
|
||||
_ballPositions:
|
||||
- {x: -1.2, y: 0.8, z: 0}
|
||||
- {x: 1.2, y: 0.8, z: 0}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74d68861704a8b541bb8ac1d37613620
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user