9/30 플랫포머 #1

Hongryeol In·2024년 9월 30일

멋사유니티TIL

목록 보기
3/3
post-thumbnail

프로젝트 생성

마리오라이크 플랫포머 게임을 만들거다.

Universal 2D로 프로젝트를 생성하고
경로도 설정해준다.

에셋

에셋1
배경과 플랫폼
https://anokolisa.itch.io/basic-140-tiles-grassland-and-
에셋2
캐릭터와 오브젝트
https://assetstore.unity.com/packages/2d/characters/pixel-adventure-1-155360


배경 생성

배경 에셋의 Filter Mode를 Point(no filter)로 변경.

  • Bilinear는 안티앨리어싱처럼 흐릿해짐
    따라서 도트게임에는 적합하지 않다.


배경 에셋들의 Pixel Per Unit도 25로 변경.

그런다음 첫번째 선택하고 오픈 스프라이트 에디터

열고
1. 상단 Slice
2. 그리드 바이 셀 사이즈
3. Pixel Size X:16 Y:16
4. 적용(Apply)

잘 잘렸는지 확인

배경으로 쓸 2개는 스프라이트 모드 Single로 변경하고

그리고 Background레이어를 추가한다.

설정하고 구름이 하늘보다 앞에 있을수 있게
Order in Layer를 1로 명시한다.

Order in Layer:

같은 수준의 레이어 안에서의
우선순위를 설정할 수 있다.

이름을 변경하고 그룹화 해줬다.


플랫폼 생성

타일 팔레트

타일맵을 하나 만들고

Terrain 레이어를 만들고 적용

타일 팔레트 팝업을 연다.

  • 상단 Window > 2D > Tile Palette

    이름은 Terrain1

    팔레트에 아까 슬라이스한 에셋을 Drang & Drop하고

    아무 타일이나 선택하고 씬에 그려보면

    사이즈가 이상하다.

Grid의 셀 사이즈를 0.64로 하면 해결된다.

이제 팔레트로 적당히 플랫폼을 만들고

마음에 드는 캐릭터를 추가한다.
추가한 캐릭터에
Player레이어를 만들고 적용한다.

Pixel Per Unit도 25로 변경한다.

Terrain에서

  • Tilemap Collider 2D
  • Composite Collider 2D

2개를 추가한다.

Composite Collider 2D를 추가하면
자동으로 RigidBody 2D가 추가된다.
플랫폼은 안움직이게 할거라 Static으로 바꾼다.

Composite Collider 2D에서
composite Operation을 Merge로 바꿔준다.


플레이어 생성

플레이어에 박스콜라이더2D를 추가하고
크기와 위치를 적당히 맞춘다.

리지드바디2D도 추가하고 타입은 다이나믹.
Z축을 고정해서 캐릭터가 넘어지지 않도록 한다.

플레이어 이동

PlayerController.cs 스크립트를 만듭니다.
플레이어한테 붙여주고

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float Speed = 8;
    float vx = 0;
    void Start()
    {
        
    }
    void Update()
    {
        vx = Input.GetAxisRaw("Horizontal") * Speed;
        GetComponent<Rigidbody2D>().linearVelocity= new Vector2(vx, 0);       
    }
}

좌우 이동과 점프

좌우 이동을 구현한다.

GetAxis vs GetAxisRaw

GetAxis: 값이 선형적으로 바뀐다.
GetAxisRaw: 값이 비선형적으로 -1, 0, 1처럼 바뀐다.

바로 바뀌는게 좋아서 GetAxisRaw를 썼다.


캐릭터가 가는 방향을 쳐다보게 할거다
스프라이트랜더러 Flip을 이용한다.

방향이랑 점프 구현.

// PlayerController.cs
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float Speed = 8;
    public float JumpSpeed = 20;
    float vx = 0;

    {
        vx = Input.GetAxisRaw("Horizontal") * Speed;
        float vy = GetComponent<Rigidbody2D>().velocityY;

        if(vx<0)
        {
            GetComponent<SpriteRenderer>().flipX = true;
        }
        else if(vx>0)
        {
            GetComponent<SpriteRenderer>().flipX = false;
        }

        if(Input.GetButtonDown("Jump"))
        {
            vy = JumpSpeed;
        }

        GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);
    }
}

}

떨어지는 속도가 느린것같다
리지드바디2D에서 그래비티 스케일을 설정한다.

테스트 해보니 2가지 문제가 있다.

  1. 점프해서 공중에 떠있는 상태로 벽에 붙어서 계속 하면 껴버리는 문제가 있다.
  2. 높은 위치에서 떨어지면 플레이어가 플랫폼을 뚫어버린다.

1번의 해결방법
플레이어에 피직스 머테리얼을 추가해서 해결한다.


만들고 플레이어 리지드바디2D에 적용

2번의 해결방법
플레이어 리지드바디2D의 Collision Detection을 Continuous로 바꾼다.
Discrete보다 좀더 연속적인 방법이지만 조금 더 부하가 있다.


다중 점프 방지

다중점프에 대한 제어문을 작성하지 않아서 만들어보자.

플레이어 밑에 "Bottom" 오브젝트 생성

Terrain 태그 할당

Bottom에 캡슐콜라이더 2D추가하고

  • 방향 Horizontal
    플레이어 발 밑으로 적당히 조정하고
  • Is Trigger 체크

    체크를 안하면 캐릭터가 콜라이더 크기만큼 공중부양한다.
// PlayerController.cs
bool grounded;

void Update()
{
    grounded = BottomCollider.IsTouching(TerrainCollider);

    if (Input.GetButtonDown("Jump") && grounded)
    {
        vy = JumpSpeed;
    }

    GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);
}


이제 땅에 닿아있을때만 점프할 수 있다.


카메라

카메라 구현

카메라가 플레이어를 추적하게 할거다.

  • 방법 1(사용X)

메인카메라를 플레이어 밑으로 옮긴다

  • 방법 2

유니티에서 제공하는 Chinemachine 패키지를 이용한다.

다운로드 했으면 시네머신 카메라 오브젝트를 추가

시네머신 인스펙터에서

  • Lens : 5
  • Position Control : Follow
  • Tracking Target : Player 오브젝트

카메라 범위 제한

카메라가 맵 밖도 보여주기 때문에 고칠거다.

빈 오브젝트 생성.
이름은 Border.

폴리곤 콜라이더 2D생성하고 맵 크기에 맞춰 조정

시네머신 카메라에서 시네머신 컨파이어2D추가

시네머신 컨파이어2D에 Border 할당.

Border는 카메라만 제한하면 되서 체크 해제합니다.
체크하면 캐릭터가 Border의 콜라이더에 의해 맵 밖으로 밀려난다.


애니메이션

  • 플레이어에 Animator 컴포넌트 추가
  • Animator Controller 생성

플레이어의 Animator에 만든 애니메이터 컨트롤러 할당

애니메이션 창을 연다

Hierarchy에서 플레이어를 선택한 상태로
Create New Clip.
이름은 맘대로. 나는 PlayerIdle로 했다.

생성한 PlayerIdle에 Idle에셋 Drag & Drop.
Samples로 애니메이션 속도 조절.

Samples가 안보인다면

이런식으로

  • Run
  • Jump
    애니메이션도 만든다.

그리고 애니메이터를 열면

이렇게 표시된다.

Any State 우클릭 > Make Transition
모두 연결한다.

각 트랜지션의 트리거를 생성

Any State에서 Idle로 가는 트랜지션을 클릭하고

  • has Exit Taime : 체크 해제
  • Transition Duration : 0
  • Can Transition To Self : 체크
  • Conditions : Idle 추가

    Run이랑 Jump도 같은 방법으로

완성했으면 스크립트 작성

//PlayerController.cs

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float Speed = 5;
    public float JumpSpeed = 12;
    public Collider2D BottomCollider;
    public CompositeCollider2D TerrainCollider;

    float vx = 0;
    bool grounded;
    float prevVx = 0;
    void Start()
    {
        
    }

    void Update()
    {
        vx = Input.GetAxisRaw("Horizontal") * Speed;
        float vy = GetComponent<Rigidbody2D>().velocityY;

        if(vx<0)
        {
            GetComponent<SpriteRenderer>().flipX = true;
        }
        else if(vx>0)
        {
            GetComponent<SpriteRenderer>().flipX = false;
        }

        if (BottomCollider.IsTouching(TerrainCollider))
        {
            if (!grounded)
            {
                if (vx == 0)
                {
                    GetComponent<Animator>().SetTrigger("Idle");
                }
                else
                {
                    GetComponent<Animator>().SetTrigger("Run");
                }
            }
            else
            {
                if(vx!=prevVx)
                {
                    if (vx == 0)
                    {
                        GetComponent<Animator>().SetTrigger("Idle");
                    }
                    else
                    {
                        GetComponent<Animator>().SetTrigger("Run");
                    }
                }
            }
        }
        else
        {
            if(grounded)
            {
                GetComponent<Animator>().SetTrigger("Jump");
            }
        }

        grounded = BottomCollider.IsTouching(TerrainCollider);

        if (Input.GetButtonDown("Jump") && grounded)
        {
            vy = JumpSpeed;
        }
        prevVx = vx;
        GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);
    }
}

애니메이션 완성!


수업 끝!

0개의 댓글