내일배움캠프 37일차 TIL <Unity 게임개발 숙련 프로젝트 4일차> 05/29

정광훈(Unity_9기)·2025년 5월 29일

TIL (Today I Learned)

목록 보기
47/110
post-thumbnail

오늘 있었던 일

<진행 상황>

도전 과제에서 아이템 추가있는데
버섯을 먹으면 무적이 되는 아이템을 추가했다.

버섯을 먹고 장애물과 부딪치면 사진처럼 날아가도록 했다.


<코드>

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Item : MonoBehaviour
{
    Rigidbody _rigidbody;
    public float itemMoveSpeed = 25f; // 실제로는 이동 안함 - 효과만 테스트


    void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        _rigidbody.velocity = Vector3.back * itemMoveSpeed; // 장애물 이동속도
    }

    public void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            PlayerCondition player = other.GetComponent<PlayerCondition>();
            // 테스트로 무적 100초로 설정
            player.ActivateInvincibility(100f);

            Destroy(gameObject); // 아이템 파괴
        }
    }
}

================

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObstacleBehavior : MonoBehaviour
{
    Rigidbody _rigidbody;
    Obstacle _obstacle;
    public float obstacleSpeed = 25f; // 장애물 이동속도
    public float knockbackForce = 500f; // 넉백 강도

    void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
        Destroy(gameObject,4f); // 생성 후 4초뒤 파괴
    }
    
    // Update is called once per frame
    void FixedUpdate()
    {
        _rigidbody.velocity = Vector3.back * obstacleSpeed; // 장애물 이동방향과 속도
    }

    public void InitObstacle() // 초기화
    {
        _rigidbody.velocity = Vector3.back * obstacleSpeed; // 장애물 이동방향과 속도
        _rigidbody.angularVelocity = Vector3.zero; // 회전각도 초기화
    }
    
    // 플레이어와 장애물이 충돌하면 게임 정지
    private void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.CompareTag("Player")) // 플레이어와 충돌하면
        {
            // 충돌한 상대방 오브젝트에서 PlayerCondition이라는 스크립트 컴포넌트를 가져와라
            PlayerCondition playerCondition = other.gameObject.GetComponent<PlayerCondition>();
            if (playerCondition.IsInvincible == false) // 무적이 아닐 때
            {
                StartCoroutine(nameof(GameOver)); // 게임 오버
            }
            else // 무적일 때
            {
                int direction = Random.Range(0, 2); // 장애물 날아가는 방향 정하기
                Vector3 selectedDirection;
                
                if (direction == 0)
                {
                    selectedDirection = Vector3.right; // 오른쪽으로 날림
                }
                else 
                {
                    selectedDirection = Vector3.left; // 왼쪽으로 날림
                }
                
                // 플레이어와 충돌하면 장애물이 대각선 방향으로 날아감
                Vector3 knockbackDirection = (selectedDirection + Vector3.up * 2f).normalized; 
                // Impulse 모드는 즉각적인 힘을 가함
               _rigidbody.AddForce(knockbackDirection * knockbackForce, ForceMode.Impulse); 
            }
        }
    }

    IEnumerator GameOver()
    {
        CharacterManager.Instance.Player.controller.Dead();
        Time.timeScale = 0;
        yield return new WaitForSecondsRealtime(2.28f);

        Debug.Log("장애물과 충돌로 인한 게임정지");
        UIController.Instance.ShowGameOverUI();
    }
}

=========

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerCondition : MonoBehaviour
{
    private bool isInvincible = false; // 무적상태 확인

    public bool IsInvincible // 외부에서 무적 상태인지 확인할 수 있도록 함
    {
        get { return isInvincible; }
        private set { isInvincible = value; }
    }

    public void ActivateInvincibility(float duration)
    {
        if (!isInvincible) // 무적일 때
        {
            IsInvincible = true; // 무적상태
            // InvincibilityCoroutine 발동
            StartCoroutine(InvincibilityCoroutine(duration));
        }
    }

    IEnumerator InvincibilityCoroutine(float duration)
    {
        // duration(무적 시간)동안 기다림
        yield return new WaitForSeconds(duration);
        IsInvincible = false; // 무적 해제
    }
}

<문제 발생>

처음에는 버섯을 먹고 장애물에 부딪치면 통과하는 식으로 만들려고 했다.
그래서 장애물의 Collider를 IsTrigger로 바꿔서 테스트 했다.

버섯을 먹었을 때는 정상적으로 장애물을 통과했는데
버섯을 안 먹고 장애물을 회피했을 때 충돌판정이 나는 것이었다.


<해결>

왜 그런가 이것 저것 테스트 해봤다.
아이템 추가하면서 만든 스크립트와 관련 문장을 주석 처리도 해보고
Collider도 건드려봤다.

혹시나 하는 생각에 점수 판정 트리거와 장애물 충돌 트리거가 겹치는 건가라는 생각이 들었다.
(큰 네모: 점수 판정 Trigger / 작은 네모: 장애물 충돌 판정 Trigger)
(큰 네모와 충돌하면 장애물과 충돌한 판정으로 나와 게임오버가 되는 현상이 나왔다.)

Gemini에게 물어본 결과
부모 오브젝트가 IsTrigger상태이고, 자식 오브젝트도 IsTrigger상태면
자식 오브젝트의 IsTrigger에 감지되었을 때
부모 오브젝트에게도 똑같이 감지된 것처럼 인식을 한다는 것이었다.

그래서 부모 오브젝트를 다시 Collision상태로 바꾸고
차라리 장애물과 충돌하면 장애물을 날려버리자는 생각으로 바꿔서 해결했다.


<그리고>

이걸 설정하면 물체가 좀 더 자연스럽게 움직인다고 한다.
장애물에 설정하면 장애물이 좀 더 자연스럽게 날아가는 것을 볼 수 있다.

0개의 댓글