이번 포스팅에서는 굉장히 많이 쓰이는 기술 중 하나인 Raycast에 대해 정리해보겠습니다.
아래 그림은 Raycast 를 아주 쉽게 도식화한 그림입니다.
Origin 은 Ray의 시점입니다. 예를 들어 FPS 게임을 만든다고 하면, 총구의 위치가 Origin이 될 수 있겠네요.
그렇다면 MaxDistance 는 무엇을 의미할까요?
Ray를 쏠 수 있는 거리를 의미합니다. 마찬가지로 FPS 게임으로 예를 들면 총기의 사거리를 생각하면 이해하기 편하실겁니다.
Direction 은 Ray를 발사하는 방향을 의미합니다. hit 는 Ray 에 닿는 상대를 의미합니다. 여기서 주의할 점은 Ray가 다른 Object를 감지하기 위해서는 그 오브젝트에 충돌체(Collider)가 반드시 필요하다는 점입니다.
아래 코드는 유니티 화면에서 Player 기준 앞쪽 방향으로 Ray를 쐈을 때 맞은 Enemy의 체력이 깎이는 것을 구현한 코드이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// 플레이어의 공격력
public int atk = 10;
// Ray가 닿을 수 있는 최대 거리
public float maxDistance = 10;
void Update()
{
// 레이캐스트
// ray 에 닿으려면 닿는 객체에 Collider 필요하다.
// 실습1. ray를 LeftShift를 눌렀을 때만 앞쪽 방면으로 쏘기
// 언제? LeftShift를 누를 때
if (Input.GetKeyDown(KeyCode.LeftShift))
{
// ray를 맞게될 변수
RaycastHit enemyHit;
// 매개변수 0.5f 는 Line이 그려지는 지속시간을 뜻함.
Debug.DrawLine(transform.position,transform.forward * maxDistance,Color.yellow,0.5f);
// 플레이어 기준 Forward 방향으로 ray를 쏜다.
Physics.Raycast(transform.position,transform.forward, out enemyHit, maxDistance);
// 실습2. 레이에 맞은 몹이 있을 때 몬스터의 체력을 깎아라
if(enemyHit.collider.gameObject.GetComponent<Enemy>() != null)
{
enemyHit.collider.gameObject.GetComponent<Enemy>().Hp -= atk;
}
}
}
}
플레이어 기준에서 Ray를 쏘는 코드를 보면 Phsics.Raycast() 부분이 보이는데, 매개변수를 보면 enemyHit 앞에 out 이란 키워드가 붙어있다.
잠시 out 키워드에 대해 설명하자면, out 키워드는 ref 키워드와 비슷하면서도 다른 의미를 가지고있다.
그렇다면 ref 키워드는 무엇인가? ref 키워드는 그 변수의 주소로 직접 접근하는 키워드로 함수의 매개변수에 ref 키워드가 붙은 경우, 함수 호출시 사용되는 매개변수의 주소에 직접 접근하여 값을 변경하거나 참조할 수 있게한다.
out 키워드는 이런 ref 키워드의 특징을 전부 가지지만 "내부에서 반드시 값 변경이 일어나야함" 이란 규칙을 하나 더 가지고있다고 보면 된다.
그와 반대로 in 키워드는 값을 변경하려 할 시 오류가 발생한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// out , in 키워드 // 참조자
// in : 내부에서 값 변경 하지말 것. 즉, 읽기 전용
// out : 내부에서 값 변경 '반드시' 할 것
int num = 10;
void Foo1(out int value)
{
value = 0;
}
int Foo2(in int value)
{
// value = 20; // 오류 발생
return value;
}
private void Start()
{
Foo1(out num);
Foo2(in num);
}
}
위 코드를 보면 value = 20; 부분에 오류 발생이라고 쓰여있다. 실제로 저 부분의 주석을 해제하면 컴파일 에러가 발생하는 것을 확인 할 수 있다.
이번엔 player가 땅을 기준으로 점프 가능한 상태인지 Layer를 통해 검사하고 점프하는 기능을 구현한 것이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public int atk = 10;
public float maxDistance = 10;
public float maxJumpHeight = 3;
public float jumpPower = 5;
public bool isGround;
public bool isJumpable;
Rigidbody rb;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
public void Jump()
{
// 점프가 가능한 상태라면
if(isJumpable)
{
// 위쪽 방향으로 점프력만큼 힘을 가한다.
rb.AddRelativeForce(transform.up * jumpPower, ForceMode.Impulse);
}
}
void Update()
{
// 레이캐스트
// Ray 를 맞는 타겟의 정보
RaycastHit hit = null;
// 플레이어 위치 기준 아래방향으로 점프력 만큼 라인 발사
Debug.DrawLine(transform.position, transform.position + (-transform.up * maxJumpHeight), Color.red);
// 플레이어가 점프 가능한 상태인지 검사
// 1<<8 은 Ground 의 Layer
isGround = Physics.Raycast(transform.position, -transform.up, out hit, maxJumpHeight, 1<<8) ;
isJumpable = isGround;
// 스페이스바 입력 받기
if (Input.GetKeyDown(KeyCode.Space))
{
// 점프하기
Jump();
}
}
}
'Unity' 카테고리의 다른 글
Unity <스크립터블오브젝트(ScriptableObject) 사용하여 몬스터의 아이템 드랍 구현하기> (2) | 2024.01.13 |
---|