Add duty free systems and travel stage updates
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,27 @@
|
||||
using System;
|
||||
|
||||
public enum DutyFreeItemType {
|
||||
None = 0,
|
||||
Lunchbox = 1,
|
||||
MileageCard = 4,
|
||||
Supplement = 5
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class GameSaveData {
|
||||
public int currentMapIndex;
|
||||
public int unlockedMapIndex;
|
||||
public int totalMileage;
|
||||
public int bagSlots;
|
||||
public int shieldStock;
|
||||
public int lunchboxStock;
|
||||
public int speedShoesStock;
|
||||
public int mileageCardStock;
|
||||
public int supplementPurchases;
|
||||
public int dutyFreeLimitStageIndex;
|
||||
public bool purchasedMileageCardThisStage;
|
||||
public bool purchasedSupplementThisStage;
|
||||
public DutyFreeItemType equippedSlot1;
|
||||
public DutyFreeItemType equippedSlot2;
|
||||
public DutyFreeItemType equippedSlot3;
|
||||
public int bestScore;
|
||||
|
||||
public static GameSaveData CreateDefault() {
|
||||
@@ -18,10 +30,15 @@ public class GameSaveData {
|
||||
unlockedMapIndex = 0,
|
||||
totalMileage = 0,
|
||||
bagSlots = 1,
|
||||
shieldStock = 0,
|
||||
lunchboxStock = 0,
|
||||
speedShoesStock = 0,
|
||||
mileageCardStock = 0,
|
||||
supplementPurchases = 0,
|
||||
dutyFreeLimitStageIndex = -1,
|
||||
purchasedMileageCardThisStage = false,
|
||||
purchasedSupplementThisStage = false,
|
||||
equippedSlot1 = DutyFreeItemType.None,
|
||||
equippedSlot2 = DutyFreeItemType.None,
|
||||
equippedSlot3 = DutyFreeItemType.None,
|
||||
bestScore = 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,10 +66,148 @@ public static class GameSaveManager {
|
||||
saveData.currentMapIndex = Mathf.Min(saveData.currentMapIndex, saveData.unlockedMapIndex);
|
||||
saveData.totalMileage = Mathf.Max(0, saveData.totalMileage);
|
||||
saveData.bagSlots = Mathf.Clamp(saveData.bagSlots, 1, 3);
|
||||
saveData.shieldStock = Mathf.Max(0, saveData.shieldStock);
|
||||
saveData.lunchboxStock = Mathf.Max(0, saveData.lunchboxStock);
|
||||
saveData.speedShoesStock = Mathf.Max(0, saveData.speedShoesStock);
|
||||
saveData.mileageCardStock = Mathf.Max(0, saveData.mileageCardStock);
|
||||
saveData.supplementPurchases = Mathf.Clamp(saveData.supplementPurchases, 0, 4);
|
||||
saveData.dutyFreeLimitStageIndex = saveData.dutyFreeLimitStageIndex < 0
|
||||
? -1
|
||||
: Mathf.Clamp(saveData.dutyFreeLimitStageIndex, 0, MapDatabase.LastMapIndex);
|
||||
NormalizeEquippedItems(saveData);
|
||||
NormalizeDutyFreeStockCapacity(saveData);
|
||||
NormalizeEquippedItems(saveData);
|
||||
saveData.bestScore = Mathf.Max(0, saveData.bestScore);
|
||||
}
|
||||
|
||||
private static void NormalizeDutyFreeStockCapacity(GameSaveData saveData) {
|
||||
int bagSlots = Mathf.Clamp(saveData.bagSlots, 1, 3);
|
||||
int equippedLunchboxes = CountEquippedItem(saveData, DutyFreeItemType.Lunchbox, bagSlots);
|
||||
int equippedMileageCards = CountEquippedItem(saveData, DutyFreeItemType.MileageCard, bagSlots);
|
||||
|
||||
saveData.lunchboxStock = Mathf.Max(equippedLunchboxes, Mathf.Min(saveData.lunchboxStock, bagSlots));
|
||||
saveData.mileageCardStock = Mathf.Max(equippedMileageCards, Mathf.Min(saveData.mileageCardStock, bagSlots));
|
||||
|
||||
while(saveData.lunchboxStock + saveData.mileageCardStock > bagSlots)
|
||||
{
|
||||
if(saveData.mileageCardStock > equippedMileageCards)
|
||||
{
|
||||
saveData.mileageCardStock--;
|
||||
}
|
||||
else if(saveData.lunchboxStock > equippedLunchboxes)
|
||||
{
|
||||
saveData.lunchboxStock--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int CountEquippedItem(GameSaveData saveData, DutyFreeItemType itemType, int bagSlots) {
|
||||
int count = 0;
|
||||
|
||||
for(int i = 0; i < bagSlots; i++)
|
||||
{
|
||||
if(GetEquippedSlot(saveData, i) == itemType)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static void NormalizeEquippedItems(GameSaveData saveData) {
|
||||
int bagSlots = Mathf.Clamp(saveData.bagSlots, 1, 3);
|
||||
if(bagSlots < 3)
|
||||
{
|
||||
saveData.equippedSlot3 = DutyFreeItemType.None;
|
||||
}
|
||||
|
||||
if(bagSlots < 2)
|
||||
{
|
||||
saveData.equippedSlot2 = DutyFreeItemType.None;
|
||||
}
|
||||
|
||||
saveData.equippedSlot1 = NormalizeItemType(saveData.equippedSlot1);
|
||||
saveData.equippedSlot2 = NormalizeItemType(saveData.equippedSlot2);
|
||||
saveData.equippedSlot3 = NormalizeItemType(saveData.equippedSlot3);
|
||||
|
||||
int lunchboxCount = 0;
|
||||
int mileageCardCount = 0;
|
||||
|
||||
ClampEquippedSlot(saveData, 0, ref lunchboxCount, ref mileageCardCount);
|
||||
ClampEquippedSlot(saveData, 1, ref lunchboxCount, ref mileageCardCount);
|
||||
ClampEquippedSlot(saveData, 2, ref lunchboxCount, ref mileageCardCount);
|
||||
}
|
||||
|
||||
private static DutyFreeItemType NormalizeItemType(DutyFreeItemType itemType) {
|
||||
switch(itemType)
|
||||
{
|
||||
case DutyFreeItemType.Lunchbox:
|
||||
case DutyFreeItemType.MileageCard:
|
||||
return itemType;
|
||||
default:
|
||||
return DutyFreeItemType.None;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClampEquippedSlot(
|
||||
GameSaveData saveData,
|
||||
int slotIndex,
|
||||
ref int lunchboxCount,
|
||||
ref int mileageCardCount) {
|
||||
DutyFreeItemType itemType = GetEquippedSlot(saveData, slotIndex);
|
||||
if(itemType == DutyFreeItemType.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool overStock = false;
|
||||
switch(itemType)
|
||||
{
|
||||
case DutyFreeItemType.Lunchbox:
|
||||
overStock = lunchboxCount >= saveData.lunchboxStock;
|
||||
lunchboxCount++;
|
||||
break;
|
||||
case DutyFreeItemType.MileageCard:
|
||||
overStock = mileageCardCount >= saveData.mileageCardStock;
|
||||
mileageCardCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
if(overStock)
|
||||
{
|
||||
SetEquippedSlot(saveData, slotIndex, DutyFreeItemType.None);
|
||||
}
|
||||
}
|
||||
|
||||
private static DutyFreeItemType GetEquippedSlot(GameSaveData saveData, int slotIndex) {
|
||||
switch(slotIndex)
|
||||
{
|
||||
case 0:
|
||||
return saveData.equippedSlot1;
|
||||
case 1:
|
||||
return saveData.equippedSlot2;
|
||||
case 2:
|
||||
return saveData.equippedSlot3;
|
||||
default:
|
||||
return DutyFreeItemType.None;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetEquippedSlot(GameSaveData saveData, int slotIndex, DutyFreeItemType itemType) {
|
||||
switch(slotIndex)
|
||||
{
|
||||
case 0:
|
||||
saveData.equippedSlot1 = itemType;
|
||||
break;
|
||||
case 1:
|
||||
saveData.equippedSlot2 = itemType;
|
||||
break;
|
||||
case 2:
|
||||
saveData.equippedSlot3 = itemType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55433eabfe544a199c2b2899e3256b3b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,178 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public partial class GameFlowManager {
|
||||
#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~0, F1/F2");
|
||||
|
||||
AddDebugButton("1. 인트로", ShowDebugIntroPreview, new Vector2(-235f, -32f));
|
||||
AddDebugButton("2. 현재 맵 시작", ShowDebugGameStartPreview, new Vector2(-235f, -74f));
|
||||
AddDebugButton("3. 현재 출국 실패", delegate { ShowDebugResultPreview(false); }, new Vector2(-235f, -116f));
|
||||
AddDebugButton("4. 현재 출국 성공", delegate { ShowDebugResultPreview(true); }, new Vector2(-235f, -158f));
|
||||
AddDebugButton("5. 면세점", ShowDebugDutyFreeShopPreview, new Vector2(-235f, -200f));
|
||||
AddDebugButton("6. 지도", ShowDebugMapPreview, new Vector2(-235f, -242f));
|
||||
|
||||
AddDebugButton("7. 일본 게임시작", delegate { ShowDebugMapGameStartPreview(MapId.Japan); }, new Vector2(235f, -32f));
|
||||
AddDebugButton("8. 일본 출국성공", delegate { ShowDebugMapResultPreview(MapId.Japan, true); }, new Vector2(235f, -74f));
|
||||
AddDebugButton("9. 중국 게임시작", delegate { ShowDebugMapGameStartPreview(MapId.China); }, new Vector2(235f, -116f));
|
||||
AddDebugButton("0. 중국 출국성공", delegate { ShowDebugMapResultPreview(MapId.China, true); }, new Vector2(235f, -158f));
|
||||
AddDebugButton("F1. 미국 게임시작", delegate { ShowDebugMapGameStartPreview(MapId.America); }, new Vector2(235f, -200f));
|
||||
AddDebugButton("F2. 미국 출국성공", delegate { ShowDebugMapResultPreview(MapId.America, true); }, new Vector2(235f, -242f));
|
||||
}
|
||||
|
||||
private void AddDebugButton(string label, UnityEngine.Events.UnityAction action, Vector2 position) {
|
||||
GameObject buttonObject = CreateUiObject("Debug 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 = new Vector2(310f, 34f);
|
||||
|
||||
Image buttonImage = buttonObject.GetComponent<Image>();
|
||||
buttonImage.color = new Color(0.92f, 0.96f, 1f, 0.94f);
|
||||
buttonImage.raycastTarget = true;
|
||||
|
||||
Button button = buttonObject.GetComponent<Button>();
|
||||
button.targetGraphic = buttonImage;
|
||||
button.navigation = new Navigation {
|
||||
mode = Navigation.Mode.None
|
||||
};
|
||||
button.onClick.AddListener(action);
|
||||
|
||||
TextMeshProUGUI buttonText = AddTextTo(buttonObject.transform, "Label", label, 14f, FontStyles.Bold);
|
||||
RectTransform textRect = buttonText.rectTransform;
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = Vector2.zero;
|
||||
textRect.offsetMax = Vector2.zero;
|
||||
buttonText.color = new Color(0.04f, 0.07f, 0.09f, 1f);
|
||||
}
|
||||
|
||||
private void ShowDebugIntroPreview() {
|
||||
ShowIntro();
|
||||
}
|
||||
|
||||
private void ShowDebugGameStartPreview() {
|
||||
EnsureDebugPreviewData();
|
||||
LoadGameSceneForCurrentMap();
|
||||
}
|
||||
|
||||
private void ShowDebugMapGameStartPreview(MapId mapId) {
|
||||
SetDebugCurrentMap(mapId);
|
||||
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 ShowDebugMapResultPreview(MapId mapId, bool cleared) {
|
||||
SetDebugCurrentMap(mapId);
|
||||
|
||||
gameplayActive = false;
|
||||
pendingStartGameplay = false;
|
||||
currentScreen = FlowScreen.Result;
|
||||
completedMap = currentMap;
|
||||
lastResultCleared = cleared;
|
||||
|
||||
int mapIndex = MapDatabase.GetIndex(mapId);
|
||||
lastResultScore = cleared ? 12800 + (mapIndex * 2200) : 7200 + (mapIndex * 900);
|
||||
lastResultMileage = cleared ? 190 + (mapIndex * 70) : 84;
|
||||
lastResultTime = currentMap != null
|
||||
? Mathf.Max(10f, currentMap.timeLimit * (cleared ? 0.78f : 1.08f))
|
||||
: cleared ? 23.9f : 38.4f;
|
||||
lastResultDistance = currentMap != null
|
||||
? (cleared ? currentMap.targetDistance : currentMap.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 SetDebugCurrentMap(MapId mapId) {
|
||||
EnsureDebugPreviewData();
|
||||
currentMap = MapDatabase.GetMap(mapId);
|
||||
|
||||
if(saveData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int mapIndex = MapDatabase.GetIndex(mapId);
|
||||
saveData.currentMapIndex = mapIndex;
|
||||
saveData.unlockedMapIndex = Mathf.Max(saveData.unlockedMapIndex, mapIndex);
|
||||
GameSaveManager.Save(saveData);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc38b07e718f43dda9e26895c85dbf3f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,390 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public partial class GameFlowManager {
|
||||
private void ShowDutyFreeShop() {
|
||||
currentScreen = FlowScreen.DutyFreeShop;
|
||||
gameplayActive = false;
|
||||
pendingStartGameplay = false;
|
||||
|
||||
if(TryLoadFlowScene(DutyFreeShopSceneName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureOverlay();
|
||||
ClearOverlay();
|
||||
SetOverlayVisible(true);
|
||||
|
||||
BuildDutyFreeShopScreen();
|
||||
}
|
||||
|
||||
private void BuildDutyFreeShopScreen() {
|
||||
EnsureDutyFreeStagePurchaseLimits();
|
||||
ApplyDutyFreeShopBackground();
|
||||
|
||||
RectTransform boardRect = AddDutyFreeBoard();
|
||||
AddDutyFreeHeader(boardRect);
|
||||
|
||||
AddDutyFreeItemCard(
|
||||
boardRect,
|
||||
"도시락",
|
||||
DutyFreeItemType.Lunchbox,
|
||||
LunchboxCost,
|
||||
saveData.lunchboxStock,
|
||||
LoadUiSprite("", DutyFreeLunchboxAssetPath),
|
||||
BuyLunchbox,
|
||||
new Vector2(75f, -135f));
|
||||
|
||||
AddDutyFreeSupplementCard(
|
||||
boardRect,
|
||||
"영양제",
|
||||
SupplementCost,
|
||||
saveData.supplementPurchases,
|
||||
LoadUiSprite("", DutyFreeSupplementAssetPath),
|
||||
BuySupplement,
|
||||
new Vector2(303f, -135f));
|
||||
|
||||
AddDutyFreeItemCard(
|
||||
boardRect,
|
||||
"마일리지 카드",
|
||||
DutyFreeItemType.MileageCard,
|
||||
MileageCardCost,
|
||||
saveData.mileageCardStock,
|
||||
LoadUiSprite("", DutyFreeMileageCardAssetPath),
|
||||
BuyMileageCard,
|
||||
new Vector2(760f, -135f));
|
||||
|
||||
AddDutyFreeNextTravelButton();
|
||||
}
|
||||
|
||||
private void ApplyDutyFreeShopBackground() {
|
||||
if(overlayBackground != null)
|
||||
{
|
||||
overlayBackground.sprite = null;
|
||||
overlayBackground.preserveAspect = false;
|
||||
overlayBackground.color = new Color(0.018f, 0.041f, 0.052f, 0.98f);
|
||||
}
|
||||
|
||||
if(flowCamera != null)
|
||||
{
|
||||
flowCamera.backgroundColor = new Color(0.018f, 0.041f, 0.052f, 1f);
|
||||
}
|
||||
|
||||
AddDutyFreeBackdropImage(
|
||||
"Duty Free Shop Interior",
|
||||
LoadUiSprite(DutyFreeBackgroundResourcePath, DutyFreeBackgroundAssetPath),
|
||||
Vector2.zero,
|
||||
new Vector2(1378f, 724f),
|
||||
true,
|
||||
Color.white);
|
||||
|
||||
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.22f);
|
||||
scrimImage.raycastTarget = false;
|
||||
}
|
||||
|
||||
private Image AddDutyFreeBackdropImage(string objectName, Sprite sprite, Vector2 position, Vector2 size, bool preserveAspect, Color color) {
|
||||
GameObject imageObject = CreateUiObject(objectName, overlayRoot, typeof(Image));
|
||||
RectTransform imageRect = imageObject.GetComponent<RectTransform>();
|
||||
imageRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
imageRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
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 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, 20f);
|
||||
boardRect.sizeDelta = new Vector2(1038f, 552f);
|
||||
|
||||
Image boardImage = boardObject.GetComponent<Image>();
|
||||
boardImage.sprite = LoadUiSprite(DutyFreeWindowPanelResourcePath, DutyFreeWindowPanelAssetPath);
|
||||
boardImage.color = boardImage.sprite != null
|
||||
? Color.white
|
||||
: new Color(0.92f, 0.98f, 1f, 0.78f);
|
||||
boardImage.preserveAspect = false;
|
||||
boardImage.raycastTarget = false;
|
||||
|
||||
return boardRect;
|
||||
}
|
||||
|
||||
private void AddDutyFreeHeader(RectTransform parent) {
|
||||
AddResultImage(parent, "Duty Free Equip Slots Panel", LoadUiSprite(DutyFreeEquipSlotPanelResourcePath, "Assets/Resources/UI_DutyFreeBagSlotPanel.png"), new Vector2(50f, -570f), new Vector2(276f, 124f), true, Color.white);
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
AddDutyFreeEquipSlot(parent, i, new Vector2(-65f + (i * 82f), -540f));
|
||||
}
|
||||
|
||||
AddDutyFreeBagUpgradeButton(parent, new Vector2(190f, -560f));
|
||||
|
||||
AddResultImage(parent, "Duty Free Mileage Price Tag", LoadDutyFreeResourceSprite(DutyFreePriceTagResourcePath), new Vector2(1000f, -48f), new Vector2(230f, 100f), false, Color.white);
|
||||
AddResultText(parent, "Duty Free Mileage Label", "보유 마일리지", new Vector2(990f, -26f), new Vector2(118f, 20f), 14f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 0.96f), TextAlignmentOptions.MidlineLeft);
|
||||
AddResultText(parent, "Duty Free Mileage Value", saveData.totalMileage + " M", new Vector2(1000f, -45f), new Vector2(122f, 28f), 21f, FontStyles.Bold, new Color(1f, 0.90f, 0.38f, 1f), TextAlignmentOptions.MidlineLeft);
|
||||
}
|
||||
|
||||
private void AddDutyFreeEquipSlot(RectTransform parent, int slotIndex, Vector2 topLeftPosition) {
|
||||
bool unlocked = slotIndex < saveData.bagSlots;
|
||||
DutyFreeItemType itemType = unlocked ? GetEquippedDutyFreeItem(slotIndex) : DutyFreeItemType.None;
|
||||
bool hasItem = itemType != DutyFreeItemType.None;
|
||||
|
||||
GameObject slotObject = CreateUiObject("Duty Free Equip Slot " + (slotIndex + 1), parent, typeof(Image), typeof(Button));
|
||||
RectTransform slotRect = slotObject.GetComponent<RectTransform>();
|
||||
slotRect.anchorMin = new Vector2(0f, 1f);
|
||||
slotRect.anchorMax = new Vector2(0f, 1f);
|
||||
slotRect.pivot = new Vector2(0f, 1f);
|
||||
slotRect.anchoredPosition = topLeftPosition;
|
||||
slotRect.sizeDelta = new Vector2(64f, 64f);
|
||||
|
||||
Image slotImage = slotObject.GetComponent<Image>();
|
||||
if(hasItem)
|
||||
{
|
||||
slotImage.sprite = LoadDutyFreeResourceSprite(DutyFreeOccupiedSlotResourcePath);
|
||||
slotImage.color = slotImage.sprite != null ? Color.white : new Color(0.05f, 0.16f, 0.20f, 0.88f);
|
||||
}
|
||||
else if(unlocked)
|
||||
{
|
||||
slotImage.sprite = LoadDutyFreeResourceSprite(DutyFreeActiveSlotResourcePath);
|
||||
slotImage.color = slotImage.sprite != null ? Color.white : new Color(0.58f, 0.36f, 0.18f, 0.88f);
|
||||
}
|
||||
else
|
||||
{
|
||||
slotImage.sprite = LoadDutyFreeResourceSprite(DutyFreeInactiveSlotResourcePath);
|
||||
slotImage.color = slotImage.sprite != null ? Color.white : new Color(0.35f, 0.35f, 0.35f, 0.78f);
|
||||
}
|
||||
|
||||
slotImage.preserveAspect = true;
|
||||
slotImage.raycastTarget = hasItem;
|
||||
|
||||
Button slotButton = slotObject.GetComponent<Button>();
|
||||
slotButton.targetGraphic = slotImage;
|
||||
slotButton.interactable = hasItem;
|
||||
slotButton.navigation = new Navigation {
|
||||
mode = Navigation.Mode.None
|
||||
};
|
||||
|
||||
if(hasItem)
|
||||
{
|
||||
int capturedSlotIndex = slotIndex;
|
||||
slotButton.onClick.AddListener(delegate { UnequipDutyFreeSlot(capturedSlotIndex); });
|
||||
}
|
||||
|
||||
AddResultText(slotRect, "Duty Free Slot Number", (slotIndex + 1).ToString(), new Vector2(3f, -3f), new Vector2(18f, 18f), 10f, FontStyles.Bold, new Color(0.78f, 0.92f, 0.97f, 0.94f), TextAlignmentOptions.Center);
|
||||
|
||||
if(hasItem)
|
||||
{
|
||||
AddResultImage(slotRect, "Duty Free Slot Icon", GetDutyFreeItemSprite(itemType), new Vector2(32f, -31f), new Vector2(36f, 36f), true, Color.white);
|
||||
AddResultText(slotRect, "Duty Free Slot Name", GetDutyFreeItemShortName(itemType), new Vector2(5f, -50f), new Vector2(54f, 12f), 8f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 0.96f), TextAlignmentOptions.Center);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDutyFreeBagUpgradeButton(RectTransform parent, Vector2 topLeftPosition) {
|
||||
bool isMax = saveData.bagSlots >= 3;
|
||||
bool canBuy = !isMax && saveData.totalMileage >= BagSlotUpgradeCost;
|
||||
|
||||
GameObject buttonObject = CreateUiObject("Duty Free Bag Upgrade", parent, typeof(Image), typeof(Button));
|
||||
RectTransform buttonRect = buttonObject.GetComponent<RectTransform>();
|
||||
buttonRect.anchorMin = new Vector2(0f, 1f);
|
||||
buttonRect.anchorMax = new Vector2(0f, 1f);
|
||||
buttonRect.pivot = new Vector2(0f, 1f);
|
||||
buttonRect.anchoredPosition = topLeftPosition;
|
||||
buttonRect.sizeDelta = new Vector2(160f, 64f);
|
||||
|
||||
Image buttonImage = buttonObject.GetComponent<Image>();
|
||||
buttonImage.sprite = LoadUiSprite(
|
||||
canBuy ? DutyFreeButtonPrimaryResourcePath : DutyFreeButtonDisabledResourcePath,
|
||||
canBuy ? "Assets/Resources/UI_DutyFreeButton_PrimaryYellow.png" : "Assets/Resources/UI_DutyFreeButton_DisabledGray.png");
|
||||
buttonImage.color = canBuy
|
||||
? Color.white
|
||||
: (buttonImage.sprite != null ? Color.white : new Color(0.36f, 0.43f, 0.47f, 0.76f));
|
||||
buttonImage.preserveAspect = false;
|
||||
buttonImage.raycastTarget = canBuy;
|
||||
|
||||
Button button = buttonObject.GetComponent<Button>();
|
||||
button.targetGraphic = buttonImage;
|
||||
button.interactable = canBuy;
|
||||
button.navigation = new Navigation {
|
||||
mode = Navigation.Mode.None
|
||||
};
|
||||
button.onClick.AddListener(BuyBagSlotUpgrade);
|
||||
|
||||
AddResultImage(buttonRect, "Duty Free Bag Upgrade Icon", LoadUiSprite("", DutyFreeBackpackAssetPath), new Vector2(45f, -32f), new Vector2(42f, 42f), true, canBuy ? Color.white : new Color(1f, 1f, 1f, 0.48f));
|
||||
AddResultText(buttonRect, "Duty Free Bag Upgrade Label", isMax ? "가방 MAX" : "가방 +1", new Vector2(75f, -11f), new Vector2(66f, 24f), 16f, FontStyles.Bold, canBuy ? new Color(0.06f, 0.16f, 0.22f, 1f) : new Color(0.72f, 0.80f, 0.84f, 0.92f), TextAlignmentOptions.MidlineLeft);
|
||||
AddResultText(buttonRect, "Duty Free Bag Upgrade Cost", isMax ? "" : BagSlotUpgradeCost + " M", new Vector2(85f, -36f), new Vector2(66f, 18f), 14f, FontStyles.Bold, canBuy ? new Color(0.87f, 0.55f, 0.08f, 1f) : new Color(0.62f, 0.68f, 0.70f, 0.92f), TextAlignmentOptions.MidlineLeft);
|
||||
}
|
||||
|
||||
private void AddDutyFreeItemCard(RectTransform parent, string itemName, DutyFreeItemType itemType, int cost, int stock, Sprite itemSprite, UnityEngine.Events.UnityAction buyAction, Vector2 topLeftPosition) {
|
||||
bool canBuy = CanBuyDutyFreeItem(itemType, cost);
|
||||
bool hasFreeSlot = HasFreeDutyFreeSlot();
|
||||
int equippedCount = GetEquippedDutyFreeItemCount(itemType);
|
||||
bool canEquip = stock > equippedCount && hasFreeSlot;
|
||||
bool canInteract = canEquip || canBuy;
|
||||
GameObject cardObject = CreateUiObject("Duty Free Item " + itemName, parent, typeof(Image));
|
||||
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, 288f);
|
||||
|
||||
Image cardImage = cardObject.GetComponent<Image>();
|
||||
cardImage.sprite = GetDutyFreeProductCardSprite(itemType);
|
||||
cardImage.color = cardImage.sprite != null
|
||||
? (canInteract ? Color.white : new Color(0.68f, 0.70f, 0.72f, 0.92f))
|
||||
: canInteract
|
||||
? new Color(0.97f, 0.91f, 0.78f, 0.96f)
|
||||
: new Color(0.40f, 0.45f, 0.48f, 0.88f);
|
||||
cardImage.preserveAspect = false;
|
||||
cardImage.raycastTarget = false;
|
||||
|
||||
Color textColor = canInteract
|
||||
? new Color(0.06f, 0.16f, 0.22f, 1f)
|
||||
: new Color(0.78f, 0.84f, 0.86f, 1f);
|
||||
|
||||
AddResultImage(cardRect, "Duty Free " + itemName + " Image", itemSprite, new Vector2(103f, -107f), new Vector2(92f, 96f), true, canInteract ? Color.white : new Color(1f, 1f, 1f, 0.54f));
|
||||
Image priceTagImage = AddResultImage(cardRect, "Duty Free " + itemName + " Price Tag", LoadDutyFreeResourceSprite(DutyFreeProductPriceTagResourcePath), new Vector2(151f, -150f), new Vector2(52f, 78f), true, canInteract ? Color.white : new Color(1f, 1f, 1f, 0.62f));
|
||||
priceTagImage.rectTransform.localEulerAngles = new Vector3(0f, 0f, 110f);
|
||||
TextMeshProUGUI priceText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Price", cost + "M", new Vector2(153f, -150f), new Vector2(40f, 18f), 11f, FontStyles.Bold, canInteract ? new Color(0.03f, 0.03f, 0.028f, 1f) : new Color(0.36f, 0.36f, 0.34f, 0.92f), TextAlignmentOptions.Center);
|
||||
priceText.rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
priceText.rectTransform.anchoredPosition = new Vector2(155f, -150f);
|
||||
priceText.rectTransform.localEulerAngles = new Vector3(0f, 0f, 20f);
|
||||
TextMeshProUGUI nameText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Name", itemName + "\n" + GetDutyFreeItemEffectText(itemType), new Vector2(103f, -199f), new Vector2(126f, 34f), 13f, FontStyles.Bold, textColor, TextAlignmentOptions.Center);
|
||||
nameText.lineSpacing = -8f;
|
||||
|
||||
GameObject buyObject = CreateUiObject("Duty Free " + itemName + " Buy Area", cardRect, typeof(Image), typeof(Button));
|
||||
RectTransform buyRect = buyObject.GetComponent<RectTransform>();
|
||||
buyRect.anchorMin = new Vector2(0f, 1f);
|
||||
buyRect.anchorMax = new Vector2(0f, 1f);
|
||||
buyRect.pivot = new Vector2(0f, 1f);
|
||||
buyRect.anchoredPosition = new Vector2(39f, -232f);
|
||||
buyRect.sizeDelta = new Vector2(128f, 22f);
|
||||
|
||||
Image buyImage = buyObject.GetComponent<Image>();
|
||||
buyImage.color = Color.clear;
|
||||
buyImage.raycastTarget = canInteract;
|
||||
|
||||
Button buyButton = buyObject.GetComponent<Button>();
|
||||
buyButton.targetGraphic = buyImage;
|
||||
buyButton.interactable = canInteract;
|
||||
buyButton.transition = Selectable.Transition.None;
|
||||
buyButton.navigation = new Navigation {
|
||||
mode = Navigation.Mode.None
|
||||
};
|
||||
buyButton.onClick.AddListener(buyAction);
|
||||
|
||||
TextMeshProUGUI buyText = AddResultText(buyRect, "Duty Free " + itemName + " Buy Label", GetDutyFreePurchaseLabel(itemType, canEquip, canBuy, hasFreeSlot, stock, equippedCount), Vector2.zero, new Vector2(128f, 22f), 11f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 1f), TextAlignmentOptions.Center);
|
||||
buyText.outlineColor = new Color(0f, 0.04f, 0.07f, 0.98f);
|
||||
buyText.outlineWidth = 0.12f;
|
||||
}
|
||||
|
||||
private void AddDutyFreeSupplementCard(RectTransform parent, string itemName, int cost, int purchaseCount, Sprite itemSprite, UnityEngine.Events.UnityAction buyAction, Vector2 topLeftPosition) {
|
||||
bool isMax = purchaseCount >= MaxSupplementPurchases;
|
||||
bool alreadyPurchasedThisStage = HasPurchasedSupplementInDutyFreeStage();
|
||||
bool canBuy = CanBuySupplement();
|
||||
|
||||
GameObject cardObject = CreateUiObject("Duty Free Item " + itemName, parent, typeof(Image));
|
||||
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, 288f);
|
||||
|
||||
Image cardImage = cardObject.GetComponent<Image>();
|
||||
cardImage.sprite = GetDutyFreeProductCardSprite(DutyFreeItemType.Supplement);
|
||||
cardImage.color = cardImage.sprite != null
|
||||
? (canBuy || isMax ? Color.white : new Color(0.68f, 0.70f, 0.72f, 0.92f))
|
||||
: canBuy
|
||||
? new Color(0.97f, 0.91f, 0.78f, 0.96f)
|
||||
: new Color(0.40f, 0.45f, 0.48f, 0.88f);
|
||||
cardImage.preserveAspect = false;
|
||||
cardImage.raycastTarget = false;
|
||||
|
||||
Color textColor = canBuy || isMax
|
||||
? new Color(0.06f, 0.16f, 0.22f, 1f)
|
||||
: new Color(0.78f, 0.84f, 0.86f, 1f);
|
||||
|
||||
AddResultImage(cardRect, "Duty Free " + itemName + " Image", itemSprite, new Vector2(103f, -107f), new Vector2(92f, 96f), true, canBuy || isMax ? Color.white : new Color(1f, 1f, 1f, 0.54f));
|
||||
Image priceTagImage = AddResultImage(cardRect, "Duty Free " + itemName + " Price Tag", LoadDutyFreeResourceSprite(DutyFreeProductPriceTagResourcePath), new Vector2(151f, -150f), new Vector2(52f, 78f), true, canBuy || isMax ? Color.white : new Color(1f, 1f, 1f, 0.62f));
|
||||
priceTagImage.rectTransform.localEulerAngles = new Vector3(0f, 0f, 110f);
|
||||
|
||||
TextMeshProUGUI priceText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Price", isMax ? "MAX" : cost + "M", new Vector2(153f, -150f), new Vector2(40f, 18f), 11f, FontStyles.Bold, canBuy || isMax ? new Color(0.03f, 0.03f, 0.028f, 1f) : new Color(0.36f, 0.36f, 0.34f, 0.92f), TextAlignmentOptions.Center);
|
||||
priceText.rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
priceText.rectTransform.anchoredPosition = new Vector2(155f, -150f);
|
||||
priceText.rectTransform.localEulerAngles = new Vector3(0f, 0f, 20f);
|
||||
|
||||
TextMeshProUGUI nameText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Name", itemName + "\n" + GetDutyFreeSupplementEffectText(purchaseCount), new Vector2(103f, -199f), new Vector2(126f, 34f), 13f, FontStyles.Bold, textColor, TextAlignmentOptions.Center);
|
||||
nameText.lineSpacing = -8f;
|
||||
|
||||
GameObject buyObject = CreateUiObject("Duty Free " + itemName + " Buy Area", cardRect, typeof(Image), typeof(Button));
|
||||
RectTransform buyRect = buyObject.GetComponent<RectTransform>();
|
||||
buyRect.anchorMin = new Vector2(0f, 1f);
|
||||
buyRect.anchorMax = new Vector2(0f, 1f);
|
||||
buyRect.pivot = new Vector2(0f, 1f);
|
||||
buyRect.anchoredPosition = new Vector2(39f, -232f);
|
||||
buyRect.sizeDelta = new Vector2(128f, 22f);
|
||||
|
||||
Image buyImage = buyObject.GetComponent<Image>();
|
||||
buyImage.color = Color.clear;
|
||||
buyImage.raycastTarget = canBuy;
|
||||
|
||||
Button buyButton = buyObject.GetComponent<Button>();
|
||||
buyButton.targetGraphic = buyImage;
|
||||
buyButton.interactable = canBuy;
|
||||
buyButton.transition = Selectable.Transition.None;
|
||||
buyButton.navigation = new Navigation {
|
||||
mode = Navigation.Mode.None
|
||||
};
|
||||
buyButton.onClick.AddListener(buyAction);
|
||||
|
||||
TextMeshProUGUI buyText = AddResultText(buyRect, "Duty Free " + itemName + " Buy Label", GetDutyFreeSupplementPurchaseLabel(canBuy, isMax, alreadyPurchasedThisStage), Vector2.zero, new Vector2(128f, 22f), 11f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 1f), TextAlignmentOptions.Center);
|
||||
buyText.outlineColor = new Color(0f, 0.04f, 0.07f, 0.98f);
|
||||
buyText.outlineWidth = 0.12f;
|
||||
}
|
||||
|
||||
private void AddDutyFreeNextTravelButton() {
|
||||
GameObject buttonObject = CreateUiObject("Duty Free Next Travel Sign", 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 = new Vector2(548f, -247f);
|
||||
buttonRect.sizeDelta = new Vector2(200f, 160f);
|
||||
|
||||
Image buttonImage = buttonObject.GetComponent<Image>();
|
||||
buttonImage.sprite = LoadDutyFreeResourceSprite(DutyFreeDirectionSignResourcePath);
|
||||
buttonImage.color = buttonImage.sprite != null ? Color.white : new Color(0.82f, 0.91f, 0.96f, 0.90f);
|
||||
buttonImage.preserveAspect = true;
|
||||
buttonImage.raycastTarget = true;
|
||||
|
||||
Button button = buttonObject.GetComponent<Button>();
|
||||
button.targetGraphic = buttonImage;
|
||||
button.onClick.AddListener(ShowMapPreview);
|
||||
button.navigation = new Navigation {
|
||||
mode = Navigation.Mode.None
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8edc62b4b60248ce8001165fb0588bf8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,377 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public partial class GameFlowManager {
|
||||
private void ShowResult() {
|
||||
if(TryLoadFlowScene(ResultSceneName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureOverlay();
|
||||
ClearOverlay();
|
||||
SetOverlayVisible(true);
|
||||
BuildResultScreen();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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, ResultPassportPanelAssetPath);
|
||||
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);
|
||||
|
||||
AddResultImage(parent, "Result Rank Badge", rankSprite, new Vector2(150f, -140f), new Vector2(48f, 48f), 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);
|
||||
AddResultCenteredText(parent, "Result Title", title, new Vector2(244f, -140f), new Vector2(220f, 50f), 25f, FontStyles.Bold, titleColor, TextAlignmentOptions.Center);
|
||||
|
||||
AddResultRouteBox(parent, "From", GetResultOriginAirportCode(resultMap), GetResultOriginCityName(resultMap), new Vector2(440f, -122f));
|
||||
AddResultRouteBox(parent, "To", GetResultDestinationAirportCode(resultMap), GetResultDestinationCityName(resultMap), new Vector2(660f, -122f));
|
||||
AddResultBoardingField(parent, "Flight", "항공편", GetResultFlightName(resultMap), new Vector2(400f, -253f));
|
||||
AddResultBoardingField(parent, "Seat", "좌석", GetResultSeatName(resultMap), new Vector2(497f, -253f));
|
||||
AddResultBoardingField(parent, "Boarding", "탑승", System.DateTime.Now.ToString("HH:mm"), new Vector2(595f, -253f));
|
||||
AddResultBoardingField(parent, "Class", "클래스", lastResultCleared ? "일반석" : "대기", new Vector2(695f, -253f));
|
||||
}
|
||||
|
||||
private void AddResultStats(RectTransform parent, int gainedMileage, int shownDistance, int targetDistance) {
|
||||
AddResultStat(parent, "Mileage", LoadUiSprite("", MileageIconAssetPath), "마일리지", "+" + gainedMileage, new Vector2(812f, -140f));
|
||||
AddResultStat(parent, "Time", LoadUiSprite("", TimerIconAssetPath), "도착 시간", lastResultTime.ToString("0.0") + "s", new Vector2(903f, -140f));
|
||||
|
||||
string distance = targetDistance > 0
|
||||
? shownDistance + "/" + targetDistance + "m"
|
||||
: shownDistance + "m";
|
||||
AddResultStat(parent, "Distance", LoadUiSprite("", CheckpointIconAssetPath), "이동 거리", distance, new Vector2(993f, -140f));
|
||||
}
|
||||
|
||||
private void AddResultTickets(RectTransform parent, MapDefinition resultMap, int rewardMileage) {
|
||||
AddResultTicket(
|
||||
parent,
|
||||
"Destination",
|
||||
LoadUiSprite("", CheckpointIconAssetPath),
|
||||
"목적지",
|
||||
GetResultDestinationCityName(resultMap),
|
||||
new Vector2(812f, -251f));
|
||||
|
||||
AddResultTicket(
|
||||
parent,
|
||||
"Souvenir",
|
||||
lastResultCleared ? GetResultSouvenirSprite(resultMap) : LoadUiSprite("", SouvenirCollectionIconAssetPath),
|
||||
"보상",
|
||||
lastResultCleared ? GetResultSouvenirName(resultMap) : "다음 도전",
|
||||
new Vector2(900f, -251f));
|
||||
|
||||
AddResultTicket(
|
||||
parent,
|
||||
"Total Mileage",
|
||||
LoadUiSprite("", MileageIconAssetPath),
|
||||
"보유",
|
||||
saveData.totalMileage + " M",
|
||||
new Vector2(991f, -251f));
|
||||
}
|
||||
|
||||
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, 5f), new Vector2(26f, 26f), true, Color.white);
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Value", value, centerPosition + new Vector2(0f, -17f), new Vector2(90f, 22f), 12f, FontStyles.Bold, new Color(0.05f, 0.17f, 0.25f, 1f), TextAlignmentOptions.Center);
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Label", label, centerPosition + new Vector2(0f, -32f), new Vector2(90f, 16f), 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 centerPosition) {
|
||||
AddResultImage(parent, "Result " + objectName + " Icon", iconSprite, centerPosition + new Vector2(0f, 27f), new Vector2(34f, 34f), true, Color.white);
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Label", label, centerPosition + new Vector2(0f, -9f), new Vector2(110f, 18f), 11f, FontStyles.Bold, new Color(0.43f, 0.58f, 0.64f, 0.96f), TextAlignmentOptions.Center);
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Value", value, centerPosition + new Vector2(0f, -35f), new Vector2(118f, 26f), 11f, FontStyles.Bold, new Color(0.05f, 0.18f, 0.27f, 1f), TextAlignmentOptions.Center);
|
||||
}
|
||||
|
||||
private void AddResultRouteBox(RectTransform parent, string objectName, string code, string cityName, Vector2 centerPosition) {
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Airport Code", code, centerPosition + new Vector2(0f, 7f), new Vector2(150f, 48f), 34f, FontStyles.Bold, new Color(0.05f, 0.17f, 0.27f, 1f), TextAlignmentOptions.Center);
|
||||
AddResultCenteredText(parent, "Result " + objectName + " City", cityName, centerPosition + new Vector2(0f, -30f), new Vector2(160f, 22f), 12f, FontStyles.Bold, new Color(0.43f, 0.58f, 0.64f, 0.96f), TextAlignmentOptions.Center);
|
||||
}
|
||||
|
||||
private void AddResultBoardingField(RectTransform parent, string objectName, string label, string value, Vector2 centerPosition) {
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Label", label, centerPosition + new Vector2(0f, 13f), new Vector2(104f, 17f), 9f, FontStyles.Bold, new Color(0.43f, 0.58f, 0.64f, 0.96f), TextAlignmentOptions.Center);
|
||||
AddResultCenteredText(parent, "Result " + objectName + " Value", value, centerPosition + new Vector2(0f, -12f), new Vector2(108f, 28f), 14f, FontStyles.Bold, new Color(0.05f, 0.18f, 0.27f, 1f), TextAlignmentOptions.Center);
|
||||
}
|
||||
|
||||
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 TextMeshProUGUI AddResultCenteredText(RectTransform parent, string objectName, string text, Vector2 centerPosition, Vector2 size, float fontSize, FontStyles fontStyle, Color color, TextAlignmentOptions alignment) {
|
||||
Vector2 topLeftPosition = centerPosition + new Vector2(-size.x * 0.5f, size.y * 0.5f);
|
||||
return AddResultText(parent, objectName, text, topLeftPosition, size, fontSize, fontStyle, color, alignment);
|
||||
}
|
||||
|
||||
private string GetResultOriginAirportCode(MapDefinition resultMap) {
|
||||
return GetAirportCode(GetResultOriginMapId(resultMap));
|
||||
}
|
||||
|
||||
private string GetResultDestinationAirportCode(MapDefinition resultMap) {
|
||||
return GetAirportCode(GetResultDestinationMapId(resultMap));
|
||||
}
|
||||
|
||||
private string GetResultOriginCityName(MapDefinition resultMap) {
|
||||
return GetAirportCityName(GetResultOriginMapId(resultMap));
|
||||
}
|
||||
|
||||
private string GetResultDestinationCityName(MapDefinition resultMap) {
|
||||
return GetAirportCityName(GetResultDestinationMapId(resultMap));
|
||||
}
|
||||
|
||||
private MapId GetResultOriginMapId(MapDefinition resultMap) {
|
||||
if(resultMap == null)
|
||||
{
|
||||
return MapId.TutorialIncheon;
|
||||
}
|
||||
|
||||
return resultMap.mapId;
|
||||
}
|
||||
|
||||
private MapId GetResultDestinationMapId(MapDefinition resultMap) {
|
||||
if(resultMap == null)
|
||||
{
|
||||
return MapId.Japan;
|
||||
}
|
||||
|
||||
if(resultMap.hasNextMap)
|
||||
{
|
||||
return resultMap.nextMapId;
|
||||
}
|
||||
|
||||
return resultMap.mapId;
|
||||
}
|
||||
|
||||
private string GetAirportCode(MapId mapId) {
|
||||
switch(mapId)
|
||||
{
|
||||
case MapId.TutorialIncheon:
|
||||
return "ICN";
|
||||
case MapId.Japan:
|
||||
return "FUK";
|
||||
case MapId.China:
|
||||
return "PVG";
|
||||
case MapId.America:
|
||||
return "LAX";
|
||||
default:
|
||||
return "TRP";
|
||||
}
|
||||
}
|
||||
|
||||
private string GetAirportCityName(MapId mapId) {
|
||||
switch(mapId)
|
||||
{
|
||||
case MapId.TutorialIncheon:
|
||||
return "인천공항";
|
||||
case MapId.Japan:
|
||||
return "후쿠오카";
|
||||
case MapId.China:
|
||||
return "상하이";
|
||||
case MapId.America:
|
||||
return "로스앤젤레스";
|
||||
default:
|
||||
return "여행지";
|
||||
}
|
||||
}
|
||||
|
||||
private string GetResultFlightName(MapDefinition resultMap) {
|
||||
int mapNumber = resultMap != null ? (int)resultMap.mapId + 1 : 1;
|
||||
return "UNR-" + mapNumber.ToString("000");
|
||||
}
|
||||
|
||||
private string GetResultSeatName(MapDefinition resultMap) {
|
||||
int mapNumber = resultMap != null ? (int)resultMap.mapId + 1 : 1;
|
||||
return (10 + mapNumber).ToString() + "A";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bf10c40d6cc4b319e90f0bf9279966b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user