feat(content): author thirty stages, live hints, progression and Blender themes

This commit is contained in:
NINI
2026-10-05 13:05:27 +09:00
parent 60f8a55bb9
commit 64f4f19ae9
304 changed files with 20710 additions and 419 deletions
+68
View File
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MagnetismHeroes.Core
{
public enum HintKind { Collect, Count, Merge, Split }
public sealed class BoardHint
{
public HintKind Kind { get; }
public string[] BallIds { get; }
public string FirstGroupId { get; }
public string SecondGroupId { get; }
public int GroupSize { get; }
public int SelectionCount => BallIds.Length;
public string VoiceId => Kind == HintKind.Collect ? "guide_find" : Kind == HintKind.Count ? "guide_uncounted"
: Kind == HintKind.Merge ? "guide_merge" : $"guide_split_{GroupSize}_{SelectionCount}";
internal BoardHint(HintKind kind, GroupState first, string[] balls, GroupState second = null)
{ Kind = kind; FirstGroupId = first.id; SecondGroupId = second?.id; GroupSize = first.ballIds.Length; BallIds = balls; }
public static BoardHint Find(BoardRules board, StageDefinition definition)
{
if (board == null || board.Mode == BoardMode.FreePlay || board.IsSolved) return null;
var groups = board.Groups;
if (board.Mode == BoardMode.Counting)
{
var collectedGroups = groups.Where(group => group.ballIds.All(id => board.CollectedBallIds.Contains(id))).ToArray();
if (collectedGroups.Length > 1) return Merge(collectedGroups[0], collectedGroups[1]);
var uncollected = board.Balls.FirstOrDefault(ball => !board.CollectedBallIds.Contains(ball.id));
if (uncollected != null) return new BoardHint(HintKind.Collect, groups.First(group => group.ballIds.Contains(uncollected.id)), new[] { uncollected.id });
if (groups.Length > 1) return Merge(groups[0], groups[1]);
return new BoardHint(HintKind.Count, groups[0], new[] { groups[0].ballIds.First(id => !board.CountedBallIds.Contains(id)) });
}
// Integer partitions of at most ten balls are a small, finite undirected graph.
// Distances from the target make every suggested live operation shorten a valid solution.
var distance = new Dictionary<string, int>(); var queue = new Queue<int[]>();
var target = definition.TargetGroups.OrderBy(size => size).ToArray();
distance.Add(Key(target), 0); queue.Enqueue(target);
while (queue.Count > 0)
{
var sizes = queue.Dequeue(); int nextDistance = distance[Key(sizes)] + 1;
foreach (var next in Neighbors(sizes))
if (!distance.ContainsKey(Key(next))) { distance.Add(Key(next), nextDistance); queue.Enqueue(next); }
}
var current = groups.Select(group => group.ballIds.Length).ToArray(); int desired = distance[Key(current)] - 1;
for (int i = 0; i < groups.Length; i++)
for (int j = i + 1; j < groups.Length; j++)
if (distance[Key(Merged(current, i, j))] == desired) return Merge(groups[i], groups[j]);
for (int i = 0; i < groups.Length; i++)
for (int count = 1; count <= current[i] / 2; count++)
if (distance[Key(Split(current, i, count))] == desired)
return new BoardHint(HintKind.Split, groups[i], groups[i].ballIds.Take(count).ToArray());
throw new InvalidOperationException("A valid unsolved partition must have a shorter neighbor.");
}
private static BoardHint Merge(GroupState first, GroupState second) => new BoardHint(HintKind.Merge, first, first.ballIds.Concat(second.ballIds).ToArray(), second);
private static string Key(IEnumerable<int> sizes) => string.Join(",", sizes.OrderBy(size => size));
private static int[] Merged(int[] sizes, int i, int j) => sizes.Where((size, index) => index != i && index != j).Concat(new[] { sizes[i] + sizes[j] }).ToArray();
private static int[] Split(int[] sizes, int i, int count) => sizes.Where((size, index) => index != i).Concat(new[] { count, sizes[i] - count }).ToArray();
private static IEnumerable<int[]> Neighbors(int[] sizes)
{
for (int i = 0; i < sizes.Length; i++)
{
for (int j = i + 1; j < sizes.Length; j++) yield return Merged(sizes, i, j);
for (int count = 1; count <= sizes[i] / 2; count++) yield return Split(sizes, i, count);
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9c5d298887e9598459597d508e8a1bb5
@@ -22,6 +22,9 @@ namespace MagnetismHeroes.Core
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 BoardHint Hint => BoardHint.Find(Board, _definitions.FirstOrDefault(stage => stage.Id == Board?.StageId));
public bool HasNextStage => Screen == SessionScreen.FreePlay && _definitions.Any(stage => stage.Id == Board.StageId + 1) && IsUnlocked(Board.StageId + 1);
public bool StartNextStage() => HasNextStage && StartStage(Board.StageId + 1);
public bool MarkTutorialSeen(string id)
{
@@ -0,0 +1,202 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using MagnetismHeroes.Core;
using MagnetismHeroes.UnityRuntime.Bootstrap;
using MagnetismHeroes.UnityRuntime.Presentation;
using MagnetismHeroes.UnityRuntime.StageAssets;
using TMPro;
using UnityEditor;
using UnityEngine;
namespace MagnetismHeroes.Editor
{
public static class ContentAssets
{
public static void InspectModels()
{
foreach (string path in Directory.GetFiles(Presentation + "Prefabs/Scenery", "*.prefab"))
{
var root=UnityEngine.Object.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(path));
foreach (var mesh in root.GetComponentsInChildren<MeshFilter>()) Debug.Log($"[ModelBounds] {path} rootRotation={root.transform.rotation} childRotation={mesh.transform.rotation} scale={mesh.transform.lossyScale} mesh={mesh.sharedMesh.bounds} renderer={mesh.GetComponent<MeshRenderer>().bounds}");
UnityEngine.Object.DestroyImmediate(root);
}
}
private const string Presentation = "Assets/MagnetismHeroes/UnityRuntime/Presentation/";
private static readonly int[][] Initial = {
new[] {1,1}, new[] {2,1}, new[] {3,1}, new[] {2,3}, new[] {2},
new[] {3}, new[] {4}, new[] {5}, new[] {3,1}, new[] {4,1},
new[] {5,1}, new[] {3,4}, new[] {4,4}, new[] {5,5}, new[] {6},
new[] {7}, new[] {9}, new[] {10}, new[] {5,3}, new[] {6,4} };
private static readonly int[][] Target = {
new[] {2}, new[] {3}, new[] {4}, new[] {5}, new[] {1,1},
new[] {2,1}, new[] {2,2}, new[] {3,2}, new[] {2,2}, new[] {3,2},
new[] {6}, new[] {7}, new[] {8}, new[] {10}, new[] {5,1},
new[] {4,3}, new[] {5,4}, new[] {5,5}, new[] {4,4}, new[] {5,5} };
[MenuItem("Magnetism Heroes/Build Content Assets")]
public static void Build()
{
foreach (string folder in new[] { "Models", "Materials", "Prefabs/Scenery" }) Directory.CreateDirectory(Presentation + folder);
AssetDatabase.Refresh();
string[] modelNames = { "Island", "BlockArch", "ToySteps", "Pebbles", "GardenFlower", "GardenMushroom", "GardenLeaf", "CloudPuff", "CloudRainbow", "CloudMoon", "WorkshopStar", "WorkshopGear", "WorkshopCrystals" };
var props = modelNames.ToDictionary(name => name, Prop);
var stages = Enumerable.Range(1, 30).Select(id => Stage(id, props)).ToArray();
var font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(Presentation + "Fonts/NotoSansCJKkr-FirstSlice.asset");
const string glyphs = "0123456789 · 잠금 완료 이어하기 시작 도움 다음 시범 나누기 → 하나 선택 끌어내기 친구를 끌어와 붙여 보자 이 친구를 찾아 끌어와 볼까? 아직 세지 않은 이 구를 눌러 볼까? 빛나는 두 친구를 가까이 끌어와 붙여 볼까? 빛나는 친구에서 나누기를 누르고 개를 골라 끌어내 보자.";
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 content glyphs: " + missing); }
finally { font.atlasPopulationMode = AtlasPopulationMode.Static; }
EditorUtility.SetDirty(font);
}
var root = PrefabUtility.LoadPrefabContents(FirstSliceAssets.AppPrefabPath);
try
{
var app = new SerializedObject(root.GetComponent<GameApp>());
var catalog = app.FindProperty("_stages"); catalog.arraySize = stages.Length;
for (int i = 0; i < stages.Length; i++) catalog.GetArrayElementAtIndex(i).objectReferenceValue = stages[i];
// These representative controls are now members of the complete ordered catalog.
app.FindProperty("_compositionButtons").arraySize = 3;
var selection = root.transform.Find("Interface/SafeArea/StageSelection");
var template = selection.Find("Stage01Button").gameObject;
var buttons = app.FindProperty("_stageButtons"); buttons.arraySize = 30;
for (int i = 0; i < 30; i++)
{
var button = Button(selection, template, $"Stage{i + 1:D2}Button", $"{i + 1} · 잠금",
new Vector2(.12f + i % 6 * .152f, .76f - i / 6 * .123f), new Vector2(165, 66), 24);
buttons.GetArrayElementAtIndex(i).objectReferenceValue = button;
}
for (int i = 0; i < 3; i++) app.FindProperty("_compositionButtons").GetArrayElementAtIndex(i).objectReferenceValue = selection.Find($"Stage{new[] { 6, 10, 14 }[i]:D2}Button").GetComponent<UnityEngine.UI.Button>();
var title = (RectTransform)selection.Find("SelectionTitle"); title.anchorMin = title.anchorMax = new Vector2(.5f, .92f); title.sizeDelta = new Vector2(820, 65);
var back = (RectTransform)selection.Find("SelectionHomeButton"); back.anchorMin = back.anchorMax = new Vector2(.5f, .11f); back.sizeDelta = new Vector2(230, 60);
var play = root.transform.Find("Interface/SafeArea/Play"); var playTemplate = play.Find("HomeButton").gameObject;
app.FindProperty("_helpButton").objectReferenceValue = Button(play, playTemplate, "HelpButton", "도움", new Vector2(.13f, .34f), new Vector2(170, 62), 28);
app.FindProperty("_nextButton").objectReferenceValue = Button(play, playTemplate, "NextButton", "다음", new Vector2(.86f, .4f), new Vector2(170, 62), 28);
var world = root.transform.Find("Playground");
foreach (string name in new[] { "ToyStep", "ToyArchPost" })
{ var old = world.Find(name); if (old != null) UnityEngine.Object.DestroyImmediate(old.gameObject); }
var floor=world.Find("PlaygroundIsland");
if (floor==null) { floor=new GameObject("PlaygroundIsland",typeof(MeshFilter),typeof(MeshRenderer),typeof(MeshCollider)).transform; floor.SetParent(world,false); }
var island=props["Island"].GetComponentInChildren<MeshFilter>();
floor.localPosition=new Vector3(0,-.45f,0); floor.localRotation=island.transform.localRotation; floor.localScale=Vector3.one;
floor.GetComponent<MeshFilter>().sharedMesh=island.sharedMesh;
floor.GetComponent<MeshRenderer>().sharedMaterial=island.GetComponent<MeshRenderer>().sharedMaterial;
floor.GetComponent<MeshCollider>().sharedMesh=island.sharedMesh;
var environment = world.Find("Environment");
if (environment == null) { environment = new GameObject("Environment", typeof(BoardEnvironment)).transform; environment.SetParent(world, false); }
app.FindProperty("_environment").objectReferenceValue = environment.GetComponent<BoardEnvironment>();
var ghost = play.Find("GhostDemonstration");
if (ghost == null)
{
ghost = new GameObject("GhostDemonstration", typeof(RectTransform), typeof(UnityEngine.UI.Image), typeof(GhostDemonstration)).transform;
ghost.SetParent(play, false); var rect = (RectTransform)ghost; rect.anchorMin = rect.anchorMax = new Vector2(.22f, .58f); rect.sizeDelta = new Vector2(330, 160);
var background = ghost.GetComponent<UnityEngine.UI.Image>(); background.color = new Color(.12f, .2f, .31f, .92f); background.raycastTarget = false;
var serialized = new SerializedObject(ghost.GetComponent<GhostDemonstration>());
foreach (string field in new[] { "_first", "_second" })
{
var ball = new GameObject(field, typeof(RectTransform), typeof(UnityEngine.UI.Image)); ball.transform.SetParent(ghost, false);
var ballRect = (RectTransform)ball.transform; ballRect.sizeDelta = new Vector2(54, 54);
var image = ball.GetComponent<UnityEngine.UI.Image>(); image.raycastTarget = false;
image.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/Knob.psd");
serialized.FindProperty(field).objectReferenceValue = ballRect;
}
var caption = new GameObject("Caption", typeof(RectTransform), typeof(TextMeshProUGUI)); caption.transform.SetParent(ghost, false);
var text = caption.GetComponent<TextMeshProUGUI>(); text.font = font; text.fontSize = 22; text.color = Color.white; text.alignment = TextAlignmentOptions.Center; text.raycastTarget = false;
text.rectTransform.anchorMin = text.rectTransform.anchorMax = new Vector2(.5f, .17f); text.rectTransform.sizeDelta = new Vector2(310, 55);
serialized.FindProperty("_caption").objectReferenceValue = text; serialized.ApplyModifiedPropertiesWithoutUndo();
}
ghost.gameObject.SetActive(false); app.FindProperty("_demonstration").objectReferenceValue = ghost.GetComponent<GhostDemonstration>();
app.ApplyModifiedPropertiesWithoutUndo();
var voice = new SerializedObject(root.GetComponent<VoicePlayer>()); var clips = voice.FindProperty("_clips");
foreach (string path in Directory.GetFiles(Presentation + "Audio/Voice", "*.wav"))
{
string id = Path.GetFileNameWithoutExtension(path);
var clip = AssetDatabase.LoadAssetAtPath<AudioClip>(path.Replace('\\', '/'));
var importer = (AudioImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(clip)); var settings = importer.defaultSampleSettings;
settings.loadType = AudioClipLoadType.DecompressOnLoad; settings.compressionFormat = AudioCompressionFormat.PCM; settings.preloadAudioData = true;
importer.defaultSampleSettings = settings; importer.SaveAndReimport();
int index = Enumerable.Range(0, clips.arraySize).Where(i => clips.GetArrayElementAtIndex(i).FindPropertyRelative("id").stringValue == id).DefaultIfEmpty(-1).First();
if (index < 0) { index = clips.arraySize; clips.arraySize++; }
clips.GetArrayElementAtIndex(index).FindPropertyRelative("id").stringValue = id;
clips.GetArrayElementAtIndex(index).FindPropertyRelative("clip").objectReferenceValue = clip;
}
voice.ApplyModifiedPropertiesWithoutUndo(); PrefabUtility.SaveAsPrefabAsset(root, FirstSliceAssets.AppPrefabPath);
}
finally { PrefabUtility.UnloadPrefabContents(root); }
AssetDatabase.SaveAssets(); Debug.Log("[Content] All 30 fixed assets, three Blender scenery themes, ordered controls, live help, next and ghost demonstrations built.");
}
private static GameObject Prop(string name)
{
string modelPath = Presentation + "Models/" + name + ".fbx";
var importer = (ModelImporter)AssetImporter.GetAtPath(modelPath);
if (importer == null) throw new InvalidOperationException("Blender export missing: " + modelPath);
importer.globalScale = 1; importer.useFileScale = true; importer.bakeAxisConversion = true; importer.importCameras = false; importer.importLights = false; importer.importAnimation = false;
importer.SaveAndReimport();
var model = AssetDatabase.LoadAssetAtPath<GameObject>(modelPath);
var instance = new GameObject(name);
var modelInstance=(GameObject)PrefabUtility.InstantiatePrefab(model); modelInstance.transform.SetParent(instance.transform,false);
try
{
var color = name.StartsWith("Garden") ? new Color(.96f,.56f,.48f) : name.StartsWith("Cloud") ? new Color(.8f,.88f,1) : name.StartsWith("Workshop") ? new Color(1,.79f,.27f) : name == "Island" ? new Color(.61f,.83f,.71f) : new Color(.61f,.69f,.92f);
string materialPath = Presentation + "Materials/" + name + ".mat";
var material = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
if (material == null) { material = new Material(Shader.Find("Universal Render Pipeline/Lit")); AssetDatabase.CreateAsset(material, materialPath); }
material.color = color; EditorUtility.SetDirty(material);
foreach (var renderer in instance.GetComponentsInChildren<MeshRenderer>()) renderer.sharedMaterial = material;
foreach (var filter in instance.GetComponentsInChildren<MeshFilter>())
{ var collider = filter.gameObject.GetComponent<MeshCollider>(); if (collider == null) collider = filter.gameObject.AddComponent<MeshCollider>(); collider.sharedMesh = filter.sharedMesh; collider.convex = false; }
return PrefabUtility.SaveAsPrefabAsset(instance, Presentation + "Prefabs/Scenery/" + name + ".prefab");
}
finally { UnityEngine.Object.DestroyImmediate(instance); }
}
private static StageAsset Stage(int id, System.Collections.Generic.Dictionary<string, GameObject> props)
{
bool counting = id <= 5 || id >= 16 && id <= 20;
int n = id <= 5 ? id : id - 10; int index = id <= 15 ? id - 6 : id - 11;
int[] initial = counting ? Enumerable.Repeat(1, n).ToArray() : Initial[index];
int[] target = counting ? new[] { n } : Target[index];
string path = $"Assets/MagnetismHeroes/UnityRuntime/StageAssets/Stage{id:D2}.asset";
var stage = AssetDatabase.LoadAssetAtPath<StageAsset>(path);
bool preserveLayout = stage != null;
if (stage == null) { stage = ScriptableObject.CreateInstance<StageAsset>(); AssetDatabase.CreateAsset(stage, path); }
var data = new SerializedObject(stage); data.FindProperty("_stageId").intValue = id;
data.FindProperty("_kind").enumValueIndex = (int)(counting ? StageKind.Counting : StageKind.Composition);
foreach (var spec in new[] { ("_initialGroups", initial), ("_targetGroups", target) })
{ var field = data.FindProperty(spec.Item1); field.arraySize = spec.Item2.Length; for (int i = 0; i < spec.Item2.Length; i++) field.GetArrayElementAtIndex(i).intValue = spec.Item2[i]; }
if (!preserveLayout)
{
var positions = data.FindProperty("_ballPositions"); positions.arraySize = initial.Sum(); int ball = 0;
if (counting)
{
var layout = new[] { new Vector3(-2,.8f,0), new Vector3(2,.8f,0), new Vector3(0,2.3f,0), new Vector3(-3.4f,.8f,2.8f), new Vector3(3.2f,2.7f,1.5f), new Vector3(0,.8f,2.5f), new Vector3(-2.2f,2.7f,-1.5f), new Vector3(2.2f,.8f,-1.8f), new Vector3(-.5f,2.2f,2.5f), new Vector3(3.4f,.8f,2.8f) };
for (int i = 0; i < positions.arraySize; i++) positions.GetArrayElementAtIndex(i).vector3Value = layout[i];
}
else for (int group = 0; group < initial.Length; group++)
for (int i = 0; i < initial[group]; i++)
positions.GetArrayElementAtIndex(ball++).vector3Value = new Vector3(i - (initial[group] - 1) * .5f, .8f, initial.Length == 1 ? 0 : group == 0 ? -1.2f : 1.2f);
}
string theme = id <= 10 ? "Garden" : id <= 20 ? "Cloud" : "Workshop"; data.FindProperty("_theme").stringValue = theme;
string[] themed = theme == "Garden" ? new[] { "GardenFlower", "GardenMushroom", "GardenLeaf" } : theme == "Cloud" ? new[] { "CloudPuff", "CloudRainbow", "CloudMoon" } : new[] { "WorkshopStar", "WorkshopGear", "WorkshopCrystals" };
string[] names = new[] { "Island", "BlockArch", "ToySteps", "Pebbles" }.Concat(themed).ToArray();
var locations = new[] { new Vector3(0,-.45f,0), new Vector3(-4,0,1.6f), new Vector3(4,0,1.7f), new Vector3(3.8f,0,-2.6f), new Vector3(-4.1f,0,-1.8f), new Vector3(-3.4f,0,1.4f), new Vector3(3.7f,0,3) };
var decorations = data.FindProperty("_decorations"); decorations.arraySize = names.Length;
for (int i = 0; i < names.Length; i++)
{
var placement = decorations.GetArrayElementAtIndex(i); placement.FindPropertyRelative("prefab").objectReferenceValue = props[names[i]];
placement.FindPropertyRelative("position").vector3Value = locations[i]; placement.FindPropertyRelative("eulerAngles").vector3Value = Vector3.zero; placement.FindPropertyRelative("scale").vector3Value = Vector3.one;
}
data.ApplyModifiedPropertiesWithoutUndo(); return stage;
}
private static UnityEngine.UI.Button Button(Transform parent, GameObject template, string name, string label, Vector2 anchor, Vector2 size, float fontSize)
{
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.fontSize = fontSize; text.rectTransform.sizeDelta = size;
return button.GetComponent<UnityEngine.UI.Button>();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1023d9efc73aff743bf77a461d6d5ce6
@@ -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(5)); var definitions = Enumerable.Range(0, stages.arraySize)
Assert.That(stages.arraySize, Is.EqualTo(30)); 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, 2, 6, 10, 14 }));
Assert.That(definitions.Select(stage => stage.Id), Is.EqualTo(Enumerable.Range(1, 30)));
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));
@@ -0,0 +1,41 @@
using System.Linq;
using MagnetismHeroes.Core;
using MagnetismHeroes.UnityRuntime.StageAssets;
using NUnit.Framework;
using UnityEditor;
namespace MagnetismHeroes.Tests
{
public sealed class ContentAssetTests
{
[Test] public void EveryFixedStageHasExactlyOneAsset()
{
var assets = AssetDatabase.FindAssets("t:StageAsset", new[] { "Assets/MagnetismHeroes/UnityRuntime/StageAssets" })
.Select(guid => AssetDatabase.LoadAssetAtPath<StageAsset>(AssetDatabase.GUIDToAssetPath(guid))).ToArray();
Assert.That(assets.Length, Is.EqualTo(30));
Assert.That(assets.Select(asset => asset.StageId).OrderBy(id => id), Is.EqualTo(Enumerable.Range(1, 30)));
}
[Test] public void FixedOrderMatchesEveryR07InitialTargetAndKind()
{
string[] expected = { "1>1", "1,1>2", "1,1,1>3", "1,1,1,1>4", "1,1,1,1,1>5",
"1,1>2", "2,1>3", "3,1>4", "2,3>5", "2>1,1", "3>2,1", "4>2,2", "5>3,2", "3,1>2,2", "4,1>3,2",
"1,1,1,1,1,1>6", "1,1,1,1,1,1,1>7", "1,1,1,1,1,1,1,1>8", "1,1,1,1,1,1,1,1,1>9", "1,1,1,1,1,1,1,1,1,1>10",
"5,1>6", "3,4>7", "4,4>8", "5,5>10", "6>5,1", "7>4,3", "9>5,4", "10>5,5", "5,3>4,4", "6,4>5,5" };
for (int id=1; id<=30; id++)
{
var asset=AssetDatabase.LoadAssetAtPath<StageAsset>($"Assets/MagnetismHeroes/UnityRuntime/StageAssets/Stage{id:D2}.asset");
var definition=asset.ToDefinition();
Assert.That(string.Join(",",definition.InitialGroups)+">"+string.Join(",",definition.TargetGroups), Is.EqualTo(expected[id-1]), $"Stage {id}");
Assert.That(definition.Kind, Is.EqualTo(id<=5 || id>=16 && id<=20 ? StageKind.Counting : StageKind.Composition));
Assert.That(definition.Total, Is.EqualTo(definition.TargetGroups.Sum())); Assert.That(definition.Total, Is.InRange(1,10));
Assert.That(definition.BallPositions.Count, Is.EqualTo(definition.Total));
Assert.That(asset.Theme, Is.EqualTo(id<=10 ? "Garden" : id<=20 ? "Cloud" : "Workshop"));
Assert.That(asset.Decorations.Count, Is.EqualTo(7));
foreach (var placement in asset.Decorations) Assert.That(placement.prefab, Is.Not.Null);
string before=EditorJsonUtility.ToJson(asset); var board=new BoardRules(definition);
board.TryMoveGroup(board.Groups[0].id,new Position3(1,0,0));
Assert.That(EditorJsonUtility.ToJson(asset), Is.EqualTo(before), "Runtime rules never mutate their source asset.");
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ae9003f830dded844a056f200eb4b634
@@ -0,0 +1,111 @@
using System;
using System.Linq;
using MagnetismHeroes.Core;
using MagnetismHeroes.UnityRuntime.StageAssets;
using NUnit.Framework;
using UnityEditor;
namespace MagnetismHeroes.Tests
{
public sealed class ContentSessionTests
{
private sealed class Store : 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; }
}
private static StageDefinition[] Definitions() => Enumerable.Range(1,30).Select(id =>
AssetDatabase.LoadAssetAtPath<StageAsset>($"Assets/MagnetismHeroes/UnityRuntime/StageAssets/Stage{id:D2}.asset").ToDefinition()).ToArray();
private static void Apply(GameSession session, BoardHint hint)
{
Assert.That(hint, Is.Not.Null);
RuleResult result;
switch (hint.Kind)
{
case HintKind.Collect: result = session.MoveGroup(hint.FirstGroupId, new Position3(.1f,0,0)); break;
case HintKind.Count: result = session.Count(hint.BallIds[0]); break;
case HintKind.Merge: result = session.MoveAndMerge(hint.FirstGroupId, new Position3(.1f,0,0), hint.SecondGroupId); break;
default: result = session.SplitAndMove(hint.FirstGroupId, hint.BallIds, "hint-split-" + Guid.NewGuid().ToString("N"), new Position3(1,0,0)); break;
}
Assert.That(result.Accepted, Is.True, result.Reason.ToString());
}
[Test] public void FreshSaveSolvesAllThirtyThroughActualCoreCallsUnlocksNextAndNeverThirtyOne()
{
var definitions = Definitions(); var store = new Store(); var session = new GameSession(definitions, store);
Assert.That(Enumerable.Range(1,30).Where(session.IsUnlocked), Is.EqualTo(new[] {1}));
for (int id = 1; id <= 30; id++)
{
if (id == 1) Assert.That(session.StartStage(id), Is.True);
else Assert.That(session.StartNextStage(), Is.True);
Assert.That(session.Board.StageId, Is.EqualTo(id));
for (int step = 0; session.Screen == SessionScreen.Puzzle && step < 40; step++)
{
var before = UnityEngine.JsonUtility.ToJson(store.Saved); var ids = session.Board.Balls.Select(ball => ball.id).ToArray();
var hint = session.Hint;
Assert.That(UnityEngine.JsonUtility.ToJson(store.Saved), Is.EqualTo(before), "Help is read-only.");
Apply(session, hint); Assert.That(session.Board.Balls.Select(ball => ball.id), Is.EqualTo(ids));
}
Assert.That(session.Screen, Is.EqualTo(SessionScreen.FreePlay), $"Stage {id}");
Assert.That(store.Saved.completedStageIds, Is.EqualTo(Enumerable.Range(1,id)));
Assert.That(session.HasNextStage, Is.EqualTo(id < 30));
Assert.That(store.Saved.latestFreePlay.sourceStageId, Is.EqualTo(id));
session = new GameSession(definitions, store); Assert.That(session.ContinueFreePlay(), Is.True);
}
Assert.That(session.IsUnlocked(31), Is.False); Assert.That(session.StartNextStage(), Is.False); Assert.That(session.StartStage(31), Is.False);
Assert.That(session.StartStage(6), Is.True); session.MoveGroup(session.Board.Groups[0].id, new Position3(.2f,0,0)); session.ShowHome();
Assert.That(store.Saved.completedStageIds, Is.EqualTo(Enumerable.Range(1,30))); Assert.That(session.IsUnlocked(30), Is.True);
Assert.That(session.StartStage(6), Is.True); Assert.That(session.Board.Balls[0].position.x, Is.EqualTo(definitions[5].BallPositions[0].x+.2f));
}
[Test] public void NextPrefersSavedPuzzleAndHelpRecoversFromAlternativeDisconnectedPartitions()
{
var definitions = Definitions(); var store = new Store { Saved = new ProgressSave { completedStageIds = Enumerable.Range(1,29).ToArray() } };
var session = new GameSession(definitions,store); Assert.That(session.StartStage(30), Is.True);
var group = session.Board.Groups[0]; session.SplitAndMove(group.id,new[] {group.ballIds[0],group.ballIds[2]},"alternative",new Position3(0,2,0));
session.CommitCamera(new CameraState { distance=12 }); session.ShowHome();
Assert.That(session.StartStage(29), Is.True);
for (int i=0; session.Screen==SessionScreen.Puzzle && i<30; i++) Apply(session,session.Hint);
Assert.That(session.StartNextStage(), Is.True); Assert.That(session.Camera.distance, Is.EqualTo(12));
Assert.That(session.Board.Groups.Any(value=>value.id=="alternative"), Is.True);
for (int i=0; session.Screen==SessionScreen.Puzzle && i<30; i++) Apply(session,session.Hint);
Assert.That(session.Screen, Is.EqualTo(SessionScreen.FreePlay));
Assert.That(session.Board.Groups.Select(value=>value.ballIds.Length).OrderBy(size=>size), Is.EqualTo(new[] {5,5}));
}
[Test] public void AllIntegerPartitionsHaveLiveHintsThatReachEachCompositionTarget()
{
foreach (var definition in Definitions().Where(stage=>stage.Kind==StageKind.Composition))
foreach (var sizes in Partitions(definition.Total,1))
{
var board = new BoardRules(new StageDefinition(definition.Id,StageKind.Composition,sizes,definition.TargetGroups.ToArray()));
for (int i=0; !board.IsSolved && i<20; i++)
{
var hint=BoardHint.Find(board,definition); Assert.That(hint, Is.Not.Null);
var result=hint.Kind==HintKind.Merge ? board.TryMerge(hint.FirstGroupId,hint.SecondGroupId)
: board.TrySplit(hint.FirstGroupId,hint.BallIds,"split-"+i);
Assert.That(result.Accepted, Is.True);
}
Assert.That(board.IsSolved, Is.True, $"{definition.Id}: {string.Join(",",sizes)}");
}
}
private static System.Collections.Generic.IEnumerable<int[]> Partitions(int total,int minimum)
{
if (total==0) { yield return Array.Empty<int>(); yield break; }
for (int first=minimum; first<=total; first++)
foreach (var rest in Partitions(total-first,first)) yield return new[] {first}.Concat(rest).ToArray();
}
[Test] public void CountingHelpRejoinsCollectedSplitBeforeFindingOtherFriendsThenCountsOnlyUncountedId()
{
var definition=new StageDefinition(4,StageKind.Counting,new[] {1,1,1,1},new[] {4}); var board=new BoardRules(definition);
board.TryMerge(board.Groups[0].id,board.Groups[1].id); var collected=board.Groups.First(group=>group.ballIds.Length==2);
board.TrySplit(collected.id,new[] {collected.ballIds[0]},"resplit");
var hint=BoardHint.Find(board,definition); Assert.That(hint.Kind, Is.EqualTo(HintKind.Merge));
Assert.That(hint.BallIds.All(board.CollectedBallIds.Contains), Is.True); board.TryMerge(hint.FirstGroupId,hint.SecondGroupId);
Assert.That(BoardHint.Find(board,definition).Kind, Is.EqualTo(HintKind.Collect));
foreach (var group in board.Groups) board.TryMoveGroup(group.id,new Position3(.1f,0,0));
while (board.Groups.Length>1) board.TryMerge(board.Groups[0].id,board.Groups[1].id);
board.TryCount(board.Balls[0].id); hint=BoardHint.Find(board,definition);
Assert.That(hint.Kind, Is.EqualTo(HintKind.Count)); Assert.That(board.CountedBallIds, Does.Not.Contain(hint.BallIds[0]));
Assert.That(board.TryCount(hint.BallIds[0]).Accepted, Is.True);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f65031cb242c4e746b894204a7e7c4a1
@@ -0,0 +1,39 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using MagnetismHeroes.UnityRuntime.Presentation;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
namespace MagnetismHeroes.Tests
{
public sealed class ContentVoiceTests
{
[Test] public void EveryLiveHelpPairAndBothActualGhostScriptsHaveOfflinePcmClips()
{
var prefab=AssetDatabase.LoadAssetAtPath<GameObject>("Assets/MagnetismHeroes/UnityRuntime/Presentation/Prefabs/GameApp.prefab");
var clips=new SerializedObject(prefab.GetComponent<VoicePlayer>()).FindProperty("_clips");
var ids=Enumerable.Range(0,clips.arraySize).Select(i=>clips.GetArrayElementAtIndex(i).FindPropertyRelative("id").stringValue).ToArray();
Assert.That(ids.Length, Is.EqualTo(44)); Assert.That(ids.Distinct().Count(), Is.EqualTo(44));
foreach (string id in new[] {"guide_find","guide_uncounted","demo_merge6","demo_split10"}.Concat(
Enumerable.Range(2,9).SelectMany(size=>Enumerable.Range(1,size/2).Select(count=>$"guide_split_{size}_{count}"))))
{
Assert.That(ids, Does.Contain(id));
int index=System.Array.IndexOf(ids,id); var clip=(AudioClip)clips.GetArrayElementAtIndex(index).FindPropertyRelative("clip").objectReferenceValue;
Assert.That(clip, Is.Not.Null,id); Assert.That(clip.frequency, Is.EqualTo(44100)); Assert.That(clip.channels, Is.EqualTo(1)); Assert.That(clip.samples, Is.GreaterThan(0));
var importer=(AudioImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(clip));
Assert.That(importer.defaultSampleSettings.compressionFormat, Is.EqualTo(AudioCompressionFormat.PCM));
Assert.That(importer.defaultSampleSettings.loadType, Is.EqualTo(AudioClipLoadType.DecompressOnLoad));
}
Assert.That(ids.Count(id=>id.StartsWith("guide_split_")), Is.EqualTo(25));
}
[TestCase("count_01","13A882CE1620140D447635E14F2D4758045D5E348960C17386DF1C720050C100")]
[TestCase("guide_collect","62E15C9E38C36F4094A6C7E9C5148510141290B5F41DB5AAD9DC1D8F1A158594")]
[TestCase("guide_count","DEBE29B89F3E2856F2BF4C5E01707A5F0A0657E5768C03BE385EC88FA2328B40")]
public void UserApprovedVoiceBytesRemainExact(string id,string hash)
{
using (var sha=SHA256.Create()) Assert.That(System.BitConverter.ToString(sha.ComputeHash(File.ReadAllBytes($"Assets/MagnetismHeroes/UnityRuntime/Presentation/Audio/Voice/{id}.wav"))).Replace("-",""), Is.EqualTo(hash));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f2e9d6608639d744397aad7855886e4b
@@ -0,0 +1,159 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MagnetismHeroes.Core;
using MagnetismHeroes.UnityRuntime.Bootstrap;
using MagnetismHeroes.UnityRuntime.Presentation;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.TestTools;
namespace MagnetismHeroes.Tests
{
public sealed class ContentPlayTests
{
private sealed class Store : IProgressStore
{
public ProgressSave Saved = new ProgressSave { completedStageIds=Enumerable.Range(1,30).ToArray() };
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; }
}
private GameApp _app;
private Store _store;
private string _evidence;
[System.Serializable] private sealed class CaptureRecord
{
public int stageId;
public string theme;
public CameraState camera;
public int width=1280, height=720;
public string method="Camera.Render to 1280x720 RenderTexture; temporary ScreenSpaceCamera Canvas; RGB24 ReadPixels PNG; restores render mode/target";
}
private void Capture(string filename)
{
var camera=_app.Presenter.Camera; var canvas=_app.GetComponentInChildren<Canvas>();
var texture=RenderTexture.GetTemporary(1280,720,24); var prior=RenderTexture.active;
var renderMode=canvas.renderMode; var oldCamera=canvas.worldCamera; var oldTarget=camera.targetTexture;
canvas.renderMode=RenderMode.ScreenSpaceCamera; canvas.worldCamera=camera; canvas.planeDistance=1;
camera.targetTexture=texture; Canvas.ForceUpdateCanvases(); camera.Render(); RenderTexture.active=texture;
var image=new Texture2D(1280,720,TextureFormat.RGB24,false); image.ReadPixels(new Rect(0,0,1280,720),0,0); image.Apply();
File.WriteAllBytes(Path.Combine(_evidence,filename),image.EncodeToPNG()); Object.Destroy(image);
File.WriteAllText(Path.Combine(_evidence,filename+".camera.json"),JsonUtility.ToJson(new CaptureRecord {stageId=_app.Session.Board.StageId,theme=_app.Environment.Theme,camera=_app.Orbit.Snapshot()},true));
camera.targetTexture=oldTarget; canvas.renderMode=renderMode; canvas.worldCamera=oldCamera; RenderTexture.active=prior; RenderTexture.ReleaseTemporary(texture);
Canvas.ForceUpdateCanvases();
}
[UnitySetUp] public IEnumerator SetUp()
{
foreach (var listener in Object.FindObjectsByType<AudioListener>(FindObjectsSortMode.None)) listener.enabled=false;
foreach (var camera in Object.FindObjectsByType<Camera>(FindObjectsSortMode.None)) camera.enabled=false;
_app=Object.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>("Assets/MagnetismHeroes/UnityRuntime/Presentation/Prefabs/GameApp.prefab")).GetComponent<GameApp>();
_store=new Store(); _app.Initialize(_store);
_evidence=Path.GetFullPath("artifacts/verification/Content/editor-play"); Directory.CreateDirectory(_evidence);
yield return null;
}
[UnityTearDown] public IEnumerator TearDown() { Object.Destroy(_app.gameObject); yield return null; }
[UnityTest] public IEnumerator EveryCountingBallCanBeFoundPickedAndDirectlyDraggedAfterOrbit()
{
var proof=new List<string>();
foreach (int stage in new[] {1,2,3,4,5,16,17,18,19,20})
{
_app.StartStage(stage); yield return null; Physics.SyncTransforms(); Capture($"counting-{stage:D2}-default.png");
foreach (string id in _app.Session.Board.Balls.Select(ball=>ball.id).ToArray())
{
bool moved=false;
for (int pitch=-45; pitch<=45 && !moved; pitch+=15)
for (int yaw=0; yaw<360 && !moved; yaw+=30)
{
var rotation=Quaternion.Euler(pitch,yaw,0);
_app.Orbit.Apply(new CameraState { target=new Position3(0,.6f,0),distance=11,rotation=new Rotation4(rotation.x,rotation.y,rotation.z,rotation.w) });
var camera=_app.Presenter.Camera; var view=_app.Presenter.Balls[id]; var point=(Vector2)camera.WorldToScreenPoint(view.transform.position);
var viewport=camera.WorldToViewportPoint(view.transform.position);
if (viewport.z<=0 || viewport.x<.1f || viewport.x>.9f || viewport.y<.25f || viewport.y>.82f) continue;
if (!Physics.Raycast(camera.ScreenPointToRay(point),out var hit,100) || hit.collider.GetComponent<BallView>()!=view) continue;
var before=_app.Session.Board.Balls.First(ball=>ball.id==id).position;
foreach (var offset in new[] {new Vector2(0,35),new Vector2(35,0),new Vector2(-35,0),new Vector2(0,-35)})
{
_app.Input.Begin(point,false); _app.Input.Move(point+offset); _app.Input.End(point+offset);
var after=_app.Session.Board.Balls.First(ball=>ball.id==id).position;
if (after.x==before.x && after.y==before.y && after.z==before.z) continue;
Assert.That(_app.Session.Board.CollectedBallIds, Does.Contain(id));
proof.Add($"stage={stage} id={id} yaw={yaw} pitch={pitch} pick={hit.collider.name} direct-drag={offset}");
Capture($"found-{id}.png"); moved=true; break;
}
}
Assert.That(moved, Is.True,$"Stage {stage} ball {id} has a discoverable and draggable view.");
}
File.WriteAllLines(Path.Combine(_evidence,"counting-discovery.txt"),proof);
Capture($"counting-{stage:D2}.png"); yield return null;
}
Assert.That(proof.Count, Is.EqualTo(55));
}
[UnityTest] public IEnumerator FirstSixAndTenGhostsPreserveRealBoardAndNeverRepeatOnReentry()
{
foreach (int stage in new[] {6,10})
{
_app.StartStage(stage); yield return null;
Assert.That(_app.Demonstration.IsShowing, Is.True);
var board=JsonUtility.ToJson(_app.Session.Board.ToPuzzleState(_app.Session.Camera));
var completed=_app.Session.CompletedStageIds;
yield return new WaitForSecondsRealtime(1.3f);
Capture($"ghost-{stage:D2}-selected.png"); yield return null;
yield return new WaitForSecondsRealtime(1.7f);
Capture($"ghost-{stage:D2}-moved.png"); yield return null;
Assert.That(JsonUtility.ToJson(_app.Session.Board.ToPuzzleState(_app.Session.Camera)), Is.EqualTo(board));
Assert.That(_app.Session.CompletedStageIds, Is.EqualTo(completed));
_app.ShowHome(); _app.StartStage(stage); Assert.That(_app.Demonstration.IsShowing, Is.False);
Assert.That(_app.Session.HasSeenTutorial(stage==6 ? "merge" : "split"), Is.True);
}
}
[UnityTest] public IEnumerator EveryThemeSuppliesZeroThroughTenAndRestoresSameSceneryAfterSuccess()
{
foreach (int stage in new[] {1,16,21})
{
_app.StartStage(stage); yield return null;
string theme=_app.Environment.Theme;
for (int step=0; _app.Session.Screen==SessionScreen.Puzzle && step<40; step++)
{
var hint=_app.Session.Hint;
if (hint.Kind==HintKind.Collect) _app.CommitMove(hint.FirstGroupId,new Position3(.1f,0,0));
else if (hint.Kind==HintKind.Merge) _app.CommitMove(hint.FirstGroupId,new Position3(.1f,0,0),hint.SecondGroupId);
else if (hint.Kind==HintKind.Count) _app.CountBall(hint.BallIds[0]);
else _app.CommitSplit(hint.FirstGroupId,hint.BallIds,new Position3(1,0,0));
}
Assert.That(_app.Session.Screen, Is.EqualTo(SessionScreen.FreePlay)); Assert.That(_app.Environment.Theme, Is.EqualTo(theme));
foreach (var group in _app.Session.Board.Groups) Assert.That(_app.Session.ReturnGroup(group.id).Accepted, Is.True);
_app.ContinueFreePlay(); yield return null;
for (int total=0; total<10; total++)
{
bool found=false;
for (int yaw=0; yaw<360 && !found; yaw+=30)
{
var rotation=Quaternion.Euler(-10,yaw,0); _app.Orbit.Apply(new CameraState {target=new Position3(0,.6f,0),distance=11,rotation=new Rotation4(rotation.x,rotation.y,rotation.z,rotation.w)});
if (_app.Presenter.TryFindSpawnPosition(out _)) { _app.SpawnFriend(); found=true; }
}
Assert.That(found, Is.True,$"Theme {theme}, supply {total+1}");
Assert.That(_app.Session.Board.BallCount, Is.EqualTo(total+1)); yield return null;
}
_app.SpawnFriend(); Assert.That(_app.Session.Board.BallCount, Is.EqualTo(10));
_app.Session.CommitCamera(_app.Orbit.Snapshot()); _app.ShowHome(); _app.ContinueFreePlay(); yield return null;
Assert.That(_app.Environment.Theme, Is.EqualTo(theme)); Assert.That(_app.Session.Board.StageId, Is.EqualTo(stage));
Capture($"theme-{theme}-free10.png"); yield return null;
}
}
[UnityTest] public IEnumerator MeshArchReallyHasAnOpenGapAndHelpHighlightsOnlyCurrentIdsWithoutExecuting()
{
_app.StartStage(14); yield return null; Physics.SyncTransforms();
var arch=_app.Environment.GetComponentsInChildren<MeshCollider>().First(collider=>collider.sharedMesh.name.Contains("BlockArch"));
var local=new Ray(new Vector3(0,1,-3),Vector3.forward);
Assert.That(arch.Raycast(new Ray(arch.transform.parent.TransformPoint(local.origin),Vector3.forward),out _,6), Is.False,"No box collider can close the Blender arch gap.");
var before=JsonUtility.ToJson(_store.Saved); var hint=_app.Session.Hint; _app.ShowHelp();
Assert.That(JsonUtility.ToJson(_store.Saved), Is.EqualTo(before));
Assert.That(_app.Presenter.Balls.Values.Where(ball=>ball.Hinted).Select(ball=>ball.BallId), Is.EquivalentTo(hint.BallIds));
Assert.That(_app.Voice.CurrentClipId, Is.EqualTo(hint.VoiceId));
}
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 781a56d13cd91d54c8e742b2da8ce4f6
@@ -37,11 +37,18 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
[SerializeField] private OrbitCamera _orbit;
[SerializeField] private BoardInput _input;
[SerializeField] private VoicePlayer _voice;
[SerializeField] private UnityEngine.UI.Button[] _stageButtons = Array.Empty<UnityEngine.UI.Button>();
[SerializeField] private UnityEngine.UI.Button _helpButton;
[SerializeField] private UnityEngine.UI.Button _nextButton;
[SerializeField] private BoardEnvironment _environment;
[SerializeField] private GhostDemonstration _demonstration;
public GameSession Session { get; private set; }
public BoardPresenter Presenter => _presenter;
public BoardInput Input => _input;
public OrbitCamera Orbit => _orbit;
public VoicePlayer Voice => _voice;
public BoardEnvironment Environment => _environment;
public GhostDemonstration Demonstration => _demonstration;
public string Instruction => _instruction.text;
public string Counter => _counter.text;
@@ -49,13 +56,20 @@ 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 (_stageButtons.Length == 0)
{
_stageOneButton.onClick.AddListener(() => StartStage(1));
if (_stageTwoButton != null) _stageTwoButton.onClick.AddListener(() => StartStage(2));
}
for (int index = 0; index < _stageButtons.Length; index++)
{ int stageId = _stages[index].StageId; _stageButtons[index].onClick.AddListener(() => StartStage(stageId)); }
if (_helpButton != null) _helpButton.onClick.AddListener(ShowHelp);
if (_nextButton != null) _nextButton.onClick.AddListener(StartNextStage);
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++)
for (int index = 0; _stageButtons.Length == 0 && index < _compositionButtons.Length; index++)
{ 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.CancelGuide(); });
@@ -93,20 +107,35 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
if (Session.ReturnGroup(groupId).Accepted) Refresh(false);
}
public void ShowSelection()
{ _input.CancelSplit(); _voice.Clear(); Session.ShowSelection(); Refresh(true); }
{ _input.CancelSplit(); _voice.Clear(); _demonstration?.Hide(); Session.ShowSelection(); Refresh(true); }
public void ShowHome()
{ _input.CancelSplit(); _voice.Clear(); Session.ShowHome(); Refresh(true); }
{ _input.CancelSplit(); _voice.Clear(); _demonstration?.Hide(); Session.ShowHome(); Refresh(true); }
public void StartStage(int id)
{
_input.CancelSplit(); _voice.Clear(); bool restored = Session.HasUnfinishedStage(id);
_input.CancelSplit(); _voice.Clear(); _demonstration?.Hide(); bool restored = Session.HasUnfinishedStage(id);
if (!Session.StartStage(id)) return;
Refresh(true);
string tutorial = id == 6 ? "merge" : id == 10 ? "split" : null;
if (tutorial != null && !Session.HasSeenTutorial(tutorial) && _demonstration != null)
{ Session.MarkTutorialSeen(tutorial); _demonstration.Show(id == 10); _voice.Guide(id == 6 ? "demo_merge6" : "demo_split10"); return; }
// Restoring never replays historical count/celebration clips.
if (Session.Board.Mode == BoardMode.Counting && Session.Board.CollectedBallIds.Length == 0) _voice.Guide("guide_collect");
else if (!restored) _voice.Guide(id == 10 ? "guide_split" : "guide_merge");
}
public void ContinueFreePlay()
{ _input.CancelSplit(); _voice.Clear(); if (Session.ContinueFreePlay()) Refresh(true); }
{ _input.CancelSplit(); _voice.Clear(); _demonstration?.Hide(); if (Session.ContinueFreePlay()) Refresh(true); }
public void StartNextStage()
{ if (Session.HasNextStage) StartStage(Session.Board.StageId + 1); }
public void ShowHelp()
{
var hint = Session.Hint; if (hint == null) return;
_voice.CancelGuide();
_instruction.text = hint.Kind == HintKind.Collect ? "이 친구를 찾아 끌어와 볼까?"
: hint.Kind == HintKind.Count ? "아직 세지 않은 이 구를 눌러 볼까?"
: hint.Kind == HintKind.Merge ? "빛나는 두 친구를 가까이 끌어와 붙여 볼까?"
: $"빛나는 {hint.GroupSize} 친구에서 나누기를 누르고 {hint.SelectionCount}개를 골라 끌어내 보자.";
_presenter.ShowHint(hint.BallIds); _voice.Guide(hint.VoiceId);
}
public void CommitMove(string groupId, Position3 delta, string mergeTarget = null)
{
var result = mergeTarget == null ? Session.MoveGroup(groupId, delta) : Session.MoveAndMerge(groupId, delta, mergeTarget);
@@ -142,12 +171,22 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
_playPanel.SetActive(playing); _world.SetActive(playing);
_continueButton.gameObject.SetActive(Session.HasFreePlay);
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);
for (int index = 0; index < _stageButtons.Length; index++)
{
int id = _stages[index].StageId; bool unlocked = Session.IsUnlocked(id);
_stageButtons[index].interactable = unlocked;
string state = !unlocked ? "잠금" : Session.HasUnfinishedStage(id) ? "이어하기" : Session.CompletedStageIds.Contains(id) ? "완료" : "시작";
_stageButtons[index].GetComponentInChildren<TMP_Text>().text = $"{id} · {state}";
}
for (int index = 0; _stageButtons.Length == 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 (_helpButton != null) _helpButton.gameObject.SetActive(screen == SessionScreen.Puzzle);
if (_nextButton != null) _nextButton.gameObject.SetActive(Session.HasNextStage);
if (applyCamera) _orbit.Apply(Session.Camera);
_presenter.Render(Session.Board);
if (!playing) return;
_environment?.Apply(_stages.First(stage => stage.StageId == Session.Board.StageId));
_stageTitle.text = screen == SessionScreen.FreePlay ? "자유 놀이터" : $"숫자 {Session.Board.BallCount} 친구 찾기";
_counter.text = screen == SessionScreen.FreePlay ? $"친구 {Session.Board.BallCount}" : $"센 친구 {Session.Board.CountedCount} / {Session.Board.BallCount}";
_instruction.text = screen == SessionScreen.FreePlay ? "해냈어! 친구와 자유롭게 놀아 보자."
@@ -175,7 +214,7 @@ namespace MagnetismHeroes.UnityRuntime.Bootstrap
_presenter.ShowSelection(_input.SelectedIds);
}
private void OnApplicationPause(bool paused)
{ if (paused && Session != null) { _input.CancelSplit(); _voice.Clear(); Session.SaveCurrent(); } }
{ if (paused && Session != null) { _input.CancelSplit(); _voice.Clear(); _demonstration?.Hide(); Session.SaveCurrent(); } }
private void OnApplicationQuit() { if (Session != null) { _input.Cancel(); Session.SaveCurrent(); } }
}
}
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 58025cea9c2040e4a866ed42207c867a
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: cfab8218f298faa4484c14332487074f
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 029611a21afb8fc4998f0a72346484f9
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 8c596c03be9587c4d90bdb5141a6631d
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: e7e6ff936279732459e83e01fcf624c6
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 7cf93b46361e1c44f902d0766279ba4b
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 02090e6696802124a9350812f9de6360
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 5fa85b27a09c0b443a41138e43fba9a1
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 1258240731e6b884c89e58037ff2fbbd
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 48624da8dcdcef54b9a0b887b093eb45
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: cce7913b2aeec7b4ea960aee1192fe82
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: f36392d682b388f43bae674497f4015a
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: b781181e28c7a424e995be73bfd79379
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 001c522f673271549afbf7e9059e2d7c
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 9d0de476fb2c6b74793ab90ff2e21b63
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: f5aab5f862a25184c8c06d2be87e8d09
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 31c718bcb553fc3419ecb5d559cb224c
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 7c371891b275c6a4d98244ec667782bc
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: ddb9effc1d457344aaa2f13ab43a1c29
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 10b3914e60e5be6449e5e41cc46a9ea1
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: e421602cce67a114a82883dbc737166f
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 4d69afe4cdc782443beb3ecf0b8fca63
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 037a10d759e7b3e44adc1ace4c80bf1e
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: b1e7f725b0ede124385bf111a3ace1cb
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 0e7e25522a0b918409f315cd6bbef97f
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 818d55fef3b09654e874ccdad5bf5b11
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: fe870d2060859af448839ab57d6f1c7a
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 338adfb5a08e5aa41adfefb1736f5e0f
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: a8a32005454a3f04592662df650cce47
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: a8479c76c9f24ec4295b92edfd056542
AudioImporter:
externalObjects: {}
serializedVersion: 8
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 0
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
@@ -11,6 +11,7 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
private float _encourageUntil;
public bool Selected { get; set; }
public bool ContactCandidate { get; set; }
public bool Hinted { get; set; }
public string BallId { get; private set; }
public string GroupId { get; private set; }
public void Bind(string ballId, string groupId, bool counted)
@@ -20,7 +21,7 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
private void Update()
{
float glow = Mathf.Clamp01((_encourageUntil - Time.unscaledTime) / 0.35f);
var color = Selected ? new Color(1, 0.78f, 0.2f) : ContactCandidate ? new Color(0.5f, 1, 0.7f) : _normalColor;
var color = Selected ? new Color(1, 0.78f, 0.2f) : ContactCandidate ? new Color(0.5f, 1, 0.7f) : Hinted ? Color.Lerp(_normalColor, Color.white, .5f + .3f * Mathf.Sin(Time.unscaledTime * 4)) : _normalColor;
_colors.SetColor("_BaseColor", Color.Lerp(color, Color.white, glow * 0.7f)); _body.SetPropertyBlock(_colors);
}
}
@@ -0,0 +1,25 @@
using MagnetismHeroes.UnityRuntime.StageAssets;
using UnityEngine;
namespace MagnetismHeroes.UnityRuntime.Presentation
{
public sealed class BoardEnvironment : MonoBehaviour
{
private int _stageId;
public string Theme { get; private set; }
public void Apply(StageAsset stage)
{
if (_stageId == stage.StageId) return;
foreach (Transform child in transform) { child.gameObject.SetActive(false); Destroy(child.gameObject); }
foreach (var placement in stage.Decorations)
{
if (placement.prefab.name == "Island" && transform.parent.Find("PlaygroundIsland") != null) continue;
var prop = Instantiate(placement.prefab, transform);
prop.transform.localPosition = placement.position;
prop.transform.localRotation = Quaternion.Euler(placement.eulerAngles);
prop.transform.localScale = placement.scale;
}
_stageId = stage.StageId; Theme = stage.Theme;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c76b84d0084f787458ed6a2d3cff26cf
@@ -88,6 +88,8 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
public void ShowSelection(IReadOnlyCollection<string> selected)
{ foreach (var ball in _balls.Values) ball.Selected = selected.Contains(ball.BallId); }
public void ShowHint(IReadOnlyCollection<string> ids)
{ foreach (var ball in _balls.Values) ball.Hinted = ids.Contains(ball.BallId); }
public void CancelPreview()
{
File diff suppressed because one or more lines are too long
@@ -0,0 +1,32 @@
using UnityEngine;
namespace MagnetismHeroes.UnityRuntime.Presentation
{
// UI-only silhouettes: no board IDs, colliders, rules, input, or progress mutations.
public sealed class GhostDemonstration : MonoBehaviour
{
[SerializeField] private RectTransform _first;
[SerializeField] private RectTransform _second;
[SerializeField] private TMPro.TMP_Text _caption;
private float _started;
private bool _split;
public bool IsShowing => gameObject.activeSelf;
public void Show(bool split)
{
_split = split; _started = Time.unscaledTime; gameObject.SetActive(true);
_caption.text = split ? "나누기 → 하나 선택 → 끌어내기" : "친구를 끌어와 붙여 보자";
Update();
}
public void Hide() => gameObject.SetActive(false);
private void Update()
{
float elapsed = Time.unscaledTime - _started;
if (elapsed > 5) { Hide(); return; }
float travel = Mathf.SmoothStep(0, 1, Mathf.Clamp01((elapsed - (_split ? 2 : .5f)) / 1.5f));
_first.anchoredPosition = new Vector2(_split ? -28 : Mathf.Lerp(-95, -28, travel), 10);
_second.anchoredPosition = new Vector2(_split ? Mathf.Lerp(28, 100, travel) : 28, 10);
_first.GetComponent<UnityEngine.UI.Image>().color = new Color(.55f, .85f, 1, .8f);
_second.GetComponent<UnityEngine.UI.Image>().color = _split && elapsed > 1 ? new Color(1, .78f, .2f, .85f) : new Color(.55f, .85f, 1, .8f);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 05454bd1d2ac00140bc02d964d0e829b
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: BlockArch
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.61, g: 0.69, b: 0.92, a: 1}
- _Color: {r: 0.61, g: 0.69, b: 0.92, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &494216862960930982
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d4ad0716a76717e4599e9c6e443325fe
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: CloudMoon
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.8, g: 0.88, b: 1, a: 1}
- _Color: {r: 0.8, g: 0.88, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &2949793290921366565
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a9991983aa00cfd42816d34944d4b0ea
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-6889183827092388892
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: CloudPuff
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.8, g: 0.88, b: 1, a: 1}
- _Color: {r: 0.8, g: 0.88, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6cc1af7e47e7ea84d92e5cd7abc2afd5
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2501202161621321635
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: CloudRainbow
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.8, g: 0.88, b: 1, a: 1}
- _Color: {r: 0.8, g: 0.88, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dcf11f2be45f8b643a7d5e5f253afad1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-315070192422014952
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: GardenFlower
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.96, g: 0.56, b: 0.48, a: 1}
- _Color: {r: 0.96, g: 0.56, b: 0.47999996, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e7e8b4a457f2323468a5ba16e84b947b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2308729174112483146
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: GardenLeaf
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.96, g: 0.56, b: 0.48, a: 1}
- _Color: {r: 0.96, g: 0.56, b: 0.47999996, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 50c3369cb0351054ca0766874e5d83b7
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-3248462766839265823
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: GardenMushroom
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.96, g: 0.56, b: 0.48, a: 1}
- _Color: {r: 0.96, g: 0.56, b: 0.47999996, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 27da176a26715144c8f8a8b72701130c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-652441358681187221
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Island
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.61, g: 0.83, b: 0.71, a: 1}
- _Color: {r: 0.61, g: 0.83, b: 0.71, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6191ae0d8f7856d40b6d0ae53663e544
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2831621163233419917
MonoBehaviour:
m_ObjectHideFlags: 11
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Pebbles
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScreenSpaceReflections: 1
- _ScreenSpaceReflectionsContributeTransparent: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.61, g: 0.69, b: 0.92, a: 1}
- _Color: {r: 0.61, g: 0.69, b: 0.92, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fd49f70eea35ef142b4ecfab9bc4ffb2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More