Short Cake
8PM - Animal Crossing Wild World

사생활 보호 설정

https://gamjia.tistory.com

Mini Rooms

  • 내 미니룸
  • 미니미설정
  • 미니룸설정
  • 답글수 [0]

What Friends Say

한마디로 표현해봐~

1촌평 관리

[Day 9] Save The Dog Tutorial 3

GamJia 2024. 11. 15. 22:51

오블완 챌린지 9일차


매주 금요일은 기타 레슨 날이라

기타 레슨을 받은 뒤 선생님께

칭찬 받아서 기분 좋은 GamJia 입니다

 

어제 강의에 이어서
Save The Dog을 만들어 보겠습니다

 


Before & After

 

오늘은 특별하게 먼저

Before와 After를 비교해드리겠습니다

 

사실 어제, 오늘 유튜브 강의를 좀 봤는데

다 너무 어려운 방법으로 가는 것 같아서..

단순하면서 쉬운 방법으로

제가 (회사에서) 재구성 해보았습니다

 


using UnityEngine;

public class LineManager : MonoBehaviour
{
    [SerializeField] GameObject line; 

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Instantiate(line, Vector3.zero, Quaternion.identity, this.transform);
        }
    }
}

 

일단 선들을 하나하나 분리하기 위해

Line Prefab 객체로 분리하고

그걸 LineManager가 만들어주는

역할로 바꾸어주도록 하겠습니다

 


 

그리고 배경 침범을 방지하기 위해

Background라는 새 Layer를

만들어주도록 하겠습니다

 


 

그리고 LineRenderer Component만 있는

Line 객체를 따로 생성해주겠습니다

여기서 가장 중요한건

Use World Space가 무조건 해제 되어야 합니다

 

Use World Space 좌표 기준 GameObject 이동/회전 시 결과
true 월드 좌표 (World Space) 라인의 위치와 형태는 변하지 않음.
false 로컬 좌표 (Local Space) 라인의 위치와 형태가 GameObject의 위치/회전에 따라 변함.

 


using System.Collections.Generic;
using UnityEngine;

public class Line : MonoBehaviour
{
    [SerializeField] private LayerMask backgroundLayer; // 백그라운드 레이어 설정
    private LineRenderer lineRenderer;
    private EdgeCollider2D edgeCollider;
    private List<Vector2> linePoints = new List<Vector2>();
    private bool isDrawing = false; // 초기값은 true로 설정하여 첫 그림은 허용

    void Awake()
    {
        lineRenderer = GetComponent<LineRenderer>();
    }

    void Update()
    {
        if (isDrawing) return; 

        if (Input.GetMouseButton(0)) 
        {
            Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);

            // Raycast로 마우스 위치가 backgroundLayer에 속하는지 확인
            if (IsMouseOnBackground(mousePos))
            {
                return;
            }

            if (linePoints.Count == 0 || Vector2.Distance(linePoints[^1], mousePos) > 0.1f)
            {
                linePoints.Add(mousePos);
                UpdateLineRenderer();
            }
        }

        if (Input.GetMouseButtonUp(0)) 
        {
            isDrawing = true; 
            UpdateCollider();
        }
    }

    private void UpdateLineRenderer()
    {
        lineRenderer.positionCount = linePoints.Count;
        for (int i = 0; i < linePoints.Count; i++)
        {
            lineRenderer.SetPosition(i, linePoints[i]);
        }
    }

    private void UpdateCollider()
    {
        if (!edgeCollider)
        {
            edgeCollider = gameObject.AddComponent<EdgeCollider2D>();
            edgeCollider.edgeRadius = 0.05f;
        }

        List<Vector2> edgePoints = new List<Vector2>();
        for (int i = 0; i < lineRenderer.positionCount; i++)
        {
            Vector3 pos = lineRenderer.GetPosition(i);
            edgePoints.Add(new Vector2(pos.x, pos.y)); // 2D 좌표로 변환
        }
        edgeCollider.SetPoints(edgePoints);

        if (!gameObject.GetComponent<Rigidbody2D>())
        {
            gameObject.AddComponent<Rigidbody2D>();
        }
    }

    private bool IsMouseOnBackground(Vector2 mousePos)
    {
        RaycastHit2D hit = Physics2D.Raycast(mousePos, Vector2.zero, 0, backgroundLayer);
        return hit.collider != null; 
    }
}

 

보면 굉장히 복잡해보이지만

쉽게 설명 드리도록 하겠습니다

 

Awake LineRenderer 컴포넌트를 가져와서 선을 그릴 준비를 합니다.
Update
  • 마우스 왼쪽 버튼(Input.GetMouseButton(0))을 누르는 동안:
    • 마우스 위치가 백그라운드 레이어 위에 있는지 확인합니다. (그럴 경우 무시해서 못 그리게 막음)
    • 새 위치가 이전 위치와 일정 거리 이상 떨어졌다면, 선에 점을 추가하고 화면에 업데이트합니다.
  • 마우스 버튼을 뗄 때(Input.GetMouseButtonUp(0)):
    • 선 그리기를 종료하고(isDrawing = true), 충돌 처리를 위해 EdgeCollider2D와 Rigidbody2D를 추가합니다.
UpdateCollider
  • EdgeCollider2D를 생성하고, 선의 모든 점(Positions)을 설정합니다.
  • 물리 연산을 위해 Rigidbody2D도 추가합니다.
IsMouseOnBackground 마우스 위치에 Raycast를 쏴서 마우스가 특정 레이어에 속하는 객체 위에 있는지 확인합니다.

 


 

아까 만든 Background Layer

연결해주고 Prefab으로 변환한 다음

Scene에 있던 기존 Line은 지워주겠습니다

 

Prefab 변환이 완료 됐다면

Line Manager에 할당해주겠습니다


 

어떤가요 원작 느낌이 조금 나나요?ㅎㅎ

이렇게 선을 그리고 거기에

물리 충돌 설정을 넣어주었습니다

 

이번에는 강아지를 한번 볼까요?

 


 

강아지의 표정은 크게 기본, 행복, 슬픈

표정으로 나뉘는데요 일단 Idle 표정

Animation을 위해 관련 Sprite들을 선택하고

Dog 객체에 드래그 해주겠습니다

 


 

방금 만든 Animation을 확인하는데

뭔가 눈을 감는거 같기는 한데..

좀 어색하지 않나요?

뭔가 끊기는 느낌도 들고...

 

 

그럴 때는 가장 마지막 Frame을

기준으로 이렇게 Frame을 복사해주세요

그러면 이전보다는 훨씬 자연스러워진답니다

 


 

어떤가요?? 아까보다는 자연스럽게

눈을 깜빡이고 있는 모습 같죠??

Loop Animation들은 이런식으로

해주면 대부분 훨씬 자연스러워진답니다

 


 

Happy와 Sad Animation도

Idle과 같은 방식으로 생성해줄게요

이 둘은 Loop Animation이 아니라

위와 같은 과정은 따로 안 거쳐도 됩니다

 


 

Windows / Animation / Animator를 활성화하면

다음과 같은 모습이 나오게 되는데요

방금 말한것처럼 Idle만 Loop Animation이기 때문에

나머지는 더블 클릭해서 관련 설정을

해제 해주도록 하겠습니다

 


 

Idle은 평소의 표정이고

Happy와 Sad는 특수한 경우에

짓게 되는 표정이라

그걸 bool값으로 관리해주도록 하겠습니다

 

isClear(게임을 클리어 한 경우) : Happy

isHit(벌에게 쏘인 경우) : Sad

 


 

제가 원할 때면 언제든 상태를 바꿀 수 있게

Make Transition을 설정해 오른쪽 이미지처럼

Happy와 Sad에 연결해주세요

 


 

방금 연결한 Transition을 클릭하면

이런식으로 Condition을 설정할 수 있게 됩니다

아까 설명처럼 isClear가 true일 때 Happy

isHit이 true일 때 Sad 표정을 짓게 설정해주세요

 


 

제가 Animator 자체에서

isHit을 true로 설정하고 확인해보니

condition에 맞게 멍멍이의

표정이 잘 바뀐걸 확인했습니다!

 



오늘은 여기까지 하고

GitHub에 Commit하는걸로

마무리 하겠습니다!

오늘 내용이 좀 어려웠는데

따라오는데 문제는 없으셨을지

조금 걱정 됩니다 하지만 어려운건

다 지나갔으니 안심하셔도 됩니다

 

감사합니다!!
 


 

'Challenge' 카테고리의 다른 글

[Day 11] Save The Dog Tutorial 5  (0) 2024.11.17
[Day 10] Save The Dog Tutorial 4  (2) 2024.11.16
[Day 8] Save The Dog Tutorial 2  (4) 2024.11.14
[Day 7] Save The Dog Tutorial 1  (8) 2024.11.13
[Day 6] Flappy Bird Tutorial 5  (0) 2024.11.12