Refactor course maps and travel UI

This commit is contained in:
jongjae0305
2026-07-07 15:57:11 +09:00
parent 74498dcf87
commit a708f18499
37 changed files with 1983 additions and 1633 deletions
+53 -84
View File
@@ -1,44 +1,9 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
// 발판을 생성하고 주기적으로 재배치하는 스크립트
public class PlatformSpawner : MonoBehaviour {
public enum CoursePlatformType {
Basic,
Jump,
Slide,
ForceHit
}
private enum TutorialStepKind {
None,
Jump,
DoubleJumpTakeoff,
Slide,
ForceHit,
HealthItem,
InvincibleItem,
ShieldItem,
SpeedItem,
MileageCardItem
}
[Serializable]
public class TutorialStep {
public CoursePlatformType coursePlatformType;
public Platform.PlatformPattern platformPattern;
public Platform.MileagePattern mileagePattern;
public SlideObstaclePattern.SlideLayout slideLayout;
public Platform.ItemPattern itemPattern;
public GameManager.TutorialGuideType guideType;
public float yPosition;
public float spawnInterval;
public string title;
public string message;
}
private class PendingTutorialGuide {
public Transform target;
public GameManager.TutorialGuideType guideType;
@@ -53,8 +18,8 @@ public class PlatformSpawner : MonoBehaviour {
public int count = 12; // 기본 발판 풀 개수
public bool usePatternCourse = true; // 검증된 발판 패턴 코스를 사용
public bool tutorialMode = true; // 처음에는 튜토리얼 패턴을 먼저 배치
public TutorialStep[] tutorialSteps; // 튜토리얼 발판 순서
public TutorialStep[] stagePatternSteps; // 튜토리얼 이후 반복할 검증된 발판 순서
public CourseStep[] tutorialSteps; // 튜토리얼 발판 순서
public CourseStep[] stagePatternSteps; // 튜토리얼 이후 반복할 검증된 발판 순서
public bool keepWorldSpacingBySpeed = true; // 게임 속도가 빨라져도 발판 사이 실제 거리를 유지
public int continuousCoursePoolCount = 12; // 기본 발판을 촘촘히 깔 때 필요한 최소 풀 크기
@@ -99,8 +64,8 @@ public class PlatformSpawner : MonoBehaviour {
usePatternCourse = true;
tutorialMode = mapDefinition.isTutorial;
mapPlatformSkin = mapDefinition.platformSkin;
tutorialSteps = MapDatabase.CloneSteps(mapDefinition.openingSteps);
stagePatternSteps = MapDatabase.CloneSteps(mapDefinition.loopSteps);
tutorialSteps = CourseStepFactory.CloneSteps(mapDefinition.openingSteps);
stagePatternSteps = CourseStepFactory.CloneSteps(mapDefinition.loopSteps);
courseStepIndex = 0;
courseSpawningStopped = false;
pendingTutorialGuides.Clear();
@@ -123,7 +88,7 @@ public class PlatformSpawner : MonoBehaviour {
activeFinishLandingPlatform = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
activeFinishLandingPlatform.SetActive(false);
TutorialStep landingStep = CreateStep(
CourseStep landingStep = CreateStep(
Platform.PlatformPattern.Empty,
Platform.MileagePattern.None,
SlideObstaclePattern.SlideLayout.Random,
@@ -266,7 +231,7 @@ public class PlatformSpawner : MonoBehaviour {
{
lastSpawnTime = Time.time;
TutorialStep step = usePatternCourse ? GetCurrentCourseStep() : null;
CourseStep step = usePatternCourse ? GetCurrentCourseStep() : null;
timeBetSpawn = step != null ? GetStepSpawnInterval(step) : Random.Range(timeBetSpawnMin, timeBetSpawnMax);
float yPos = step != null
@@ -319,7 +284,7 @@ public class PlatformSpawner : MonoBehaviour {
}
}
private void RegisterTutorialGuide(Transform target, TutorialStep step) {
private void RegisterTutorialGuide(Transform target, CourseStep step) {
if(target == null
|| step == null
|| step.guideType == GameManager.TutorialGuideType.None
@@ -337,7 +302,7 @@ public class PlatformSpawner : MonoBehaviour {
});
}
private float GetTutorialGuideTriggerX(TutorialStep step) {
private float GetTutorialGuideTriggerX(CourseStep step) {
if(step != null && step.guideType == GameManager.TutorialGuideType.DoubleJump)
{
return -2f;
@@ -346,7 +311,7 @@ public class PlatformSpawner : MonoBehaviour {
return tutorialGuideTriggerX;
}
private void SpawnCourseObstacles(TutorialStep step, float yPos) {
private void SpawnCourseObstacles(CourseStep step, float yPos) {
if(step == null)
{
return;
@@ -355,7 +320,6 @@ public class PlatformSpawner : MonoBehaviour {
if(step.coursePlatformType == CoursePlatformType.ForceHit || step.platformPattern == Platform.PlatformPattern.ForceHit)
{
SpawnJumpObstacle(Platform.PlatformPattern.LowMid, yPos);
SpawnSlideObstacle(SlideObstaclePattern.SlideLayout.WidePair, yPos);
return;
}
@@ -440,7 +404,7 @@ public class PlatformSpawner : MonoBehaviour {
return platformObject;
}
private void ConfigurePlatform(GameObject platformObject, TutorialStep step) {
private void ConfigurePlatform(GameObject platformObject, CourseStep step) {
Platform platform = platformObject.GetComponent<Platform>();
if(platform == null)
@@ -454,12 +418,12 @@ public class PlatformSpawner : MonoBehaviour {
return;
}
platform.ConfigureForTutorial(Platform.PlatformPattern.Empty, step.mileagePattern, step.slideLayout, step.itemPattern, mapPlatformSkin);
platform.ConfigureForTutorial(step.mileagePattern, step.itemPattern, mapPlatformSkin);
// 설명은 발판 생성 시점이 아니라 실제 체험 직전에 RegisterTutorialGuide가 띄운다.
}
private float GetStepSpawnInterval(TutorialStep step) {
private float GetStepSpawnInterval(CourseStep step) {
float spawnInterval;
if(step != null && step.spawnInterval > 0f)
@@ -479,7 +443,7 @@ public class PlatformSpawner : MonoBehaviour {
return Mathf.Max(0.05f, spawnInterval);
}
private TutorialStep GetCurrentCourseStep() {
private CourseStep GetCurrentCourseStep() {
EnsurePatternSteps();
if(tutorialMode && courseStepIndex < tutorialSteps.Length)
@@ -525,23 +489,28 @@ public class PlatformSpawner : MonoBehaviour {
return;
}
tutorialSteps = new TutorialStep[] {
CreateTutorialStep(TutorialStepKind.Jump, Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(TutorialStepKind.DoubleJumpTakeoff, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackAerialSpacing),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(TutorialStepKind.Slide, Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(TutorialStepKind.ForceHit, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(TutorialStepKind.HealthItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing, Platform.ItemPattern.HealthSushi),
CreateTutorialStep(TutorialStepKind.InvincibleItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.InvincibleRamen),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(TutorialStepKind.ShieldItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.Shield),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(TutorialStepKind.SpeedItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.SpeedShoes),
CreateTutorialStep(TutorialStepKind.MileageCardItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.MileageCard),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
tutorialSteps = new CourseStep[] {
CreateTutorialStep(CourseStepKind.Jump, Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(CourseStepKind.DoubleJumpTakeoff, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackAerialSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(CourseStepKind.Slide, Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(CourseStepKind.ForceHit, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(CourseStepKind.HealthItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing, Platform.ItemPattern.HealthSushi),
CreateTutorialStep(CourseStepKind.InvincibleItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.InvincibleRamen),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackLandingSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
CreateTutorialStep(CourseStepKind.ShieldItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.Shield),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(CourseStepKind.MileageCardItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.MileageCard),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, FallbackGroundY, FallbackActionSpacing),
CreateTutorialStep(CourseStepKind.SpeedItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing, Platform.ItemPattern.SpeedShoes),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
CreateTutorialStep(CourseStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, FallbackGroundY, FallbackBasicSpacing),
};
}
@@ -551,7 +520,7 @@ public class PlatformSpawner : MonoBehaviour {
return;
}
stagePatternSteps = new TutorialStep[] {
stagePatternSteps = new CourseStep[] {
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackBasicSpacing, "", ""),
CreateStep(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Jump),
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackLandingSpacing, "", ""),
@@ -569,7 +538,7 @@ public class PlatformSpawner : MonoBehaviour {
};
}
private TutorialStep CreateStep(
private CourseStep CreateStep(
Platform.PlatformPattern platformPattern,
Platform.MileagePattern mileagePattern,
SlideObstaclePattern.SlideLayout slideLayout,
@@ -580,7 +549,7 @@ public class PlatformSpawner : MonoBehaviour {
string message,
Platform.ItemPattern itemPattern = Platform.ItemPattern.None,
CoursePlatformType coursePlatformType = CoursePlatformType.Basic) {
TutorialStep step = new TutorialStep();
CourseStep step = new CourseStep();
step.coursePlatformType = coursePlatformType;
step.platformPattern = platformPattern;
step.mileagePattern = mileagePattern;
@@ -594,8 +563,8 @@ public class PlatformSpawner : MonoBehaviour {
return step;
}
private TutorialStep CreateTutorialStep(
TutorialStepKind stepKind,
private CourseStep CreateTutorialStep(
CourseStepKind stepKind,
Platform.PlatformPattern platformPattern,
Platform.MileagePattern mileagePattern,
SlideObstaclePattern.SlideLayout slideLayout,
@@ -608,47 +577,47 @@ public class PlatformSpawner : MonoBehaviour {
switch(stepKind)
{
case TutorialStepKind.Jump:
case CourseStepKind.Jump:
guideType = GameManager.TutorialGuideType.Jump;
title = "점프";
message = "가방 장애물이 보이면 왼쪽 클릭으로 뛰어넘습니다.";
break;
case TutorialStepKind.DoubleJumpTakeoff:
case CourseStepKind.DoubleJumpTakeoff:
guideType = GameManager.TutorialGuideType.DoubleJump;
title = "2단 점프";
message = "다음 발판이 멀리 있으면 공중에서 한 번 더 왼쪽 클릭합니다.";
break;
case TutorialStepKind.Slide:
case CourseStepKind.Slide:
guideType = GameManager.TutorialGuideType.Slide;
title = "슬라이드";
message = "천장 표지판이 보이면 오른쪽 클릭을 누르고 지나갑니다.";
break;
case TutorialStepKind.ForceHit:
case CourseStepKind.ForceHit:
guideType = GameManager.TutorialGuideType.Damage;
title = "피격";
message = "이번 구간은 일부러 맞아 목숨과 속도 감소를 확인합니다.";
break;
case TutorialStepKind.HealthItem:
case CourseStepKind.HealthItem:
guideType = GameManager.TutorialGuideType.Items;
title = "초밥";
message = "초밥을 먹으면 잃은 목숨을 1 회복합니다.";
break;
case TutorialStepKind.InvincibleItem:
case CourseStepKind.InvincibleItem:
guideType = GameManager.TutorialGuideType.Items;
title = "라멘";
message = "라멘을 먹고 다음 충돌을 피해 없이 지나가 봅니다.";
break;
case TutorialStepKind.ShieldItem:
case CourseStepKind.ShieldItem:
guideType = GameManager.TutorialGuideType.Items;
title = "방어막";
message = "방어막을 먹고 다음 충돌 1회를 막아 봅니다.";
break;
case TutorialStepKind.SpeedItem:
case CourseStepKind.SpeedItem:
guideType = GameManager.TutorialGuideType.Items;
title = "운동화";
message = "운동화는 속도를 회복해 일정이 늦어지는 것을 줄입니다.";
break;
case TutorialStepKind.MileageCardItem:
case CourseStepKind.MileageCardItem:
guideType = GameManager.TutorialGuideType.Items;
title = "마일리지 카드";
message = "카드를 먹은 뒤 마일리지를 모으면 획득량이 늘어납니다.";
@@ -668,18 +637,18 @@ public class PlatformSpawner : MonoBehaviour {
GetCoursePlatformType(stepKind, platformPattern, yPosition));
}
private CoursePlatformType GetCoursePlatformType(TutorialStepKind stepKind, Platform.PlatformPattern platformPattern, float yPosition) {
if(stepKind == TutorialStepKind.ForceHit || platformPattern == Platform.PlatformPattern.ForceHit)
private CoursePlatformType GetCoursePlatformType(CourseStepKind stepKind, Platform.PlatformPattern platformPattern, float yPosition) {
if(stepKind == CourseStepKind.ForceHit || platformPattern == Platform.PlatformPattern.ForceHit)
{
return CoursePlatformType.ForceHit;
}
if(stepKind == TutorialStepKind.Slide || platformPattern == Platform.PlatformPattern.Slide)
if(stepKind == CourseStepKind.Slide || platformPattern == Platform.PlatformPattern.Slide)
{
return CoursePlatformType.Slide;
}
if(stepKind == TutorialStepKind.Jump
if(stepKind == CourseStepKind.Jump
|| platformPattern == Platform.PlatformPattern.LowLeft
|| platformPattern == Platform.PlatformPattern.LowMid
|| platformPattern == Platform.PlatformPattern.LowRight)