2026-01-21 12:37:37 +00:00
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using TreeEditor;
|
|
|
|
|
using UnityEngine;
|
2026-01-27 11:58:00 +00:00
|
|
|
using UnityEngine.InputSystem;
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-02-02 12:41:06 +00:00
|
|
|
[System.Serializable]
|
|
|
|
|
public class PlayerStat
|
|
|
|
|
{
|
|
|
|
|
public PlayerData data;
|
|
|
|
|
public PlayerStat() { }
|
|
|
|
|
|
|
|
|
|
public PlayerStat(PlayerData data)
|
|
|
|
|
{
|
|
|
|
|
this.data = data;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-21 12:37:37 +00:00
|
|
|
public class PlayerController : MonoBehaviour
|
|
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
[Header("Player Datas")]
|
|
|
|
|
[SerializeField] private PlayerData playerData;
|
2026-02-02 12:41:06 +00:00
|
|
|
|
|
|
|
|
// 런타임에서 계산된 스탯을 담아둘 리스트
|
2026-02-03 08:26:37 +00:00
|
|
|
private PlayerStat playerStat;
|
2026-02-02 12:41:06 +00:00
|
|
|
private PlayerStat currentStat;
|
|
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
[SerializeField] private Rigidbody2D rbody;
|
|
|
|
|
private Vector2 moveInput;
|
|
|
|
|
|
|
|
|
|
private float axisH = 0.0f; // 좌우 입력 값 저장
|
|
|
|
|
bool isDash = false; // 대시 플래그
|
2026-01-21 12:37:37 +00:00
|
|
|
bool goJump = false; // 점프 개시 플래그
|
|
|
|
|
bool isDead = false; // 사망 플래그
|
|
|
|
|
bool onGround = false; // 지면에 서 있는 플래그
|
2026-02-02 12:41:06 +00:00
|
|
|
bool isHit = false;
|
|
|
|
|
private bool isInvincible = false;
|
2026-01-27 11:58:00 +00:00
|
|
|
public LayerMask groundLayer; // 착지할 수 있는 레이어
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
private Animator animator;
|
2026-01-28 12:32:29 +00:00
|
|
|
private Animator nanimator;
|
|
|
|
|
private Animator tanimator;
|
2026-01-27 11:58:00 +00:00
|
|
|
private PlayerAttacks playerAttacks;
|
2026-02-02 12:41:06 +00:00
|
|
|
SpriteRenderer spriteRenderer;
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-28 12:32:29 +00:00
|
|
|
|
|
|
|
|
[SerializeField] private GameObject nano;
|
2026-01-27 11:58:00 +00:00
|
|
|
[SerializeField] private GameObject tera;
|
|
|
|
|
bool isnano = false;
|
2026-01-28 12:32:29 +00:00
|
|
|
bool istera = false;
|
2026-02-03 08:26:37 +00:00
|
|
|
int CurrentHp;
|
|
|
|
|
|
|
|
|
|
[Header("Tag System")]
|
|
|
|
|
private float maxGauge = 60f; // 한 칸을 채우는 데 필요한 게이지
|
|
|
|
|
private float CurrentGauge;
|
|
|
|
|
private int TagCount;
|
|
|
|
|
private int maxTagCount = 5;
|
2026-01-21 12:37:37 +00:00
|
|
|
|
|
|
|
|
void Start()
|
|
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
if (playerData != null) playerStat = new PlayerStat(playerData);
|
2026-01-28 12:32:29 +00:00
|
|
|
|
|
|
|
|
nano.SetActive(true);
|
|
|
|
|
isnano = true;
|
|
|
|
|
tera.SetActive(false);
|
2026-02-03 08:26:37 +00:00
|
|
|
currentStat = playerStat;
|
2026-01-28 12:32:29 +00:00
|
|
|
|
|
|
|
|
rbody = GetComponent<Rigidbody2D>();
|
|
|
|
|
nanimator = nano.GetComponent<Animator>();
|
|
|
|
|
tanimator = tera.GetComponent<Animator>();
|
2026-01-27 11:58:00 +00:00
|
|
|
playerAttacks = GetComponent<PlayerAttacks>();
|
2026-02-02 12:41:06 +00:00
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
CurrentHp = playerStat.data.playerHp;
|
|
|
|
|
CurrentGauge = playerStat.data.playerCurrentGauge;
|
|
|
|
|
TagCount = playerStat.data.playerTagCount;
|
2026-01-28 12:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
public void ChargeTagGauge(float amount)
|
2026-01-28 12:32:29 +00:00
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
// 태그 카운트가 이미 최대라면 더 이상 충전하지 않음
|
|
|
|
|
if (TagCount >= maxTagCount) return;
|
2026-01-28 12:32:29 +00:00
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
CurrentGauge += amount;
|
|
|
|
|
Debug.Log($"게이지 충전: +{amount} / 현재 게이지: {CurrentGauge}");
|
2026-01-28 12:32:29 +00:00
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
// 게이지가 60을 넘었을 때 카운트 처리 (이월 포함)
|
|
|
|
|
while (CurrentGauge >= maxGauge && TagCount < maxTagCount)
|
|
|
|
|
{
|
|
|
|
|
CurrentGauge -= maxGauge; // 오버된 만큼 이월
|
|
|
|
|
TagCount++;
|
|
|
|
|
Debug.Log($"태그 카운트 상승! 현재 카운트: {TagCount}");
|
|
|
|
|
|
|
|
|
|
// 카운트가 최대치에 도달하면 게이지를 0으로 고정하고 탈출
|
|
|
|
|
if (TagCount >= maxTagCount)
|
|
|
|
|
{
|
|
|
|
|
CurrentGauge = 0;
|
|
|
|
|
Debug.Log("태그 카운트 최대 도달! 태그 준비 완료.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void OnTagKey(InputValue value)
|
|
|
|
|
{
|
|
|
|
|
if (isDead) return;
|
|
|
|
|
if (!value.isPressed) return;
|
2026-01-28 12:32:29 +00:00
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
if (TagCount < maxTagCount)
|
2026-01-28 12:32:29 +00:00
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
Debug.Log($"태그 불가! 카운트가 부족합니다. (현재: {TagCount}/{maxTagCount})");
|
|
|
|
|
return;
|
2026-01-28 12:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
Debug.Log(" Z 버튼 눌림! ");
|
|
|
|
|
|
|
|
|
|
isnano = !isnano;
|
|
|
|
|
istera = !isnano;
|
|
|
|
|
nano.SetActive(isnano);
|
|
|
|
|
tera.SetActive(istera);
|
|
|
|
|
|
|
|
|
|
if (CurrentHp < 5)
|
2026-01-28 12:32:29 +00:00
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
CurrentHp += 1;
|
2026-01-28 12:32:29 +00:00
|
|
|
}
|
2026-01-27 11:58:00 +00:00
|
|
|
|
2026-01-29 09:11:23 +00:00
|
|
|
animator = (isnano) ? nanimator : tanimator;
|
2026-02-03 08:26:37 +00:00
|
|
|
TagCount = 0;
|
|
|
|
|
CurrentGauge = 0;
|
2026-01-21 12:37:37 +00:00
|
|
|
}
|
2026-01-29 12:38:56 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
void OnMove(InputValue value)
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
if (isDead) return;
|
2026-01-27 11:58:00 +00:00
|
|
|
// Vector2 값 중 x축(좌우) 값만 가져옴
|
|
|
|
|
Vector2 inputVector = value.Get<Vector2>();
|
|
|
|
|
axisH = inputVector.x;
|
|
|
|
|
}
|
|
|
|
|
void OnDash(InputValue value)
|
|
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
if (isDead) return;
|
2026-01-27 11:58:00 +00:00
|
|
|
isDash = value.isPressed;
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
if (isDash) Debug.Log("대시 중...");
|
|
|
|
|
else Debug.Log("대시 중단");
|
|
|
|
|
}
|
|
|
|
|
public void OnJump(InputValue value)
|
|
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
if (isDead) return;
|
2026-01-27 11:58:00 +00:00
|
|
|
// 버튼이 눌린 순간(isPressed)이고 지면 위라면 점프 예약
|
|
|
|
|
if (value.isPressed && onGround)
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
2026-01-27 11:58:00 +00:00
|
|
|
goJump = true;
|
2026-02-03 08:26:37 +00:00
|
|
|
if (isnano) nanimator.SetBool("jump", true);
|
|
|
|
|
else if (istera) tanimator.SetBool("jump", true);
|
2026-01-27 11:58:00 +00:00
|
|
|
Debug.Log(" 점프 버튼 눌림! ");
|
2026-01-21 12:37:37 +00:00
|
|
|
}
|
2026-01-27 11:58:00 +00:00
|
|
|
}
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
public void OnSAtk(InputValue value)
|
|
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
if (isDead) return;
|
2026-01-28 12:32:29 +00:00
|
|
|
if (!value.isPressed) return;
|
|
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
Debug.Log(" s 버튼 눌림! ");
|
2026-01-30 09:58:52 +00:00
|
|
|
if (playerAttacks.IsAnyWeaponInUse) return;
|
|
|
|
|
|
|
|
|
|
playerAttacks.IsAnyWeaponInUse = true;
|
2026-01-29 12:38:56 +00:00
|
|
|
StartCoroutine(playerAttacks.ableAtk(0, "SAtk", isnano));
|
2026-01-27 11:58:00 +00:00
|
|
|
}
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
public void OnAAtk(InputValue value)
|
|
|
|
|
{
|
2026-02-03 08:26:37 +00:00
|
|
|
if (isDead) return;
|
2026-01-28 12:32:29 +00:00
|
|
|
if (!value.isPressed) return;
|
|
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
Debug.Log(" a 버튼 눌림! ");
|
2026-01-30 09:58:52 +00:00
|
|
|
if (playerAttacks.IsAnyWeaponInUse) return;
|
|
|
|
|
|
|
|
|
|
playerAttacks.IsAnyWeaponInUse = true;
|
|
|
|
|
StartCoroutine(playerAttacks.ableAtk(0, "AAtk", isnano));
|
2026-01-27 11:58:00 +00:00
|
|
|
}
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
if (isDead) return;
|
|
|
|
|
|
|
|
|
|
bool isMoving = axisH != 0;
|
|
|
|
|
// 지면 상태 확인
|
2026-01-28 12:32:29 +00:00
|
|
|
if (isnano) nanimator.SetBool("jump", !onGround);
|
|
|
|
|
else if (istera) tanimator.SetBool("jump", !onGround);
|
2026-01-27 11:58:00 +00:00
|
|
|
|
2026-01-28 12:32:29 +00:00
|
|
|
if (isnano) nanimator.SetBool("Dash", isDash);
|
2026-01-29 09:11:23 +00:00
|
|
|
else if (istera) tanimator.SetBool("Dash", isDash);
|
2026-01-28 12:32:29 +00:00
|
|
|
if (isnano) nanimator.SetBool("Move", isMoving);
|
|
|
|
|
else if (istera) tanimator.SetBool("Move", isMoving);
|
2026-01-27 11:58:00 +00:00
|
|
|
|
|
|
|
|
// 플래그 초기화
|
|
|
|
|
if (Keyboard.current.leftShiftKey.wasReleasedThisFrame) isDash = false;
|
|
|
|
|
|
|
|
|
|
// 방향 조절
|
2026-01-29 12:38:56 +00:00
|
|
|
if (isMoving && !playerAttacks.IsAnyWeaponInUse)
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
2026-01-27 11:58:00 +00:00
|
|
|
float direction = axisH > 0 ? 1 : -1;
|
|
|
|
|
transform.localScale = new Vector2(direction, 1);
|
2026-01-21 12:37:37 +00:00
|
|
|
}
|
2026-01-28 12:32:29 +00:00
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (isnano) nanimator.SetBool("Dash", false);
|
|
|
|
|
else if (istera) tanimator.SetBool("Dash", false);
|
|
|
|
|
}
|
2026-01-21 12:37:37 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 09:11:23 +00:00
|
|
|
private void FixedUpdate()
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
|
|
|
|
onGround = Physics2D.Linecast(transform.position,
|
|
|
|
|
transform.position - (transform.up * 0.1f),
|
|
|
|
|
groundLayer);
|
|
|
|
|
|
2026-02-02 12:41:06 +00:00
|
|
|
if (isDead || isHit) return;
|
2026-01-27 11:58:00 +00:00
|
|
|
|
|
|
|
|
// 공격중인지 확인
|
2026-01-30 09:58:52 +00:00
|
|
|
if (playerAttacks.IsAnyWeaponInUse && onGround)
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
2026-01-27 11:58:00 +00:00
|
|
|
rbody.linearVelocity = new Vector2(0, rbody.linearVelocity.y); // 정지
|
2026-01-21 12:37:37 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 12:41:06 +00:00
|
|
|
float speed = (isDash && onGround) ? currentStat.data.playerDashSpeed : currentStat.data.playerDefaultSpeed;
|
|
|
|
|
rbody.linearVelocity = new Vector2(axisH * speed, rbody.linearVelocity.y);
|
2026-01-21 12:37:37 +00:00
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
if (goJump)
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
|
|
|
|
Debug.Log("점프!");
|
2026-02-02 12:41:06 +00:00
|
|
|
rbody.AddForce(Vector2.up * currentStat.data.playerJumpPower, ForceMode2D.Impulse);
|
2026-01-21 12:37:37 +00:00
|
|
|
goJump = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void OnTriggerEnter2D(Collider2D collision)
|
|
|
|
|
{
|
2026-02-02 12:41:06 +00:00
|
|
|
if (isDead) return;
|
2026-01-27 11:58:00 +00:00
|
|
|
if (collision.CompareTag("Goal"))
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
2026-01-27 11:58:00 +00:00
|
|
|
GameStop();
|
2026-01-21 12:37:37 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-27 11:58:00 +00:00
|
|
|
else if (collision.CompareTag("Dead"))
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
|
|
|
|
GameOver();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 12:41:06 +00:00
|
|
|
public void TakeDamage(int damageAmount, Vector2 attackerPos) //데미지 크기, 공격 위치
|
|
|
|
|
{
|
|
|
|
|
// 이미 죽었거나, 무적 상태라면 데미지 무시
|
|
|
|
|
if (isDead || isInvincible) return;
|
|
|
|
|
|
|
|
|
|
// 체력 감소
|
2026-02-03 08:26:37 +00:00
|
|
|
CurrentHp -= damageAmount;
|
2026-02-02 12:41:06 +00:00
|
|
|
|
2026-02-03 08:26:37 +00:00
|
|
|
Debug.Log($"남은 체력: {CurrentHp}");
|
2026-02-02 12:41:06 +00:00
|
|
|
|
|
|
|
|
// 체력 0 체크
|
2026-02-03 08:26:37 +00:00
|
|
|
if (CurrentHp <= 0)
|
2026-02-02 12:41:06 +00:00
|
|
|
{
|
|
|
|
|
Die();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 넉백 및 무적 코루틴 실행
|
|
|
|
|
StartCoroutine(KnockBack(attackerPos));
|
|
|
|
|
}
|
|
|
|
|
IEnumerator KnockBack(Vector2 attackerPos)
|
|
|
|
|
{
|
|
|
|
|
isHit = true;
|
|
|
|
|
isInvincible = true;
|
|
|
|
|
|
|
|
|
|
Vector2 knockbackDir = (transform.position - (Vector3)attackerPos).normalized;
|
|
|
|
|
rbody.linearVelocity = Vector2.zero;
|
|
|
|
|
rbody.AddForce(knockbackDir * 2f + Vector2.up * 1f, ForceMode2D.Impulse);
|
|
|
|
|
|
|
|
|
|
if (spriteRenderer != null) spriteRenderer.color = new Color(1, 0, 0, 0.5f);
|
|
|
|
|
|
|
|
|
|
yield return new WaitForSeconds(0.5f);
|
|
|
|
|
isHit = false;
|
|
|
|
|
|
|
|
|
|
if (spriteRenderer != null) spriteRenderer.color = Color.white;
|
|
|
|
|
|
|
|
|
|
yield return new WaitForSeconds(1f);
|
|
|
|
|
isInvincible = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Die()
|
|
|
|
|
{
|
|
|
|
|
isDead = true;
|
2026-02-03 08:26:37 +00:00
|
|
|
animator.SetTrigger("Die");
|
2026-02-02 12:41:06 +00:00
|
|
|
rbody.linearVelocity = Vector2.zero;
|
|
|
|
|
GetComponent<Collider2D>().enabled = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void GameStop()
|
2026-01-21 12:37:37 +00:00
|
|
|
{
|
2026-01-27 11:58:00 +00:00
|
|
|
rbody.linearVelocity = Vector2.zero;
|
2026-01-21 12:37:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GameOver()
|
|
|
|
|
{
|
|
|
|
|
isDead = true;
|
2026-01-27 11:58:00 +00:00
|
|
|
animator.SetBool("Move", false);
|
2026-02-02 12:41:06 +00:00
|
|
|
//anim.SetTrigger("Die");
|
2026-01-21 12:37:37 +00:00
|
|
|
GameStop();
|
|
|
|
|
}
|
|
|
|
|
}
|