ㅇ
//등급별 캐싱을 통해 가챠마다 리스트 필터링 없이 바로 접근 가능
gearsByGrade = Managers.Data.GearDataDic.Values
.GroupBy(g => g.rarity)
.ToDictionary(g => g.Key, g => g.ToList());
//1. 현재 레벨 기준 확률 테이블 가져오기
GachaTableData rate = Managers.Data.GachaTableDataDic[gachaLevel[type]];
//2. 확률 기반으로 등급 결정
RarityType rarity = GetRandomRarity(rate);
//3. 해당 등급 내에서 아이템 무작위 추출
List<GearData> candidates = gearsByGrade[rarity];
int index = Random.Range(0, candidates.Count);
int dataId = candidates[index].dataId;
gachaExp[type]++; //1. 가챠 1회 시 경험치 1 증가
TryLevelUp(type); //2. 레벨업 체크
void TryLevelUp(GachaType type)
{
int curLevel = gachaLevel[type];
int needExp = Managers.Data.GachaLevelTableDataDic[curLevel].experience;
if (gachaExp[type] >= needExp)
{
gachaExp[type] -= needExp; // 초과분 보존
gachaLevel[type]++; // 레벨업
}
}
private float _basePressedInterval = 0.1f; // 초기 호출 주기
private float _pressedElapsed = 0f;
private float _pressedDuration = 0f;
private const float _maxSpeedMultiplier = 10f; // 최대 10배 빠르게
private float _minInterval => _basePressedInterval / _maxSpeedMultiplier;
private void Update()
{
if (_pressed)
{
if ((button != null && !button.interactable) ||
(toggle != null && !toggle.interactable))
{
_pressed = false;
return;
}
_pressedElapsed += Time.unscaledDeltaTime;
_pressedDuration += Time.unscaledDeltaTime;
// 선형 가속: 2초 이상 누르면 최대 속도 도달
float t = Mathf.Clamp01(_pressedDuration / 2f); // 0~2초 사이 비율
float dynamicInterval = Mathf.Lerp(_basePressedInterval, _minInterval, t);
if (_pressedElapsed >= dynamicInterval)
{
_pressedElapsed = 0f;
OnPressedHandler?.Invoke();
}
}
}
public static class NumberFormatter
{
// 사용할 숫자 단위 접미사 리스트
private static readonly List<string> suffixes = new List<string>
{ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ"};
// 접미사를 제곱 지수로 매핑하는 딕셔너리
private static readonly Dictionary<string, int> suffixToPower = new Dictionary<string, int>();
// 정적 생성자에서 접미사 매핑 초기화
static NumberFormatter()
{
for (int i = 0; i < suffixes.Count; i++)
{
suffixToPower[suffixes[i]] = (i + 1) * 3; // A -> 10^3, B -> 10^6, ...
}
}
// BigInteger 타입의 매우 큰 숫자를 A, B, C 단위의 축약된 문자열로 변환
public static string FormatNumber(BigInteger number)
{
if (number < 1000)
return number.ToString();
int unitIndex = 0;
BigInteger divisor = 1000;
//단위 인덱스 계산
while (number / divisor >= 1000 && unitIndex < suffixes.Count - 1)
{
divisor *= 1000;
unitIndex++;
}
//정수부 계산
BigInteger whole = number / divisor;
//소수점 첫째 자리 계산
BigInteger remainder = (number % divisor) * 10 / divisor;
//문자열로 조합
return $"{whole}.{remainder}{suffixes[unitIndex]}";
}
자동 전투 기반 스킬 시스템 구현
// Skill.cs
public class Skill
{
private float _cooldownTimer;
private SkillData _data;
private StatManager _casterStat;
public bool IsReady => _cooldownTimer <= 0f;
public void UpdateCooldown(float deltaTime)
{
_cooldownTimer -= deltaTime;
}
public void TryUse(List<IDamageable> enemies)
{
if (!IsReady) return;
var targets = FindTargets(enemies);
foreach (var target in targets)
{
var damage = CalculateDamage();
target.TakeDamage(damage);
}
_cooldownTimer = _data.cooldown;
}
// 대상 필터링 / 데미지 계산 생략
}
// SkillExecutor.cs
private void Update()
{
foreach (var skill in equippedSkills)
skill.UpdateCooldown(Time.deltaTime);
if (SkillAutoManager.IsAutoSkillOn)
{
var enemies = FindEnemiesInRange();
foreach (var skill in equippedSkills)
skill.TryUse(enemies);
}
}
ObjectPool 기반 UI/연출 최적화 시스템