693 lines
29 KiB
C#
693 lines
29 KiB
C#
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;
|
|
public string title;
|
|
public string message;
|
|
public float triggerX;
|
|
}
|
|
|
|
public GameObject platformPrefab; // 계속 이어지는 기본 발판 프리팹
|
|
public GameObject jumpObstaclePrefab; // 낮은 점프 장애물 프리팹
|
|
public GameObject slideObstaclePrefab; // 위쪽 슬라이딩 장애물 프리팹
|
|
public int count = 12; // 기본 발판 풀 개수
|
|
public bool usePatternCourse = true; // 검증된 발판 패턴 코스를 사용
|
|
public bool tutorialMode = true; // 처음에는 튜토리얼 패턴을 먼저 배치
|
|
public TutorialStep[] tutorialSteps; // 튜토리얼 발판 순서
|
|
public TutorialStep[] stagePatternSteps; // 튜토리얼 이후 반복할 검증된 발판 순서
|
|
|
|
public bool keepWorldSpacingBySpeed = true; // 게임 속도가 빨라져도 발판 사이 실제 거리를 유지
|
|
public int continuousCoursePoolCount = 12; // 기본 발판을 촘촘히 깔 때 필요한 최소 풀 크기
|
|
public int obstaclePoolCount = 6; // 점프/슬라이드 장애물별 재사용 풀 크기
|
|
public float timeBetSpawnMin = 1.25f; // 다음 배치까지의 시간 간격 최솟값
|
|
public float timeBetSpawnMax = 2.25f; // 다음 배치까지의 시간 간격 최댓값
|
|
public float tutorialSpawnInterval = 2.2f; // 튜토리얼 발판 배치 간격
|
|
private float timeBetSpawn; // 다음 배치까지의 시간 간격
|
|
|
|
private const float FallbackGroundY = -2.4f;
|
|
private const float FallbackBasicSpacing = 0.58f;
|
|
private const float FallbackActionSpacing = 0.72f;
|
|
private const float FallbackLandingSpacing = 0.64f;
|
|
private const float FallbackAerialSpacing = 2.05f;
|
|
|
|
public float yMin = -3.5f; // 배치할 위치의 최소 y값
|
|
public float yMax = 1.5f; // 배치할 위치의 최대 y값
|
|
public float tutorialGuideTriggerX = 5f; // 발판/장애물이 이 위치까지 오면 설명을 띄운다.
|
|
private float xPos = 20f; // 배치할 위치의 x 값
|
|
|
|
private GameObject[] platforms; // 기본 발판 풀
|
|
private GameObject[] jumpObstacles; // 점프 장애물 풀
|
|
private GameObject[] slideObstacles; // 슬라이드 장애물 풀
|
|
private int platformIndex = 0; // 기본 발판 풀 순번
|
|
private int jumpObstacleIndex = 0; // 점프 장애물 풀 순번
|
|
private int slideObstacleIndex = 0; // 슬라이드 장애물 풀 순번
|
|
private int courseStepIndex = 0; // 진행 중인 패턴 코스 순번
|
|
private Platform.PlatformSkin mapPlatformSkin = Platform.PlatformSkin.Airport; // 현재 맵에서 사용할 발판 스킨
|
|
private readonly List<PendingTutorialGuide> pendingTutorialGuides = new List<PendingTutorialGuide>(); // 실제 체험 직전에 띄울 설명들
|
|
private GameObject activeFinishLandingPlatform; // 도착 게이트가 공중에 뜨지 않도록 깔아두는 전용 발판
|
|
private bool courseSpawningStopped = false; // 도착 게이트 뒤로 새 발판/장애물이 나오지 않게 막는다.
|
|
|
|
private Vector2 poolPosition = new Vector2(0, -25); // 초반에 생성된 발판들을 화면 밖에 숨겨둘 위치
|
|
private float lastSpawnTime; // 마지막 배치 시점
|
|
|
|
public void ApplyMap(MapDefinition mapDefinition) {
|
|
if(mapDefinition == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
usePatternCourse = true;
|
|
tutorialMode = mapDefinition.isTutorial;
|
|
mapPlatformSkin = mapDefinition.platformSkin;
|
|
tutorialSteps = MapDatabase.CloneSteps(mapDefinition.openingSteps);
|
|
stagePatternSteps = MapDatabase.CloneSteps(mapDefinition.loopSteps);
|
|
courseStepIndex = 0;
|
|
courseSpawningStopped = false;
|
|
pendingTutorialGuides.Clear();
|
|
ClearFinishLandingPlatform();
|
|
ResetPoolIndices();
|
|
lastSpawnTime = Time.time;
|
|
timeBetSpawn = 0f;
|
|
count = Mathf.Max(count, continuousCoursePoolCount);
|
|
EnsurePlatformPool();
|
|
DeactivateAllPlatformPools();
|
|
}
|
|
|
|
public void SpawnFinishLandingPlatform(float spawnX, float groundY) {
|
|
if(platformPrefab == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ClearFinishLandingPlatform();
|
|
activeFinishLandingPlatform = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
|
|
activeFinishLandingPlatform.SetActive(false);
|
|
|
|
TutorialStep landingStep = CreateStep(
|
|
Platform.PlatformPattern.Empty,
|
|
Platform.MileagePattern.None,
|
|
SlideObstaclePattern.SlideLayout.Random,
|
|
GameManager.TutorialGuideType.None,
|
|
Mathf.Clamp(groundY, yMin, yMax),
|
|
FallbackLandingSpacing,
|
|
"",
|
|
"",
|
|
Platform.ItemPattern.None,
|
|
CoursePlatformType.Basic);
|
|
|
|
ConfigurePlatform(activeFinishLandingPlatform, landingStep);
|
|
activeFinishLandingPlatform.transform.position = new Vector2(spawnX, landingStep.yPosition);
|
|
activeFinishLandingPlatform.SetActive(true);
|
|
}
|
|
|
|
public void ClearFinishLandingPlatform() {
|
|
if(activeFinishLandingPlatform != null)
|
|
{
|
|
Destroy(activeFinishLandingPlatform);
|
|
activeFinishLandingPlatform = null;
|
|
}
|
|
}
|
|
|
|
public void StopCourseSpawningAfterFinishGate() {
|
|
courseSpawningStopped = true;
|
|
pendingTutorialGuides.Clear();
|
|
}
|
|
|
|
void Start() {
|
|
EnsurePatternSteps();
|
|
|
|
if(usePatternCourse && tutorialMode)
|
|
{
|
|
count = Mathf.Max(count, continuousCoursePoolCount);
|
|
}
|
|
|
|
// 변수들을 초기화하고 사용할 발판들을 미리 생성
|
|
EnsurePlatformPool();
|
|
|
|
// 마지막 배치 시점 초기화
|
|
lastSpawnTime = 0f;
|
|
|
|
// 다음번 배치까지의 시간 간격을 0으로 초기화
|
|
timeBetSpawn = 0f;
|
|
}
|
|
|
|
private void EnsurePlatformPool() {
|
|
int basicCount = usePatternCourse ? Mathf.Max(count, continuousCoursePoolCount) : Mathf.Max(1, count);
|
|
int obstacleCount = Mathf.Max(1, obstaclePoolCount);
|
|
|
|
EnsurePool(ref platforms, basicCount, platformPrefab);
|
|
EnsurePool(ref jumpObstacles, obstacleCount, jumpObstaclePrefab);
|
|
EnsurePool(ref slideObstacles, obstacleCount, slideObstaclePrefab);
|
|
count = platforms != null ? platforms.Length : count;
|
|
}
|
|
|
|
private void EnsurePool(ref GameObject[] pool, int requiredCount, GameObject prefab) {
|
|
if(prefab == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(pool != null && pool.Length >= requiredCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameObject[] nextPool = new GameObject[requiredCount];
|
|
|
|
if(pool != null)
|
|
{
|
|
for(int i = 0; i < pool.Length; i++)
|
|
{
|
|
nextPool[i] = pool[i];
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < nextPool.Length; i++)
|
|
{
|
|
if(nextPool[i] == null)
|
|
{
|
|
nextPool[i] = Instantiate(prefab, poolPosition, Quaternion.identity);
|
|
nextPool[i].SetActive(false);
|
|
}
|
|
}
|
|
|
|
pool = nextPool;
|
|
}
|
|
|
|
private void ResetPoolIndices() {
|
|
platformIndex = 0;
|
|
jumpObstacleIndex = 0;
|
|
slideObstacleIndex = 0;
|
|
}
|
|
|
|
private void DeactivateAllPlatformPools() {
|
|
DeactivatePool(platforms);
|
|
DeactivatePool(jumpObstacles);
|
|
DeactivatePool(slideObstacles);
|
|
}
|
|
|
|
private void DeactivatePool(GameObject[] pool) {
|
|
if(pool == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < pool.Length; i++)
|
|
{
|
|
if(pool[i] != null)
|
|
{
|
|
pool[i].SetActive(false);
|
|
pool[i].transform.position = poolPosition;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Update() {
|
|
// 순서를 돌아가며 주기적으로 발판을 배치
|
|
if(GameManager.instance == null || GameManager.instance.isGameover || !GameFlowManager.IsGameplayActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(courseSpawningStopped)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdatePendingTutorialGuides();
|
|
if(GameManager.instance != null && GameManager.instance.IsTutorialGuidePaused)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EnsurePlatformPool();
|
|
|
|
if(Time.time >= lastSpawnTime + timeBetSpawn)
|
|
{
|
|
lastSpawnTime = Time.time;
|
|
|
|
TutorialStep step = usePatternCourse ? GetCurrentCourseStep() : null;
|
|
timeBetSpawn = step != null ? GetStepSpawnInterval(step) : Random.Range(timeBetSpawnMin, timeBetSpawnMax);
|
|
|
|
float yPos = step != null
|
|
? Mathf.Clamp(step.yPosition, yMin, yMax)
|
|
: Random.Range(yMin, yMax);
|
|
|
|
GameObject platformObject = TakeFromPool(platforms, ref platformIndex);
|
|
if(platformObject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
platformObject.SetActive(false);
|
|
ConfigurePlatform(platformObject, step);
|
|
platformObject.SetActive(true);
|
|
platformObject.transform.position = new Vector2(xPos, yPos);
|
|
SpawnCourseObstacles(step, yPos);
|
|
RegisterTutorialGuide(platformObject.transform, step);
|
|
|
|
if(usePatternCourse)
|
|
{
|
|
courseStepIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdatePendingTutorialGuides() {
|
|
if(GameManager.instance == null || pendingTutorialGuides.Count == 0 || GameManager.instance.IsTutorialGuidePaused)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < pendingTutorialGuides.Count; i++)
|
|
{
|
|
PendingTutorialGuide guide = pendingTutorialGuides[i];
|
|
|
|
if(guide == null || guide.target == null || !guide.target.gameObject.activeInHierarchy)
|
|
{
|
|
pendingTutorialGuides.RemoveAt(i);
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
if(guide.target.position.x <= guide.triggerX)
|
|
{
|
|
GameManager.instance.SetTutorialGuide(guide.guideType, guide.title, guide.message);
|
|
pendingTutorialGuides.RemoveAt(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RegisterTutorialGuide(Transform target, TutorialStep step) {
|
|
if(target == null
|
|
|| step == null
|
|
|| step.guideType == GameManager.TutorialGuideType.None
|
|
|| (string.IsNullOrEmpty(step.title) && string.IsNullOrEmpty(step.message)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
pendingTutorialGuides.Add(new PendingTutorialGuide {
|
|
target = target,
|
|
guideType = step.guideType,
|
|
title = step.title,
|
|
message = step.message,
|
|
triggerX = GetTutorialGuideTriggerX(step)
|
|
});
|
|
}
|
|
|
|
private float GetTutorialGuideTriggerX(TutorialStep step) {
|
|
if(step != null && step.guideType == GameManager.TutorialGuideType.DoubleJump)
|
|
{
|
|
return -2f;
|
|
}
|
|
|
|
return tutorialGuideTriggerX;
|
|
}
|
|
|
|
private void SpawnCourseObstacles(TutorialStep step, float yPos) {
|
|
if(step == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(step.coursePlatformType == CoursePlatformType.ForceHit || step.platformPattern == Platform.PlatformPattern.ForceHit)
|
|
{
|
|
SpawnJumpObstacle(Platform.PlatformPattern.LowMid, yPos);
|
|
SpawnSlideObstacle(SlideObstaclePattern.SlideLayout.WidePair, yPos);
|
|
return;
|
|
}
|
|
|
|
if(step.coursePlatformType == CoursePlatformType.Jump || IsJumpPattern(step.platformPattern))
|
|
{
|
|
Platform.PlatformPattern jumpPattern = IsJumpPattern(step.platformPattern)
|
|
? step.platformPattern
|
|
: Platform.PlatformPattern.LowMid;
|
|
SpawnJumpObstacle(jumpPattern, yPos);
|
|
return;
|
|
}
|
|
|
|
if(step.coursePlatformType == CoursePlatformType.Slide || step.platformPattern == Platform.PlatformPattern.Slide)
|
|
{
|
|
SpawnSlideObstacle(step.slideLayout, yPos);
|
|
}
|
|
}
|
|
|
|
private void SpawnJumpObstacle(Platform.PlatformPattern platformPattern, float yPos) {
|
|
GameObject obstacleObject = TakeFromPool(jumpObstacles, ref jumpObstacleIndex);
|
|
if(obstacleObject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
obstacleObject.SetActive(false);
|
|
ConfigureObstacle(obstacleObject, platformPattern, SlideObstaclePattern.SlideLayout.Random);
|
|
obstacleObject.transform.position = new Vector2(xPos, yPos);
|
|
obstacleObject.SetActive(true);
|
|
}
|
|
|
|
private void SpawnSlideObstacle(SlideObstaclePattern.SlideLayout slideLayout, float yPos) {
|
|
GameObject obstacleObject = TakeFromPool(slideObstacles, ref slideObstacleIndex);
|
|
if(obstacleObject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
obstacleObject.SetActive(false);
|
|
ConfigureObstacle(obstacleObject, Platform.PlatformPattern.Slide, slideLayout);
|
|
obstacleObject.transform.position = new Vector2(xPos, yPos);
|
|
obstacleObject.SetActive(true);
|
|
}
|
|
|
|
private void ConfigureObstacle(
|
|
GameObject obstacleObject,
|
|
Platform.PlatformPattern platformPattern,
|
|
SlideObstaclePattern.SlideLayout slideLayout) {
|
|
CourseObstacle obstacle = obstacleObject.GetComponent<CourseObstacle>();
|
|
|
|
if(obstacle != null)
|
|
{
|
|
obstacle.Configure(mapPlatformSkin, platformPattern, slideLayout);
|
|
}
|
|
}
|
|
|
|
private bool IsJumpPattern(Platform.PlatformPattern platformPattern) {
|
|
return platformPattern == Platform.PlatformPattern.LowLeft
|
|
|| platformPattern == Platform.PlatformPattern.LowMid
|
|
|| platformPattern == Platform.PlatformPattern.LowRight;
|
|
}
|
|
|
|
private GameObject TakeFromPool(GameObject[] pool, ref int poolIndex) {
|
|
if(pool == null || pool.Length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if(poolIndex < 0 || poolIndex >= pool.Length)
|
|
{
|
|
poolIndex = 0;
|
|
}
|
|
|
|
GameObject platformObject = pool[poolIndex];
|
|
poolIndex++;
|
|
|
|
if(poolIndex >= pool.Length)
|
|
{
|
|
poolIndex = 0;
|
|
}
|
|
|
|
return platformObject;
|
|
}
|
|
|
|
private void ConfigurePlatform(GameObject platformObject, TutorialStep step) {
|
|
Platform platform = platformObject.GetComponent<Platform>();
|
|
|
|
if(platform == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(step == null)
|
|
{
|
|
platform.ConfigureForRandom(mapPlatformSkin);
|
|
return;
|
|
}
|
|
|
|
platform.ConfigureForTutorial(Platform.PlatformPattern.Empty, step.mileagePattern, step.slideLayout, step.itemPattern, mapPlatformSkin);
|
|
|
|
// 설명은 발판 생성 시점이 아니라 실제 체험 직전에 RegisterTutorialGuide가 띄운다.
|
|
}
|
|
|
|
private float GetStepSpawnInterval(TutorialStep step) {
|
|
float spawnInterval;
|
|
|
|
if(step != null && step.spawnInterval > 0f)
|
|
{
|
|
spawnInterval = step.spawnInterval;
|
|
}
|
|
else
|
|
{
|
|
spawnInterval = tutorialSpawnInterval;
|
|
}
|
|
|
|
if(keepWorldSpacingBySpeed && GameManager.instance != null)
|
|
{
|
|
spawnInterval /= Mathf.Max(0.1f, GameManager.instance.gameSpeed);
|
|
}
|
|
|
|
return Mathf.Max(0.05f, spawnInterval);
|
|
}
|
|
|
|
private TutorialStep GetCurrentCourseStep() {
|
|
EnsurePatternSteps();
|
|
|
|
if(tutorialMode && courseStepIndex < tutorialSteps.Length)
|
|
{
|
|
return tutorialSteps[courseStepIndex];
|
|
}
|
|
|
|
int loopIndex = tutorialMode
|
|
? courseStepIndex - tutorialSteps.Length
|
|
: courseStepIndex;
|
|
|
|
if(stagePatternSteps == null || stagePatternSteps.Length == 0)
|
|
{
|
|
return CreateStep(
|
|
Platform.PlatformPattern.Empty,
|
|
Platform.MileagePattern.SafeLine,
|
|
SlideObstaclePattern.SlideLayout.Random,
|
|
GameManager.TutorialGuideType.None,
|
|
-2.2f,
|
|
tutorialSpawnInterval,
|
|
"",
|
|
"");
|
|
}
|
|
|
|
loopIndex %= stagePatternSteps.Length;
|
|
|
|
if(loopIndex < 0)
|
|
{
|
|
loopIndex += stagePatternSteps.Length;
|
|
}
|
|
|
|
return stagePatternSteps[loopIndex];
|
|
}
|
|
|
|
private void EnsurePatternSteps() {
|
|
EnsureTutorialSteps();
|
|
EnsureStagePatternSteps();
|
|
}
|
|
|
|
private void EnsureTutorialSteps() {
|
|
if(tutorialSteps != null && tutorialSteps.Length > 0)
|
|
{
|
|
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),
|
|
};
|
|
}
|
|
|
|
private void EnsureStagePatternSteps() {
|
|
if(stagePatternSteps != null && stagePatternSteps.Length > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
stagePatternSteps = new TutorialStep[] {
|
|
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, 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, "", ""),
|
|
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Slide),
|
|
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackBasicSpacing, "", ""),
|
|
CreateStep(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Jump),
|
|
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.LeftPair, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Slide),
|
|
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackBasicSpacing, "", ""),
|
|
CreateStep(Platform.PlatformPattern.LowRight, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Jump),
|
|
CreateStep(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackAerialSpacing, "", ""),
|
|
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.RightPair, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Slide),
|
|
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, FallbackBasicSpacing, "", ""),
|
|
CreateStep(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, FallbackGroundY, FallbackActionSpacing, "", "", Platform.ItemPattern.None, CoursePlatformType.Slide),
|
|
};
|
|
}
|
|
|
|
private TutorialStep CreateStep(
|
|
Platform.PlatformPattern platformPattern,
|
|
Platform.MileagePattern mileagePattern,
|
|
SlideObstaclePattern.SlideLayout slideLayout,
|
|
GameManager.TutorialGuideType guideType,
|
|
float yPosition,
|
|
float spawnInterval,
|
|
string title,
|
|
string message,
|
|
Platform.ItemPattern itemPattern = Platform.ItemPattern.None,
|
|
CoursePlatformType coursePlatformType = CoursePlatformType.Basic) {
|
|
TutorialStep step = new TutorialStep();
|
|
step.coursePlatformType = coursePlatformType;
|
|
step.platformPattern = platformPattern;
|
|
step.mileagePattern = mileagePattern;
|
|
step.slideLayout = slideLayout;
|
|
step.itemPattern = itemPattern;
|
|
step.guideType = guideType;
|
|
step.yPosition = yPosition;
|
|
step.spawnInterval = spawnInterval;
|
|
step.title = title;
|
|
step.message = message;
|
|
return step;
|
|
}
|
|
|
|
private TutorialStep CreateTutorialStep(
|
|
TutorialStepKind stepKind,
|
|
Platform.PlatformPattern platformPattern,
|
|
Platform.MileagePattern mileagePattern,
|
|
SlideObstaclePattern.SlideLayout slideLayout,
|
|
float yPosition,
|
|
float spawnInterval,
|
|
Platform.ItemPattern itemPattern = Platform.ItemPattern.None) {
|
|
GameManager.TutorialGuideType guideType = GameManager.TutorialGuideType.None;
|
|
string title = "";
|
|
string message = "";
|
|
|
|
switch(stepKind)
|
|
{
|
|
case TutorialStepKind.Jump:
|
|
guideType = GameManager.TutorialGuideType.Jump;
|
|
title = "점프";
|
|
message = "가방 장애물이 보이면 왼쪽 클릭으로 뛰어넘습니다.";
|
|
break;
|
|
case TutorialStepKind.DoubleJumpTakeoff:
|
|
guideType = GameManager.TutorialGuideType.DoubleJump;
|
|
title = "2단 점프";
|
|
message = "다음 발판이 멀리 있으면 공중에서 한 번 더 왼쪽 클릭합니다.";
|
|
break;
|
|
case TutorialStepKind.Slide:
|
|
guideType = GameManager.TutorialGuideType.Slide;
|
|
title = "슬라이드";
|
|
message = "천장 표지판이 보이면 오른쪽 클릭을 누르고 지나갑니다.";
|
|
break;
|
|
case TutorialStepKind.ForceHit:
|
|
guideType = GameManager.TutorialGuideType.Damage;
|
|
title = "피격";
|
|
message = "이번 구간은 일부러 맞아 목숨과 속도 감소를 확인합니다.";
|
|
break;
|
|
case TutorialStepKind.HealthItem:
|
|
guideType = GameManager.TutorialGuideType.Items;
|
|
title = "초밥";
|
|
message = "초밥을 먹으면 잃은 목숨을 1 회복합니다.";
|
|
break;
|
|
case TutorialStepKind.InvincibleItem:
|
|
guideType = GameManager.TutorialGuideType.Items;
|
|
title = "라멘";
|
|
message = "라멘을 먹고 다음 충돌을 피해 없이 지나가 봅니다.";
|
|
break;
|
|
case TutorialStepKind.ShieldItem:
|
|
guideType = GameManager.TutorialGuideType.Items;
|
|
title = "방어막";
|
|
message = "방어막을 먹고 다음 충돌 1회를 막아 봅니다.";
|
|
break;
|
|
case TutorialStepKind.SpeedItem:
|
|
guideType = GameManager.TutorialGuideType.Items;
|
|
title = "운동화";
|
|
message = "운동화는 속도를 회복해 일정이 늦어지는 것을 줄입니다.";
|
|
break;
|
|
case TutorialStepKind.MileageCardItem:
|
|
guideType = GameManager.TutorialGuideType.Items;
|
|
title = "마일리지 카드";
|
|
message = "카드를 먹은 뒤 마일리지를 모으면 획득량이 늘어납니다.";
|
|
break;
|
|
}
|
|
|
|
return CreateStep(
|
|
platformPattern,
|
|
mileagePattern,
|
|
slideLayout,
|
|
guideType,
|
|
yPosition,
|
|
spawnInterval,
|
|
title,
|
|
message,
|
|
itemPattern,
|
|
GetCoursePlatformType(stepKind, platformPattern, yPosition));
|
|
}
|
|
|
|
private CoursePlatformType GetCoursePlatformType(TutorialStepKind stepKind, Platform.PlatformPattern platformPattern, float yPosition) {
|
|
if(stepKind == TutorialStepKind.ForceHit || platformPattern == Platform.PlatformPattern.ForceHit)
|
|
{
|
|
return CoursePlatformType.ForceHit;
|
|
}
|
|
|
|
if(stepKind == TutorialStepKind.Slide || platformPattern == Platform.PlatformPattern.Slide)
|
|
{
|
|
return CoursePlatformType.Slide;
|
|
}
|
|
|
|
if(stepKind == TutorialStepKind.Jump
|
|
|| platformPattern == Platform.PlatformPattern.LowLeft
|
|
|| platformPattern == Platform.PlatformPattern.LowMid
|
|
|| platformPattern == Platform.PlatformPattern.LowRight)
|
|
{
|
|
return CoursePlatformType.Jump;
|
|
}
|
|
|
|
return CoursePlatformType.Basic;
|
|
}
|
|
}
|