본문 바로가기

Unity 3D 미니 프로젝트 - 🕹️ SpartaDungeon

@코야딩구2025. 8. 13. 20:53

- 이번 프로젝트에서는 다양한 플레이어 조작, 상호작용, 환경 요소를 구현한 3D 액션 어드벤처 스타일 게임을 개발했다.

- Unity 엔진과 C#을 활용하여 기본 이동, 시점 전환, 상호작용 시스템, 아이템 사용 시스템 등을 구현했다.

🔗 깃허브 링크

🎥 게임 영상

📅 개발 기간

- 2025.08.08 ~ 2025.08.13 (주말 제외 4일)

✨ 구현 기능

1. 기본 이동 및 점프

- WASD로 이동하고 Spacebar로 점프한다. 대쉬(Shift)를 통해 가속 이동을 할 수 있도록 구현했다.

2. 플레이어 상태바 UI

- 플레이어의 체력, 스태미나, 버프 지속 시간을 UI로 실시간 표시했다.

3. 동적 환경 조사 - 상호작용 가능한 오브젝트 표시

- Raycast를 사용해 플레이어 시선 방향의 오브젝트를 탐지한다.
- 탐지된 오브젝트의 이름과 설명을 UI에 표시하며, 상호작용 가능한 경우에는 해당 UI가 활성화되도록 했다.

4. 점프대

- 밟으면 캐릭터가 위로 튀어 오르는 점프대를 구현했다.

5. 다양한 아이템 구현

- 아이템 데이터는 ScriptableObject로 관리한다. 이름, 설명, 속성 등을 개별 정의할 수 있도록 했다.

6. 아이템 사용 시스템

- 특정 아이템을 사용하면 무적, 더블 점프, 스피드 부스트 등 효과가 일정 시간 동안 지속된다.
- 효과의 남은 시간은 우측 상단에 아이콘으로 표시한다.

7. 시점 전환

- 1인칭 ↔ 3인칭 시점을 전환할 수 있도록 구현했다.

8. 움직이는 플랫폼

- 시간에 따라 이동하는 발판을 구현했다. 플레이어가 발판 위에서 이동하면 자연스럽게 함께 이동한다.

9. 벽 타기 및 매달리기

- 플레이어가 벽을 타고 오르거나 매달릴 수 있도록 구현했다.

10. 레이저 트랩 (플랫폼 발사기)

- Raycast로 특정 구간을 감시하고, 플레이어가 일정 시간 닿으면 특정 방향으로 발사되도록 구현했다.

🛠️ 트러블 슈팅 - 플레이어에 AddForce 적용

문제 상황

- 플레이어에 AddForce를 적용했지만 X, Z 축 방향의 힘이 적용되지 않는 문제가 발생했다.
- 원인은 플레이어 이동을 Rigidbody.velocity로 제어하는 로직에 있었다.
- 매 프레임 이동 입력 시 velocity를 직접 덮어쓰는 방식 때문에 외부에서 가하는 힘이 무시되는 현상이 있었다.

해결 방법

- 이동 제어 방식을 변경했다. 입력이 있을 때만 AddForce로 이동을 처리하도록 했다.
- 입력이 없을 경우 OnMoveStop()을 호출해 강제로 이동을 멈추도록 했다.
- 또한 벽에서 자연스럽게 떨어지지 않는 문제를 해결하기 위해 Physic Material의 마찰을 0으로 설정했다.
- 마찰이 0이면 미끄러지는 현상이 발생하므로 강제 정지 로직이 필요했다.

// FixedUpdate() 내 이동 처리
void Move()
{
    if (curMovementInput == Vector3.zero) return; // 입력 없으면 작동 안 함

    Vector3 dir = Vector3.zero;
    Vector3 velocityChange = Vector3.zero;

    // 플레이어 상태에 따라 이동 방향과 속도 결정
    if (player.IsClimbing)
    {
        dir = transform.up * curMovementInput.z + transform.right * curMovementInput.x;
        dir = dir.normalized;

        float climbRunSpeed = player.WalkSpeed / player.RunSpeed * climb.ClimbSpeed;
        dir *= player.IsDashing ? climbRunSpeed : climb.ClimbSpeed;

        velocityChange = dir - _rigidbody.velocity;
    }
    else
    {
        dir = transform.forward * curMovementInput.z + transform.right * curMovementInput.x;
        dir = dir.normalized;
        dir *= player.IsDashing ? player.RunSpeed : player.WalkSpeed;

        velocityChange = dir - new Vector3(_rigidbody.velocity.x, 0, _rigidbody.velocity.z);
    }

    _rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
}

// 인풋 액션 처리
// 입력시(performed)
void OnMove(InputAction.CallbackContext context)
{
    curMovementInput = context.ReadValue<Vector3>();
}
// 입력이 없으면(cancel) 정지
void OnMoveStop()
{
    curMovementInput = Vector3.zero;
    _rigidbody.velocity = new Vector3(0f, _rigidbody.velocity.y, 0f)
}

결과

- 이 방식을 적용한 뒤, 외부 힘(트랩, 폭발 등)에 자연스럽게 반응할 수 있게 됐다.
- 또한 벽이나 오브젝트에 끼이지 않고 부드럽게 미끄러지는 움직임을 구현했다.
- 플레이어 조작과 물리 반응이 모두 자연스러운 상태로 유지된다.


⚙️ 기술 스택

- Engine: Unity 2022.3.17f1

- Language: C#

- Version Control: GitHub

목차