구현하고자 하는것 !

방패를 진짜 던지는 듯한 느낌을 주기 위해서는 방패가 날라가는(손에서 떠나는) 시점과 방향이 중요하다,
1. 방패가 날라가는 가장 자연스러운 시점 구하기
우리가 물체를 던질 때, 원하는 방향으로 물체를 던지기 위해서는 적당한 순간에 물체를 놔야한다.
우리도 그 순간을 구하고자 한다.
가장 자연스러운 순간의 컨트롤러 속도를 확인하기 위해
world space UI를 생성해서 Oculus를 착용하고 직접 던져보면서 눈으로 확인할 수 있도록 하였다.

확인결과 컨트롤러 속도가 증가했다가 0.06이하로 떨어질 때 방패가 날라가는것이 가장 자연스럽게 느껴졌다.
var velocity = OVRInput.GetLocalControllerVelocity(OVRInput.Controller.LTouch);
this.av = Mathf.Abs((float)Math.Truncate(((velocity.x + velocity.y + velocity.z) / 3.0f) * 100f); / 100f);
if (!OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && this.av < 0.06f)
※ 컨트롤러 속도 구하는법
OVRInput.GetLocalControllerVelocity(OVRInput.Controller.LTouch) 를 이용해서 컨트롤러의 속도를 알아낼 수 있다.
참고한 블로그
2. 방향 구하기
사용자가 원하는 방향으로 나가는것이 중요하다,, 우리는 게임을 플레이해볼 수 없기 때문에 이 부분에서 생각과 테스트가 많이 필요했고, 우리 게임만의 규칙이 필요했다.
1. 사용자가 쳐다보는 방향(시선)
this.centerEyeAnchor.forward;
2. 손의 앞방향
this.pos.forward;
3. 1,2의 중간 방향(중간벡터)
this.dir = (this.pos.forward+centerEyeAnchor.forward).normalized;
이 3개의 방향을 각각 쓰레기통을 맞춰보면서 정확도를 테스트해보고 사용자가 원하는 방향으로 날아가는지 확인했다.

+ DrawArrow를 이용하여 각각의 방향으로 화살표를 길게 그린 후 방패가 던지고자 하는 방향으로 잘 날아가고 있는지 확인하였다.

▷테스트 결과◁
손의 앞방향 --> 많이 빗나감
시선과 손의 앞방향의 중간 방향 --> 손의 앞방향보다는 정확도가 증가 , but 여전히 맞추기 어려움
시선 --> 잘 맞음
시선의 방향으로 날아가기로 결정
하지만 사용자가 매번 공격하고 싶은 쪽을 바라본다는 보장은 없음 --> 경우에 따라서 방향을 구분하자
3. 경우에 따라서 방향을 구분하기
발생할 수 있는 경우의 수가 총 4가지이다.
1. 사용자가 맞추고 싶은 방향을 쳐다봄 & 그쪽으로 팔을 스윙함 ----> 시선의 방향으로 이동
2. " 쳐다봄 & 팔은 다른쪽으로 스윙함 ----> 팔의 앞방향으로 이동
3. " 쳐다보지 않음 & 그쪽으로 팔을 스윙 ----> 팔의 앞방향으로 이동
3. " 쳐다보지 않음 & 팔도 다른쪽으로 스윙함 ----> 팔의 앞방향으로 이동
팔의 앞방향은 정확도가 떨어지지만, 사용자의 시선이 다른쪽을 쳐다보고 있다면 정확도가 높지 않더라도 어색함을 느끼지 못한다.
경우의 수는 4가지이지만 코드상으로는 2가지 경우로 나누면 된다. 이걸 어떤 기준으로 구별할 것인가?
==> 시선의 방향과 팔의 앞방향 사이의 각도로 구분하자 ! 내적 사용 !!!
▶내적 값 로그로 찍어 확인해보기◀

//내적하기
this.dot = Vector3.Dot(this.pos.forward, centerEyeAnchor.forward);
Debug.LogFormat("dot : {0}" ,dot);
사용자가 방패를 던지고 싶은 방향을 쳐다봤으며 , 또한 팔도 그 방향으로 휘둘렀다고(스윙) 인정되는 최소 내적값이 몇인지 정하기 위해서 로그로 내적 값을 출력하면서 여러 번 테스트를 거쳤다.
▷테스트 결과◁
내적값이 0.8 이상일 경우가 가장 자연스럽게 동작한다.
최종적으로 짠 코드를 아래와 같다.
IEnumerator CoMove()
{
while (true)
{
//손과 눈의 위치가 비슷할때(30도 이하)
if (this.dot > 0.8f)
{
//시선의 방향으로 날아가기
this.pos.Translate(this.centerEyeAnchor.forward * this.moveSpeed * Time.fixedDeltaTime, Space.World);
}
//손과 눈의 위치가 다를 때
else
{
//손의 앞방향으로 날라가기
this.pos.Translate(this.pos.forward * this.moveSpeed * Time.fixedDeltaTime, Space.World);
}
//다시 손 위치로 방패 옮기는 코드(테스트 반복을 위해)
if (this.pos.position.z > 10f)
{
this.pos.SetParent(lHandAnchor);
this.pos.localPosition = new Vector3(0, 0, 0);
this.pos.localRotation = Quaternion.Euler(0, 0, 0);
StopCoroutine(this.coroutine);
}
yield return null;
}
}
이 코드로 실행할 경우

각도가 차이가 클 때는 손의 앞방향(노란색)으로

각도 차이가 크지 않을 때는 시선의 앞방향(빨간색)으로 잘 날라가는 모습을 확인할 수 있다.
[전체 코드]
using Oculus.Interaction.Input;
using Oculus.Platform;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UIElements;
using UnityEngine.XR;
public class TestSwing : MonoBehaviour
{
[SerializeField]
TMP_Text txtLog;
[SerializeField]
private Transform lHandAnchor;
[SerializeField]
private Transform pos;
[SerializeField]
private Transform centerEyeAnchor;
[SerializeField]
private Transform trans1;
[SerializeField]
private Transform shieldTrans;
private float moveSpeed=10;
private float turnAngle=0;
private Vector3 dir;
private float dot;
private Coroutine coroutine;
float av = 0f;
bool isShoot = true;
float dis = 0f;
void FixedUpdate()
{
this.DetectEnemy();
var velocity = OVRInput.GetLocalControllerVelocity(OVRInput.Controller.LTouch); //.normalized;
this.av = Mathf.Abs((float)Math.Truncate(((velocity.x + velocity.y + velocity.z) / 3.0f) * 100f) / 100f);
//center eye 레이 계속 찍기 방향
Debug.DrawRay(centerEyeAnchor.position, this.centerEyeAnchor.forward * 10f, Color.blue);
this.txtLog.text = this.av.ToString();
if (OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))
{
this.isShoot = false;
}
if (this.isShoot == false)
{
//손을 떼었을때 컨트롤러가 멈춘 마지막 지점은?
//손을 떼었을 때 날라감
if (!OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && this.av < 0.06f)
{
this.isShoot = true;
Debug.LogFormat("Release LTouch PrimaryHandTrigger : <color=yellow>{0}</color>", av);
//손, 노란색
DrawArrow.ForDebug(this.trans1.position, this.pos.forward * 10, 5f, Color.yellow, ArrowType.Solid);
this.pos.SetParent(null);
this.turnAngle = 80;
//중간벡터, 빨간색
DrawArrow.ForDebug(this.trans1.position, dir * 10, 5f, Color.red, ArrowType.Solid);
Debug.LogFormat("<color=lime>dir.y:{0}, pos.forward.y:{1}</color>", dir.y, pos.forward.y);
Debug.LogFormat("<color=lime>centerEyeAnchor.forward.y:{0}</color>", centerEyeAnchor.forward.y);
//내적하기
this.dot = Vector3.Dot(this.pos.forward, centerEyeAnchor.forward);
Debug.LogFormat("dot : {0}" ,dot);
this.dis = 10f;
this.coroutine = this.StartCoroutine(this.CoMove());
}
}
}
IEnumerator CoRotate()
{
while (true)
{
var left = Quaternion.Euler(new Vector3(-1 * this.turnAngle, lHandAnchor.transform.rotation.y,0)); //이렇게 하면 무조건 앞방향으로만 나감
this.shieldTrans.rotation = Quaternion.Slerp(this.shieldTrans.rotation, left, Time.deltaTime * 1f);
yield return null;
}
}
IEnumerator CoMove()
{
///손에가깝게 나가는 코루틴
while (true)
{
//손과 눈의 위치가 비슷할때(30도 이하)
if (this.dot > 0.8f)
{
//눈이 바라보는 방향으로 날라가기
this.pos.Translate(dir * this.moveSpeed * Time.fixedDeltaTime, Space.World);
Debug.LogFormat("<color=red>this.centerEyeAnchor.forward{0}</color>", this.centerEyeAnchor.forward);
}
//손과 눈의 위치가 다를 때
else
{
//손의 앞방향으로 날라가기
this.pos.Translate(this.pos.forward * this.moveSpeed * Time.fixedDeltaTime, Space.World);
Debug.LogFormat("<color=blue>this.pos.forward{0}</color>", this.centerEyeAnchor.forward);
}
//다시 손 위치로 방패 옮기는 코드
if (this.pos.position.z > 10f)
{
this.pos.SetParent(lHandAnchor);
this.pos.localPosition = new Vector3(0, 0, 0);
this.pos.localRotation = Quaternion.Euler(0, 0, 0);
StopCoroutine(this.coroutine);
}
yield return null;
}
}
결과

'마블 VR 프로젝트 제작' 카테고리의 다른 글
| [마블 VR] oculus를 사용해서 반경 안에 있는 적 공격하기 R&D (2) | 2023.12.03 |
|---|---|
| [마블 VR] 오프젝트 풀링으로 공중 적 생성하기 R&D (0) | 2023.11.30 |
| [마블 VR] 반경 안에 있는 적 공격하기 R&D (1) | 2023.11.15 |
| [마블 VR] 3ds Max를 이용해 방패 손잡이 늘리기 (2) | 2023.11.06 |
| [마블 VR] Curved UI(캐릭터 선택 제작) - 3 (0) | 2023.11.06 |