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
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e8469e5a7a7443f9adff42c0c7bf921
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,6 @@
public enum CoursePlatformType {
Basic,
Jump,
Slide,
ForceHit
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02a1bb5c51284fd8ad76d51d8327a14c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+15
View File
@@ -0,0 +1,15 @@
using System;
[Serializable]
public class CourseStep {
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;
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21d873850c7043ef8b2854e1a5f16d9b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+189
View File
@@ -0,0 +1,189 @@
public static class CourseStepFactory {
public const float GroundY = -2.4f;
public const float AerialY = -0.85f;
public const float BasicSpacing = 0.58f;
public const float ActionSpacing = 0.72f;
public const float LandingSpacing = 0.64f;
public const float AerialSpacing = 2.05f;
public static CourseStep[] CreateEasyLoop() {
return new CourseStep[] {
Basic(),
Jump(),
Basic(GroundY, LandingSpacing),
Aerial(),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.CenterPair),
Basic()
};
}
public static CourseStep 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,
GroundY,
spawnInterval,
title,
message,
itemPattern,
CoursePlatformType.Basic);
}
public static CourseStep 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,
CoursePlatformType.Jump);
}
public static CourseStep Jump(
GameManager.TutorialGuideType guideType,
string title,
string message) {
return Jump(Platform.PlatformPattern.LowMid, ActionSpacing, guideType, title, message);
}
public static CourseStep Aerial(
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None,
string title = "",
string message = "") {
return Aerial(AerialY, AerialSpacing, guideType, title, message);
}
public static CourseStep 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,
yPosition,
spawnInterval,
title,
message,
Platform.ItemPattern.None,
CoursePlatformType.Basic);
}
public static CourseStep 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,
CoursePlatformType.Slide);
}
public static CourseStep Slide(
GameManager.TutorialGuideType guideType,
string title,
string message) {
return Slide(SlideObstaclePattern.SlideLayout.CenterPair, ActionSpacing, guideType, title, message);
}
public static CourseStep 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,
CoursePlatformType.ForceHit);
}
public static CourseStep Step(
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,
CoursePlatformType coursePlatformType = CoursePlatformType.Basic) {
return new CourseStep {
coursePlatformType = coursePlatformType,
platformPattern = platformPattern,
mileagePattern = mileagePattern,
slideLayout = slideLayout,
itemPattern = itemPattern,
guideType = guideType,
yPosition = yPosition,
spawnInterval = spawnInterval,
title = title,
message = message
};
}
public static CourseStep[] CloneSteps(CourseStep[] source) {
if(source == null)
{
return new CourseStep[0];
}
CourseStep[] steps = new CourseStep[source.Length];
for(int i = 0; i < source.Length; i++)
{
CourseStep sourceStep = source[i];
steps[i] = Step(
sourceStep.platformPattern,
sourceStep.mileagePattern,
sourceStep.slideLayout,
sourceStep.guideType,
sourceStep.yPosition,
sourceStep.spawnInterval,
sourceStep.title,
sourceStep.message,
sourceStep.itemPattern,
sourceStep.coursePlatformType);
}
return steps;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b8e2ef0ff2346e8ab5e6d6557e41b10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+12
View File
@@ -0,0 +1,12 @@
public enum CourseStepKind {
None,
Jump,
DoubleJumpTakeoff,
Slide,
ForceHit,
HealthItem,
InvincibleItem,
ShieldItem,
SpeedItem,
MileageCardItem
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e543ce69f5964c1195ce10e5fe7e2a7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+620 -33
View File
@@ -15,7 +15,8 @@ public class GameFlowManager : MonoBehaviour {
Game,
Result,
DutyFreeShop,
MapPreview
MapPreview,
DebugMenu
}
public static GameFlowManager Instance { get; private set; }
@@ -39,6 +40,27 @@ public class GameFlowManager : MonoBehaviour {
private const string ResultSceneName = "Result";
private const string DutyFreeShopSceneName = "DutyFreeShop";
private const string MapPreviewSceneName = "MapPreview";
private const string DepartureStampResourcePath = "UI_DepartureStamp_Red";
private const string ResultPassportPanelResourcePath = "UI_LeftHudPassportHorizontalGridPanel";
private const string ResultAirportBackgroundResourcePath = "Map_Tutorial_Incheon_Airport";
private const string ResultButtonResourcePath = "UI_TutorialNextButton";
private const string ResultButtonAssetPath = "Assets/Resources/UI_TutorialNextButton.png";
private const string MileageIconAssetPath = "Assets/Sprites/UIIcons/UI_Mileage.png";
private const string TimerIconAssetPath = "Assets/Sprites/UIIcons/UI_Timer.png";
private const string CheckpointIconAssetPath = "Assets/Sprites/UIIcons/UI_Checkpoint.png";
private const string ClearRankIconAssetPath = "Assets/Sprites/UIIcons/UI_ClearRank.png";
private const string DutyFreeIconAssetPath = "Assets/Sprites/UIIcons/UI_DutyFreeShop.png";
private const string AirplaneTravelIconAssetPath = "Assets/Sprites/UIIcons/UI_AirplaneTravel.png";
private const string DutyFreeBackgroundAssetPath = "Assets/ConceptArt/duty_free_shop_screen_concept_01.png";
private const string DutyFreeLunchboxAssetPath = "Assets/Sprites/DutyFree/DutyFree_Normal_Lunchbox.png";
private const string DutyFreeShieldAssetPath = "Assets/Sprites/DutyFree/DutyFree_Normal_ShieldCharm.png";
private const string DutyFreeShoesAssetPath = "Assets/Sprites/DutyFree/DutyFree_Normal_Shoes.png";
private const string DutyFreeMileageCardAssetPath = "Assets/Sprites/DutyFree/DutyFree_Normal_MileageCard.png";
private const string SouvenirCollectionIconAssetPath = "Assets/Sprites/UIIcons/UI_SouvenirCollection.png";
private const string AirportSouvenirAssetPath = "Assets/Sprites/Souvenirs/Souvenir_AirportMagnet.png";
private const string JapanSouvenirAssetPath = "Assets/Sprites/Souvenirs/Souvenir_Japan_Magnet.png";
private const string ChinaSouvenirAssetPath = "Assets/Sprites/Souvenirs/Souvenir_TempleCharm.png";
private const string AmericaSouvenirAssetPath = "Assets/Sprites/Souvenirs/Souvenir_SkylineMagnet.png";
private const int ShieldCost = 120;
private const int LunchboxCost = 80;
private const int SpeedShoesCost = 140;
@@ -98,6 +120,50 @@ public class GameFlowManager : MonoBehaviour {
ShowIntro();
}
#if UNITY_EDITOR || DEVELOPMENT_BUILD
private void Update() {
if(Input.GetKeyDown(KeyCode.Escape))
{
ShowDebugMenu();
return;
}
HandleDebugMenuShortcutInput();
}
private void HandleDebugMenuShortcutInput() {
if(currentScreen != FlowScreen.DebugMenu)
{
return;
}
if(Input.GetKeyDown(KeyCode.Alpha1) || Input.GetKeyDown(KeyCode.Keypad1))
{
ShowDebugIntroPreview();
}
else if(Input.GetKeyDown(KeyCode.Alpha2) || Input.GetKeyDown(KeyCode.Keypad2))
{
ShowDebugGameStartPreview();
}
else if(Input.GetKeyDown(KeyCode.Alpha3) || Input.GetKeyDown(KeyCode.Keypad3))
{
ShowDebugResultPreview(false);
}
else if(Input.GetKeyDown(KeyCode.Alpha4) || Input.GetKeyDown(KeyCode.Keypad4))
{
ShowDebugResultPreview(true);
}
else if(Input.GetKeyDown(KeyCode.Alpha5) || Input.GetKeyDown(KeyCode.Keypad5))
{
ShowDebugDutyFreeShopPreview();
}
else if(Input.GetKeyDown(KeyCode.Alpha6) || Input.GetKeyDown(KeyCode.Keypad6))
{
ShowDebugMapPreview();
}
}
#endif
private void OnDestroy() {
if(Instance == this)
{
@@ -173,6 +239,95 @@ public class GameFlowManager : MonoBehaviour {
ShowResult();
}
#if UNITY_EDITOR || DEVELOPMENT_BUILD
private void ShowDebugMenu() {
EnsureDebugPreviewData();
gameplayActive = false;
pendingStartGameplay = false;
currentScreen = FlowScreen.DebugMenu;
EnsureOverlay();
ClearOverlay();
SetOverlayVisible(true);
SetDefaultOverlayBackground();
AddTitle("디버그 메뉴");
AddBody("화면 조정용 바로 이동\n숫자키 1~6도 사용할 수 있습니다.");
AddButton("1. 인트로", ShowDebugIntroPreview);
AddButton("2. 게임 시작", ShowDebugGameStartPreview);
AddButton("3. 출국 실패", delegate { ShowDebugResultPreview(false); });
AddButton("4. 출국 성공", delegate { ShowDebugResultPreview(true); });
AddButton("5. 면세점", ShowDebugDutyFreeShopPreview);
AddButton("6. 지도", ShowDebugMapPreview);
}
private void ShowDebugIntroPreview() {
ShowIntro();
}
private void ShowDebugGameStartPreview() {
EnsureDebugPreviewData();
LoadGameSceneForCurrentMap();
}
private void ShowDebugResultPreview(bool cleared) {
EnsureDebugPreviewData();
gameplayActive = false;
pendingStartGameplay = false;
currentScreen = FlowScreen.Result;
completedMap = currentMap;
lastResultCleared = cleared;
lastResultScore = cleared ? 12800 : 7200;
lastResultMileage = cleared ? 263 : 84;
lastResultTime = cleared ? 23.9f : 38.4f;
lastResultDistance = completedMap != null
? (cleared ? completedMap.targetDistance : completedMap.targetDistance * 0.62f)
: 380f;
if(saveData != null)
{
saveData.totalMileage = Mathf.Max(saveData.totalMileage, 4120);
}
ShowResult();
}
private void ShowDebugDutyFreeShopPreview() {
EnsureDebugPreviewData();
if(saveData != null)
{
saveData.totalMileage = Mathf.Max(saveData.totalMileage, 4120);
}
ShowDutyFreeShop();
}
private void ShowDebugMapPreview() {
EnsureDebugPreviewData();
ShowMapPreview();
}
private void EnsureDebugPreviewData() {
if(saveData == null)
{
saveData = GameSaveManager.Load();
}
if(currentMap == null)
{
currentMap = MapDatabase.GetMapByIndex(saveData != null ? saveData.currentMapIndex : 0);
}
if(currentMap == null)
{
currentMap = MapDatabase.GetMapByIndex(0);
}
}
#endif
private void StartNewJourney() {
saveData = GameSaveManager.ResetSave();
currentMap = MapDatabase.GetMapByIndex(saveData.currentMapIndex);
@@ -271,33 +426,298 @@ public class GameFlowManager : MonoBehaviour {
EnsureOverlay();
ClearOverlay();
SetOverlayVisible(true);
SetDefaultOverlayBackground();
BuildResultScreen();
}
string title = lastResultCleared ? "맵 클리어" : "일정 실패";
string body = completedMap.displayName
+ "\n점수: " + lastResultScore
+ "\n획득 마일리지: " + lastResultMileage
+ "\n거리: " + Mathf.FloorToInt(lastResultDistance) + "m / " + Mathf.FloorToInt(completedMap.targetDistance) + "m"
+ "\n시간: " + lastResultTime.ToString("0.0") + "s";
private void BuildResultScreen() {
ApplyResultAirportBackground();
MapDefinition resultMap = completedMap != null ? completedMap : currentMap;
int rewardMileage = lastResultCleared && resultMap != null ? resultMap.clearMileageReward : 0;
int gainedMileage = Mathf.Max(0, lastResultMileage) + rewardMileage;
int targetDistance = resultMap != null ? Mathf.FloorToInt(resultMap.targetDistance) : 0;
int shownDistance = targetDistance > 0
? Mathf.Clamp(Mathf.FloorToInt(lastResultDistance), 0, targetDistance)
: Mathf.Max(0, Mathf.FloorToInt(lastResultDistance));
RectTransform passportRect = AddResultPassportPanel();
AddResultHeader(passportRect, resultMap);
AddResultStats(passportRect, gainedMileage, shownDistance, targetDistance);
AddResultTickets(passportRect, resultMap, rewardMileage);
if(lastResultCleared)
{
body += "\n클리어 보상: " + completedMap.clearMileageReward + " 마일리지";
}
AddTitle(title);
AddBody(body);
if(lastResultCleared)
{
AddButton("면세점으로", ShowDutyFreeShop);
AddResultActionButton("면세점으로", ShowDutyFreeShop, new Vector2(-166f, -282f), new Vector2(250f, 48f), true, LoadUiSprite("", DutyFreeIconAssetPath));
AddResultActionButton("다음 여행지 가기", ShowMapPreview, new Vector2(160f, -282f), new Vector2(292f, 48f), false, LoadUiSprite("", AirplaneTravelIconAssetPath));
}
else
{
AddButton("다시 도전", RetryCurrentMap);
AddResultActionButton("다시 도전", RetryCurrentMap, new Vector2(-166f, -282f), new Vector2(250f, 48f), true, LoadUiSprite("", CheckpointIconAssetPath));
AddResultActionButton("다음 여행지 가기", ShowMapPreview, new Vector2(160f, -282f), new Vector2(292f, 48f), false, LoadUiSprite("", AirplaneTravelIconAssetPath));
}
}
private void ApplyResultAirportBackground() {
if(overlayBackground != null)
{
overlayBackground.sprite = LoadUiSprite(ResultAirportBackgroundResourcePath, "Assets/Resources/Map_Tutorial_Incheon_Airport.png");
overlayBackground.preserveAspect = false;
overlayBackground.color = overlayBackground.sprite != null
? Color.white
: new Color(0.008f, 0.024f, 0.034f, 0.96f);
}
AddButton("인트로", ShowIntro);
if(flowCamera != null)
{
flowCamera.backgroundColor = new Color(0.006f, 0.022f, 0.035f, 1f);
}
GameObject scrimObject = CreateUiObject("Result Airport Background Scrim", overlayRoot, typeof(Image));
RectTransform scrimRect = scrimObject.GetComponent<RectTransform>();
scrimRect.anchorMin = Vector2.zero;
scrimRect.anchorMax = Vector2.one;
scrimRect.offsetMin = Vector2.zero;
scrimRect.offsetMax = Vector2.zero;
Image scrimImage = scrimObject.GetComponent<Image>();
scrimImage.color = new Color(0.005f, 0.015f, 0.020f, 0.30f);
scrimImage.raycastTarget = false;
}
private RectTransform AddResultPassportPanel() {
GameObject panelObject = CreateUiObject("Result Passport Page", overlayRoot, typeof(Image));
RectTransform panelRect = panelObject.GetComponent<RectTransform>();
panelRect.anchorMin = new Vector2(0.5f, 0.5f);
panelRect.anchorMax = new Vector2(0.5f, 0.5f);
panelRect.pivot = new Vector2(0.5f, 0.5f);
panelRect.anchoredPosition = new Vector2(0f, 38f);
panelRect.sizeDelta = new Vector2(1092f, 330f);
Image panelImage = panelObject.GetComponent<Image>();
panelImage.sprite = LoadUiSprite(ResultPassportPanelResourcePath, "Assets/Resources/UI_LeftHudPassportHorizontalGridPanel.png");
panelImage.color = panelImage.sprite != null
? Color.white
: new Color(0.95f, 0.91f, 0.80f, 0.98f);
panelImage.preserveAspect = true;
panelImage.raycastTarget = false;
return panelRect;
}
private void AddResultHeader(RectTransform parent, MapDefinition resultMap) {
Sprite rankSprite = LoadUiSprite("", ClearRankIconAssetPath);
Sprite stampSprite = LoadUiSprite(DepartureStampResourcePath, "Assets/Resources/UI_DepartureStamp_Red.png");
AddResultImage(parent, "Result Rank Badge", rankSprite, new Vector2(170f, -106f), new Vector2(50f, 50f), true, Color.white);
string title = lastResultCleared ? "출국 성공!" : "일정 실패";
Color titleColor = lastResultCleared
? new Color(0.05f, 0.17f, 0.27f, 1f)
: new Color(0.52f, 0.08f, 0.07f, 1f);
AddResultText(parent, "Result Title", title, new Vector2(194f, -88f), new Vector2(210f, 50f), 28f, FontStyles.Bold, titleColor, TextAlignmentOptions.MidlineLeft);
string destination = GetResultDestinationName(resultMap);
AddResultText(parent, "Result Route", destination, new Vector2(260f, -140f), new Vector2(210f, 22f), 13f, FontStyles.Bold, new Color(0.25f, 0.42f, 0.50f, 0.96f), TextAlignmentOptions.MidlineLeft);
if(lastResultCleared)
{
AddResultImage(parent, "Result Departure Stamp", stampSprite, new Vector2(250f, -232f), new Vector2(108f, 108f), true, new Color(1f, 1f, 1f, 0.92f));
TextMeshProUGUI stampText = AddResultText(parent, "Result Stamp Text", "출국\n성공", new Vector2(228f, -218f), new Vector2(92f, 48f), 21f, FontStyles.Bold, new Color(0.70f, 0.04f, 0.03f, 0.96f), TextAlignmentOptions.Center);
stampText.lineSpacing = -16f;
}
else
{
AddResultText(parent, "Result Retry Note", "다시 준비해서\n출국 게이트까지", new Vector2(178f, -216f), new Vector2(200f, 56f), 17f, FontStyles.Bold, new Color(0.32f, 0.46f, 0.54f, 0.96f), TextAlignmentOptions.Center);
}
}
private void AddResultStats(RectTransform parent, int gainedMileage, int shownDistance, int targetDistance) {
AddResultStat(parent, "Mileage", LoadUiSprite("", MileageIconAssetPath), "마일리지", "+" + gainedMileage, new Vector2(478f, -90f));
AddResultStat(parent, "Time", LoadUiSprite("", TimerIconAssetPath), "도착 시간", lastResultTime.ToString("0.0") + "s", new Vector2(626f, -90f));
string distance = targetDistance > 0
? shownDistance + "/" + targetDistance + "m"
: shownDistance + "m";
AddResultStat(parent, "Distance", LoadUiSprite("", CheckpointIconAssetPath), "이동 거리", distance, new Vector2(770f, -90f));
}
private void AddResultTickets(RectTransform parent, MapDefinition resultMap, int rewardMileage) {
AddResultTicket(
parent,
"Destination",
LoadUiSprite("", CheckpointIconAssetPath),
"목적지",
GetResultDestinationName(resultMap),
new Vector2(410f, -200f));
AddResultTicket(
parent,
"Souvenir",
lastResultCleared ? GetResultSouvenirSprite(resultMap) : LoadUiSprite("", SouvenirCollectionIconAssetPath),
"보상",
lastResultCleared ? GetResultSouvenirName(resultMap) : "다음 도전",
new Vector2(560f, -200f));
AddResultTicket(
parent,
"Total Mileage",
LoadUiSprite("", MileageIconAssetPath),
"보유",
saveData.totalMileage + " M",
new Vector2(710f, -200f));
}
private void AddResultStat(RectTransform parent, string objectName, Sprite iconSprite, string label, string value, Vector2 centerPosition) {
AddResultImage(parent, "Result " + objectName + " Icon", iconSprite, centerPosition + new Vector2(0f, -4f), new Vector2(42f, 42f), true, Color.white);
AddResultText(parent, "Result " + objectName + " Value", value, centerPosition + new Vector2(-70f, -25f), new Vector2(140f, 24f), 15f, FontStyles.Bold, new Color(0.05f, 0.17f, 0.25f, 1f), TextAlignmentOptions.Center);
AddResultText(parent, "Result " + objectName + " Label", label, centerPosition + new Vector2(-70f, -48f), new Vector2(140f, 18f), 8f, FontStyles.Bold, new Color(0.42f, 0.58f, 0.64f, 0.92f), TextAlignmentOptions.Center);
}
private void AddResultTicket(RectTransform parent, string objectName, Sprite iconSprite, string label, string value, Vector2 topLeftPosition) {
AddResultImage(parent, "Result " + objectName + " Icon", iconSprite, topLeftPosition + new Vector2(28f, -40f), new Vector2(40f, 40f), true, Color.white);
AddResultText(parent, "Result " + objectName + " Label", label, topLeftPosition + new Vector2(56f, -19f), new Vector2(94f, 18f), 13f, FontStyles.Bold, new Color(0.43f, 0.58f, 0.64f, 0.96f), TextAlignmentOptions.MidlineLeft);
AddResultText(parent, "Result " + objectName + " Value", value, topLeftPosition + new Vector2(56f, -42f), new Vector2(112f, 26f), 12f, FontStyles.Bold, new Color(0.05f, 0.18f, 0.27f, 1f), TextAlignmentOptions.MidlineLeft);
}
private void AddResultActionButton(string label, UnityEngine.Events.UnityAction action, Vector2 position, Vector2 size, bool primary, Sprite iconSprite) {
GameObject buttonObject = CreateUiObject("Result Button " + label, overlayRoot, typeof(Image), typeof(Button));
RectTransform buttonRect = buttonObject.GetComponent<RectTransform>();
buttonRect.anchorMin = new Vector2(0.5f, 0.5f);
buttonRect.anchorMax = new Vector2(0.5f, 0.5f);
buttonRect.pivot = new Vector2(0.5f, 0.5f);
buttonRect.anchoredPosition = position;
buttonRect.sizeDelta = size;
Image buttonImage = buttonObject.GetComponent<Image>();
buttonImage.sprite = LoadUiSprite(ResultButtonResourcePath, ResultButtonAssetPath);
buttonImage.color = buttonImage.sprite != null
? (primary ? Color.white : new Color(0.86f, 0.94f, 1f, 0.94f))
: primary
? new Color(1f, 0.82f, 0.28f, 0.98f)
: new Color(0.82f, 0.91f, 0.96f, 0.90f);
buttonImage.preserveAspect = false;
buttonImage.raycastTarget = true;
Button button = buttonObject.GetComponent<Button>();
button.onClick.AddListener(action);
if(iconSprite != null)
{
AddResultImage(buttonRect, "Result Button Icon", iconSprite, new Vector2(34f, -(size.y * 0.5f)), new Vector2(24f, 24f), true, Color.white);
}
TextMeshProUGUI buttonText = AddResultText(buttonRect, "Result Button Label", label, new Vector2(iconSprite != null ? 54f : 0f, -1f), new Vector2(iconSprite != null ? size.x - 70f : size.x, size.y), 16f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 1f), TextAlignmentOptions.Center);
RectTransform textRect = buttonText.rectTransform;
textRect.anchorMin = new Vector2(0f, 0.5f);
textRect.anchorMax = new Vector2(0f, 0.5f);
textRect.pivot = new Vector2(0f, 0.5f);
buttonText.outlineColor = new Color(0f, 0.04f, 0.07f, 0.98f);
buttonText.outlineWidth = 0.12f;
}
private Image AddResultImage(RectTransform parent, string objectName, Sprite sprite, Vector2 position, Vector2 size, bool preserveAspect, Color color) {
GameObject imageObject = CreateUiObject(objectName, parent, typeof(Image));
RectTransform imageRect = imageObject.GetComponent<RectTransform>();
imageRect.anchorMin = new Vector2(0f, 1f);
imageRect.anchorMax = new Vector2(0f, 1f);
imageRect.pivot = new Vector2(0.5f, 0.5f);
imageRect.anchoredPosition = position;
imageRect.sizeDelta = size;
Image image = imageObject.GetComponent<Image>();
image.sprite = sprite;
image.color = sprite != null ? color : new Color(0.30f, 0.46f, 0.54f, 0.28f);
image.preserveAspect = preserveAspect;
image.raycastTarget = false;
return image;
}
private TextMeshProUGUI AddResultText(RectTransform parent, string objectName, string text, Vector2 position, Vector2 size, float fontSize, FontStyles fontStyle, Color color, TextAlignmentOptions alignment) {
GameObject textObject = CreateUiObject(objectName, parent);
RectTransform textRect = textObject.GetComponent<RectTransform>();
textRect.anchorMin = new Vector2(0f, 1f);
textRect.anchorMax = new Vector2(0f, 1f);
textRect.pivot = new Vector2(0f, 1f);
textRect.anchoredPosition = position;
textRect.sizeDelta = size;
TextMeshProUGUI textComponent = textObject.AddComponent<TextMeshProUGUI>();
textComponent.text = text;
textComponent.font = runtimeFont != null ? runtimeFont : textComponent.font;
textComponent.fontSize = fontSize;
textComponent.fontStyle = fontStyle;
textComponent.alignment = alignment;
textComponent.color = color;
textComponent.raycastTarget = false;
textComponent.textWrappingMode = TextWrappingModes.Normal;
textComponent.overflowMode = TextOverflowModes.Ellipsis;
textComponent.enableAutoSizing = true;
textComponent.fontSizeMin = Mathf.Max(8f, fontSize * 0.66f);
textComponent.fontSizeMax = fontSize;
return textComponent;
}
private string GetResultDestinationName(MapDefinition resultMap) {
if(resultMap == null)
{
return "여행지";
}
switch(resultMap.mapId)
{
case MapId.TutorialIncheon:
return "인천공항";
case MapId.Japan:
return "일본";
case MapId.China:
return "중국";
case MapId.America:
return "미국";
default:
return resultMap.displayName;
}
}
private string GetResultSouvenirName(MapDefinition resultMap) {
if(resultMap == null)
{
return "여행 도장";
}
switch(resultMap.mapId)
{
case MapId.TutorialIncheon:
return "공항 마그넷";
case MapId.Japan:
return "일본 마그넷";
case MapId.China:
return "여행 부적";
case MapId.America:
return "스카이라인";
default:
return "여행 도장";
}
}
private Sprite GetResultSouvenirSprite(MapDefinition resultMap) {
if(resultMap == null)
{
return LoadUiSprite("", SouvenirCollectionIconAssetPath);
}
switch(resultMap.mapId)
{
case MapId.TutorialIncheon:
return LoadUiSprite("", AirportSouvenirAssetPath);
case MapId.Japan:
return LoadUiSprite("", JapanSouvenirAssetPath);
case MapId.China:
return LoadUiSprite("", ChinaSouvenirAssetPath);
case MapId.America:
return LoadUiSprite("", AmericaSouvenirAssetPath);
default:
return LoadUiSprite("", SouvenirCollectionIconAssetPath);
}
}
private void ShowDutyFreeShop() {
@@ -313,20 +733,166 @@ public class GameFlowManager : MonoBehaviour {
EnsureOverlay();
ClearOverlay();
SetOverlayVisible(true);
SetDefaultOverlayBackground();
AddTitle("면세점");
AddBody("보유 마일리지: " + saveData.totalMileage
+ "\n도시락: " + saveData.lunchboxStock
+ " / 방어막: " + saveData.shieldStock
+ "\n운동화: " + saveData.speedShoesStock
+ " / 마일리지 카드: " + saveData.mileageCardStock);
BuildDutyFreeShopScreen();
}
AddButton("도시락 구매 " + LunchboxCost, BuyLunchbox);
AddButton("방어막 구매 " + ShieldCost, BuyShield);
AddButton("운동화 구매 " + SpeedShoesCost, BuySpeedShoes);
AddButton("마일리지 카드 구매 " + MileageCardCost, BuyMileageCard);
AddButton("다음 맵 보기", ShowMapPreview);
private void BuildDutyFreeShopScreen() {
ApplyDutyFreeShopBackground();
RectTransform boardRect = AddDutyFreeBoard();
AddDutyFreeHeader(boardRect);
AddDutyFreeItemCard(
boardRect,
"도시락",
"HP 회복",
LunchboxCost,
saveData.lunchboxStock,
LoadUiSprite("", DutyFreeLunchboxAssetPath),
BuyLunchbox,
new Vector2(58f, -130f));
AddDutyFreeItemCard(
boardRect,
"방어막",
"1회 방어",
ShieldCost,
saveData.shieldStock,
LoadUiSprite("", DutyFreeShieldAssetPath),
BuyShield,
new Vector2(296f, -130f));
AddDutyFreeItemCard(
boardRect,
"운동화",
"속도 회복",
SpeedShoesCost,
saveData.speedShoesStock,
LoadUiSprite("", DutyFreeShoesAssetPath),
BuySpeedShoes,
new Vector2(534f, -130f));
AddDutyFreeItemCard(
boardRect,
"마일리지 카드",
"획득량 증가",
MileageCardCost,
saveData.mileageCardStock,
LoadUiSprite("", DutyFreeMileageCardAssetPath),
BuyMileageCard,
new Vector2(772f, -130f));
AddResultActionButton("다음 여행지 가기", ShowMapPreview, new Vector2(0f, -292f), new Vector2(292f, 48f), false, LoadUiSprite("", AirplaneTravelIconAssetPath));
}
private void ApplyDutyFreeShopBackground() {
if(overlayBackground != null)
{
overlayBackground.sprite = LoadUiSprite("", DutyFreeBackgroundAssetPath);
overlayBackground.preserveAspect = false;
overlayBackground.color = overlayBackground.sprite != null
? Color.white
: new Color(0.03f, 0.035f, 0.038f, 0.96f);
}
if(flowCamera != null)
{
flowCamera.backgroundColor = new Color(0.03f, 0.035f, 0.038f, 1f);
}
GameObject scrimObject = CreateUiObject("Duty Free Background Scrim", overlayRoot, typeof(Image));
RectTransform scrimRect = scrimObject.GetComponent<RectTransform>();
scrimRect.anchorMin = Vector2.zero;
scrimRect.anchorMax = Vector2.one;
scrimRect.offsetMin = Vector2.zero;
scrimRect.offsetMax = Vector2.zero;
Image scrimImage = scrimObject.GetComponent<Image>();
scrimImage.color = new Color(0.01f, 0.012f, 0.014f, 0.34f);
scrimImage.raycastTarget = false;
}
private RectTransform AddDutyFreeBoard() {
GameObject boardObject = CreateUiObject("Duty Free Product Board", overlayRoot, typeof(Image));
RectTransform boardRect = boardObject.GetComponent<RectTransform>();
boardRect.anchorMin = new Vector2(0.5f, 0.5f);
boardRect.anchorMax = new Vector2(0.5f, 0.5f);
boardRect.pivot = new Vector2(0.5f, 0.5f);
boardRect.anchoredPosition = new Vector2(0f, 28f);
boardRect.sizeDelta = new Vector2(1038f, 462f);
Image boardImage = boardObject.GetComponent<Image>();
boardImage.color = new Color(0.015f, 0.055f, 0.085f, 0.84f);
boardImage.raycastTarget = false;
return boardRect;
}
private void AddDutyFreeHeader(RectTransform parent) {
AddResultImage(parent, "Duty Free Header Icon", LoadUiSprite("", DutyFreeIconAssetPath), new Vector2(84f, -60f), new Vector2(48f, 48f), true, Color.white);
AddResultText(parent, "Duty Free Title", "면세점", new Vector2(120f, -38f), new Vector2(180f, 46f), 32f, FontStyles.Bold, new Color(0.96f, 0.99f, 1f, 1f), TextAlignmentOptions.MidlineLeft);
AddResultText(parent, "Duty Free Subtitle", "다음 여행 준비", new Vector2(122f, -82f), new Vector2(220f, 24f), 15f, FontStyles.Bold, new Color(0.64f, 0.82f, 0.92f, 0.96f), TextAlignmentOptions.MidlineLeft);
AddResultImage(parent, "Duty Free Mileage Icon", LoadUiSprite("", MileageIconAssetPath), new Vector2(760f, -61f), new Vector2(42f, 42f), true, Color.white);
AddResultText(parent, "Duty Free Mileage Label", "보유 마일리지", new Vector2(794f, -43f), new Vector2(140f, 22f), 13f, FontStyles.Bold, new Color(0.64f, 0.82f, 0.92f, 0.96f), TextAlignmentOptions.MidlineLeft);
AddResultText(parent, "Duty Free Mileage Value", saveData.totalMileage + " M", new Vector2(794f, -66f), new Vector2(160f, 32f), 24f, FontStyles.Bold, new Color(1f, 0.90f, 0.38f, 1f), TextAlignmentOptions.MidlineLeft);
}
private void AddDutyFreeItemCard(RectTransform parent, string itemName, string effectText, int cost, int stock, Sprite itemSprite, UnityEngine.Events.UnityAction buyAction, Vector2 topLeftPosition) {
bool canBuy = saveData.totalMileage >= cost;
GameObject cardObject = CreateUiObject("Duty Free Item " + itemName, parent, typeof(Image), typeof(Button));
RectTransform cardRect = cardObject.GetComponent<RectTransform>();
cardRect.anchorMin = new Vector2(0f, 1f);
cardRect.anchorMax = new Vector2(0f, 1f);
cardRect.pivot = new Vector2(0f, 1f);
cardRect.anchoredPosition = topLeftPosition;
cardRect.sizeDelta = new Vector2(206f, 242f);
Image cardImage = cardObject.GetComponent<Image>();
cardImage.color = canBuy
? new Color(0.97f, 0.91f, 0.78f, 0.96f)
: new Color(0.40f, 0.45f, 0.48f, 0.88f);
cardImage.raycastTarget = true;
Button button = cardObject.GetComponent<Button>();
button.targetGraphic = cardImage;
button.interactable = canBuy;
button.onClick.AddListener(buyAction);
button.navigation = new Navigation {
mode = Navigation.Mode.None
};
Color textColor = canBuy
? new Color(0.06f, 0.16f, 0.22f, 1f)
: new Color(0.78f, 0.84f, 0.86f, 1f);
Color subColor = canBuy
? new Color(0.34f, 0.49f, 0.54f, 0.98f)
: new Color(0.66f, 0.72f, 0.74f, 0.98f);
AddResultImage(cardRect, "Duty Free " + itemName + " Image", itemSprite, new Vector2(103f, -70f), new Vector2(100f, 88f), true, canBuy ? Color.white : new Color(1f, 1f, 1f, 0.54f));
AddResultText(cardRect, "Duty Free " + itemName + " Name", itemName, new Vector2(16f, -116f), new Vector2(174f, 28f), 20f, FontStyles.Bold, textColor, TextAlignmentOptions.Center);
AddResultText(cardRect, "Duty Free " + itemName + " Effect", effectText, new Vector2(16f, -146f), new Vector2(174f, 22f), 13f, FontStyles.Bold, subColor, TextAlignmentOptions.Center);
AddResultText(cardRect, "Duty Free " + itemName + " Stock", "보유 " + stock, new Vector2(20f, -174f), new Vector2(72f, 22f), 13f, FontStyles.Bold, subColor, TextAlignmentOptions.MidlineLeft);
AddResultText(cardRect, "Duty Free " + itemName + " Cost", cost + " M", new Vector2(102f, -174f), new Vector2(84f, 22f), 15f, FontStyles.Bold, new Color(0.87f, 0.55f, 0.08f, 1f), TextAlignmentOptions.MidlineRight);
GameObject stripObject = CreateUiObject("Duty Free " + itemName + " Buy Strip", cardRect, typeof(Image));
RectTransform stripRect = stripObject.GetComponent<RectTransform>();
stripRect.anchorMin = new Vector2(0.5f, 0f);
stripRect.anchorMax = new Vector2(0.5f, 0f);
stripRect.pivot = new Vector2(0.5f, 0f);
stripRect.anchoredPosition = new Vector2(0f, 14f);
stripRect.sizeDelta = new Vector2(160f, 34f);
Image stripImage = stripObject.GetComponent<Image>();
stripImage.sprite = LoadUiSprite(ResultButtonResourcePath, ResultButtonAssetPath);
stripImage.color = canBuy ? Color.white : new Color(0.60f, 0.65f, 0.68f, 0.88f);
stripImage.preserveAspect = false;
stripImage.raycastTarget = false;
TextMeshProUGUI stripText = AddResultText(cardRect, "Duty Free " + itemName + " Buy Label", canBuy ? "구매" : "마일리지 부족", new Vector2(23f, -200f), new Vector2(160f, 32f), 14f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 1f), TextAlignmentOptions.Center);
stripText.outlineColor = new Color(0f, 0.04f, 0.07f, 0.98f);
stripText.outlineWidth = 0.12f;
}
private void ShowMapPreview() {
@@ -384,6 +950,11 @@ public class GameFlowManager : MonoBehaviour {
case FlowScreen.OpeningStory:
ShowOpeningStory();
break;
#if UNITY_EDITOR || DEVELOPMENT_BUILD
case FlowScreen.DebugMenu:
ShowDebugMenu();
break;
#endif
case FlowScreen.Intro:
default:
ShowIntro();
@@ -474,6 +1045,7 @@ public class GameFlowManager : MonoBehaviour {
private void EnsureOverlay() {
EnsureEventSystem();
EnsureFlowCamera();
if(overlayCanvas != null)
{
@@ -487,6 +1059,7 @@ public class GameFlowManager : MonoBehaviour {
overlayCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
overlayCanvas.worldCamera = null;
overlayCanvas.sortingOrder = 100;
overlayCanvas.targetDisplay = 0;
SetUiLayer(canvasObject);
CanvasScaler scaler = canvasObject.GetComponent<CanvasScaler>();
@@ -515,6 +1088,8 @@ public class GameFlowManager : MonoBehaviour {
private void SetDefaultOverlayBackground() {
if(overlayBackground != null)
{
overlayBackground.sprite = null;
overlayBackground.preserveAspect = false;
overlayBackground.color = new Color(0.02f, 0.035f, 0.045f, 0.92f);
}
@@ -527,6 +1102,8 @@ public class GameFlowManager : MonoBehaviour {
private void BuildIntroScreen() {
if(overlayBackground != null)
{
overlayBackground.sprite = null;
overlayBackground.preserveAspect = false;
overlayBackground.color = Color.clear;
}
@@ -547,6 +1124,8 @@ public class GameFlowManager : MonoBehaviour {
private void BuildOpeningStoryScreen() {
if(overlayBackground != null)
{
overlayBackground.sprite = null;
overlayBackground.preserveAspect = false;
overlayBackground.color = new Color(0.012f, 0.018f, 0.024f, 0.96f);
}
@@ -976,9 +1555,9 @@ public class GameFlowManager : MonoBehaviour {
stampRect.localRotation = Quaternion.Euler(0f, 0f, -12f);
Image stampImage = stampObject.GetComponent<Image>();
stampImage.sprite = LoadUiSpriteRegion("Assets/ConceptArt/Intro/intro_stamps_01.png", new Rect(54f, 48f, 790f, 790f));
stampImage.sprite = LoadUiSprite(DepartureStampResourcePath, "Assets/Resources/UI_DepartureStamp_Red.png");
stampImage.color = stampImage.sprite != null
? new Color(1f, 1f, 1f, 0.94f)
? new Color(1f, 1f, 1f, 0.96f)
: new Color(0.76f, 0.08f, 0.06f, 0.96f);
stampImage.preserveAspect = true;
stampImage.raycastTarget = false;
@@ -1274,6 +1853,8 @@ public class GameFlowManager : MonoBehaviour {
private void EnsureFlowCamera() {
if(flowCamera != null)
{
flowCamera.enabled = true;
flowCamera.targetDisplay = 0;
return;
}
@@ -1288,6 +1869,7 @@ public class GameFlowManager : MonoBehaviour {
flowCamera.depth = 100f;
flowCamera.orthographic = true;
flowCamera.orthographicSize = 360f;
flowCamera.targetDisplay = 0;
}
private void ClearOverlay() {
@@ -1303,6 +1885,11 @@ public class GameFlowManager : MonoBehaviour {
}
private void SetOverlayVisible(bool visible) {
if(visible)
{
EnsureFlowCamera();
}
if(overlayCanvas != null)
{
overlayCanvas.gameObject.SetActive(visible);
+40 -39
View File
@@ -86,7 +86,7 @@ public class GameManager : MonoBehaviour {
private const string TotalMileageKey = "UniRun.TotalMileage";
private const string InitialMileageGrantedKey = "UniRun.InitialMileageGranted";
private const string CharacterFaceResourcePath = "UI_JJ_PassportPhoto";
private const string PassportPanelResourcePath = "UI_LeftHudPassportHorizontalGridPanel";
private const string PassportPanelResourcePath = "UI_LeftHudPassportCompactPanel";
private const string LifeStampResourcePath = "UI_LifeStamp";
private const string PassportItemSlotResourcePath = "UI_PassportItemSlot";
private const string TutorialGuideFrameResourcePath = "UI_TutorialAirportMonitorFrame";
@@ -95,7 +95,7 @@ public class GameManager : MonoBehaviour {
private const string RightHudLuggageLabelJapanResourcePath = "UI_RightHudLuggageLabel_Japan";
private const string RightHudLuggageLabelChinaResourcePath = "UI_RightHudLuggageLabel_China";
private const string RightHudLuggageLabelAmericaResourcePath = "UI_RightHudLuggageLabel_America";
private const float PassportHudWidth = 320f;
private const float PassportHudWidth = 261f;
private const float PassportHudHeight = 102f;
private const float PassportHudScale = 0.5f;
private const float RightInfoHudWidth = 260f;
@@ -383,7 +383,7 @@ public class GameManager : MonoBehaviour {
for(int i = 0; i < currentMapDefinition.openingSteps.Length; i++)
{
PlatformSpawner.TutorialStep step = currentMapDefinition.openingSteps[i];
CourseStep step = currentMapDefinition.openingSteps[i];
if(step != null
&& (step.guideType != TutorialGuideType.None
|| !string.IsNullOrEmpty(step.title)
@@ -436,7 +436,7 @@ public class GameManager : MonoBehaviour {
SetTutorialGuide(TutorialGuideType.Slide, "슬라이드", "오른쪽 클릭을 누르고 있으면 낮게 지나갑니다.");
break;
case 3:
SetTutorialGuide(TutorialGuideType.Items, "아이템", "초밥 -> 라멘 -> 방어막 -> 운동화 -> 마일리지 카드 순서입니다.");
SetTutorialGuide(TutorialGuideType.Items, "아이템", "초밥 -> 라멘 -> 방어막 -> 마일리지 카드 -> 운동화 순서입니다.");
break;
default:
tutorialGuideSequenceComplete = true;
@@ -795,24 +795,24 @@ public class GameManager : MonoBehaviour {
}
private void UpdateTutorialTextLayout(bool showItemRow, bool showFullText) {
Vector2 textPosition = new Vector2(104f, -38f);
Vector2 textSize = new Vector2(250f, 20f);
Vector2 bodyPosition = new Vector2(104f, -60f);
Vector2 bodySize = new Vector2(250f, 38f);
Vector2 textPosition = new Vector2(118f, -38f);
Vector2 textSize = new Vector2(236f, 20f);
Vector2 bodyPosition = new Vector2(118f, -60f);
Vector2 bodySize = new Vector2(236f, 38f);
if(showItemRow)
{
textPosition = new Vector2(110f, -38f);
textSize = new Vector2(242f, 20f);
bodyPosition = new Vector2(110f, -60f);
bodySize = new Vector2(242f, 38f);
textPosition = new Vector2(124f, -38f);
textSize = new Vector2(228f, 20f);
bodyPosition = new Vector2(124f, -60f);
bodySize = new Vector2(228f, 38f);
}
else if(showFullText)
{
textPosition = new Vector2(54f, -39f);
textSize = new Vector2(284f, 20f);
bodyPosition = new Vector2(54f, -61f);
bodySize = new Vector2(284f, 39f);
textPosition = new Vector2(68f, -39f);
textSize = new Vector2(270f, 20f);
bodyPosition = new Vector2(68f, -61f);
bodySize = new Vector2(270f, 39f);
}
if(tutorialTitleText != null)
@@ -1006,7 +1006,7 @@ public class GameManager : MonoBehaviour {
frameRect.anchorMin = new Vector2(0f, 1f);
frameRect.anchorMax = new Vector2(0f, 1f);
frameRect.pivot = new Vector2(0f, 1f);
frameRect.anchoredPosition = new Vector2(30f, -20f);
frameRect.anchoredPosition = new Vector2(32f, -20f);
frameRect.sizeDelta = new Vector2(72f, 68f);
Image frameImage = faceFrame.GetComponent<Image>();
@@ -1045,8 +1045,8 @@ public class GameManager : MonoBehaviour {
lifeRect.anchorMin = new Vector2(0f, 1f);
lifeRect.anchorMax = new Vector2(0f, 1f);
lifeRect.pivot = new Vector2(0f, 1f);
lifeRect.anchoredPosition = new Vector2(124f + (i * 44f), -20f);
lifeRect.sizeDelta = new Vector2(30f, 30f);
lifeRect.anchoredPosition = new Vector2(125f + (i * 45f), -23f);
lifeRect.sizeDelta = new Vector2(28f, 28f);
Image lifeImage = lifeObject.GetComponent<Image>();
lifeImage.sprite = lifeSprite;
@@ -1071,15 +1071,15 @@ public class GameManager : MonoBehaviour {
slotRect.anchorMin = new Vector2(0f, 1f);
slotRect.anchorMax = new Vector2(0f, 1f);
slotRect.pivot = new Vector2(0f, 1f);
slotRect.anchoredPosition = new Vector2(118f + (i * 46f), -66f);
slotRect.sizeDelta = new Vector2(40f, 24f);
slotRect.anchoredPosition = new Vector2(125f + (i * 45f), -62f);
slotRect.sizeDelta = new Vector2(30f, 30f);
Image slotImage = slotObject.GetComponent<Image>();
slotImage.sprite = slotSprite;
slotImage.color = slotSprite != null
? new Color(1f, 1f, 1f, 0.62f)
: new Color(0.92f, 0.97f, 1f, 0.22f);
slotImage.preserveAspect = false;
slotImage.preserveAspect = true;
slotImage.raycastTarget = false;
}
}
@@ -1140,8 +1140,8 @@ public class GameManager : MonoBehaviour {
CreateTutorialMainImage(tutorialGuideObject.transform);
CreateTutorialItemRow(tutorialGuideObject.transform);
tutorialTitleText = CreateTutorialText(tutorialGuideObject.transform, "Tutorial Title", new Vector2(104f, -38f), new Vector2(250f, 20f), 12f, FontStyles.Bold);
tutorialBodyText = CreateTutorialText(tutorialGuideObject.transform, "Tutorial Body", new Vector2(104f, -60f), new Vector2(250f, 38f), 9f, FontStyles.Normal);
tutorialTitleText = CreateTutorialText(tutorialGuideObject.transform, "Tutorial Title", new Vector2(118f, -38f), new Vector2(236f, 20f), 12f, FontStyles.Bold);
tutorialBodyText = CreateTutorialText(tutorialGuideObject.transform, "Tutorial Body", new Vector2(118f, -60f), new Vector2(236f, 38f), 9f, FontStyles.Normal);
tutorialTitleText.color = new Color(0.06f, 0.13f, 0.19f, 0.98f);
tutorialBodyText.color = new Color(0.10f, 0.18f, 0.23f, 0.95f);
CreateTutorialNextButton(tutorialGuideObject.transform);
@@ -1170,16 +1170,18 @@ public class GameManager : MonoBehaviour {
multiplierRect.anchorMin = new Vector2(1f, 0f);
multiplierRect.anchorMax = new Vector2(1f, 0f);
multiplierRect.pivot = new Vector2(1f, 0f);
multiplierRect.anchoredPosition = new Vector2(-2f, 1f);
multiplierRect.sizeDelta = new Vector2(22f, 15f);
multiplierRect.anchoredPosition = new Vector2(8f, -4f);
multiplierRect.sizeDelta = new Vector2(42f, 28f);
tutorialMultiplierText = multiplierObject.AddComponent<TextMeshProUGUI>();
tutorialMultiplierText.font = scoreText.font;
tutorialMultiplierText.text = "x2";
tutorialMultiplierText.text = "X2";
tutorialMultiplierText.alignment = TextAlignmentOptions.Center;
tutorialMultiplierText.fontSize = 9f;
tutorialMultiplierText.fontSize = 17f;
tutorialMultiplierText.fontStyle = FontStyles.Bold;
tutorialMultiplierText.color = new Color(1f, 0.91f, 0.33f, 1f);
tutorialMultiplierText.outlineColor = new Color(0.05f, 0.05f, 0.06f, 0.95f);
tutorialMultiplierText.outlineWidth = 0.18f;
tutorialMultiplierText.raycastTarget = false;
tutorialMultiplierText.textWrappingMode = TextWrappingModes.NoWrap;
tutorialMultiplierText.gameObject.SetActive(false);
@@ -1326,7 +1328,7 @@ public class GameManager : MonoBehaviour {
if(guideType == TutorialGuideType.Slide)
{
return LoadTutorialSprite("Assets/Sprites/JJ_Slide.png", "JJ_Slide_0");
return LoadTutorialSprite("Assets/Sprites/JJ_Slide.png", "JJ_Slide_2");
}
if(guideType == TutorialGuideType.Damage)
@@ -1519,7 +1521,7 @@ public class GameManager : MonoBehaviour {
float cursor = 0f;
AddStepMarkers(mapDefinition.openingSteps, ref cursor, targetDistance);
PlatformSpawner.TutorialStep[] loopSteps = mapDefinition.loopSteps;
CourseStep[] loopSteps = mapDefinition.loopSteps;
int loopGuard = 0;
while(cursor < targetDistance
&& loopSteps != null
@@ -1532,7 +1534,7 @@ public class GameManager : MonoBehaviour {
}
}
private void AddStepMarkers(PlatformSpawner.TutorialStep[] steps, ref float cursor, float targetDistance) {
private void AddStepMarkers(CourseStep[] steps, ref float cursor, float targetDistance) {
if(steps == null)
{
return;
@@ -1540,7 +1542,7 @@ public class GameManager : MonoBehaviour {
for(int i = 0; i < steps.Length; i++)
{
PlatformSpawner.TutorialStep step = steps[i];
CourseStep step = steps[i];
float stepDistance = GetStepDistance(step);
if(markerObjects.Count < MaxCourseObjectCount)
@@ -1564,7 +1566,7 @@ public class GameManager : MonoBehaviour {
}
}
private float GetStepDistance(PlatformSpawner.TutorialStep step) {
private float GetStepDistance(CourseStep step) {
if(step == null)
{
return CourseDistancePerInterval;
@@ -1573,7 +1575,7 @@ public class GameManager : MonoBehaviour {
return Mathf.Max(0.3f, step.spawnInterval) * CourseDistancePerInterval;
}
private bool TryGetMarkerInfo(PlatformSpawner.TutorialStep step, out MarkerInfo markerInfo) {
private bool TryGetMarkerInfo(CourseStep step, out MarkerInfo markerInfo) {
markerInfo = new MarkerInfo();
if(step == null)
@@ -1589,7 +1591,7 @@ public class GameManager : MonoBehaviour {
return true;
}
if(step.coursePlatformType == PlatformSpawner.CoursePlatformType.ForceHit
if(step.coursePlatformType == CoursePlatformType.ForceHit
|| step.platformPattern == Platform.PlatformPattern.ForceHit)
{
markerInfo.label = "!";
@@ -1606,7 +1608,7 @@ public class GameManager : MonoBehaviour {
return true;
}
if(step.coursePlatformType == PlatformSpawner.CoursePlatformType.Slide
if(step.coursePlatformType == CoursePlatformType.Slide
|| step.platformPattern == Platform.PlatformPattern.Slide)
{
markerInfo.label = "S";
@@ -1615,7 +1617,7 @@ public class GameManager : MonoBehaviour {
return true;
}
if(step.coursePlatformType == PlatformSpawner.CoursePlatformType.Jump
if(step.coursePlatformType == CoursePlatformType.Jump
|| step.platformPattern == Platform.PlatformPattern.LowLeft
|| step.platformPattern == Platform.PlatformPattern.LowMid
|| step.platformPattern == Platform.PlatformPattern.LowRight)
@@ -1652,7 +1654,7 @@ public class GameManager : MonoBehaviour {
markerObjects.Add(platformImage.gameObject);
}
private Color GetPlatformColor(PlatformSpawner.TutorialStep step) {
private Color GetPlatformColor(CourseStep step) {
if(step != null && step.spawnInterval >= 1.4f)
{
return new Color(0.28f, 0.50f, 0.57f, 0.96f);
@@ -1671,7 +1673,6 @@ public class GameManager : MonoBehaviour {
if(markerInfo.kind == "ForceHit")
{
CreateJumpFeature(progress, markerInfo);
CreateSlideFeature(progress, markerInfo);
return;
}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b33ec3906e4a4b9d90e671da7a8a31a3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
using static CourseStepFactory;
public static class AmericaMap {
public static MapDefinition Create() {
return new MapDefinition {
mapId = MapId.America,
displayName = "America",
routeName = "뉴욕 자유의 여신상",
isTutorial = false,
platformSkin = Platform.PlatformSkin.USA,
backgroundResourcePath = "Map_America_NewYork",
finishGateStyle = FinishGateStyle.AmericaLiberty,
targetDistance = 1700f,
timeLimit = 125f,
clearMileageReward = 500,
hasNextMap = false,
nextMapId = MapId.America,
openingSteps = new CourseStep[] {
Basic(),
Basic()
},
loopSteps = new CourseStep[] {
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)
}
};
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4aebf219fb334943a89524de85c8977f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,36 @@
using static CourseStepFactory;
public static class ChinaMap {
public static MapDefinition Create() {
return new MapDefinition {
mapId = MapId.China,
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 CourseStep[] {
Basic(),
Basic()
},
loopSteps = new CourseStep[] {
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)
}
};
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5fa98f4232774d458c65e430f1bd1f99
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using static CourseStepFactory;
public static class JapanMap {
public static MapDefinition Create() {
return new MapDefinition {
mapId = MapId.Japan,
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 CourseStep[] {
Basic(),
Basic()
},
loopSteps = new CourseStep[] {
Basic(),
Jump(),
Basic(GroundY, LandingSpacing),
Aerial(),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.CenterPair),
Basic(),
Jump(Platform.PlatformPattern.LowLeft),
Basic()
}
};
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8fb126c4369f4ff7a83eaad31e6e581e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,56 @@
using static CourseStepFactory;
public static class TutorialIncheonMap {
public static MapDefinition Create() {
return new MapDefinition {
mapId = MapId.TutorialIncheon,
displayName = "Tutorial / Incheon",
routeName = "인천공항 출발 준비",
isTutorial = true,
platformSkin = Platform.PlatformSkin.Airport,
backgroundResourcePath = "Map_Tutorial_Incheon_Airport",
finishGateStyle = FinishGateStyle.AirportDeparture,
targetDistance = 380f,
timeLimit = 85f,
clearMileageReward = 150,
hasNextMap = true,
nextMapId = MapId.Japan,
openingSteps = new CourseStep[] {
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),
Basic(GroundY, BasicSpacing),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "방어막", "다음 충돌 1회를 막습니다.\n먹은 뒤 바로 충돌을 막아 봅니다.", Platform.ItemPattern.Shield),
ForceHit(GameManager.TutorialGuideType.None, "", ""),
Basic(GroundY, LandingSpacing),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "마일리지 카드", "잠깐 마일리지가 2배가 됩니다.\n먹고 바로 마일리지를 모아 봅니다.", Platform.ItemPattern.MileageCard),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.SafeLine),
ForceHit(GameManager.TutorialGuideType.None, "", ""),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "운동화", "느려진 속도를 회복합니다.\n방금 떨어진 속도를 되돌려 봅니다.", Platform.ItemPattern.SpeedShoes),
Basic(GroundY, LandingSpacing, Platform.MileagePattern.None, GameManager.TutorialGuideType.Items, "실전 연습", "시간이 지나면 달리기 속도는 조금씩 빨라지고, 장애물에 맞으면 느려집니다.\n방금 먹은 신발 아이템으로 회복한 뒤 출국 게이트까지 달려보세요."),
Basic(GroundY, BasicSpacing, Platform.MileagePattern.SafeLine),
Basic(),
Basic(),
Basic(),
Basic(GroundY, LandingSpacing)
},
loopSteps = CreateEasyLoop()
};
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c16e17831dc94b26a6cfa4c6bbf17130
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+6 -342
View File
@@ -2,12 +2,6 @@ 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 {
@@ -64,313 +58,10 @@ public static class MapDatabase {
}
maps = new MapDefinition[] {
CreateTutorialIncheon(),
CreateJapan(),
CreateChina(),
CreateAmerica()
};
}
private static MapDefinition CreateTutorialIncheon() {
return new MapDefinition {
mapId = MapId.TutorialIncheon,
displayName = "Tutorial / Incheon",
routeName = "인천공항 출발 준비",
isTutorial = true,
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[] {
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()
};
}
private static MapDefinition CreateJapan() {
return new MapDefinition {
mapId = MapId.Japan,
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[] {
Basic(),
Basic()
},
loopSteps = new PlatformSpawner.TutorialStep[] {
Basic(),
Jump(),
Basic(GroundY, LandingSpacing),
Aerial(),
Basic(GroundY, LandingSpacing),
Slide(SlideObstaclePattern.SlideLayout.CenterPair),
Basic(),
Jump(Platform.PlatformPattern.LowLeft),
Basic()
}
};
}
private static MapDefinition CreateChina() {
return new MapDefinition {
mapId = MapId.China,
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[] {
Basic(),
Basic()
},
loopSteps = new PlatformSpawner.TutorialStep[] {
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)
}
};
}
private static MapDefinition CreateAmerica() {
return new MapDefinition {
mapId = MapId.America,
displayName = "America",
routeName = "뉴욕 자유의 여신상",
isTutorial = false,
platformSkin = Platform.PlatformSkin.USA,
backgroundResourcePath = "Map_America_NewYork",
finishGateStyle = FinishGateStyle.AmericaLiberty,
targetDistance = 1700f,
timeLimit = 125f,
clearMileageReward = 500,
hasNextMap = false,
nextMapId = MapId.America,
openingSteps = new PlatformSpawner.TutorialStep[] {
Basic(),
Basic()
},
loopSteps = new PlatformSpawner.TutorialStep[] {
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[] {
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,
SlideObstaclePattern.SlideLayout slideLayout,
GameManager.TutorialGuideType guideType,
float yPosition,
float spawnInterval,
string title = "",
string message = "",
Platform.ItemPattern itemPattern = Platform.ItemPattern.None,
PlatformSpawner.CoursePlatformType coursePlatformType = PlatformSpawner.CoursePlatformType.Basic) {
return new PlatformSpawner.TutorialStep {
coursePlatformType = coursePlatformType,
platformPattern = platformPattern,
mileagePattern = mileagePattern,
slideLayout = slideLayout,
itemPattern = itemPattern,
guideType = guideType,
yPosition = yPosition,
spawnInterval = spawnInterval,
title = title,
message = message
TutorialIncheonMap.Create(),
JapanMap.Create(),
ChinaMap.Create(),
AmericaMap.Create()
};
}
@@ -388,35 +79,8 @@ public static class MapDatabase {
clearMileageReward = source.clearMileageReward,
hasNextMap = source.hasNextMap,
nextMapId = source.nextMapId,
openingSteps = CloneSteps(source.openingSteps),
loopSteps = CloneSteps(source.loopSteps)
openingSteps = CourseStepFactory.CloneSteps(source.openingSteps),
loopSteps = CourseStepFactory.CloneSteps(source.loopSteps)
};
}
public static PlatformSpawner.TutorialStep[] CloneSteps(PlatformSpawner.TutorialStep[] source) {
if(source == null)
{
return new PlatformSpawner.TutorialStep[0];
}
PlatformSpawner.TutorialStep[] steps = new PlatformSpawner.TutorialStep[source.Length];
for(int i = 0; i < source.Length; i++)
{
PlatformSpawner.TutorialStep sourceStep = source[i];
steps[i] = Step(
sourceStep.platformPattern,
sourceStep.mileagePattern,
sourceStep.slideLayout,
sourceStep.guideType,
sourceStep.yPosition,
sourceStep.spawnInterval,
sourceStep.title,
sourceStep.message,
sourceStep.itemPattern,
sourceStep.coursePlatformType);
}
return steps;
}
}
+2 -2
View File
@@ -14,6 +14,6 @@ public class MapDefinition {
public int clearMileageReward;
public bool hasNextMap;
public MapId nextMapId;
public PlatformSpawner.TutorialStep[] openingSteps;
public PlatformSpawner.TutorialStep[] loopSteps;
public CourseStep[] openingSteps;
public CourseStep[] loopSteps;
}
+8 -260
View File
@@ -39,8 +39,6 @@ public class Platform : MonoBehaviour {
USA
}
public GameObject[] obstacles; // 장애물 오브젝트들
public int emptyPatternWeight = 2; // 장애물이 없는 패턴이 선택될 가중치
public Sprite mileageSprite; // 이 발판에서 사용할 마일리지 토큰 스프라이트
public int mileagePatternChance = 50; // 마일리지 패턴 등장 확률
public int smallMileageValue = 10; // 일반 토큰 가치
@@ -49,9 +47,7 @@ public class Platform : MonoBehaviour {
private bool stepped = false; // 플레이어 캐릭터가 밟았었는가
private MileagePickup[] mileagePickups; // 런타임에 생성하는 마일리지 토큰 풀
private ItemPickup[] itemPickups; // 런타임에 생성하는 튜토리얼 아이템 풀
private PlatformPattern reservedPattern = PlatformPattern.Random; // 다음 활성화 때 사용할 수동 패턴
private MileagePattern reservedMileagePattern = MileagePattern.Random; // 다음 활성화 때 사용할 마일리지 패턴
private SlideObstaclePattern.SlideLayout reservedSlideLayout = SlideObstaclePattern.SlideLayout.Random; // 다음 슬라이딩 장애물 배치
private ItemPattern reservedItemPattern = ItemPattern.None; // 다음 활성화 때 사용할 아이템 배치
private PlatformSkin reservedSkin = PlatformSkin.Airport; // 현재 맵에서 사용할 발판/장애물 스킨
private const int MileagePoolSize = 5;
@@ -63,23 +59,14 @@ public class Platform : MonoBehaviour {
private const float JumpMileageMinWidthScale = 1.8f;
private const float JumpMileageMaxWidthScale = 2.5f;
public void ConfigureForTutorial(
PlatformPattern pattern,
MileagePattern mileagePattern,
SlideObstaclePattern.SlideLayout slideLayout = SlideObstaclePattern.SlideLayout.Random,
ItemPattern itemPattern = ItemPattern.None,
PlatformSkin platformSkin = PlatformSkin.Airport) {
reservedPattern = pattern;
public void ConfigureForTutorial(MileagePattern mileagePattern, ItemPattern itemPattern = ItemPattern.None, PlatformSkin platformSkin = PlatformSkin.Airport) {
reservedMileagePattern = mileagePattern;
reservedSlideLayout = slideLayout;
reservedItemPattern = itemPattern;
reservedSkin = platformSkin;
}
public void ConfigureForRandom(PlatformSkin platformSkin = PlatformSkin.Airport) {
reservedPattern = PlatformPattern.Random;
reservedMileagePattern = MileagePattern.Random;
reservedSlideLayout = SlideObstaclePattern.SlideLayout.Random;
reservedItemPattern = ItemPattern.None;
reservedSkin = platformSkin;
}
@@ -93,38 +80,10 @@ public class Platform : MonoBehaviour {
EnsureMileagePickups();
EnsureItemPickups();
for(int i = 0; i < obstacles.Length; i++)
{
obstacles[i].SetActive(false);
}
HideMileagePickups();
HideItemPickups();
if(reservedPattern != PlatformPattern.Random)
{
ApplyReservedPattern();
return;
}
if(obstacles.Length == 0)
{
TryPlaceMileagePattern(null);
return;
}
// 낮은 장애물과 높은 장애물이 동시에 켜져 불가능한 배치가 되지 않도록 하나만 선택한다.
int patternIndex = Random.Range(0, obstacles.Length + emptyPatternWeight);
GameObject activeObstacle = null;
if(patternIndex < obstacles.Length)
{
activeObstacle = obstacles[patternIndex];
ConfigureSlideObstacle(activeObstacle);
activeObstacle.SetActive(true);
}
TryPlaceMileagePattern(activeObstacle);
PlaceReservedMileagePattern();
PlaceReservedItemPattern();
}
void OnCollisionEnter2D(Collision2D collision) {
@@ -223,100 +182,16 @@ public class Platform : MonoBehaviour {
}
}
private void TryPlaceMileagePattern(GameObject activeObstacle) {
private void TryPlaceMileagePattern() {
if(mileageSprite == null || mileagePickups == null || Random.Range(0, 100) >= mileagePatternChance)
{
return;
}
if(activeObstacle == null)
{
PlaceSafeMileageLine();
return;
}
if(activeObstacle.name.Contains("Slide"))
{
PlaceSlideMileageLine();
}
else
{
PlaceJumpMileageArc(GetWorldRelativeX(activeObstacle.transform));
}
PlaceSafeMileageLine();
}
private void ApplyReservedPattern() {
GameObject activeObstacle = null;
switch(reservedPattern)
{
case PlatformPattern.LowLeft:
activeObstacle = FindObstacle("Obstacle Left");
break;
case PlatformPattern.LowMid:
activeObstacle = FindObstacle("Obstacle Mid");
break;
case PlatformPattern.LowRight:
activeObstacle = FindObstacle("Obstacle Right");
break;
case PlatformPattern.Slide:
activeObstacle = FindObstacle("Slide Obstacle Pattern");
break;
case PlatformPattern.ForceHit:
activeObstacle = FindObstacle("Obstacle Mid");
ActivateObstacle(activeObstacle);
GameObject slideObstacle = FindObstacle("Slide Obstacle Pattern");
reservedSlideLayout = SlideObstaclePattern.SlideLayout.WidePair;
ActivateObstacle(slideObstacle);
break;
}
if(reservedPattern != PlatformPattern.ForceHit && activeObstacle != null)
{
ActivateObstacle(activeObstacle);
}
PlaceReservedMileagePattern(activeObstacle);
PlaceReservedItemPattern();
}
private void ActivateObstacle(GameObject obstacle) {
if(obstacle == null)
{
return;
}
ConfigureSlideObstacle(obstacle);
obstacle.SetActive(true);
}
private void ConfigureSlideObstacle(GameObject activeObstacle) {
if(activeObstacle == null || !activeObstacle.name.Contains("Slide"))
{
return;
}
SlideObstaclePattern slideObstaclePattern = activeObstacle.GetComponent<SlideObstaclePattern>();
if(slideObstaclePattern != null)
{
slideObstaclePattern.ConfigureLayout(reservedSlideLayout);
}
}
private GameObject FindObstacle(string obstacleName) {
for(int i = 0; i < obstacles.Length; i++)
{
if(obstacles[i] != null && obstacles[i].name == obstacleName)
{
return obstacles[i];
}
}
return null;
}
private void PlaceReservedMileagePattern(GameObject activeObstacle) {
private void PlaceReservedMileagePattern() {
if(mileageSprite == null || mileagePickups == null || reservedMileagePattern == MileagePattern.None)
{
return;
@@ -330,8 +205,7 @@ public class Platform : MonoBehaviour {
if(reservedMileagePattern == MileagePattern.JumpArc)
{
float obstacleX = activeObstacle != null ? GetWorldRelativeX(activeObstacle.transform) : 0f;
PlaceJumpMileageArc(obstacleX);
PlaceJumpMileageArc(0f);
return;
}
@@ -341,7 +215,7 @@ public class Platform : MonoBehaviour {
return;
}
TryPlaceMileagePattern(activeObstacle);
TryPlaceMileagePattern();
}
private void PlaceReservedItemPattern() {
@@ -397,22 +271,10 @@ public class Platform : MonoBehaviour {
private void ApplyVisualSkin() {
#if UNITY_EDITOR
Sprite platformSprite = LoadSpriteAtPath(GetPlatformSkinPath(reservedSkin));
Sprite ceilingSprite = LoadSpriteAtPath(GetCeilingSkinPath(reservedSkin));
Sprite lowObstacleSprite = LoadSpriteAtPath(GetLowObstacleSkinPath(reservedSkin));
Sprite hangingObstacleSprite = LoadSpriteAtPath(GetHangingObstacleSkinPath(reservedSkin));
Sprite mileageSkinSprite = LoadSpriteAtPath(GetMileageSkinPath(reservedSkin));
ApplySprite(GetComponent<SpriteRenderer>(), platformSprite);
Transform ceilingPlatform = FindChildRecursive(transform, "Ceiling Platform");
if(ceilingPlatform != null)
{
ApplySprite(ceilingPlatform.GetComponent<SpriteRenderer>(), ceilingSprite != null ? ceilingSprite : platformSprite);
}
ApplyLowObstacleSkin(lowObstacleSprite);
ApplyHangingObstacleSkin(hangingObstacleSprite);
if(mileageSkinSprite != null)
{
mileageSprite = mileageSkinSprite;
@@ -421,52 +283,6 @@ public class Platform : MonoBehaviour {
}
#if UNITY_EDITOR
private void ApplyLowObstacleSkin(Sprite obstacleSprite) {
if(obstacleSprite == null || obstacles == null)
{
return;
}
for(int i = 0; i < obstacles.Length; i++)
{
GameObject obstacle = obstacles[i];
if(obstacle == null || obstacle.name.Contains("Slide"))
{
continue;
}
ApplySprite(obstacle.GetComponent<SpriteRenderer>(), obstacleSprite);
}
}
private void ApplyHangingObstacleSkin(Sprite obstacleSprite) {
if(obstacleSprite == null)
{
return;
}
GameObject slideObstacle = FindObstacle("Slide Obstacle Pattern");
if(slideObstacle == null)
{
return;
}
SlideObstaclePattern slideObstaclePattern = slideObstacle.GetComponent<SlideObstaclePattern>();
if(slideObstaclePattern == null || slideObstaclePattern.obstacles == null)
{
return;
}
for(int i = 0; i < slideObstaclePattern.obstacles.Length; i++)
{
Transform hangingObstacle = slideObstaclePattern.obstacles[i];
if(hangingObstacle != null)
{
ApplySprite(hangingObstacle.GetComponent<SpriteRenderer>(), obstacleSprite);
}
}
}
private void ApplySprite(SpriteRenderer spriteRenderer, Sprite sprite) {
if(spriteRenderer != null && sprite != null)
{
@@ -483,31 +299,6 @@ public class Platform : MonoBehaviour {
return AssetDatabase.LoadAssetAtPath<Sprite>(assetPath);
}
private Transform FindChildRecursive(Transform parent, string childName) {
if(parent == null)
{
return null;
}
for(int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if(child.name == childName)
{
return child;
}
Transform match = FindChildRecursive(child, childName);
if(match != null)
{
return match;
}
}
return null;
}
private string GetPlatformSkinPath(PlatformSkin platformSkin) {
switch(platformSkin)
{
@@ -523,45 +314,6 @@ public class Platform : MonoBehaviour {
}
}
private string GetCeilingSkinPath(PlatformSkin platformSkin) {
if(platformSkin == PlatformSkin.Airport)
{
return "Assets/Sprites/ObstacleSkins/Skin_Platform_AirportCeiling.png";
}
return GetPlatformSkinPath(platformSkin);
}
private string GetLowObstacleSkinPath(PlatformSkin platformSkin) {
switch(platformSkin)
{
case PlatformSkin.Japan:
return "Assets/Sprites/ObstacleSkins/Skin_Obstacle_StoneLantern.png";
case PlatformSkin.China:
return "Assets/Sprites/ObstacleSkins/Skin_Obstacle_MarketCrate.png";
case PlatformSkin.USA:
return "Assets/Sprites/ObstacleSkins/Skin_Obstacle_Cone.png";
case PlatformSkin.Airport:
default:
return "Assets/Sprites/ObstacleSkins/Skin_Obstacle_Suitcases.png";
}
}
private string GetHangingObstacleSkinPath(PlatformSkin platformSkin) {
switch(platformSkin)
{
case PlatformSkin.Japan:
return "Assets/Sprites/ObstacleSkins/Skin_Hanging_RoadSign.png";
case PlatformSkin.China:
return "Assets/Sprites/ObstacleSkins/Skin_Hanging_RedLanterns.png";
case PlatformSkin.USA:
return "Assets/Sprites/ObstacleSkins/Skin_Hanging_Banner.png";
case PlatformSkin.Airport:
default:
return "Assets/Sprites/ObstacleSkins/Skin_Hanging_AirportSign.png";
}
}
private string GetMileageSkinPath(PlatformSkin platformSkin) {
switch(platformSkin)
{
@@ -681,10 +433,6 @@ public class Platform : MonoBehaviour {
return new Vector3(position.x / parentScaleX, position.y / parentScaleY, 0f);
}
private float GetWorldRelativeX(Transform child) {
return child.localPosition.x * transform.localScale.x;
}
private void SetPickupValue(int index, int value) {
if(index < 0 || index >= mileagePickups.Length || !mileagePickups[index].gameObject.activeSelf)
{
+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)