Build TravelRun intro and tutorial flow

This commit is contained in:
jongjae0305
2026-07-06 16:15:20 +09:00
parent af26dd4311
commit 2ba3882f1b
153 changed files with 13625 additions and 2086 deletions
+316
View File
@@ -0,0 +1,316 @@
using TMPro;
using UnityEngine;
public class ItemFeedbackEffect : MonoBehaviour
{
private const string SortingLayerName = "Foreground";
private const float Lifetime = 0.85f;
private static Sprite ringSprite;
private static Sprite dotSprite;
private static Sprite sparkleSprite;
private SpriteRenderer ringRenderer;
private SpriteRenderer iconRenderer;
private SpriteRenderer[] sparkleRenderers;
private TextMeshPro labelText;
private Color mainColor;
private float elapsedTime;
public static void Spawn(Vector3 worldPosition, Sprite itemSprite, GameManager.TutorialItemType itemType, bool blockedDamage)
{
GameObject effectObject = new GameObject(blockedDamage ? "Item Block Feedback" : "Item Pickup Feedback");
effectObject.transform.position = worldPosition + new Vector3(0f, blockedDamage ? 1.1f : 0.85f, 0f);
ItemFeedbackEffect effect = effectObject.AddComponent<ItemFeedbackEffect>();
effect.Initialize(itemSprite, itemType, blockedDamage);
}
private void Initialize(Sprite itemSprite, GameManager.TutorialItemType itemType, bool blockedDamage)
{
mainColor = GetItemColor(itemType, blockedDamage);
sparkleRenderers = new SpriteRenderer[5];
ringRenderer = CreateSpriteChild("Ring", GetRingSprite(), Vector3.zero, 1.4f, 28);
iconRenderer = CreateSpriteChild("Icon", itemSprite != null ? itemSprite : GetDotSprite(), new Vector3(0f, 0.03f, 0f), itemSprite != null ? 0.52f : 0.72f, 29);
labelText = CreateLabel(GetLabel(itemType, blockedDamage));
for(int i = 0; i < sparkleRenderers.Length; i++)
{
float angle = (Mathf.PI * 2f / sparkleRenderers.Length) * i;
Vector3 localPosition = new Vector3(Mathf.Cos(angle) * 0.58f, Mathf.Sin(angle) * 0.38f, 0f);
sparkleRenderers[i] = CreateSpriteChild("Sparkle " + i, GetSparkleSprite(), localPosition, 0.18f, 30);
}
ApplyAlpha(1f);
}
private void Update()
{
elapsedTime += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsedTime / Lifetime);
float fade = 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.55f, 1f, t));
float popScale = Mathf.Lerp(0.72f, 1.16f, EaseOut(t));
transform.localScale = Vector3.one * popScale;
transform.position += Vector3.up * (Time.unscaledDeltaTime * 0.28f);
if(ringRenderer != null)
{
ringRenderer.transform.localScale = Vector3.one * Mathf.Lerp(0.82f, 1.38f, EaseOut(t));
}
for(int i = 0; i < sparkleRenderers.Length; i++)
{
if(sparkleRenderers[i] == null)
{
continue;
}
sparkleRenderers[i].transform.localScale = Vector3.one * Mathf.Lerp(0.16f, 0.32f, EaseOut(t));
sparkleRenderers[i].transform.Rotate(Vector3.forward, 180f * Time.unscaledDeltaTime);
}
ApplyAlpha(fade);
if(elapsedTime >= Lifetime)
{
Destroy(gameObject);
}
}
private SpriteRenderer CreateSpriteChild(string objectName, Sprite sprite, Vector3 localPosition, float scale, int sortingOrder)
{
GameObject child = new GameObject(objectName, typeof(SpriteRenderer));
child.transform.SetParent(transform, false);
child.transform.localPosition = localPosition;
child.transform.localScale = Vector3.one * scale;
SpriteRenderer spriteRenderer = child.GetComponent<SpriteRenderer>();
spriteRenderer.sprite = sprite;
spriteRenderer.color = mainColor;
spriteRenderer.sortingLayerName = SortingLayerName;
spriteRenderer.sortingOrder = sortingOrder;
return spriteRenderer;
}
private TextMeshPro CreateLabel(string text)
{
GameObject textObject = new GameObject("Label", typeof(TextMeshPro));
textObject.transform.SetParent(transform, false);
textObject.transform.localPosition = new Vector3(0f, 0.62f, 0f);
textObject.transform.localScale = Vector3.one * 0.28f;
TextMeshPro textMesh = textObject.GetComponent<TextMeshPro>();
textMesh.text = text;
textMesh.alignment = TextAlignmentOptions.Center;
textMesh.fontSize = 3.2f;
textMesh.fontStyle = FontStyles.Bold;
textMesh.color = Color.white;
textMesh.textWrappingMode = TextWrappingModes.NoWrap;
MeshRenderer textRenderer = textMesh.GetComponent<MeshRenderer>();
textRenderer.sortingLayerName = SortingLayerName;
textRenderer.sortingOrder = 31;
return textMesh;
}
private void ApplyAlpha(float alpha)
{
if(ringRenderer != null)
{
ringRenderer.color = WithAlpha(mainColor, alpha * 0.72f);
}
if(iconRenderer != null)
{
iconRenderer.color = WithAlpha(Color.white, alpha);
}
if(labelText != null)
{
labelText.color = WithAlpha(Color.white, alpha);
}
if(sparkleRenderers == null)
{
return;
}
for(int i = 0; i < sparkleRenderers.Length; i++)
{
if(sparkleRenderers[i] != null)
{
sparkleRenderers[i].color = WithAlpha(mainColor, alpha);
}
}
}
private static string GetLabel(GameManager.TutorialItemType itemType, bool blockedDamage)
{
if(blockedDamage)
{
return itemType == GameManager.TutorialItemType.InvincibleRamen ? "SAFE" : "BLOCK";
}
switch(itemType)
{
case GameManager.TutorialItemType.InvincibleRamen:
return "SAFE";
case GameManager.TutorialItemType.Shield:
return "SHIELD";
case GameManager.TutorialItemType.SpeedShoes:
return "SPEED";
case GameManager.TutorialItemType.MileageCard:
return "x2";
case GameManager.TutorialItemType.HealthSushi:
default:
return "+1";
}
}
private static Color GetItemColor(GameManager.TutorialItemType itemType, bool blockedDamage)
{
if(blockedDamage)
{
return itemType == GameManager.TutorialItemType.InvincibleRamen
? new Color(1f, 0.76f, 0.24f, 1f)
: new Color(0.36f, 0.82f, 1f, 1f);
}
switch(itemType)
{
case GameManager.TutorialItemType.InvincibleRamen:
return new Color(1f, 0.58f, 0.12f, 1f);
case GameManager.TutorialItemType.Shield:
return new Color(0.32f, 0.78f, 1f, 1f);
case GameManager.TutorialItemType.SpeedShoes:
return new Color(0.35f, 1f, 0.5f, 1f);
case GameManager.TutorialItemType.MileageCard:
return new Color(1f, 0.92f, 0.26f, 1f);
case GameManager.TutorialItemType.HealthSushi:
default:
return new Color(1f, 0.34f, 0.42f, 1f);
}
}
private static float EaseOut(float value)
{
return 1f - Mathf.Pow(1f - Mathf.Clamp01(value), 3f);
}
private static Color WithAlpha(Color color, float alpha)
{
return new Color(color.r, color.g, color.b, Mathf.Clamp01(alpha));
}
private static Sprite GetRingSprite()
{
if(ringSprite == null)
{
ringSprite = CreateRingSprite(64, 21f, 29f);
}
return ringSprite;
}
private static Sprite GetDotSprite()
{
if(dotSprite == null)
{
dotSprite = CreateDiscSprite(48, 19f);
}
return dotSprite;
}
private static Sprite GetSparkleSprite()
{
if(sparkleSprite == null)
{
sparkleSprite = CreateSparkleSprite(24);
}
return sparkleSprite;
}
private static Sprite CreateRingSprite(int size, float innerRadius, float outerRadius)
{
Texture2D texture = CreateTexture(size);
Color[] pixels = new Color[size * size];
Vector2 center = new Vector2((size - 1) * 0.5f, (size - 1) * 0.5f);
for(int y = 0; y < size; y++)
{
for(int x = 0; x < size; x++)
{
float distance = Vector2.Distance(new Vector2(x, y), center);
float outerAlpha = 1f - Mathf.SmoothStep(outerRadius - 2f, outerRadius, distance);
float innerAlpha = Mathf.SmoothStep(innerRadius - 2f, innerRadius, distance);
pixels[y * size + x] = new Color(1f, 1f, 1f, outerAlpha * innerAlpha);
}
}
texture.SetPixels(pixels);
texture.Apply();
return Sprite.Create(texture, new Rect(0f, 0f, size, size), new Vector2(0.5f, 0.5f), size);
}
private static Sprite CreateDiscSprite(int size, float radius)
{
Texture2D texture = CreateTexture(size);
Color[] pixels = new Color[size * size];
Vector2 center = new Vector2((size - 1) * 0.5f, (size - 1) * 0.5f);
for(int y = 0; y < size; y++)
{
for(int x = 0; x < size; x++)
{
float distance = Vector2.Distance(new Vector2(x, y), center);
float alpha = 1f - Mathf.SmoothStep(radius - 2f, radius, distance);
pixels[y * size + x] = new Color(1f, 1f, 1f, alpha);
}
}
texture.SetPixels(pixels);
texture.Apply();
return Sprite.Create(texture, new Rect(0f, 0f, size, size), new Vector2(0.5f, 0.5f), size);
}
private static Sprite CreateSparkleSprite(int size)
{
Texture2D texture = CreateTexture(size);
Color[] pixels = new Color[size * size];
float center = (size - 1) * 0.5f;
for(int y = 0; y < size; y++)
{
for(int x = 0; x < size; x++)
{
float horizontal = Mathf.Abs(y - center);
float vertical = Mathf.Abs(x - center);
float diagonalA = Mathf.Abs((x - center) - (y - center));
float diagonalB = Mathf.Abs((x - center) + (y - center));
float alpha = Mathf.Max(
1f - horizontal * 0.42f - Mathf.Abs(x - center) * 0.08f,
1f - vertical * 0.42f - Mathf.Abs(y - center) * 0.08f);
alpha = Mathf.Max(alpha, 0.62f - Mathf.Min(diagonalA, diagonalB) * 0.28f);
pixels[y * size + x] = new Color(1f, 1f, 1f, Mathf.Clamp01(alpha));
}
}
texture.SetPixels(pixels);
texture.Apply();
return Sprite.Create(texture, new Rect(0f, 0f, size, size), new Vector2(0.5f, 0.5f), size);
}
private static Texture2D CreateTexture(int size)
{
Texture2D texture = new Texture2D(size, size, TextureFormat.RGBA32, false);
texture.wrapMode = TextureWrapMode.Clamp;
texture.filterMode = FilterMode.Bilinear;
texture.hideFlags = HideFlags.HideAndDontSave;
return texture;
}
}