반응형
[14회차 수업 내용]
1. 문 미닫이 열기 (복습)
2. 코인 애니메이션 + 코인 먹는 코드 만들기
3. Sprite Animation 실습
1. 문 미닫이 열기
1.1 애니메이션 생성 간단정리
- 녹화를 켠다
- Position - 우클릭 - Add key
- 원하는 위치 찍고 원하는대로 이동시킨다
- 녹화를 끈다
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 왜 coinCount를 Movement 클래스에 두었을까?
이유 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로 간결화한버전
반응형