ThreeKingdomsSlingshot/Assets/Scripts/Runtime/RangeIndicator.cs

113 lines
4.0 KiB
C#
Raw Permalink Normal View History

using UnityEngine;
namespace TKS
{
/// <summary>
/// 선택(터치)한 유닛의 사거리 표시 (PD 2026-11-04).
/// · 모든 병종: 슬링샷 최대 거리 = 얇은 반투명 원 (아군·적군 모두)
/// · 궁병·책사: 추가로 슬링샷 범위 ~ 슬링샷 범위 × (1 + archerRangeRatio) 까지를 채워진 반투명 붉은 도넛으로 (실제 공격 가능 범위)
/// — 그 범위 안에 적이 하나도 없으면 회색.
/// </summary>
public class RangeIndicator : MonoBehaviour
{
public static readonly Color RingColor = new Color(1f, 1f, 1f, 0.42f);
public static readonly Color DonutColor = new Color(0.95f, 0.25f, 0.2f, 0.3f);
public static readonly Color DonutIdleColor = new Color(0.6f, 0.6f, 0.6f, 0.18f);
SpriteRenderer ring;
SpriteRenderer donut;
Unit target;
float ratio;
public Unit Target
{
get { return target; }
}
public bool RingVisible
{
get { return ring != null && ring.gameObject.activeSelf; }
}
public bool DonutVisible
{
get { return donut != null && donut.gameObject.activeSelf; }
}
/// <summary>얇은 원의 지름(월드) = 슬링샷 최대 거리 × 2.</summary>
public float RingDiameter
{
get { return ring != null ? ring.transform.localScale.x : 0f; }
}
/// <summary>도넛 바깥 지름(월드) = 슬링샷 최대 거리 × (1 + 비율) × 2.</summary>
public float DonutDiameter
{
get { return donut != null ? donut.transform.localScale.x : 0f; }
}
public void Init(float archerRangeRatio)
{
ratio = Mathf.Max(0f, archerRangeRatio);
ring = ProceduralSprites.NewSprite(transform, "SlingRange", ProceduralSprites.ThinRing, RingColor, 1f, -9);
// 도넛 안쪽 지름 = 바깥 지름 ÷ (1 + 비율) → 안쪽 테두리가 슬링샷 범위 원과 일치
donut = ProceduralSprites.NewSprite(transform, "ArcherReach", ProceduralSprites.Donut(1f / (1f + ratio)), DonutColor, 1f, -10);
ring.gameObject.SetActive(false);
donut.gameObject.SetActive(false);
}
public void Show(Unit u)
{
target = u;
if (u == null)
{
Hide();
return;
}
스킬 시스템(PD #1093 세션 B) — skills.csv effect_key 51종 처리기 · 액티브(예약/즉시)·패시브 · HUD 스킬 버튼 · 적 무장 패시브 · 스킬 레벨업·스킬서 - 데이터: SkillInfoDb(= 스킬 DB) 에 effect_key·p1~p3(pMask)·lv_scale·needs_impl 추가 · 임포터 검증(trigger · 키 51종 · p 칸 · skill_levels 연속 · lv_max) · skill_levels = levels(비용 표) - 처리기 Runtime/Skills: SkillKeys(51종 · 레벨 계수 = 값×계수 / 배율은 1 넘는 몫 / 횟수 반올림 / 켜기·치환 고정 · 팀 키) · SkillDef·SkillCatalog · SkillSystem(유닛별 쿨·예약 · 즉시형 시한 효과 이번 아군 턴/이번 적 턴 · 행동 훅 · 호위 분담 · HUD 한 줄) · SkillMods(전투 코드 수치 질의) · SkillRules(상한 = 등급 + ★3 액티브 +1 · ★5 패시브 ×1.5 = evolve.csv · 레벨업 · 스킬서 판매) - 전투 연결: ActionResolver(밀기·튕김·추가 이동 n·추가 이동 공격·충돌 추가 피해·밀며 전진 ×·삼첨도·관통 피해/넉백/반격 없음/빗나가도 복귀/한 번 더 관통·사거리·사선 통과·크리·광역 반경/비율/아군 0·백기습영 이동 후 사격·군령/대장군 공격 횟수) · Combat(상성 하한·공 %·주는/받는 피해·근접 패널티 해제·반격 배율/받는 반격·견제 배율) · BattleManager(편성·적 무장 부착 · 견제 반경/횟수/무제한/회복 · 교전 반응 정지 · 교전 범위 · 즉시형 실행) · EnemyAI·RangeIndicator(슬링·사거리 스킬 반영) - UI: HUD 스킬 버튼(이름·Lv·쿨·사용 가능/불가·패시브) · 탭 = 예약/취소/즉시 · 조준 중 2손가락 탭 · 발동 = 이름 글자 + 플래시 · 스킬 한 줄 · 예약 배지 · 변진 반경 원 · 영웅 상세 스킬 레벨업 팝업 · 거래 상점 스킬서 칸(임시) - 표: economy.csv start_skill_books 10 · skill_book_shop_daily 3 · skill_book_price 300(임시 · PD 확인) - 테스트 73/73(기존 56 + SkillTests 17 · 51종 전부) · console error 0 · 캡처 = DataImporter.CaptureSkills Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:31:27 +00:00
float r = SkillMods.SlingMax(u); // 스킬(동남풍·적토마) 반영 · 없으면 슬링샷 최대 거리
ring.transform.localScale = new Vector3(r * 2f, r * 2f, 1f);
ring.gameObject.SetActive(true);
bool archer = UnitTypeInfo.IsRanged(u.Type); // 궁병·책사(#1087 ⑤ 같은 사거리 규칙)
if (archer)
{
스킬 시스템(PD #1093 세션 B) — skills.csv effect_key 51종 처리기 · 액티브(예약/즉시)·패시브 · HUD 스킬 버튼 · 적 무장 패시브 · 스킬 레벨업·스킬서 - 데이터: SkillInfoDb(= 스킬 DB) 에 effect_key·p1~p3(pMask)·lv_scale·needs_impl 추가 · 임포터 검증(trigger · 키 51종 · p 칸 · skill_levels 연속 · lv_max) · skill_levels = levels(비용 표) - 처리기 Runtime/Skills: SkillKeys(51종 · 레벨 계수 = 값×계수 / 배율은 1 넘는 몫 / 횟수 반올림 / 켜기·치환 고정 · 팀 키) · SkillDef·SkillCatalog · SkillSystem(유닛별 쿨·예약 · 즉시형 시한 효과 이번 아군 턴/이번 적 턴 · 행동 훅 · 호위 분담 · HUD 한 줄) · SkillMods(전투 코드 수치 질의) · SkillRules(상한 = 등급 + ★3 액티브 +1 · ★5 패시브 ×1.5 = evolve.csv · 레벨업 · 스킬서 판매) - 전투 연결: ActionResolver(밀기·튕김·추가 이동 n·추가 이동 공격·충돌 추가 피해·밀며 전진 ×·삼첨도·관통 피해/넉백/반격 없음/빗나가도 복귀/한 번 더 관통·사거리·사선 통과·크리·광역 반경/비율/아군 0·백기습영 이동 후 사격·군령/대장군 공격 횟수) · Combat(상성 하한·공 %·주는/받는 피해·근접 패널티 해제·반격 배율/받는 반격·견제 배율) · BattleManager(편성·적 무장 부착 · 견제 반경/횟수/무제한/회복 · 교전 반응 정지 · 교전 범위 · 즉시형 실행) · EnemyAI·RangeIndicator(슬링·사거리 스킬 반영) - UI: HUD 스킬 버튼(이름·Lv·쿨·사용 가능/불가·패시브) · 탭 = 예약/취소/즉시 · 조준 중 2손가락 탭 · 발동 = 이름 글자 + 플래시 · 스킬 한 줄 · 예약 배지 · 변진 반경 원 · 영웅 상세 스킬 레벨업 팝업 · 거래 상점 스킬서 칸(임시) - 표: economy.csv start_skill_books 10 · skill_book_shop_daily 3 · skill_book_price 300(임시 · PD 확인) - 테스트 73/73(기존 56 + SkillTests 17 · 51종 전부) · console error 0 · 캡처 = DataImporter.CaptureSkills Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:31:27 +00:00
float ro = SkillMods.Range(u) * (1f + ratio); // 사거리 스킬(단기·대도독) 반영 · 없으면 = 슬링 × (1 + 비율)
donut.transform.localScale = new Vector3(ro * 2f, ro * 2f, 1f);
donut.color = DonutColor;
}
if (donut.gameObject.activeSelf != archer) donut.gameObject.SetActive(archer);
Follow();
}
public void Hide()
{
target = null;
if (ring != null) ring.gameObject.SetActive(false);
if (donut != null) donut.gameObject.SetActive(false);
}
/// <summary>궁병 도넛 색: 공격 가능 범위 안에 적이 있으면 붉게, 없으면 회색.</summary>
public void SetArcherReachable(bool any)
{
if (donut != null) donut.color = any ? DonutColor : DonutIdleColor;
}
void LateUpdate()
{
if (target == null) return;
if (!target.IsAlive)
{
Hide();
return;
}
Follow();
}
void Follow()
{
Vector2 p = target.Position;
transform.position = new Vector3(p.x, p.y, 0f);
}
}
}