지우너
[Unity 3D Run] 장애물 충돌 설정 본문
03.13
장애물 설치하기
장애물에 닿으면 게임오버 → OnCollisionEnter
게임 오버 함수 -캐릭터 움직임 중지, 카메라 움직임 중지, 게임오버 UI
현재 c# 스크립트 파일이 아래와 같이 있다.
- Player.cs
Player 스크립트는 모든 입력이 들어오는 스크립트이고, Player 스크립트는 이 입력을 PlayerController 스크립트로 보낸다.
- PlayerController.cs
PlayerController 스크립트는 실제 플레이어 컨트롤을 담당.
- CameraController.cs
카메라의 움직임을 관리하는 스크립트. 플레이어가 살아있다면(=게임이 진행 중이라면) 플레이어를 따라가도록 설정했다.
- Obstacle.cs
플레이어가 부딪히면 죽도록 설계되어야 함.
https://github.com/SebLague/Create-a-Game-Source/tree/master/Episode%2025
위 사이트에서 Die를 구현할 때 썼던 코드에 나온 문장인데 왜 쓴 건지 모르겠어서 검색해봤다.
// Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// GetComponent<PlayerController>()는 PlayerController와 Player 스크립트가 같은 오브젝트에 붙어 있는걸 전제로 한다.
// [RequireComponent(typeof(PlayerController))] 코드를 적어줘서 이 부분이 에러를 내지 않게 됨.
[RequireComponent(typeof(PlayerController))]
public class Player : MonoBehaviour
{
public float moveSpeed = 3.0f;
protected bool dead;
public event System.Action OnDeath;
// moveVelocity를 다른 스크립트인 PlayerController로 전달해서 물리적인 부분들을 처리할 수 있도록 할 것
// 그래서 PlayerController에 대한 레퍼런스를 가져와야합니다.
PlayerController controller;
void Start()
{
}
void Awake()
{
controller = GetComponent<PlayerController>();
}
void Update()
{
// Movement input 플레이어의 움직임을 입력 받는 것
// 수평(Horizontal) 과 수직(Vertical) 방향에 대한 입력을 받고 싶으니
// Input. 을 적고 GetAxis()를 호출해서 "Horizontal"을 넣습니다.
// y값은 내버려 둬도 되며(0), 일정한 속도로 앞으로 가도록 moveSpeed를 넣어줬다.
Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0, moveSpeed);
// 입력 받은 값을 방향으로 변환하고 움직임 속도를 곱할 겁니다.
// 입력의 방향을 얻기 위해 moveInput를 정규화(nomalized)하여 가져옵니다 (nomarlized는 방향을 가리키는 단위벡터로 만드는 연산)
// 거기에 moveSpeed를 곱해줍니다
Vector3 moveVelocity = moveInput.normalized * moveSpeed;
// controller에게 velocity값을 넘겨줌
controller.Move(moveVelocity);
}
public void Die()
{
// https://github.com/SebLague/Create-a-Game-Source/tree/master/Episode%2025
// livingEntity, player.cs에 있음
dead = true;
if (OnDeath != null)
{
OnDeath();
}
GameObject.Destroy(gameObject);
}
}
// Obstacle.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Obstacle : MonoBehaviour
{
GameObject target;
private Player player;
// Start is called before the first frame update
void Start()
{
target = GameObject.FindGameObjectWithTag("Player");
player = GetComponent<Player>();
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Player")
{
// 플레이어가 접촉했다면 플레이어Die, GameOver, Camera Stop
player.Die();
}
}
}
player = GetComponent<Player>(); 이렇게 변수에 저장했기 때문에 player.Die(); 부분에서 NullReferenceException이 났다. player.target.GetComponent<Player>();이라고 변경해주어야 한다.
유니티-충돌 처리 하기(2) 게임 중지시키기 - Study@withCoffee
Time.timeScale=0으로 하면 게임 씬이 정지하게 된다.
Time.timeScale=1이면 정상적인 속도로 시간이 움직이고, Time.timeScale=2라면 2배속으로 빠르게 재생된다.
//player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// GetComponent<PlayerController>()는 PlayerController와 Player 스크립트가 같은 오브젝트에 붙어 있는걸 전제로 한다.
// [RequireComponent(typeof(PlayerController))] 코드를 적어줘서 이 부분이 에러를 내지 않게 됨.
[RequireComponent(typeof(PlayerController))]
public class Player : MonoBehaviour
{
public float moveSpeed = 3.0f;
protected bool dead;
// moveVelocity를 다른 스크립트인 PlayerController로 전달해서 물리적인 부분들을 처리할 수 있도록 할 것
// 그래서 PlayerController에 대한 레퍼런스를 가져와야합니다.
PlayerController controller;
void Start()
{
}
void Awake()
{
controller = GetComponent<PlayerController>();
}
void Update()
{
if (!dead)
{
// Movement input 플레이어의 움직임을 입력 받는 것
// 수평(Horizontal) 과 수직(Vertical) 방향에 대한 입력을 받고 싶으니
// Input. 을 적고 GetAxis()를 호출해서 "Horizontal"을 넣습니다.
// y값은 내버려 둬도 되며(0), 일정한 속도로 앞으로 가도록 moveSpeed를 넣어줬다.
Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0, moveSpeed);
// 입력 받은 값을 방향으로 변환하고 움직임 속도를 곱할 겁니다.
// 입력의 방향을 얻기 위해 moveInput를 정규화(nomalized)하여 가져옵니다 (nomarlized는 방향을 가리키는 단위벡터로 만드는 연산)
// 거기에 moveSpeed를 곱해줍니다
Vector3 moveVelocity = moveInput.normalized * moveSpeed;
// controller에게 velocity값을 넘겨줌
controller.Move(moveVelocity);
}
}
public void Die()
{
dead = true;
Time.timeScale = 0;
}
}
// Obstacle.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Obstacle : MonoBehaviour
{
GameObject target;
private Player player;
// Start is called before the first frame update
void Start()
{
target = GameObject.FindGameObjectWithTag("Player");
player = target.GetComponent<Player>();
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Player")
{
// 플레이어가 접촉했다면 플레이어Die, GameOver, Camera Stop
player.Die();
}
}
}
Time.timeScale=0으로 하는 게 뭔가 이렇게 하면 안 될 것 같다는 생각이 들어서 원래 코드처럼 player 오브젝트를 파괴하는 방식으로 코드를 수정했다.
// Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// GetComponent<PlayerController>()는 PlayerController와 Player 스크립트가 같은 오브젝트에 붙어 있는걸 전제로 한다.
// [RequireComponent(typeof(PlayerController))] 코드를 적어줘서 이 부분이 에러를 내지 않게 됨.
[RequireComponent(typeof(PlayerController))]
public class Player : MonoBehaviour
{
public float moveSpeed = 3.0f;
protected bool dead;
// moveVelocity를 다른 스크립트인 PlayerController로 전달해서 물리적인 부분들을 처리할 수 있도록 할 것
// 그래서 PlayerController에 대한 레퍼런스를 가져와야합니다.
PlayerController controller;
void Start()
{
}
void Awake()
{
controller = GetComponent<PlayerController>();
}
void Update()
{
if (!dead)
{
// Movement input 플레이어의 움직임을 입력 받는 것
// 수평(Horizontal) 과 수직(Vertical) 방향에 대한 입력을 받고 싶으니
// Input. 을 적고 GetAxis()를 호출해서 "Horizontal"을 넣습니다.
// y값은 내버려 둬도 되며(0), 일정한 속도로 앞으로 가도록 moveSpeed를 넣어줬다.
Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0, moveSpeed);
// 입력 받은 값을 방향으로 변환하고 움직임 속도를 곱할 겁니다.
// 입력의 방향을 얻기 위해 moveInput를 정규화(nomalized)하여 가져옵니다 (nomarlized는 방향을 가리키는 단위벡터로 만드는 연산)
// 거기에 moveSpeed를 곱해줍니다
Vector3 moveVelocity = moveInput.normalized * moveSpeed;
// controller에게 velocity값을 넘겨줌
controller.Move(moveVelocity);
}
}
public void Die()
{
dead = true;
GameObject.Destroy(gameObject);
}
}
그랬더니 아래와 같이 에러가 났다.
target = GameObject.FindGameObjectWithTag("Player").transform; target이 없어졌기 때문에 카메라가 이동할 새로운 위치를 받을 수 없는 것이다.
따라서 카메라 코드도 이에 맞춰 조건을 추가해줘야 한다.
// CameraController.cs
using UnityEngine;
public class CameraController : MonoBehaviour
{
private Transform target;
private Vector3 offset;
float lerpTime = 0.6f;
float currentTime = 0;
void Start()
{
target = GameObject.FindGameObjectWithTag("Player").transform;
offset = transform.position - target.position;
}
void LateUpdate()
{
// player가 obstacle에 맞아서 파괴가 되면 target은 null이 된다.
if (target != null)
{
// currentTime은 시간 흐름에 따라 증가함
currentTime += Time.deltaTime;
// 이 코드를 넣어주면 0부터 증가하다가 최대 0.5(lerpTime)까지만 증가함
if (currentTime >= lerpTime) currentTime = lerpTime;
float t = currentTime / lerpTime;
// 플레이어 이동에 따라 변하는 카메라 위치
Vector3 newPosition = new Vector3(transform.position.x, transform.position.y, offset.z + target.position.z);
transform.position = Vector3.Lerp(transform.position, newPosition, t);
}
}
}
[베이스씬에서 만들어야 할 것]
(*베이스씬: 스테이지를 만들 때 가장 기본이 될 씬인데, 뭐라고 불러야 할지 모르겠어서 일단 베이스씬이라고 부르고 있다.)1. 게임오버 UI2. esc를 눌렀을 때 게임이 일시정시 되면서, <게임 이어하기>, <그만하기> 이런 버튼이 나오도록+) 만들면 좋은 거: 플레이어가 죽을 때 애니메이션(지금은 너무 갑자기 슉 하고 없어지니까)
내일은 게임오버UI를 만들어야 할 것 같다. 원래 계획대로라면 어제 베이스씬을 다 만들었어야 했는데, 생각보다 늦어졌다...
'Project' 카테고리의 다른 글
[Unity 3D Run] 게임오버/클리어 UI (3) (1) | 2023.03.25 |
---|---|
[Unity 3D Run] 게임오버 UI (2) 공부+약간 수정 (0) | 2023.03.21 |
[Unity 3D Run] 게임 오버 UI(1) (0) | 2023.03.16 |
[Unity 3D Run] 캐릭터 이동 코드 수정, 카메라 추적 (0) | 2023.03.12 |
[Unity 3D Run] 03.05-03.09 계획, 캐릭터 이동 구현 (0) | 2023.03.09 |