[ 목차 ]
오늘의 포스팅은 Katana ZERO 3번째 실습이다.
기존에 배웠던 카메라 설정과
배경과 캐릭터 추가 설정을 계속 진행해보는 것이다.
이전 포스팅은 아래 첨부로 걸어두었으니 참고 바랍니다!
Katana ZERO (1)
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 20일차 - Katana ZERO (1)
[ 목차 ] 1945에 이어서 다른 게임을 실습해 보는 가진다. 횡스크롤 종류의 KATANA ZERO 게임을 구현해 볼 것이다.2D 횡스크롤은 엄청나게 많은 종류이면서 게임의 기본 중 기본이라고도 볼 수 있
gang-design.com
Katana ZERO (2)
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 21일차 - Katana ZERO (2)
[ 목차 ] 지난 포스팅에서 Katana ZERO (1)에 이어서 2번째 포스팅이다. 이번 포스팅은 캐릭터 애니메이션에 추가적으로 이어서 하는 것과디테일과 이펙트를 위주로 진행한다. 전의 포스팅을 보고
gang-design.com
1. Cinemachine 카메라
카메라가 배경 밖으로 나가지 않게 하는 것을 실습한다.
Window - Package Manager - Cinemachine
Cinemachine 카메라를 생성한다.
Hierarchy - Cinemachine - Targeted Camera - 2D Camera
CinemachineCamera Inspector - Cinemachine Camera - Lens
Orthographic Size가 처음엔 크게 되어 있을 것이다.
배경보다 작게 줄여서 맞추어준다.
어떤 것을 따라가게 할 것인지
Tracking Target에 정하면 된다.
여기서는 Player를 따라가게 하고 싶어 Player 오브젝트를 넣었다.
플레이어는 따라가는데, 아직 배경이 바깥으로 튀어나오니
Background 이미지에서 Box Collider 2D를 추가한다.
is Trigger 체크도 해야 한다.
다시 Cinemachine Camera로 돌아와
Add Extension - CinemachineConfiner 2D를 선택한다.
Inspector에 새롭게 Cinemachine Confiner 2D가 새로 생긴 것을 볼 수 있다.
Bounding Shape 2D에 Background Box Collider 2D를 넣는다.
이렇게 되면 배경이 밖으로 나가지 않는다.
2. 이펙트 먼지 생성하기
캐릭터의 먼지 이펙트를 추가해 볼 것이다.
애니메이션 이미지를 선택해 클립과 애니메이터를 생성한다.
새로운 스크립트 LandDust를 작성한다.
0.5초 시간 뒤에 지워지는 스크립트이다.
using UnityEngine;
public class LandDust : MonoBehaviour
{
public float lifetime = 0.5f;
private void Awake()
{
Destroy(gameObject, lifetime);
}
}
Player 스크립트로 가서
이펙트 코드를 추가한다.
이 방법은 필드에 선언하는 것이 아닌 다른 방안인데, 같은 방법으로 작동된다.
//흙먼지 이펙트
public void RandDust(GameObject dust)
{
Instantiate(dust, transform.position, Quaternion.identity);
}
이제 이 먼지 이펙트를 플레이어에게서 발생할 프레임을 골라준다.
Animation에서 0프레임을 선택해 Add Event를 추가한다.
이렇게 기존에 Add Event가 있으면 조그만한!! 엄청 조그만한 Event가 하나 더 생성될 수 있다.
(생성이 된 건지 안 된 건지 틀린그림찾기 하는 기분이었다..)
추가되면 Inspector에 Player - Methods - RandDust ( GameObject )를 선택한다.
GameObject에 먼지 이펙트 프리팹을 넣어준다.
먼지 이펙트 프리팹을 Player의 하위객체로 넣어준 후에 위치를 잡아준다.
조정한 위치의 Transform을 이제 코드로 옮겨줄 것이다.
흙먼지 이펙트 코드를 수정한다.
위치 값을 미리 지정해두는 것이다.
//흙먼지 이펙트
public void RandDust(GameObject dust)
{
Instantiate(dust, transform.position +new Vector3(-0.1f, -0.462f, 0), Quaternion.identity);
}
이제 점프 했을 때에도 먼지 발생을 하게 한다.
//점프먼지
public GameObject Jdust;
JumpDust() 메서드를 통해 먼지를 생성한다.
public void JumpDust()
{
Instantiate(Jdust, transform.position, Quaternion.identity);
}
이제 Update() 메서드에서 점프 했을 때 JumpDust() 메서드를 포함한다.
void Update()
{
KeyInput();
Move();
if (Input.GetKeyDown(KeyCode.W))
{
if (pAnimator.GetBool("Jump") == false)
{
Jump();
pAnimator.SetBool("Jump", true);
JumpDust();
}
}
}
이제 Jdust 목록에 Jumpdust 프리팹을 넣으면 된다.
3. 배경 공간 구현
이번엔 배경에서 캐릭터가 다니면 안 되는 공간을 지정하고, 벽을 짚는 공간 설정을 할 것이다.
오브젝트를 생성해서 흰색은 벽을 짚어줄 공간,
초록색은 플레이어가 밟고 다닐 공간으로 설정한다.
플레이어가 벽을 짚을 공간은 Layer - Wall로 생성해 변경한다.
플레이어가 땅을 밟고 다닐 자리는 Layer - Ground로 변경한다.
이제 빨간색 오브젝트로 플레이어가 침범하면 안 되는 공간을 설정한다.
이제 플레이어가 벽을 짚을 때 하는 애니메이션을 추가할 것이다.
해당 이미지를 가져온다.
해당 이미지로 애니메이션 클립을 생성한다.
새로운 Parameters를 생성할 것이다.
Bool로 선택해 Grab이름으로 생성한다.
플레이어가 점프를 한 뒤에 벽에 붙어야 하기 때문에
jump와 grab을 Make Transition으로 이어준다.
기본적인 애니메이션 트랜지션 설정을 해준다.
Has Exit Time 체크 해제
Transition Duration 0
그리고 jump -> grab 트랜지션은
Greb true로 해둔다.
이제 루프하지 않도록
Player_grab 애니메이션 클립의 Loop Time을 해제한다.
이제 스크립트를 수정한다.
Player 스크립트로 이동해
벽 점프에 관한 변수를 설정한다.
public Transform wallChk;
public float wallchkDistance;
public LayerMask wLayer;
bool isWall;
public float slidingSpeed;
public float wallJumpPower;
public bool isWallJump;
float isRight = 1;
상당히 많아서 이게 무슨 변수인지 하나씩 설명하면서 이해해보겠다.
(1) 벽이 있는지 확인할 지점(Transform) 변수
public Transform wallChk;
(2) 벽 체크할 때 얼마나 떨어진 거리까지 확인할지 정하는 값의 변수
public float wallchkDistance;
(3) 어떤 레이어가 벽인지 구분하는 필터의 변수
public LayerMask wLayer;
(4) 벽에 붙어있는지 여부를 나타내는 변수
bool isWall;
(5) 벽을 붙잡고 있을 때 미끄러지는 속도 변수
public float slidingSpeed;
(6) 점프할 때 튕겨 나가는 힘 변수
public float wallJumpPower;
(7) 벽 점프 중인지 아닌지 나타내는 변수
public bool isWallJump;
(8) 캐릭터가 오른쪽을 바라보고 있으면 1, 왼쪽이면 -1
float isRight = 1;
그렇게 Player 스크립트 전체 코드이다.
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[Header("플레이어 속성")]
public float speed = 5;
public float jumpUp = 1;
public float power = 5;
public Vector3 direction;
public GameObject slash;
//그림자
public GameObject Shadow1;
List<GameObject> sh = new List<GameObject>();
//히트 이펙트
public GameObject hit_lazer;
bool bJump = false;
Animator pAnimator;
Rigidbody2D pRig2D;
SpriteRenderer sp;
public GameObject Jdust;
//벽점프
public Transform wallChk;
public float wallchkDistance;
public LayerMask wLayer;
bool isWall;
public float slidingSpeed;
public float wallJumpPower;
public bool isWallJump;
float isRight = 1;
void Start()
{
pAnimator = GetComponent<Animator>();
pRig2D = GetComponent<Rigidbody2D>();
direction = Vector2.zero;
sp = GetComponent<SpriteRenderer>();
}
void KeyInput()
{
direction.x = Input.GetAxisRaw("Horizontal"); //왼쪽은 -1 0 1
if(direction.x <0)
{
//left
sp.flipX = true;
pAnimator.SetBool("Run", true);
//점프벽잡기 방향
isRight = -1;
//Shadowflip
for(int i =0; i<sh.Count; i++)
{
sh[i].GetComponent<SpriteRenderer>().flipX = sp.flipX;
}
}
else if(direction.x >0)
{
//right
sp.flipX = false;
pAnimator.SetBool("Run", true);
isRight = 1;
//Shadowflip
for (int i = 0; i < sh.Count; i++)
{
sh[i].GetComponent<SpriteRenderer>().flipX = sp.flipX;
}
}
else if(direction.x == 0)
{
pAnimator.SetBool("Run", false);
for (int i = 0; i < sh.Count; i++)
{
Destroy(sh[i]); //게임오브젝트지우기
sh.RemoveAt(i); //게임오브젝트 관리하는 리스트지우기
}
}
if (Input.GetMouseButtonDown(0)) //0번 왼쪽마우스
{
pAnimator.SetTrigger("Attack");
Instantiate(hit_lazer, transform.position, Quaternion.identity);
}
}
void Update()
{
if(!isWallJump)
{
KeyInput();
Move();
}
//벽인지 체크
isWall = Physics2D.Raycast(wallChk.position, Vector2.right * isRight, wallchkDistance, wLayer);
pAnimator.SetBool("Grab", isWall);
if(Input.GetKeyDown(KeyCode.W))
{
if(pAnimator.GetBool("Jump")==false)
{
Jump();
pAnimator.SetBool("Jump", true);
JumpDust();
}
}
if(isWall)
{
isWallJump = false;
//벽점프상태
pRig2D.linearVelocity = new Vector2(pRig2D.linearVelocityX, pRig2D.linearVelocityY * slidingSpeed);
//벽을 잡고있는 상태에서 점프
if(Input.GetKeyDown(KeyCode.W))
{
isWallJump = true;
//벽점프 먼지
Invoke("FreezeX", 0.3f);
//물리
pRig2D.linearVelocity = new Vector2(-isRight * wallJumpPower, 0.9f * wallJumpPower);
sp.flipX = sp.flipX == false ? true : false;
isRight = -isRight;
}
}
}
void FreezeX()
{
isWallJump = false;
}
private void FixedUpdate()
{
Debug.DrawRay(pRig2D.position, Vector3.down, new Color(0, 1, 0));
//레이캐스트로 땅체크
RaycastHit2D rayHit = Physics2D.Raycast(pRig2D.position, Vector3.down, 1, LayerMask.GetMask("Ground"));
if(pRig2D.linearVelocityY < 0)
{
if(rayHit.collider != null)
{
if(rayHit.distance <0.7f)
{
pAnimator.SetBool("Jump", false);
}
}
}
}
public void Jump()
{
pRig2D.linearVelocity = Vector2.zero;
pRig2D.AddForce(new Vector2(0, jumpUp), ForceMode2D.Impulse);
}
public void Move()
{
transform.position += direction * speed * Time.deltaTime;
}
public void AttSlash()
{
//플레이어 오른쪽
if(sp.flipX == false)
{
pRig2D.AddForce(Vector2.right * power, ForceMode2D.Impulse);
//플레이어 오른쪽
GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
//go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
}
else
{
pRig2D.AddForce(Vector2.left * power, ForceMode2D.Impulse);
//왼쪽
GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
//go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
}
}
//그림자
public void RunShadow()
{
if(sh.Count<6)
{
GameObject go = Instantiate(Shadow1, transform.position, Quaternion.identity);
go.GetComponent<Shadow>().TwSpeed = 10 - sh.Count;
sh.Add(go);
}
}
//흙먼지
public void RandDust(GameObject dust)
{
Instantiate(dust, transform.position +new Vector3(-0.114f,-0.467f,0), Quaternion.identity);
}
public void JumpDust()
{
Instantiate(Jdust, transform.position, Quaternion.identity);
}
}
이제 Player Inspector에 Jdust 아래부터 여러 목록이 생성된 것을 알 수 있다.
Wall Chk에 Player의 위치를 확인하기 위해 Player 오브젝트를 넣는다.
Wallchk Distance, Sliding SPeed, Wall Jump Power는 개인적으로 적당한 값을 넣어준다.
W Layer는 Wall로 설정한다.
이렇게 적용하면
게임을 플레이할 때 벽에 붙는 모습을 알 수 있다.
이렇게 Katana ZERO (3)을 마친다!!
코드가 길어질수록.. 복기하기가 힘든 게 많아지는 느낌이다.
솔직히 까먹은 것도 있긴 하다.
이 코드가 뭐였는지, 왜 쓰이는지 등..
복습 부족이겠지.....
처음과 비교하면 많이 알긴 했지만 더 노력하자!!
이 글을 보고 있는 사람도 같이 파이팅!!
'Development > 멋쟁이사자처럼 게임개발 부트캠프' 카테고리의 다른 글
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 23일차 - 유니티 게임 수학 & 물리 (0) | 2025.04.08 |
---|---|
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 23일차 - Katana ZERO (4) (0) | 2025.04.08 |
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 21일차 - Katana ZERO (2) (0) | 2025.04.03 |
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 20일차 - Katana ZERO (1) (0) | 2025.04.03 |
[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 19일차 - 코딩 없는 Timeline (0) | 2025.03.31 |