Add travel map flow and update docs
This commit is contained in:
@@ -4,18 +4,38 @@ using Random = UnityEngine.Random;
|
||||
|
||||
// 발판을 생성하고 주기적으로 재배치하는 스크립트
|
||||
public class PlatformSpawner : MonoBehaviour {
|
||||
private enum TutorialStepKind {
|
||||
None,
|
||||
Jump,
|
||||
DoubleJumpTakeoff,
|
||||
Slide,
|
||||
ForceHit,
|
||||
HealthItem,
|
||||
InvincibleItem,
|
||||
ShieldItem,
|
||||
SpeedItem,
|
||||
MileageCardItem
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TutorialStep {
|
||||
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;
|
||||
}
|
||||
|
||||
public GameObject platformPrefab; // 생성할 발판의 원본 프리팹
|
||||
public int count = 3; // 생성할 발판의 개수
|
||||
public bool tutorialMode = true; // 튜토리얼에서는 랜덤 대신 정해진 순서로 배치
|
||||
public bool usePatternCourse = true; // 검증된 발판 패턴 코스를 사용
|
||||
public bool tutorialMode = true; // 처음에는 튜토리얼 패턴을 먼저 배치
|
||||
public TutorialStep[] tutorialSteps; // 튜토리얼 발판 순서
|
||||
public TutorialStep[] stagePatternSteps; // 튜토리얼 이후 반복할 검증된 발판 순서
|
||||
|
||||
public float timeBetSpawnMin = 1.25f; // 다음 배치까지의 시간 간격 최솟값
|
||||
public float timeBetSpawnMax = 2.25f; // 다음 배치까지의 시간 간격 최댓값
|
||||
@@ -28,13 +48,46 @@ public class PlatformSpawner : MonoBehaviour {
|
||||
|
||||
private GameObject[] platforms; // 미리 생성한 발판들
|
||||
private int currentIndex = 0; // 사용할 현재 순번의 발판
|
||||
private int tutorialStepIndex = 0; // 진행 중인 튜토리얼 순번
|
||||
private int courseStepIndex = 0; // 진행 중인 패턴 코스 순번
|
||||
|
||||
private Vector2 poolPosition = new Vector2(0, -25); // 초반에 생성된 발판들을 화면 밖에 숨겨둘 위치
|
||||
private float lastSpawnTime; // 마지막 배치 시점
|
||||
|
||||
public void ApplyMap(MapDefinition mapDefinition) {
|
||||
if(mapDefinition == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
usePatternCourse = true;
|
||||
tutorialMode = mapDefinition.isTutorial;
|
||||
tutorialSteps = MapDatabase.CloneSteps(mapDefinition.openingSteps);
|
||||
stagePatternSteps = MapDatabase.CloneSteps(mapDefinition.loopSteps);
|
||||
courseStepIndex = 0;
|
||||
currentIndex = 0;
|
||||
lastSpawnTime = Time.time;
|
||||
timeBetSpawn = 0f;
|
||||
|
||||
if(platforms != null)
|
||||
{
|
||||
for(int i = 0; i < platforms.Length; i++)
|
||||
{
|
||||
if(platforms[i] != null)
|
||||
{
|
||||
platforms[i].SetActive(false);
|
||||
platforms[i].transform.position = poolPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Start() {
|
||||
EnsureTutorialSteps();
|
||||
EnsurePatternSteps();
|
||||
|
||||
if(usePatternCourse && tutorialMode)
|
||||
{
|
||||
count = Mathf.Max(count, 8);
|
||||
}
|
||||
|
||||
// 변수들을 초기화하고 사용할 발판들을 미리 생성
|
||||
platforms = new GameObject[count];
|
||||
@@ -53,7 +106,7 @@ public class PlatformSpawner : MonoBehaviour {
|
||||
|
||||
void Update() {
|
||||
// 순서를 돌아가며 주기적으로 발판을 배치
|
||||
if(GameManager.instance.isGameover)
|
||||
if(GameManager.instance == null || GameManager.instance.isGameover || !GameFlowManager.IsGameplayActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -62,12 +115,15 @@ public class PlatformSpawner : MonoBehaviour {
|
||||
{
|
||||
lastSpawnTime = Time.time;
|
||||
|
||||
timeBetSpawn = tutorialMode ? tutorialSpawnInterval : Random.Range(timeBetSpawnMin, timeBetSpawnMax);
|
||||
TutorialStep step = usePatternCourse ? GetCurrentCourseStep() : null;
|
||||
timeBetSpawn = step != null ? GetStepSpawnInterval(step) : Random.Range(timeBetSpawnMin, timeBetSpawnMax);
|
||||
|
||||
float yPos = tutorialMode ? GetTutorialYPosition() : Random.Range(yMin, yMax);
|
||||
float yPos = step != null
|
||||
? Mathf.Clamp(step.yPosition, yMin, yMax)
|
||||
: Random.Range(yMin, yMax);
|
||||
|
||||
platforms[currentIndex].SetActive(false);
|
||||
ConfigurePlatform(platforms[currentIndex]);
|
||||
ConfigurePlatform(platforms[currentIndex], step);
|
||||
platforms[currentIndex].SetActive(true);
|
||||
|
||||
platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
|
||||
@@ -79,14 +135,14 @@ public class PlatformSpawner : MonoBehaviour {
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
if(tutorialMode)
|
||||
if(usePatternCourse)
|
||||
{
|
||||
tutorialStepIndex++;
|
||||
courseStepIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigurePlatform(GameObject platformObject) {
|
||||
private void ConfigurePlatform(GameObject platformObject, TutorialStep step) {
|
||||
Platform platform = platformObject.GetComponent<Platform>();
|
||||
|
||||
if(platform == null)
|
||||
@@ -94,37 +150,74 @@ public class PlatformSpawner : MonoBehaviour {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!tutorialMode)
|
||||
if(step == null)
|
||||
{
|
||||
platform.ConfigureForRandom();
|
||||
return;
|
||||
}
|
||||
|
||||
TutorialStep step = GetCurrentTutorialStep();
|
||||
platform.ConfigureForTutorial(step.platformPattern, step.mileagePattern);
|
||||
platform.ConfigureForTutorial(step.platformPattern, step.mileagePattern, step.slideLayout, step.itemPattern);
|
||||
|
||||
if(GameManager.instance != null)
|
||||
if(GameManager.instance != null && step.guideType != GameManager.TutorialGuideType.None)
|
||||
{
|
||||
GameManager.instance.SetTutorialMessage(step.message);
|
||||
GameManager.instance.SetTutorialGuide(step.guideType, step.title, step.message);
|
||||
}
|
||||
|
||||
if(GameManager.instance != null
|
||||
&& step.guideType == GameManager.TutorialGuideType.None
|
||||
&& (!tutorialMode || courseStepIndex >= tutorialSteps.Length))
|
||||
{
|
||||
GameManager.instance.SetTutorialGuide(GameManager.TutorialGuideType.None, "", "");
|
||||
}
|
||||
}
|
||||
|
||||
private float GetTutorialYPosition() {
|
||||
return Mathf.Clamp(GetCurrentTutorialStep().yPosition, yMin, yMax);
|
||||
private float GetStepSpawnInterval(TutorialStep step) {
|
||||
if(step != null && step.spawnInterval > 0f)
|
||||
{
|
||||
return step.spawnInterval;
|
||||
}
|
||||
|
||||
return tutorialSpawnInterval;
|
||||
}
|
||||
|
||||
private TutorialStep GetCurrentTutorialStep() {
|
||||
private TutorialStep GetCurrentCourseStep() {
|
||||
EnsurePatternSteps();
|
||||
|
||||
if(tutorialMode && courseStepIndex < tutorialSteps.Length)
|
||||
{
|
||||
return tutorialSteps[courseStepIndex];
|
||||
}
|
||||
|
||||
int loopIndex = tutorialMode
|
||||
? courseStepIndex - tutorialSteps.Length
|
||||
: courseStepIndex;
|
||||
|
||||
if(stagePatternSteps == null || stagePatternSteps.Length == 0)
|
||||
{
|
||||
return CreateStep(
|
||||
Platform.PlatformPattern.Empty,
|
||||
Platform.MileagePattern.SafeLine,
|
||||
SlideObstaclePattern.SlideLayout.Random,
|
||||
GameManager.TutorialGuideType.None,
|
||||
-2.2f,
|
||||
tutorialSpawnInterval,
|
||||
"",
|
||||
"");
|
||||
}
|
||||
|
||||
loopIndex %= stagePatternSteps.Length;
|
||||
|
||||
if(loopIndex < 0)
|
||||
{
|
||||
loopIndex += stagePatternSteps.Length;
|
||||
}
|
||||
|
||||
return stagePatternSteps[loopIndex];
|
||||
}
|
||||
|
||||
private void EnsurePatternSteps() {
|
||||
EnsureTutorialSteps();
|
||||
|
||||
if(tutorialStepIndex < tutorialSteps.Length)
|
||||
{
|
||||
return tutorialSteps[tutorialStepIndex];
|
||||
}
|
||||
|
||||
int reviewStartIndex = Mathf.Max(0, tutorialSteps.Length - 3);
|
||||
int reviewLength = tutorialSteps.Length - reviewStartIndex;
|
||||
int reviewIndex = reviewStartIndex + ((tutorialStepIndex - tutorialSteps.Length) % reviewLength);
|
||||
return tutorialSteps[reviewIndex];
|
||||
EnsureStagePatternSteps();
|
||||
}
|
||||
|
||||
private void EnsureTutorialSteps() {
|
||||
@@ -134,21 +227,133 @@ public class PlatformSpawner : MonoBehaviour {
|
||||
}
|
||||
|
||||
tutorialSteps = new TutorialStep[] {
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, -2.4f, "Tutorial 1: Run forward and collect mileage."),
|
||||
CreateStep(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, -2.4f, "Tutorial 2: Left click to jump over suitcase obstacles."),
|
||||
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, -2.4f, "Tutorial 3: Hold right click to slide under airport signs."),
|
||||
CreateStep(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, -2.1f, "Tutorial 4: Suitcases mean jump."),
|
||||
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, -2.2f, "Tutorial 5: Hanging signs mean slide."),
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, -1.8f, "Tutorial complete: collect mileage and keep moving."),
|
||||
CreateTutorialStep(TutorialStepKind.Jump, Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, -2.4f, 1.05f),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, -2.4f, 1f),
|
||||
CreateTutorialStep(TutorialStepKind.DoubleJumpTakeoff, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, -2.4f, 2.10f),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, -2.4f, 1.10f),
|
||||
CreateTutorialStep(TutorialStepKind.Slide, Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, -2.4f, 1.15f),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, -2.4f, 1f),
|
||||
CreateTutorialStep(TutorialStepKind.ForceHit, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, -2.4f, 1.15f),
|
||||
CreateTutorialStep(TutorialStepKind.HealthItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, -2.4f, 0.95f, Platform.ItemPattern.HealthSushi),
|
||||
CreateTutorialStep(TutorialStepKind.InvincibleItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, -2.4f, 0.9f, Platform.ItemPattern.InvincibleRamen),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, -2.4f, 1.05f),
|
||||
CreateTutorialStep(TutorialStepKind.ShieldItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, -2.4f, 0.9f, Platform.ItemPattern.Shield),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, -2.4f, 1.05f),
|
||||
CreateTutorialStep(TutorialStepKind.SpeedItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, -2.4f, 0.95f, Platform.ItemPattern.SpeedShoes),
|
||||
CreateTutorialStep(TutorialStepKind.MileageCardItem, Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, -2.4f, 0.95f, Platform.ItemPattern.MileageCard),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, -2.4f, 1f),
|
||||
CreateTutorialStep(TutorialStepKind.None, Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, -2.4f, 1f),
|
||||
};
|
||||
}
|
||||
|
||||
private TutorialStep CreateStep(Platform.PlatformPattern platformPattern, Platform.MileagePattern mileagePattern, float yPosition, string message) {
|
||||
private void EnsureStagePatternSteps() {
|
||||
if(stagePatternSteps != null && stagePatternSteps.Length > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
stagePatternSteps = new TutorialStep[] {
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 2.25f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.3f, 2.4f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.95f, 2.2f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.25f, 2.65f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.0f, 2.2f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.35f, 2.35f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.LeftPair, GameManager.TutorialGuideType.None, -2.35f, 2.7f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 2.2f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.LowRight, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.0f, 2.35f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.85f, 2.15f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.RightPair, GameManager.TutorialGuideType.None, -2.25f, 2.65f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.35f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.0f, 2.2f, "", ""),
|
||||
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.2f, 2.7f, "", ""),
|
||||
};
|
||||
}
|
||||
|
||||
private TutorialStep CreateStep(
|
||||
Platform.PlatformPattern platformPattern,
|
||||
Platform.MileagePattern mileagePattern,
|
||||
SlideObstaclePattern.SlideLayout slideLayout,
|
||||
GameManager.TutorialGuideType guideType,
|
||||
float yPosition,
|
||||
float spawnInterval,
|
||||
string title,
|
||||
string message,
|
||||
Platform.ItemPattern itemPattern = Platform.ItemPattern.None) {
|
||||
TutorialStep step = new TutorialStep();
|
||||
step.platformPattern = platformPattern;
|
||||
step.mileagePattern = mileagePattern;
|
||||
step.slideLayout = slideLayout;
|
||||
step.itemPattern = itemPattern;
|
||||
step.guideType = guideType;
|
||||
step.yPosition = yPosition;
|
||||
step.spawnInterval = spawnInterval;
|
||||
step.title = title;
|
||||
step.message = message;
|
||||
return step;
|
||||
}
|
||||
|
||||
private TutorialStep CreateTutorialStep(
|
||||
TutorialStepKind stepKind,
|
||||
Platform.PlatformPattern platformPattern,
|
||||
Platform.MileagePattern mileagePattern,
|
||||
SlideObstaclePattern.SlideLayout slideLayout,
|
||||
float yPosition,
|
||||
float spawnInterval,
|
||||
Platform.ItemPattern itemPattern = Platform.ItemPattern.None) {
|
||||
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None;
|
||||
string title = "";
|
||||
string message = "";
|
||||
|
||||
switch(stepKind)
|
||||
{
|
||||
case TutorialStepKind.Jump:
|
||||
guideType = GameManager.TutorialGuideType.Jump;
|
||||
title = "점프";
|
||||
message = "가방 장애물이 보이면 왼쪽 클릭으로 뛰어넘습니다.";
|
||||
break;
|
||||
case TutorialStepKind.DoubleJumpTakeoff:
|
||||
guideType = GameManager.TutorialGuideType.DoubleJump;
|
||||
title = "2단 점프";
|
||||
message = "다음 발판이 멀리 있으면 공중에서 한 번 더 왼쪽 클릭합니다.";
|
||||
break;
|
||||
case TutorialStepKind.Slide:
|
||||
guideType = GameManager.TutorialGuideType.Slide;
|
||||
title = "슬라이드";
|
||||
message = "천장 표지판이 보이면 오른쪽 클릭을 누르고 지나갑니다.";
|
||||
break;
|
||||
case TutorialStepKind.ForceHit:
|
||||
guideType = GameManager.TutorialGuideType.Damage;
|
||||
title = "피격";
|
||||
message = "이번 구간은 일부러 맞아 목숨과 속도 감소를 확인합니다.";
|
||||
break;
|
||||
case TutorialStepKind.HealthItem:
|
||||
guideType = GameManager.TutorialGuideType.Items;
|
||||
title = "초밥";
|
||||
message = "초밥을 먹으면 잃은 목숨을 1 회복합니다.";
|
||||
break;
|
||||
case TutorialStepKind.InvincibleItem:
|
||||
guideType = GameManager.TutorialGuideType.Items;
|
||||
title = "라멘";
|
||||
message = "라멘을 먹고 다음 충돌을 피해 없이 지나가 봅니다.";
|
||||
break;
|
||||
case TutorialStepKind.ShieldItem:
|
||||
guideType = GameManager.TutorialGuideType.Items;
|
||||
title = "방어막";
|
||||
message = "방어막을 먹고 다음 충돌 1회를 막아 봅니다.";
|
||||
break;
|
||||
case TutorialStepKind.SpeedItem:
|
||||
guideType = GameManager.TutorialGuideType.Items;
|
||||
title = "운동화";
|
||||
message = "운동화는 속도를 회복해 일정이 늦어지는 것을 줄입니다.";
|
||||
break;
|
||||
case TutorialStepKind.MileageCardItem:
|
||||
guideType = GameManager.TutorialGuideType.Items;
|
||||
title = "마일리지 카드";
|
||||
message = "카드를 먹은 뒤 마일리지를 모으면 획득량이 늘어납니다.";
|
||||
break;
|
||||
}
|
||||
|
||||
return CreateStep(platformPattern, mileagePattern, slideLayout, guideType, yPosition, spawnInterval, title, message, itemPattern);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user