[XR 전문 인력 과정] 유니티 타워디펜스 만들기(2) -총쏘기(Raycast), 무기 잡기, 무기 던지기
2023. 11. 23. 22:07ㆍUnity
728x90
반응형
Player와 Tower는 빼고 다른 물체는 Ray에 맞게 구현할 예정
Ray가 맞은 부분에 이펙트 생성
PlayerFire 스크립트 생성
XRInput.cs 스크립트의 IndexTrigger를 사용한다.
public enum Button
{
#if PC
One = ButtonTarget.Fire1,
Two = ButtonTarget.Jump,
Thumbstick = ButtonTarget.Fire1,
IndexTrigger = ButtonTarget.Fire2
#elif Oculus
One = OVRInput.Button.One,
Two = OVRInput.Button.Two,
Thumbstick = OVRInput.Button.PrimaryThumbstick,
IndexTrigger = OVRInput.Button.PrimaryIndexTrigger
#endif
}
XRInput 스크립트에서 Button에서 IndexTrigger가져오기
void Update()
{
//버튼을 누르면 Ray를 생성
if (XRInput.GetDown(XRInput.Button.IndexTrigger))
{
//레이 생성 구조체 변수로 가져오기. 괄호안에 시작점의 위치와 방향 넣기
Ray ray = new Ray(XRInput.RHandPosition, XRInput.RHandDirection);
//충돌 정보 저장(RaycastHit)
RaycastHit hitInfo;
}
}
Player에 Player 레이어 추가, Tower에 Tower 레이어 추가
레이어 관련 코드줄 추가 Update 함수에서,
void Update()
{
//버튼을 누르면 Ray를 생성
if (XRInput.GetDown(XRInput.Button.IndexTrigger))
{
//레이 생성 구조체 변수로 가져오기. 괄호안에 시작점의 위치와 방향 넣기
Ray ray = new Ray(XRInput.RHandPosition, XRInput.RHandDirection);
//충돌 정보 저장(RaycastHit)
RaycastHit hitInfo;
//플레이어 레이어를 받아오기 레이어 번호 숫자 형태로 가져올 수 있다.
int playerLayer = 1 << LayerMask.NameToLayer("Player"); ; //꺾쇠는 레이어를 쭉 훑어보는 느낌
//타워 레이어 받아오기
int towerLayer = 1 << LayerMask.NameToLayer("Tower");
int layerMask = playerLayer | towerLayer; //레이어 마스크에 저장
}
}
총 효과 에셋 가져오기
https://assetstore.unity.com/packages/vfx/particles/war-fx-5669
에셋 효과 하나 선택해서 Hierarchy로 가져오고 안에 원래 들어있는 스크립트 삭제
해당 이펙트에 접근해서 Particle System에 접근하기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerFire : MonoBehaviour
{
//Transform 가져오기
public Transform bulletObj;
//bulletObj의 Particle System 가져오기
ParticleSystem bulletEffect;
void Start()
{
//bulletEffect 할당하기
bulletEffect = bulletObj.GetComponent<ParticleSystem>();
}
void Update()
{
//버튼을 누르면 Ray를 생성
if (XRInput.GetDown(XRInput.Button.IndexTrigger))
{
//레이 생성 구조체 변수로 가져오기. 괄호안에 시작점의 위치와 방향 넣기
Ray ray = new Ray(XRInput.RHandPosition, XRInput.RHandDirection);
//충돌 정보 저장(RaycastHit)
RaycastHit hitInfo;
//플레이어 레이어를 받아오기 레이어 번호 숫자 형태로 가져올 수 있다.
int playerLayer = 1 << LayerMask.NameToLayer("Player"); ; //꺾쇠는 레이어를 쭉 훑어보는 느낌
//타워 레이어 받아오기
int towerLayer = 1 << LayerMask.NameToLayer("Tower");
int layerMask = playerLayer | towerLayer; //레이어 마스크에 저장
//Ray 발사 괄호 안에 (ray 대상, 충돌 정보, 얼마만큼 뻗어나갈 것인지, )
if (Physics.Raycast(ray, out hitInfo, 1200, ~layerMask)) //~ 뜻은 ~빼고
{
//이펙트 생성. 이펙트를 한 번 Stop하고 그 다음 Play
bulletEffect.Stop();
bulletEffect.Play();
//파티클 이펙트를 맞은 위치에 순간이동
bulletObj.position = hitInfo.point;
//땅에 맞으면 해당 부분에 normal로 나타나게
bulletObj.forward = hitInfo.normal;
}
}
}
}
스크립트를 Player에 넣고 비어있는 Bullet Obj에 파티클 프리팹을 넣는다.
폭탄 에셋 받아오기
마음에 드는 에셋 가져오기
폭탄 에셋에 Capsule Collider, Rigidbody 추가, IsKinematic 활성화
Weapon 레이어 생성해서 프리팹에 적용
HandGrab 스크립트 만들기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandGrab : MonoBehaviour
{
//변수 생성
//물체를 잡고 있는지 여부 처음에는 안잡고 있기
bool isGrabbing = false;
//잡고 있는 물체
GameObject grabbedObject;
//잡을 물체 레이어
public LayerMask grabbedLayer;
//잡을 거리 설정
public float grabRange = 5f;
void Update()
{
if(isGrabbing == false)
{
TryGrab();
}
}
void TryGrab()
{
//만약 잡기 버튼을 누른다면 일정 영역 안의 무기를 잡는다
if (XRInput.GetDown(XRInput.Button.Thumbstick, XRInput.Controller.RTouch))
{
//구 모양의 일정 영역안의 무기 찾기. 배열 사용
//영역 안 모든 무기를 찾기
Collider[] hitObjects = Physics.OverlapSphere(XRInput.RHandPosition, grabRange, grabbedLayer);
//가장 가까운 무기 인덱스를 찾아옴
int closest = 0;
//손과 가장 가까운 물체 선택
for (int i = 1; i < hitObjects.Length; i++)
{
//손과 가장 가까운 물체의 거리
Vector3 closestPos = hitObjects[closest].transform.position;
float closestDistance = Vector3.Distance(closestPos, XRInput.RHandPosition);
//다음 물체와 손의 거리
Vector3 nextPos = hitObjects[i].transform.position;
float nextDistance = Vector3.Distance(nextPos, XRInput.RHandPosition);
//만약 다음 물체 거리가 더 가까우면, 인덱스 교체
if(nextDistance < closestDistance)
{
closest = i;
}
}
//만약 검출된 물체가 있다면
if(hitObjects.Length > 0)
{
//잡은 상태로 전환
isGrabbing = true;
grabbedObject = hitObjects[closest].gameObject;
//잡은 물체를 손의 자식으로 등록
grabbedObject.transform.parent = XRInput.RHand;
//물체의 물리 기능 정지 Is Kinematic
grabbedObject.GetComponent<Rigidbody>().isKinematic = true;
print("Grab");
}
}
}
}
Player에 HandGrab 스크립트 적용,
물건 던지기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandGrab : MonoBehaviour
{
//변수 생성
//물체를 잡고 있는지 여부 처음에는 안잡고 있기
bool isGrabbing = false;
//잡고 있는 물체
GameObject grabbedObject;
//잡을 물체 레이어
public LayerMask grabbedLayer;
//잡을 거리 설정
public float grabRange = 5f;
//오브젝트를 던질 힘
float throwPower = 30f;
//이전 위치
Vector3 prePos;
void Update()
{
if(isGrabbing == false)
{
TryGrab();
}
else
{
//잡고있다면
TryUngrab();
}
}
void TryGrab()
{
//만약 잡기 버튼을 누른다면 일정 영역 안의 무기를 잡는다
if (XRInput.GetDown(XRInput.Button.Thumbstick, XRInput.Controller.RTouch))
{
//구 모양의 일정 영역안의 무기 찾기. 배열 사용
//영역 안 모든 무기를 찾기
Collider[] hitObjects = Physics.OverlapSphere(XRInput.RHandPosition, grabRange, grabbedLayer);
//가장 가까운 무기 인덱스를 찾아옴
int closest = 0;
//손과 가장 가까운 물체 선택
for (int i = 1; i < hitObjects.Length; i++)
{
//손과 가장 가까운 물체의 거리
Vector3 closestPos = hitObjects[closest].transform.position;
float closestDistance = Vector3.Distance(closestPos, XRInput.RHandPosition);
//다음 물체와 손의 거리
Vector3 nextPos = hitObjects[i].transform.position;
float nextDistance = Vector3.Distance(nextPos, XRInput.RHandPosition);
//만약 다음 물체 거리가 더 가까우면, 인덱스 교체
if(nextDistance < closestDistance)
{
closest = i;
}
}
//만약 검출된 물체가 있다면
if(hitObjects.Length > 0)
{
//잡은 상태로 전환
isGrabbing = true;
grabbedObject = hitObjects[closest].gameObject;
//잡은 물체를 손의 자식으로 등록
grabbedObject.transform.parent = XRInput.RHand;
//물체의 물리 기능 정지 Is Kinematic
grabbedObject.GetComponent<Rigidbody>().isKinematic = true;
print("Grab");
}
}
}
void TryUngrab()
{
//던질 방향
Vector3 throwDirection = XRInput.RHandPosition - prePos;
prePos = XRInput.RHandPosition;
//잡기 버튼을 놓았다면
if(XRInput.GetUp(XRInput.Button.Thumbstick, XRInput.Controller.RTouch))
{
//잡지 않은 상태로 전환
isGrabbing = false;
//물리 기능 활성화
grabbedObject.GetComponent<Rigidbody>().isKinematic = false;
//손에서 무기 떼어내기
grabbedObject.transform.parent = null;
//던지기 (방향 * 힘)
grabbedObject.GetComponent<Rigidbody>().velocity = throwDirection * throwPower;
//잡은 물체를 비워줌
grabbedObject = null;
}
}
}
728x90
반응형
'Unity' 카테고리의 다른 글
[Unity] 던전앤파이터 API 활용 -진행중 (3) | 2023.12.07 |
---|---|
[XR 전문 인력 과정] 유니티 타워디펜스 만들기(3) -HDRI 적용, AINavMeshAgent 적용, 적이 타워를 공격하게 하기 (1) | 2023.11.29 |
[XR 전문 인력 과정] 유니티 타워디펜스 만들기(1) -XR 세팅, 씬 세팅, 화면 회전, 플레이어 이동 (1) | 2023.11.22 |
[Unity Project] <ShootOut2D> 2D 슈팅 게임 만들기(15) 화면 해상도 고려하기 (0) | 2023.09.25 |
[Unity Project] <ShootOut2D> 2D 슈팅 게임 만들기(14) 메인 메뉴 UI 추가하기 (2) | 2023.09.25 |