Refactor course maps and travel UI
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user