DEG-25 [Feat] 강화 애니메이션 및 코드 리팩토링

This commit is contained in:
99jamin 2025-05-02 11:41:32 +09:00
parent 5eed0c81c5
commit 6c7536c1ae
10 changed files with 1317 additions and 939 deletions

BIN
Assets/KJM/KJM.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -11,11 +11,11 @@ using Random = UnityEngine.Random;
public class TestScript : MonoBehaviour,ISaveable
{
//던전
private int attackPowerLevel;
private int attackSpeedLevel;
private int heartLevel;
private int moveSpeedLevel;
private int dashCoolDownLevel;
// private int attackPowerLevel;
// private int attackSpeedLevel;
// private int heartLevel;
// private int moveSpeedLevel;
// private int dashCoolDownLevel;
private int stageLevel;
//일상
@ -34,10 +34,10 @@ public class TestScript : MonoBehaviour,ISaveable
float floatValue = Random.Range(0f, 2f);
int intValue = Random.Range(0, 10);
attackPowerLevel = intValue;
attackSpeedLevel = intValue;
heartLevel = intValue;
moveSpeedLevel = intValue;
// attackPowerLevel = intValue;
// attackSpeedLevel = intValue;
// heartLevel = intValue;
// moveSpeedLevel = intValue;
stageLevel = intValue;
@ -59,11 +59,11 @@ public class TestScript : MonoBehaviour,ISaveable
{
if (save?.dungeonSave != null)
{
attackPowerLevel = save.dungeonSave.attackPowerLevel;
attackSpeedLevel = save.dungeonSave.attackSpeedLevel;
heartLevel = save.dungeonSave.heartLevel;
moveSpeedLevel = save.dungeonSave.moveSpeedLevel;
dashCoolDownLevel = save.dungeonSave.dashCoolDownLevel;
// attackPowerLevel = save.dungeonSave.attackPowerLevel;
// attackSpeedLevel = save.dungeonSave.attackSpeedLevel;
// heartLevel = save.dungeonSave.heartLevel;
// moveSpeedLevel = save.dungeonSave.moveSpeedLevel;
// dashCoolDownLevel = save.dungeonSave.dashCoolDownLevel;
stageLevel = save.dungeonSave.stageLevel;
}
@ -90,11 +90,11 @@ public class TestScript : MonoBehaviour,ISaveable
{
dungeonSave = new DungeonSave()
{
attackPowerLevel = this.attackPowerLevel,
attackSpeedLevel = this.attackSpeedLevel,
heartLevel = this.heartLevel,
moveSpeedLevel = this.moveSpeedLevel,
dashCoolDownLevel = this.dashCoolDownLevel,
// attackPowerLevel = this.attackPowerLevel,
// attackSpeedLevel = this.attackSpeedLevel,
// heartLevel = this.heartLevel,
// moveSpeedLevel = this.moveSpeedLevel,
// dashCoolDownLevel = this.dashCoolDownLevel,
stageLevel = this.stageLevel,
},

Binary file not shown.

Binary file not shown.

BIN
Assets/KJM/KJM_Test/Upgrade/Sprite/Max!.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,150 @@
fileFormatVersion: 2
guid: d32af0a170ee68a4baafe29418a7c7e7
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: Max!_0
rect:
serializedVersion: 2
x: 4
y: 72
width: 1003
height: 901
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 79aa739531277a148a344ca8f1df525f
internalID: -1446879825
vertices: []
indices:
edges: []
weights: []
outline: []
physicsShape: []
bones: []
spriteID: 4211bd0831b53be45a41c594c940d0ca
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable:
Max!_0: -1446879825
Max!_1: -1829641980
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,16 +7,19 @@ using UnityEngine.UI;
public class UpgradeCard : MonoBehaviour
{
public Sprite[] upgradeSprite;
public Sprite[] upgradeSpriteResource;
UpgradeManager upgradeManager;
StatType currentStatType;
Image[] upgradeIcon;
TextMeshProUGUI upgradeText;
void Awake()
{
upgradeManager = UpgradeManager.Instance;
upgradeIcon = gameObject.GetComponentsInChildren<Image>();
upgradeText = gameObject.GetComponentInChildren<TextMeshProUGUI>();
}
public void Init(StatType statType)
@ -24,13 +27,18 @@ public class UpgradeCard : MonoBehaviour
currentStatType = statType;
//텍스트 설정
upgradeText.text = StatNameText(currentStatType) + " Lv." + (UpgradeManager.Instance.upgradeStat.CurrentUpgradeLevel(currentStatType));
upgradeText.text = StatNameText(currentStatType) + " Lv." + UpgradeLevelText(currentStatType);
//아이콘 설정
upgradeIcon[1].sprite = upgradeSprite[(int)statType-1];
upgradeIcon[1].sprite = upgradeSpriteResource[(int)statType-1];
}
/// <summary>
/// 강화 요소 텍스트 반환
/// </summary>
/// <param name="statType"></param>
/// <returns></returns>
private String StatNameText(StatType statType)
{
switch (statType)
@ -45,15 +53,43 @@ public class UpgradeCard : MonoBehaviour
return "대시 쿨타임";
case StatType.Heart:
return "최대 하트";
case StatType.Max:
return "용사";
default:
return "";
}
}
/// <summary>
/// 레벨 텍스트 반환
/// </summary>
/// <param name="statType"></param>
/// <returns></returns>
private String UpgradeLevelText(StatType statType)
{
if (statType == StatType.Max)
return "999";
if (upgradeManager.upgradeStat.IsOneBeforeMax(statType))
{
return "Max";
}
else
{
return (upgradeManager.upgradeStat.CurrentUpgradeLevel(statType)+1).ToString();
}
}
/// <summary>
/// 강화 카드 클릭
/// </summary>
public void ClickCard()
{
//레벨 증가
UpgradeManager.Instance.upgradeStat.UpgradeLevel(currentStatType);
Debug.Log(UpgradeManager.Instance.upgradeStat.CurrentUpgradeLevel(currentStatType));
upgradeManager.upgradeStat.UpgradeLevel(currentStatType);
//UI 비활성화
upgradeManager.DestroyUpgradeCard();
}
}

View File

@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
@ -11,13 +12,14 @@ public enum StatType
AttackSpeed,
MoveSpeed,
DashCoolDown,
Heart
Heart,
Max
}
public class UpgradeManager : Singleton<UpgradeManager>
{
//현재 캔버스 찾는 함수 설정
public Canvas canvas;
//캔버스 프리팹 사용..?
Canvas canvas;
public GameObject backgroundPanel;
public Button upgradeButton;
@ -25,40 +27,212 @@ public class UpgradeManager : Singleton<UpgradeManager>
public UpgradeStat upgradeStat;
private readonly List<int> statNumbers = new List<int> { 1, 2, 3, 4, 5 };
public void GenerateUpgradeCard()
{
//카드 번호 셔플
ShuffleStatNumber();
//강화 수치가 맥스인 항목은 제외하는 로직
private List<int> stats = new List<int>();
private RectTransform backgroundRectTransform;
private List<Button> cards = new List<Button>();
//배경 패널 생성 애니메이션
RectTransform backgroundRectTransform = Instantiate(backgroundPanel,canvas.transform).GetComponent<RectTransform>();
var card1 = Instantiate(upgradeButton, backgroundRectTransform);
card1.GetComponent<UpgradeCard>().Init((StatType)statNumbers[0]);
var card2 = Instantiate(upgradeButton, backgroundRectTransform);
card2.GetComponent<UpgradeCard>().Init((StatType)statNumbers[1]);
var card3 = Instantiate(upgradeButton, backgroundRectTransform);
card3.GetComponent<UpgradeCard>().Init((StatType)statNumbers[2]);
public void Start()
{
if(canvas == null)
canvas = FindObjectOfType<Canvas>();
}
// 리스트 셔플
private void ShuffleStatNumber()
public void StartUpgrade()
{
DrawStatNumber();
//배경 패널 생성
if(backgroundRectTransform == null)
backgroundRectTransform = Instantiate(backgroundPanel,canvas.transform).GetComponent<RectTransform>();
//배경 패널 애니메이션 적용
backgroundRectTransform.gameObject.SetActive(true);
StartCoroutine(CoFade(backgroundRectTransform.gameObject, 0f,0.7f,0.2f));
EnsureCardListSize(3);
//카드 생성
if (stats.Count == 0)
{
//모든 강화가 MAX일때
if(cards[0] == null)
cards[0] = Instantiate(upgradeButton, backgroundRectTransform);
cards[0].gameObject.SetActive(true);
cards[0].GetComponent<UpgradeCard>().Init(StatType.Max);
StartCoroutine(CoFade(cards[0].gameObject, 0f,1f,0.4f, () =>
{
cards[0].GetComponent<CanvasGroup>().interactable = true;
}));
}
else
{
for (int i = 0; i < Mathf.Min(stats.Count, 3); i++)
{
if(cards[i] == null)
cards[i] = Instantiate(upgradeButton, backgroundRectTransform);
cards[i].gameObject.SetActive(true);
cards[i].GetComponent<UpgradeCard>().Init((StatType)stats[i]);
var index = i;
StartCoroutine(CoFade(cards[i].gameObject, 0f,1f,0.4f, () =>
{
cards[index].GetComponent<CanvasGroup>().interactable = true;
}));
}
}
}
/// <summary>
/// 중복되지 않는 랜덤한 스탯 번호 뽑기
/// </summary>
private void DrawStatNumber()
{
stats.Clear();
//번호 셔플
for (int i = 0; i < statNumbers.Count; i++)
{
int randIndex = Random.Range(i, statNumbers.Count);
(statNumbers[i], statNumbers[randIndex]) = (statNumbers[randIndex], statNumbers[i]);
}
//이미 강화 수치가 MAX이면 제외
foreach (var t in statNumbers)
{
if (upgradeStat.IsMax((StatType)t))
{
continue;
}
else
{
stats.Add(t);
}
}
}
/// <summary>
/// 리스트 사이즈 보장
/// </summary>
/// <param name="index"></param>
private void EnsureCardListSize(int index)
{
while (cards.Count <= index)
{
cards.Add(null);
}
}
/// <summary>
/// 업그레이드 창 비활성화
/// </summary>
public void DestroyUpgradeCard()
{
// 카드 비활성화
if (stats.Count == 0)
{
StartCoroutine(CoFade(cards[0].gameObject, 1f,0f,0.4f,() =>
{
cards[0].gameObject.SetActive(false);
backgroundRectTransform.gameObject.SetActive(false);
}));
}
else
{
for (int i = 0; i < Mathf.Min(stats.Count, 3); i++)
{
var index = i;
StartCoroutine(CoFade(cards[i].gameObject, 1f,0f,0.4f,() =>
{
cards[index].gameObject.SetActive(false);
if (index == Mathf.Min(stats.Count, 3) - 1)
{
backgroundRectTransform.gameObject.SetActive(false);
}
}));
}
}
//배경 패널 비활성화
StartCoroutine(CoFade(backgroundRectTransform.gameObject, 0.7f,0f,0.2f));
}
/// <summary>
/// 페이드 애니메이션 코루틴
/// </summary>
/// <param name="target"></param>
/// <param name="fromAlpha"></param>
/// <param name="toAlpha"></param>
/// <param name="duration"></param>
/// <param name="onComplete"></param>
/// <returns></returns>
public IEnumerator CoFade(GameObject target, float fromAlpha, float toAlpha, float duration,System.Action onComplete = null)
{
float elapsedTime = 0f;
CanvasGroup canvasGroup = target.GetComponent<CanvasGroup>();
Image image = target.GetComponent<Image>();
if (canvasGroup == null && image == null)
{
Debug.LogError("CanvasGroup도 Image도 없습니다!");
yield break;
}
// 초기 설정
if (canvasGroup != null)
{
canvasGroup.alpha = fromAlpha;
canvasGroup.interactable = false;
}
else if (image != null)
{
Color color = image.color;
color.a = fromAlpha;
image.color = color;
}
while (elapsedTime < duration)
{
//float alpha = Mathf.Lerp(fromAlpha, toAlpha, elapsedTime / duration);
float t = Mathf.Clamp01(elapsedTime / duration);
float alpha = Mathf.Lerp(fromAlpha, toAlpha, t);
if (canvasGroup != null)
{
canvasGroup.alpha = alpha;
}
else if (image != null)
{
Color color = image.color;
color.a = alpha;
image.color = color;
}
elapsedTime += Time.deltaTime;
yield return null;
}
// 최종 보정 (정확한 값으로 마무리)
if (canvasGroup != null)
{
canvasGroup.alpha = toAlpha;
}
else if (image != null)
{
Color color = image.color;
color.a = toAlpha;
image.color = color;
}
onComplete?.Invoke();
}
protected override void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
}
}

View File

@ -2,119 +2,107 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UpgradeStat : MonoBehaviour,ISaveable
public class UpgradeStat : MonoBehaviour, ISaveable
{
private const int MAX_UPGRADES = 4;
private const int MAX_UPGRADES_HEART = 3;
private int attackPowerLevel = 1;
private int attackSpeedLevel = 1;
private int moveSpeedLevel = 1;
private int dashCoolDownLevel = 1;
private int heartLevel = 1;
/// <summary>
/// 강화 수치 올리는 함수
/// </summary>
/// <param name="number"></param>
public void UpgradeLevel(StatType statType)
private const int DEFAULT_MAX = 4;
private const int MAX_HEART = 3;
private readonly Dictionary<StatType, int> levels = new();
private readonly Dictionary<StatType, int> maxLevels = new()
{
switch (statType)
{ StatType.AttackPower, DEFAULT_MAX },
{ StatType.AttackSpeed, DEFAULT_MAX },
{ StatType.MoveSpeed, DEFAULT_MAX },
{ StatType.DashCoolDown, DEFAULT_MAX },
{ StatType.Heart, MAX_HEART }
};
void Awake()
{
foreach (var stat in maxLevels.Keys)
{
case StatType.AttackPower:
if(attackPowerLevel<MAX_UPGRADES)
attackPowerLevel++;
break;
case StatType.AttackSpeed:
if (attackSpeedLevel < MAX_UPGRADES)
attackSpeedLevel++;
break;
case StatType.MoveSpeed:
if(moveSpeedLevel < MAX_UPGRADES)
moveSpeedLevel++;
break;
case StatType.DashCoolDown:
if(dashCoolDownLevel < MAX_UPGRADES)
dashCoolDownLevel++;
break;
case StatType.Heart:
if(heartLevel < MAX_UPGRADES_HEART)
heartLevel++;
break;
default:
break;
levels[stat] = 1; // 기본값 초기화
}
}
/// <summary>
/// 현재 강화 수치 반환 함수
/// 강화 레벨 상승
/// </summary>
/// <param name="number"></param>
/// <param name="statType"></param>
public void UpgradeLevel(StatType statType)
{
if (!levels.ContainsKey(statType)) return;
if (levels[statType] < maxLevels[statType])
levels[statType]++;
}
/// <summary>
/// 현재 강화 레벨 반환
/// </summary>
/// <param name="statType"></param>
/// <returns></returns>
public int CurrentUpgradeLevel(StatType statType)
{
int currentUpgradeLevel = 0;
switch (statType)
{
case StatType.AttackPower:
currentUpgradeLevel = attackPowerLevel;
break;
case StatType.AttackSpeed:
currentUpgradeLevel = attackSpeedLevel;
break;
case StatType.MoveSpeed:
currentUpgradeLevel = moveSpeedLevel;
break;
case StatType.DashCoolDown:
currentUpgradeLevel = dashCoolDownLevel;
break;
case StatType.Heart:
currentUpgradeLevel = heartLevel;
break;
default:
break;
}
int max = statType == StatType.Heart ? MAX_UPGRADES_HEART : MAX_UPGRADES;
if (!levels.ContainsKey(statType))
return 0;
return (currentUpgradeLevel < 1 || currentUpgradeLevel > max)? 1 : currentUpgradeLevel;
int level = levels[statType];
return Mathf.Clamp(level, 1, maxLevels[statType]);
}
/// <summary>
/// 강화 수치 로컬에 저장
/// 최대 수치 검증
/// </summary>
/// <param name="statType"></param>
/// <returns></returns>
public bool IsMax(StatType statType)
{
return levels.ContainsKey(statType) && levels[statType] >= maxLevels[statType];
}
/// <summary>
/// 최대 수치 -1 검증
/// </summary>
/// <param name="statType"></param>
/// <returns></returns>
public bool IsOneBeforeMax(StatType statType)
{
return levels.ContainsKey(statType) && levels[statType] == maxLevels[statType] - 1;
}
/// <summary>
/// 세이브 매니저에 저장
/// </summary>
/// <returns></returns>
public Save ExtractSaveData()
{
return new Save
{
dungeonSave = new DungeonSave()
dungeonSave = new DungeonSave
{
attackPowerLevel = this.attackPowerLevel,
attackSpeedLevel = this.attackSpeedLevel,
heartLevel = this.heartLevel,
moveSpeedLevel = this.moveSpeedLevel,
dashCoolDownLevel = this.dashCoolDownLevel,
attackPowerLevel = levels[StatType.AttackPower],
attackSpeedLevel = levels[StatType.AttackSpeed],
moveSpeedLevel = levels[StatType.MoveSpeed],
dashCoolDownLevel = levels[StatType.DashCoolDown],
heartLevel = levels[StatType.Heart]
}
};
}
/// <summary>
/// 강화 수치 로컬에서 로드
/// 세이브 매니저에서 로드
/// </summary>
/// <param name="save"></param>
public void ApplySaveData(Save save)
{
if (save?.dungeonSave != null)
{
attackPowerLevel = save.dungeonSave.attackPowerLevel;
attackSpeedLevel = save.dungeonSave.attackSpeedLevel;
heartLevel = save.dungeonSave.heartLevel;
moveSpeedLevel = save.dungeonSave.moveSpeedLevel;
dashCoolDownLevel = save.dungeonSave.dashCoolDownLevel;
}
if (save?.dungeonSave == null) return;
levels[StatType.AttackPower] = save.dungeonSave.attackPowerLevel;
levels[StatType.AttackSpeed] = save.dungeonSave.attackSpeedLevel;
levels[StatType.MoveSpeed] = save.dungeonSave.moveSpeedLevel;
levels[StatType.DashCoolDown] = save.dungeonSave.dashCoolDownLevel;
levels[StatType.Heart] = save.dungeonSave.heartLevel;
}
}

File diff suppressed because one or more lines are too long