Unity_본캠프

[내일배움캠프 30일차] Ray 빔~!!!

티백고래 2025. 5. 20. 22:41

1. 오늘의 할 일

1. 체력바/스테미너바 만들기

2. Ray를 사용해서 Ground 레이어를 판정하고 점프가 가능하게 만들기

 

1은 금방 해냈고, 2가 이번 핵심 되시겠다.

2. 제작 개시🛠️

1. HP와 Stemina

체력과 스테미너바 되시겠다.

일단 단순한 구조로 시작한다. (가장 기본 구조)

 

구조는 다음과 같다.

-캔버스 (UI라면 기본으로 필요한 곳)

 > Conditions (빈 오브젝트): 여기에 Vertical Layout Grid 삽입

   >>Health (Icon, HPBar도 UI 이미지)

   >>Stemina (Icon, SteminaBar도 UI 이미지)

 

? Vertical Layout Group?

Layout Group. 이름에서 알 수 있듯, 레이아웃을 정렬하는 그룹 생성기.

Vertical은 세로 정렬을 시켜준다. (그간 UI 정렬한다고 y값이나 x값 통일해가며 자체 조정 하던 삶과 작별이다)

손수 해야하는 수공예 작업과는 달리, 컴퓨터가 알아서 자동정렬을 해주기 때문에 편안하다(진짜)

 

단: 반드시 배치할 공간의 사이즈를 맞춰줘야한다.

그러니까, 겨우 2개의 UI를 넣을 건데 높이가 1080이라고 해보자.

그럼 이렇게 된다.

최상단에 하나, 중앙에 하나가 배치되는 걸 볼 수있다.

140정도로 하면, 각 상태바의 높이가 65이므로 서로간의 간격을 약 5정도로 두고 균일하게 놓여진다.

 

Unity에는 기본적으로 Grid (가로세로정렬), Horizontal(가로정렬)도 있으므로 필요할 때 잘 맞춰서 작성해주도록 하자.

 

그리고 이건 이번에 HP바와 Stemina바 구현에 사용한 FillMethod.

ImageType을 Filled로 하니까 생겼다.(Image를 꼭 설정해줄 것)

Horizontal > 가로로 왔다갔다한다. 오른쪽에서 왼편으로 줄었다가 늘어났다를 해준다. HP바, 경험치 바 등 가로 UI에 활용.

Vertical > 세로로 왔다갔다. 위에서 아래로 줄어들고, 아래에서 위로 채워진다. 세로로 게이지를 채우는 걸 구현하거나, 혹은 스킬이나 아이템 쿨타임에 사용하기 좋아보인다.

Radial90 > 왼쪽 아래를 중심점으로 돌아간다.

어디서 쓰는 게 좋을지는 모르겠다....

 

Radial180> 아래 중심을 기준으로 돌아간다. 연출용으로 쓸 수 있을지도 모르겠다....(어디서 쓸 수 있을지 감이 안 옴)

 

Radial360> 이미지의 중심에서 돌아간다. 스킬/아이템 쿨타임 UI에서 Alpha값을 낮춘 검은색을 덧씌우고 쓰기 좋아보인다.

 

해당 Image를 변형하는 것은 저기 이미지에 보이는 FillAmount라는 것인데, 0~1까지의 값을 가지고 있다.

이걸 활용해서 UI 체력바와 스테미너바를 줄였다가 채우길 반복하도록 만들었다.

 

uiBar.fillAmount = GetPercentage();  // UI바의 fillAmount를 현재 수치에 비례하여 설정

 

1이 100%라고 한다면, 우리는 아주 간단한 계산식을 쓸 수 있다.

 

curValue / maxValue; (현재값/최대값)

 

여기다가 *100만 하면 확률이다 (65/100 = 0.65, *100을하면 65%)

그럼 이제 더하거나 뺄 때 변화하는 curValue값을 정하는 함수들만 넣으면 Condition은 클리어.

(그 외에 UI를 가져오거나 Player의 상태를 저장하는 함수는 각각의 스크립트를 별도 제작해서 넣는다.)

2. RayCast란?

간단하게 말하면 안보이는 빔을 하나 쏴서 물체랑 충돌했는지 감지하는 시스템이다.

Collider랑 다른데, Collider는 일단 닿아야 충돌했는지 판정한다면, Raycast는 대충 이런 느낌이다.

액션빔

 

Ray는 내가 원하는 위치에서(Vector3 Origin, 필수), 내가 원하는 방향으로(Vector3 Direction, 필수), 보이지 않는 빔을 쭉-쏴서 상대편 물체를 감지한다.

그런데 이 선에 길이를 설정할 수 있어서(float maxDistance, 선택), 일정 범위 안에 들어오면 감지하게 만들 수도 있다.

혹은, 특정 물체와 마주했을 때만 반응하게 만들어서(int layerMask, 혹은 LayerMask를 스크립트 내에서 선언하여 지정, 선택) 원하는 물체가 아니면 무시하게 만들 수도 있다.

Trigger Collider랑 마주했을 때 어떻게 반응할지도 정할 수 있다(QueryTriggerInteraction, 선택)

out RaycastHit를 이용해 충돌 정보를 얻어낼 수도 있다.(해당 개체의 콜라이더, 위치, 해당 개체와의 거리, 좌표 등)

(이를 이용해 에너미가 플레이어를 감지하고 거리를 측정해서 쫓아오게 만들 수도 있다...)

이번 코드의 경우, 미리미리 rays라는 배열 속에 각각의 OriginDirection저장해두고, 반복문에서 어느정도 범위(길이)에서 감지할지, 어떤 레이어 마스크를 읽어낼지 확인하는 작업을 거쳤다.

 

Ray[] rays = new Ray[4] //Ray가 4개 들어가는 배열
{
    // 플레이어의 위치에서 앞, 뒤, 오른쪽, 왼쪽으로 0.2f 떨어진 위치에 Ray를 쏘고, 아래 방향으로 쏘기
    // 이유: 한 방향에서만 Ray를 쏘면, 바닥이 경사이거나 모서리에 있을 때, 바닥에 닿지 않는 경우가 발생할 수 있음
    //순서대로 앞(+transform.forward), 뒤(-transform.forward),오른쪽(+transform.right), 왼쪽(-transform.right)
    
    //1번 Ray: 오브젝트의 중앙위치에서 약간 앞쪽, 아주 약간 위로 이동한 위치에서 아래로 Ray를 쏘기
    new Ray(transform.position + (transform.forward * 0.2f) + (transform.up * 0.01f), Vector3.down),
    <중략>
    
    //transform.position + (transform.forward * 0.2f) + (transform.up * 0.01f) >시작하는 위치(Origin)
    //Vector3.down > 방향(Direction)
}

// 각 Ray에 대해 바닥 레이어와 충돌하는지 확인
for (int i = 0; i < rays.Length; i++)
{
    if (Physics.Raycast(rays[i], 0.6f, groundLayerMask))
    //rays[i]에 Origin과 direction값이 있음.
    //0.6은 maxDistance, groundLayerMask는 인스펙터창에서 지정된 LayerMask
}

 

 

하지만 눈에 안보이면 너무 불편해! 최소한 눈에 보여야 부딪혔는지 안부딪혔는지 알 수 있는 거 아니야?!

한다면, Debug로 확인할 수 있다. 아래를 확인해보도록 하자.

 

 

점프를 할 때마다 붉은 선이 밑에 생겼다가 사라지는 것을 볼 수 있다.

물론 해당 Debug는 Ray선이 잘 보이게 하기 위해서 일부러 Ray선의 길이를 2배정도로 늘렸다. (실제 Ray길이값은 0.6. 디버그상의 Ray길이는 1.1이다.)

어떻게 그리나요?

 

Debug.DrawRay(rays[i].origin, rays[i].direction * 1.1fColor.red);

(현재, 해당 Ray를 배열화 시켜서 사용하고 있다.)

중요한 요소는 (origin(출발지점), direction(방향)*float(길이), 색상)이다.

위의 레이는 rays 배열에 있는 i번째 ray의 시작점에서, 해당 레이에서 지정된 방향으로 1.1f만큼 빨간색으로 내려온다.

 

이렇게 땅을 감지할 수 있게 되었다면, 이제 이렇게 판정한 Raycast값이 true일 때만 Jump를 할 수 있도록 조건문을 수정하면 완료된다.

 

나는 지금 Ray가 Cube의 중심에서 나아가서 0.6이 되고 있는데, 원한다면 초기 origin값에서 레이가 시작하는 위치를 아래로 내리면 된다. (큐브 중심부터 바닥까지의 길이가 0.5정도 된다.)

 

3. 마무리

계속 땅을 밟지 못하고 허공답보를 하던 큐브를 해결했다.

체력바도 만들었고.

이제 진짜 무시하고 있던 인벤토리를 만들어야 할 차례가 온 것이다...

Interface와 ScriptableObject의 콜라보. 실제로 한 번 구현해보겠습니다.

겸사겸사 아이템도 이제 만들 때가 왔다. 그리고 그와 연계된 Raycast 재사용도 시작한다.(아이템 정보 읽기!)

 

현재까지 필수 구현내용 진행 상황

  • 기본 이동 및 점프 Input System, Rigidbody ForceMode(완료)
  • 체력바 UI (완료) - 전부 끝나면 낙하대미지 구현 예정
  • 동적 환경 조사 Raycast UI (미완) - 내일 구현 예정
  • 점프대 Rigidbody ForceMode (미완)
  • 아이템 데이터 ScriptableObject (미완) - 내일 구현 예정 
  • 아이템 사용 Coroutine (미완) - 내일 구현 예정