
마리오라이크 플랫포머 게임을 만들거다.
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 레이어를 만들고 적용

타일 팔레트 팝업을 연다.




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

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

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

Pixel Per Unit도 25로 변경한다.
Terrain에서

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번의 해결방법
플레이어에 피직스 머테리얼을 추가해서 해결한다.


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

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

다중점프에 대한 제어문을 작성하지 않아서 만들어보자.
플레이어 밑에 "Bottom" 오브젝트 생성

Terrain 태그 할당

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


// PlayerController.cs
bool grounded;
void Update()
{
grounded = BottomCollider.IsTouching(TerrainCollider);
if (Input.GetButtonDown("Jump") && grounded)
{
vy = JumpSpeed;
}
GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);
}

이제 땅에 닿아있을때만 점프할 수 있다.
카메라가 플레이어를 추적하게 할거다.
메인카메라를 플레이어 밑으로 옮긴다

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


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

시네머신 인스펙터에서

카메라가 맵 밖도 보여주기 때문에 고칠거다.
빈 오브젝트 생성.
이름은 Border.

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

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

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

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


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

애니메이션 창을 연다

Hierarchy에서 플레이어를 선택한 상태로
Create New Clip.
이름은 맘대로. 나는 PlayerIdle로 했다.
생성한 PlayerIdle에 Idle에셋 Drag & Drop.
Samples로 애니메이션 속도 조절.

Samples가 안보인다면

이런식으로
그리고 애니메이터를 열면

이렇게 표시된다.

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

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


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

완성했으면 스크립트 작성
//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);
}
}
애니메이션 완성!
수업 끝!