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
+219 -46
View File
@@ -2,6 +2,12 @@ using UnityEngine;
public static class MapDatabase {
private static MapDefinition[] maps;
private const float GroundY = -2.4f;
private const float AerialY = -0.85f;
private const float BasicSpacing = 0.58f;
private const float ActionSpacing = 0.72f;
private const float LandingSpacing = 0.64f;
private const float AerialSpacing = 2.05f;
public static MapDefinition[] AllMaps {
get {
@@ -71,28 +77,44 @@ public static class MapDatabase {
displayName = "Tutorial / Incheon",
routeName = "인천공항 출발 준비",
isTutorial = true,
targetDistance = 850f,
timeLimit = 95f,
platformSkin = Platform.PlatformSkin.Airport,
backgroundResourcePath = "Map_Tutorial_Incheon_Airport",
finishGateStyle = FinishGateStyle.AirportDeparture,
targetDistance = 320f,
timeLimit = 75f,
clearMileageReward = 150,
hasNextMap = true,
nextMapId = MapId.Japan,
openingSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Jump, -2.4f, 1.05f, "점프", "가방 장애물이 보이면 왼쪽 클릭으로 뛰어넘습니다."),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.DoubleJump, -2.4f, 2.1f, "2단 점프", "다음 발판이 멀리 있으면 공중에서 한 번 더 왼쪽 클릭합니다."),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1.1f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.Slide, -2.4f, 1.15f, "슬라이드", "천장 표지판이 보이면 오른쪽 클릭을 누르고 지나갑니다."),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f),
Step(Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.Damage, -2.4f, 1.15f, "피격", "이번 구간은 일부러 맞아 목숨과 속도 감소를 확인합니다."),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.95f, "초밥", "초밥을 먹으면 잃은 목숨을 1 회복합니다.", Platform.ItemPattern.HealthSushi),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.9f, "라멘", "라멘을 먹고 다음 충돌을 피해 없이 지나가 봅니다.", Platform.ItemPattern.InvincibleRamen),
Step(Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.4f, 1.05f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.9f, "방어막", "방어막을 먹고 다음 충돌 1회를 막아 봅니다.", Platform.ItemPattern.Shield),
Step(Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.4f, 1.05f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.95f, "운동화", "운동화는 속도를 회복해 일정이 늦어지는 것을 줄입니다.", Platform.ItemPattern.SpeedShoes),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.95f, "마일리지 카드", "카드를 먹은 뒤 마일리지를 모으면 획득량이 늘어납니다.", Platform.ItemPattern.MileageCard),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f)
Basic(),
Basic(),
Basic(GroundY, BasicSpacing),
Jump(GameManager.TutorialGuideType.Jump, "점프 구간", "가방 장애물이 오면 왼쪽 클릭으로 뛰어넘습니다."),
Basic(GroundY, LandingSpacing),
Basic(GroundY, BasicSpacing),
Aerial(GameManager.TutorialGuideType.DoubleJump, "2단 점프 구간", "다음 발판이 멀리 떨어져 있습니다.\n공중에서 왼쪽 클릭을 한 번 더 누릅니다."),
Basic(GroundY, LandingSpacing),
Basic(GroundY, BasicSpacing),
Slide(GameManager.TutorialGuideType.Slide, "슬라이드 구간", "천장 장애물이 오면 오른쪽 클릭을 누르고 지나갑니다."),
Basic(GroundY, LandingSpacing),
Basic(GroundY, BasicSpacing),
ForceHit(GameManager.TutorialGuideType.None, "", ""),
Basic(GroundY, LandingSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "초밥", "잃은 목숨을 1 회복합니다.\n방금 줄어든 목숨을 채워 봅니다.", Platform.ItemPattern.HealthSushi),
Basic(GroundY, LandingSpacing),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "라멘", "잠깐 무적이 됩니다.\n먹은 뒤 다음 장애물에 일부러 부딪혀 봅니다.", Platform.ItemPattern.InvincibleRamen),
ForceHit(GameManager.TutorialGuideType.None, "", ""),
Basic(GroundY, LandingSpacing),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "방어막", "다음 충돌 1회를 막습니다.\n먹은 뒤 바로 충돌을 막아 봅니다.", Platform.ItemPattern.Shield),
ForceHit(GameManager.TutorialGuideType.None, "", ""),
Basic(GroundY, LandingSpacing),
ForceHit(GameManager.TutorialGuideType.None, "", ""),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "운동화", "느려진 속도를 회복합니다.\n방금 떨어진 속도를 되돌려 봅니다.", Platform.ItemPattern.SpeedShoes),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "마일리지 카드", "잠깐 마일리지가 2배가 됩니다.\n먹고 바로 마일리지를 모아 봅니다.", Platform.ItemPattern.MileageCard),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.SafeLine),
Basic(),
Basic(),
Basic(),
Basic(GroundY, LandingSpacing)
},
loopSteps = CreateEasyLoop()
};
@@ -104,21 +126,28 @@ public static class MapDatabase {
displayName = "Japan",
routeName = "후쿠오카 라멘 투어",
isTutorial = false,
platformSkin = Platform.PlatformSkin.Japan,
backgroundResourcePath = "",
finishGateStyle = FinishGateStyle.JapanTorii,
targetDistance = 1200f,
timeLimit = 105f,
clearMileageReward = 250,
hasNextMap = true,
nextMapId = MapId.China,
openingSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 1.8f)
Basic(),
Basic()
},
loopSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 2.05f),
Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.3f, 2.15f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.25f, 2.35f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.95f, 2.05f),
Step(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.35f, 2.1f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.3f, 2.45f)
Basic(),
Jump(),
Basic(GroundY, LandingSpacing),
Aerial(),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.CenterPair),
Basic(),
Jump(Platform.PlatformPattern.LowLeft),
Basic()
}
};
}
@@ -129,21 +158,29 @@ public static class MapDatabase {
displayName = "China",
routeName = "베이징 시장길",
isTutorial = false,
platformSkin = Platform.PlatformSkin.China,
backgroundResourcePath = "",
finishGateStyle = FinishGateStyle.ChinaPaifang,
targetDistance = 1450f,
timeLimit = 115f,
clearMileageReward = 350,
hasNextMap = true,
nextMapId = MapId.America,
openingSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 1.9f)
Basic(),
Basic()
},
loopSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.LowRight, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.25f, 2.0f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.8f, 2.05f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.LeftPair, GameManager.TutorialGuideType.None, -2.3f, 2.35f),
Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.05f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.RightPair, GameManager.TutorialGuideType.None, -2.25f, 2.35f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2f, 1.95f)
Basic(),
Jump(Platform.PlatformPattern.LowRight),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.LeftPair),
Basic(),
Aerial(AerialY + 0.15f, 1.08f),
Basic(GroundY, LandingSpacing),
Jump(),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.RightPair)
}
};
}
@@ -152,36 +189,166 @@ public static class MapDatabase {
return new MapDefinition {
mapId = MapId.America,
displayName = "America",
routeName = "LA 공항 고속도로",
routeName = "뉴욕 자유의 여신상",
isTutorial = false,
platformSkin = Platform.PlatformSkin.USA,
backgroundResourcePath = "Map_America_NewYork",
finishGateStyle = FinishGateStyle.AmericaRoadSign,
targetDistance = 1700f,
timeLimit = 125f,
clearMileageReward = 500,
hasNextMap = false,
nextMapId = MapId.America,
openingSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 1.8f)
Basic(),
Basic()
},
loopSteps = new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1.95f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.25f, 2.25f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.8f, 1.9f),
Step(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.35f, 1.95f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.25f, 2.2f),
Step(Platform.PlatformPattern.LowRight, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 1.9f)
Basic(),
Jump(Platform.PlatformPattern.LowMid),
Basic(GroundY, 0.86f),
Slide(SlideObstaclePattern.SlideLayout.WidePair),
Basic(),
Aerial(AerialY + 0.2f, 1.0f),
Basic(GroundY, 0.86f),
Jump(Platform.PlatformPattern.LowLeft),
Basic(),
Slide(SlideObstaclePattern.SlideLayout.CenterPair),
Basic(),
Jump(Platform.PlatformPattern.LowRight)
}
};
}
private static PlatformSpawner.TutorialStep[] CreateEasyLoop() {
return new PlatformSpawner.TutorialStep[] {
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.1f),
Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.2f),
Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 2.1f),
Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.35f, 2.35f)
Basic(),
Jump(),
Basic(GroundY, LandingSpacing),
Aerial(),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.CenterPair),
Basic()
};
}
private static PlatformSpawner.TutorialStep Basic(
float yPosition = GroundY,
float spawnInterval = BasicSpacing,
Platform.MileagePattern mileagePattern = Platform.MileagePattern.SafeLine,
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None,
string title = "",
string message = "",
Platform.ItemPattern itemPattern = Platform.ItemPattern.None) {
return Step(
Platform.PlatformPattern.Empty,
mileagePattern,
SlideObstaclePattern.SlideLayout.Random,
guideType,
yPosition,
spawnInterval,
title,
message,
itemPattern,
PlatformSpawner.CoursePlatformType.Basic);
}
private static PlatformSpawner.TutorialStep Jump(
Platform.PlatformPattern platformPattern = Platform.PlatformPattern.LowMid,
float spawnInterval = ActionSpacing,
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None,
string title = "",
string message = "") {
return Step(
platformPattern,
Platform.MileagePattern.JumpArc,
SlideObstaclePattern.SlideLayout.Random,
guideType,
GroundY,
spawnInterval,
title,
message,
Platform.ItemPattern.None,
PlatformSpawner.CoursePlatformType.Jump);
}
private static PlatformSpawner.TutorialStep Jump(
GameManager.TutorialGuideType guideType,
string title,
string message) {
return Jump(Platform.PlatformPattern.LowMid, ActionSpacing, guideType, title, message);
}
private static PlatformSpawner.TutorialStep Aerial(
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None,
string title = "",
string message = "") {
return Aerial(AerialY, AerialSpacing, guideType, title, message);
}
private static PlatformSpawner.TutorialStep Aerial(
float yPosition,
float spawnInterval,
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None,
string title = "",
string message = "") {
return Step(
Platform.PlatformPattern.Empty,
Platform.MileagePattern.SafeLine,
SlideObstaclePattern.SlideLayout.Random,
guideType,
GroundY,
spawnInterval,
title,
message,
Platform.ItemPattern.None,
PlatformSpawner.CoursePlatformType.Basic);
}
private static PlatformSpawner.TutorialStep Slide(
SlideObstaclePattern.SlideLayout slideLayout = SlideObstaclePattern.SlideLayout.CenterPair,
float spawnInterval = ActionSpacing,
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None,
string title = "",
string message = "") {
return Step(
Platform.PlatformPattern.Slide,
Platform.MileagePattern.SlideLine,
slideLayout,
guideType,
GroundY,
spawnInterval,
title,
message,
Platform.ItemPattern.None,
PlatformSpawner.CoursePlatformType.Slide);
}
private static PlatformSpawner.TutorialStep Slide(
GameManager.TutorialGuideType guideType,
string title,
string message) {
return Slide(SlideObstaclePattern.SlideLayout.CenterPair, ActionSpacing, guideType, title, message);
}
private static PlatformSpawner.TutorialStep ForceHit(
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.Damage,
string title = "",
string message = "",
float spawnInterval = ActionSpacing) {
return Step(
Platform.PlatformPattern.ForceHit,
Platform.MileagePattern.None,
SlideObstaclePattern.SlideLayout.WidePair,
guideType,
GroundY,
spawnInterval,
title,
message,
Platform.ItemPattern.None,
PlatformSpawner.CoursePlatformType.ForceHit);
}
private static PlatformSpawner.TutorialStep Step(
Platform.PlatformPattern platformPattern,
Platform.MileagePattern mileagePattern,
@@ -191,8 +358,10 @@ public static class MapDatabase {
float spawnInterval,
string title = "",
string message = "",
Platform.ItemPattern itemPattern = Platform.ItemPattern.None) {
Platform.ItemPattern itemPattern = Platform.ItemPattern.None,
PlatformSpawner.CoursePlatformType coursePlatformType = PlatformSpawner.CoursePlatformType.Basic) {
return new PlatformSpawner.TutorialStep {
coursePlatformType = coursePlatformType,
platformPattern = platformPattern,
mileagePattern = mileagePattern,
slideLayout = slideLayout,
@@ -211,6 +380,9 @@ public static class MapDatabase {
displayName = source.displayName,
routeName = source.routeName,
isTutorial = source.isTutorial,
platformSkin = source.platformSkin,
backgroundResourcePath = source.backgroundResourcePath,
finishGateStyle = source.finishGateStyle,
targetDistance = source.targetDistance,
timeLimit = source.timeLimit,
clearMileageReward = source.clearMileageReward,
@@ -241,7 +413,8 @@ public static class MapDatabase {
sourceStep.spawnInterval,
sourceStep.title,
sourceStep.message,
sourceStep.itemPattern);
sourceStep.itemPattern,
sourceStep.coursePlatformType);
}
return steps;
+3
View File
@@ -6,6 +6,9 @@ public class MapDefinition {
public string displayName;
public string routeName;
public bool isTutorial;
public Platform.PlatformSkin platformSkin;
public string backgroundResourcePath;
public FinishGateStyle finishGateStyle;
public float targetDistance;
public float timeLimit;
public int clearMileageReward;