본문 바로가기

유니티 (Door 애니메이션과 Sprite 애니메이션)멋쟁이사자처럼 유니티 부트캠프 14회차 추가학습

@salmu2025. 6. 9. 16:26
반응형

[14회차 수업 내용] 

1. 문 미닫이 열기 (복습)

2. 코인 애니메이션 + 코인 먹는 코드 만들기

3. Sprite Animation 실습

 

 

1. 문 미닫이 열기

1.1 애니메이션 생성 간단정리

  1. 녹화를 켠다
  2. Position - 우클릭 - Add key
  3. 원하는 위치 찍고 원하는대로 이동시킨다
  4. 녹화를 끈다

 

 

1.2 프레임과 시간

: Unity의 기본 애니메이션 프레임 속도 = 60FPS

0 프레임 0초
30 프레임 0.5초
60 프레임 1초

 

 

1.3 문 닫히는 애니메이션 만들기 (역재생 활용)

  • 기존 Door Open 애니메이션(0초 ~ 1초)을 복사하거나 새 파일 생성
  • 타임라인에서 키프레임 전체 선택
  • 첫 프레임(0초)을 2초 위치로 드래그 이동
  • 이렇게 하면 애니메이션이 역재생되는 효과를 쉽게 만들 수 있음

 

 

1.4 Player 가 오면 문을 열어주기 

using System;
using UnityEngine;

public class DoorEvent2 : MonoBehaviour
{
    private Animator anim;

    public string openKey;
    public string closeKey;

    void Start()
    {
        anim = GetComponent<Animator>();
    }
    
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            Debug.Log("Enter");
            anim.SetTrigger(openKey);
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            Debug.Log("Exit");
            anim.SetTrigger(closeKey);
        }
    }
}

 ** 키는 유니티에서 직접 설정해주어야함

 

 

 

 

2. 코인

2.1 360도 회전하는 애니메이션 만들기

    • Animation 창에서 녹화 버튼 클릭
    • Inspector 창 → Transform → Rotation 우클릭
    • Add Key 클릭 → 현재 상태를 키프레임으로 등록
    • 타임라인에서 1초 위치로 이동 (예: 60프레임) 후 Rotation Y 값을 360으로 설정
  •  

 

2.2 Unity 애니메이션 블렌딩 수정 — Curves 탭 사용

2.2.1  선형(Linear)로 변경

  • 두 키프레임 사이 선 클릭후 우클릭 → ‘Flat’ → ‘Linear’ 선택
  • 균등한 속도로 변하는 직선 이동으로 바뀜

2.2.2 핸들(Handle)로 수동 조절

  • 키프레임 클릭 시 곡선 핸들이 나타남
  • 직접 핸들을 끌어서 부드럽게 변화하는 커브 만들 수 있음
  • → 예: 서서히 출발하고 서서히 멈추는 자연스러운 움직임

 

 

 

2.3.코인 획득 

코인과 플레이어가 충돌할 경우, 코인을 획득(코인 오브젝트 삭제)= Collider 컴포넌트 필요

 

Coin

using System;
using UnityEngine;

public class Coin : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
	         Movement.coinCount++
	         
            Debug.Log("코인 획득!!");
            
            Destroy(this.gameObject);
        }
    }
}

 

  • OnTriggerEnter(): 충돌 감지 (코인 콜라이더에 Is Trigger 체크 필수)
  • CompareTag("Player"): 충돌 대상이 플레이어일 때만 반응
  • Destroy(gameObject): 코인 오브젝트 삭제

 

 

Movement (캐릭터)

using UnityEngine;
 
 public class Movement : MonoBehaviour
 {
     public float moveSpeed = 5f;

     public static int coinCount = 0;
     
     void Update()
     {
         float h = Input.GetAxis("Horizontal");
         float v = Input.GetAxis("Vertical");

         Vector3 dir = new Vector3(h, 0, v);
         
         Vector3 normalDir = dir.normalized;
         
         transform.position += normalDir * moveSpeed * Time.deltaTime;

         transform.LookAt(transform.position + normalDir);
     }
 }

 

 

2.3.1 왜 coinCountMovement 클래스에 두었을까?

 

이유 1:  CoinCount를 플레이어의 상태 로 간주했기 때문

  • 코인 수는 “플레이어가 얼마나 모았는지”에 대한 정보이기 때문에 “플레이어의 상태”로 관리

이유 2: 코인(Coin)은 단순 이벤트 발생자

  • Coin은 단지 “플레이어가 나를 건드렸을 때 사라지고 점수 올림”
  • 게임 내 “코인 점수”에 대한 책임은 플레이어(혹은 GameManager)가 지는 게 더 적절
  • 책임 분리 원칙(SRP): 코인은 자기 역할(사라지기)에만 집중하는 게 좋음

 

 

3. Sprite Animation

  • 스프라이트 여러 장을 드래그해서 GameObject에 드롭하면 자동으로 애니메이션과 애니메이터가 생성됨
  • 속도 조절 방법 : Animation 클립 선택 → Inspector → Sample Rate

 

3.1 좌우 이동에 맞추어 다른 그림(Sprite)을 보여주는 게임 캐릭터 

: SpriteRenderer 배열과 flipX

: 물리 연산이니 FixedUpdate() 에서 실행

using UnityEngine;
 
 public class CharacterMovement : MonoBehaviour
 {
     private Rigidbody2D characterRb;
     public SpriteRenderer[] renderers;
     
     public float moveSpeed;
     private float h;
 
     void Start()
     {
         characterRb = GetComponent<Rigidbody2D>();
         
         renderers = GetComponentsInChildren<SpriteRenderer>(true);
     }
     
     void Update()
     {
         h = Input.GetAxis("Horizontal"); // 키 입력
     }
 
     void FixedUpdate()
     {
         if (h != 0) // 움직일 때
         {
             renderers[0].gameObject.SetActive(false); // Idle
             renderers[1].gameObject.SetActive(true); // Run
             
             characterRb.linearVelocityX = h * moveSpeed; // 물리적인 이동

             if (h > 0)
             {
                 renderers[0].flipX = false;
                 renderers[1].flipX = false;
             }
             else if (h < 0)
             {
                 renderers[0].flipX = true;
                 renderers[1].flipX = true;
             }
         }
         else if (h == 0)// 움직이지 않을 때
         {
             renderers[0].gameObject.SetActive(true); // Idle
             renderers[1].gameObject.SetActive(false); // Run
         }
     }
 }

-1<h<1

 

3.1.1 renderers = GetComponentsInChildren<SpriteRenderer>(true);

  • 자식 오브젝트에 있는 모든 SpriteRenderer 컴포넌트를 배열로 가져옴
  • (true)비활성화된 오브젝트도 포함해서 가져옴

 

 

 

3.2. 점프 + 점프할 때 점프 애니메이션 구현

public float jumpPower = 10f;
private bool isGround; 

void Update()
{
    // 키 입력
    h = Input.GetAxis("Horizontal");

    Jump();
}

// 바닥과 캐릭터가 붙어 있을 때 (걷거나 뛰는 중)
private void OnCollisionEnter2D(Collision2D other)
{
    isGround = true;
    renderers[2].gameObject.SetActive(false);
}

// 바닥과 캐릭터가 떨어져 있을 때 (점프 중)
private void OnCollisionExit2D(Collision2D other)
{
    isGround = false;
    renderers[2].gameObject.SetActive(true);
}

// 점프 함수
private void Jump()
{
    if (Input.GetButtonDown("Jump"))
    {
        characterRb.AddForceY(jumpPower, ForceMode2D.Impulse);
    }
}

 

“Jump” Input Manager에 미리 등록된 가상 입력 이름 유니티 기본값은 스페이스바

 

 

 

 

3.3 통합 코드

using UnityEngine;

public class CharacterMovement : MonoBehaviour
{
    private Rigidbody2D characterRb;
    public SpriteRenderer[] renderers;

    public float moveSpeed = 5f;
    public float jumpPower = 10f;

    private float h;
    private bool isGround = false;

    void Start()
    {
        characterRb = GetComponent<Rigidbody2D>();
        renderers = GetComponentsInChildren<SpriteRenderer>(true);
    }

    void Update()
    {
        h = Input.GetAxis("Horizontal");

        if (Input.GetButtonDown("Jump") && isGround)
        {
            characterRb.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
        }
    }

    void FixedUpdate()
    {
        // linearVelocityX 사용해서 좌우 이동 (Unity 6.1 기준)
        characterRb.linearVelocityX = h * moveSpeed;

        // 방향 전환 처리
        if (h != 0)
        {
            bool isRight = h > 0;
            foreach (var renderer in renderers)
            {
                renderer.flipX = !isRight;
            }
        }

        // 스프라이트 전환 처리
        if (!isGround)
        {
            ActivateSprite(2); // Jump
        }
        else if (h != 0)
        {
            ActivateSprite(1); // Run
        }
        else
        {
            ActivateSprite(0); // Idle
        }
    }

    void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            isGround = true;
        }
    }

    void OnCollisionExit2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            isGround = false;
        }
    }

    private void ActivateSprite(int index)
    {
        for (int i = 0; i < renderers.Length; i++)
        {
            renderers[i].gameObject.SetActive(i == index);
        }
    }
}

Activate Sprite로 간결화한버전

반응형
salmu
@salmu :: SMU 각종 기록

목차