1vdlrwnsv1 님의 블로그
유니티 슬롯머신 개발 중 문제 & 보스 문제 수정 본문
슬롯머신 개발 일지
1. 슬롯머신 기능 구현
- 슬롯이 돌아감
- 일정 시간이 지나면 멈춤
- 멈춘 결과를 저장하고 버튼을 활성화
- 사용자가 슬롯을 선택하면 해당 결과를 적용
2. NullReferenceException 문제
발생 원인
- OnSlotButtonClick에서 sprite.name을 가져오려고 했는데, sprite가 null이라서 에러 발생.
- SlowDown에서 finalSprite를 OnSlotButtonClick으로 넘길 때 null이 전달된 것 같음.
해결 방법
- Sprite 객체를 넘기는 대신, SkillSprite 리스트의 인덱스를 넘기도록 수정.
- 버튼 클릭 시 인덱스를 이용해 SkillSprite에서 직접 Sprite를 가져오도록 변경.
void OnSlotButtonClick(int slotIndex, int spriteIndex)
{
if (spriteIndex < 0 || spriteIndex >= SkillSprite.Length)
{
Debug.LogError($"잘못된 인덱스: {spriteIndex}");
return;
}
Sprite sprite = SkillSprite[spriteIndex];
string upgradeMessage = "";
switch (spriteIndex)
{
case 0:
SkillManager.Instance.ChangeNumberOfBackwardProjectiles(1);
upgradeMessage = "후방 발사 화살이 1개 증가했습니다!";
break;
case 1:
SkillManager.Instance.HealPlayer(10);
upgradeMessage = "플레이어의 체력이 10 회복되었습니다!";
break;
case 2:
SkillManager.Instance.ChangeMaxHealth(10);
upgradeMessage = "플레이어의 최대 체력이 10 증가했습니다!";
break;
case 3:
SkillManager.Instance.ChangeNumberOfForwardProjectiles(1);
upgradeMessage = "전방 발사 화살이 1개 증가했습니다!";
break;
case 4:
SkillManager.Instance.ChangePower(1);
upgradeMessage = "화살의 공격력이 1 증가했습니다!";
break;
default:
upgradeMessage = "잘못된 선택입니다.";
break;
}
upgradeTxt.text = upgradeMessage;
upgradeFrame.SetActive(true);
DisableOtherSlots(slotIndex);
}
3. 슬롯이 멈춘 후 버튼에 이벤트 추가
SlowDown 코루틴에서 슬롯이 멈추면 slotFinalResults에 결과를 저장하고 버튼 클릭 시 실행할 이벤트를 설정하도록 수정.
IEnumerator SlowDown(int slotIndex, GameObject slotObject)
{
float currentY = slotObject.transform.localPosition.y;
float targetY = Mathf.Round(currentY / 100) * 100;
targetY = Mathf.Clamp(targetY, 0, 300);
while (Mathf.Abs(slotObject.transform.localPosition.y - targetY) > 1f)
{
slotObject.transform.localPosition = Vector3.Lerp(
slotObject.transform.localPosition,
new Vector3(slotObject.transform.localPosition.x, targetY, 0),
0.2f);
yield return new WaitForSeconds(0.05f);
}
slotObject.transform.localPosition = new Vector3(slotObject.transform.localPosition.x, targetY, 0);
int resultIndex = Mathf.RoundToInt(targetY / 100) % ItemCnt;
int spriteIndex = StartList[resultIndex];
slotFinalResults[slotIndex] = spriteIndex;
Slot[slotIndex].onClick.RemoveAllListeners();
Slot[slotIndex].onClick.AddListener(() => OnSlotButtonClick(slotIndex, spriteIndex));
Slot[slotIndex].interactable = true;
}
EnemyManager 몬스터 리스트 0이면 ClearStage 호출
EnemyManager에서 몬스터가 전부 죽으면 클리어 판정 내리려고 했는데 안 됨. 확인해 보니 monsterList에서 몬스터를 삭제하는 코드가 없었음.
수정 코드
public void RemoveEnemyOnDeath(GameObject enemy)
{
monsterList.Remove(enemy);
if (monsterList.Count == 0)
{
isClear = true;
skillUpSlot.SetActive(true);
}
}
이제 몬스터 다 죽으면 skillUpSlot 활성화됨.
보스가 밀리는 문제
보스를 Rigidbody2D Kinematic으로 해도 밀림. isKinematic = true 하면 물리 영향 안 받을 줄 알았는데 그래도 밀림. MovePosition으로 이동하는 게 문제였음. transform.position 직접 수정하니까 해결.
수정 코드
void FixedUpdate()
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.fixedDeltaTime);
}
ㅇㅋ 이제 안 밀림.
장애물 피해서 이동
A* 알고리즘 쓰기엔 너무 오버임. NavMeshAgent는 2D에서 지원 안 함. 그냥 Raycast 써서 길막 체크하고 우회하도록 구현.
예제 코드
RaycastHit2D hit = Physics2D.Raycast(transform.position, moveDirection, checkDistance, obstacleLayer);
if (hit.collider != null)
{
// 장애물 있음 -> 방향 바꿈
moveDirection = Vector2.Perpendicular(moveDirection);
}
transform.position += (Vector3)moveDirection * speed * Time.deltaTime;
이제 벽에 안 걸리고 돌아감.
포탈 진입 시 스킬 업 UI 활성화
플레이어가 포탈에 들어가면 enemyManager.monsterList.Count 확인해서 몬스터 다 죽었으면 스킬 업 UI 띄우게 했는데, NullReferenceException 터짐. EnemyManager.Instance가 초기화 안 된 상태에서 호출돼서 그런 듯.
수정 코드
private void Start()
{
gameManager = GameManager.Instance;
enemyManager = FindObjectOfType<EnemyManager>();
}
이제 문제 없음.
버튼 클릭 시 포탈 이동
포탈에서 버튼 눌렀을 때 PortalContoroll() 실행 안 됨. _potal이 null이었음. FindObjectOfType<PotalController>()로 초기화해줌.
수정 코드
private void Start()
{
_potal = FindObjectOfType<PotalController>();
}
딱알았다. 이제 버튼 누르면 포탈 이동됨.
1. 보스 체력 감소 기능 구현
- 보스 캐릭터에 currBossHp 추가. ResourceController에서 실시간으로 체력을 받아올 수 있도록 수정함.
- ChangeHealth 메서드를 사용하여 마우스 클릭 시 체력이 10 감소하도록 함.
- if (Input.GetMouseButtonDown(0)) { _resourceController.ChangeHealth(-10); }로 구현.
2. 보스 AI - 이동 및 공격
- 보스가 플레이어를 추적하는 FollowPlayer 메서드 추가.
- 플레이어와의 거리가 3m 이하일 경우 공격 상태로 변경, 공격 이펙트 활성화. DelayedAttackStart와 AttackPlayerRepeatedly 코루틴으로 공격 딜레이와 반복 공격 구현.
3. 보스 HP 바 및 UI 업데이트
- 보스 체력바 UI 추가. 체력 수치가 실시간으로 업데이트되고 애니메이션이 적용되도록 수정.
- fillHealthBar.fillAmount와 healthText.text로 체력바와 체력 수치를 UI에 반영.
4. ResourceController 추상화
- ResourceController 클래스를 추상 클래스로 리팩토링.
- 기본적인 체력 변화 로직을 CalculateCalChangeHealth 메서드로 분리. Death() 메서드 추가하여 죽음 처리.
- 각 캐릭터에서 ChangeHealth 호출 시 공통적인 로직을 처리하도록 설정.
내가 공부한 내용 복붙해서 지피티한테 요약 맡겼는데 이 꼴 남 다음부터 그냥 내가 쓰는게 낫겠다
'Unity' 카테고리의 다른 글
유니티 체력바 만들기, 보스 만들기 (0) | 2025.02.25 |
---|