본문 바로가기
마블 VR 프로젝트 제작

[마블 VR] 방패 던지기 다듬기

by 노재두내 2023. 12. 21.

trigger버튼에서 손 떼면 바로 날라가는게 아니라 스윙하면 날라가기 수정

void FixedUpdate()
    {
        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);
        
        if (OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))
        {
            this.isShoot = false;
        }
        if (av > 0.3f)
        {
            this.isSwing = true;
        }
        if (this.isShoot == false&&this.isSwing==true)
        {
            //손을 떼었을 때 날라감
            if (!OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && this.av < 0.06f)
            {
                this.isShoot = true;
                this.isSwing = false;
                this.pos.SetParent(null);
                this.dir = this.centerEyeAnchor.forward;
                Debug.LogFormat("<color=lime>손을 떼었을 때 날라감</color>");
                //내적하기
                if (centerEyeAnchor.forward.y > 0.2f)
                {
                    this.dir.y -= 0.15f;
                }
                this.dot = Vector3.Dot(this.pos.forward, centerEyeAnchor.forward);
                this.moveCoroutine = this.StartCoroutine(this.CoMove());
                
            }

        }
    }

 

컨트롤러의 속도를 찍어보고 컨트롤러의 속도가 0.3이상이면 isSwing=true로 해서 true일경우에만 날라가도록 했다.

 

결과물

 

가만히 있으면서 버튼만 손에서 뗀다고 날라가지 않고 스윙해야 날라감

 


문제점. 계속 흔들다보면 날라감 

로그를 찍어보니 hand trigger버튼을 한번만 누르면 계속 false이고, 속도도 0.6보다 한번만 커지면 계속 true가 되기 때문

 if (OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch)&&av>0.5f)
        {
            this.isShoot = false;
        }

원래는 손에 붙으면 isShoot=false가 되도록 했는데, 그 부분을 주석처리 하였다.

 


가장 큰 문제는 .. 적 방향으로 날라가는건데 ..  조건(내가 바라보는 방향과 손의 방향의 내적값)값을 올리면 너무 어렵게 되고, 낮추면 너무 그쪽으로 던진게 아닌데 그쪽으로 날라간다.. 

 

내적 값이 얼마정도 나오는지 확인해봐야 할거같다.

 

 

웬만하면 눈의 앞방향과 , 내 몸부터 타겟까지의 방향의 내적 값이 0.9이상 나온다. 

 

위 사진처럼 완전히 극단적으로 고개를 아래를 보지 않는 이상.. 그다지 차이가 나지 않는다

 

 

 


[전체 코드]

using Oculus.Interaction;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using System.Linq;
using System;
using UnityEditor;
using Unity.VisualScripting;
using UnityEditor.Experimental.GraphView;

public class Shield : MonoBehaviour
{
    [SerializeField] private EnemyAttackMain enemyAttackMain;
    [SerializeField] private Transform lHandAnchor;
    public Transform pos;
    [SerializeField] private Transform centerEyeAnchor;
    private float moveSpeed = 10;
    private float dot;
    private Vector3 dir;
    private float degrees = 0;
    private Coroutine moveCoroutine;
    private Vector3 targetDir;

    float av = 0f;//컨트롤러 속도
    private bool isShoot = true;
    private bool isGrab;
    private bool isSwing;

    Dictionary<GameObject, float> dic = new Dictionary<GameObject, float>();
    private float detectRadius = 10f;
    private Vector3 startPos;
    private IEnumerator shakeRoutine;

    private void Start()
    {
        //방패 진동
        this.shakeRoutine = this.CoShake(0.005f);
        this.startPos = this.transform.localPosition;
    }

    void FixedUpdate()
    {
        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);
        
        if (OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))
        {
            this.isShoot = false;
        }
        if (av > 0.4f)
        {
            this.isSwing = true;
        }
        if (this.isShoot == false&&this.isSwing==true)
        {
            //손을 떼었을 때 날라감
            if (!OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && this.av < 0.06f)
            {
                this.isShoot = true;
                this.isSwing = false;
                this.pos.SetParent(null);
                this.dir = this.centerEyeAnchor.forward;
                Debug.LogFormat("<color=lime>손을 떼었을 때 날라감</color>");
                //내적하기
                if (centerEyeAnchor.forward.y > 0.2f)
                {
                    this.dir.y -= 0.15f;
                }
                this.dot = Vector3.Dot(this.pos.forward, centerEyeAnchor.forward);
                this.moveCoroutine = this.StartCoroutine(this.CoMove());
                
            }

        }
        //다시 잡았을 때
        if (isGrab == true)
        {
            this.pos.transform.position = Vector3.MoveTowards(this.pos.transform.position, lHandAnchor.position, 10f * Time.deltaTime);
            isShoot = true;

            //if (this.pos.transform.position == lHandAnchor.position)
            //{
            //    Debug.Log("다시 잡았다");
            //    this.Init();
            //    isGrab = false;
            //    isShoot = false;

            //    Debug.LogFormat("this.moveCoroutine: {0}", this.moveCoroutine);
            //    Debug.LogFormat("moveToEnemyRoutine : {0}", this.moveToEnemyRoutine);

            //    if (this.moveToEnemyRoutine != null)
            //        StopCoroutine(this.moveToEnemyRoutine);

            //    if (this.moveCoroutine != null)
            //        StopCoroutine(this.moveCoroutine);
            //}
            if (Vector3.Distance(this.pos.transform.position, lHandAnchor.position) < 0.2f)
            {
                Debug.Log("다시 잡았다");
                this.Init();
                isGrab = false;
                isShoot = false;

                Debug.LogFormat("this.moveCoroutine: {0}", this.moveCoroutine);
                Debug.LogFormat("moveToEnemyRoutine : {0}", this.moveToEnemyRoutine);

                if (this.moveToEnemyRoutine != null)
                    StopCoroutine(this.moveToEnemyRoutine);

                if (this.moveCoroutine != null)
                    StopCoroutine(this.moveCoroutine);
            }
        }
    }


    IEnumerator CoMove()
    {
        this.Dorotate();
        var target = enemyAttackMain.FindEnemyDir();
        if (target != null)
        {
            
            this.targetDir = (target.transform.position - this.pos.transform.position).normalized;
        }
        else if (target == null)
        {
            targetDir = (this.lHandAnchor.position - this.pos.position).normalized;
            //Debug.Log("<color=yellow>다 공격했다.</color>");
        }
        var targetDot = Vector3.Dot(targetDir, centerEyeAnchor.forward);
        while (true)
        {
            //손과 눈의 위치가 비슷할때(30도 이하)
            if (this.dot > 0.8f)
            {
                if (targetDot > 0.9f)
                {
                    this.pos.Translate(targetDir * this.moveSpeed * Time.fixedDeltaTime, Space.World);
                }
                else
                {
                    this.pos.Translate(dir * this.moveSpeed * Time.fixedDeltaTime, Space.World);
                }
                
            }
            //손과 눈의 위치가 다를 때
            else
            { 
                if (targetDot > 0.9f)
                {
                    targetDir = this.pos.forward;
                    this.pos.Translate(targetDir * this.moveSpeed * Time.fixedDeltaTime, Space.World);
                    Debug.Log("손과 눈의 위치가 다를 때 타겟 방향으로 날라가기");
                }
                else
                {
                    targetDir = this.pos.forward;
                    this.pos.Translate(targetDir * this.moveSpeed * Time.fixedDeltaTime, Space.World);
                }
            }

            if (OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && this.pos.position != lHandAnchor.position)
            {
                isGrab = true;
                StopCoroutine(this.moveCoroutine);
            }

            yield return null;
        }

    }

    public void Init()
    {
        Debug.Log("위치 초기화 완료");
        this.pos.SetParent(lHandAnchor);
        this.pos.localPosition = new Vector3(0, 0, 0);
        this.pos.localRotation = Quaternion.Euler(0, 0, 0);
        this.transform.localRotation=Quaternion.Euler(0, -83, 0);
        DOTween.Kill("rotateTween");
        //this.isShoot = false;
        //this.isGrab = false;
    }

    public void Dorotate()
    {
        this.transform.DORotate(new Vector3(-90, -83, 0), 1f).SetId("rotateTween");
    }

    private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.CompareTag("Enemy"))
        {
            //EditorApplication.isPaused = true;
            Debug.Log("<color=yellow>=> 충돌됨</color>");

            if (this.moveCoroutine != null) this.StopCoroutine(this.moveCoroutine);
            if (this.moveToEnemyRoutine != null) this.StopCoroutine(this.moveToEnemyRoutine);

            var target = this.FindNextTarget();
            if (target != null)
            {
                Debug.Log("<color=yellow>=> 타겟이 있음</color>");
                Debug.DrawLine(this.transform.position, target.transform.position, Color.red, 10f);

                this.RotateShield(target);
                this.moveToEnemyRoutine = this.StartCoroutine(this.CoMoveToEnemy(target.transform));
            }
            else  // 모든 적을 맞추고 타겟이 없음
            {
                Debug.Log("<color=yellow>=> 타겟이 없음</color>");
                //되돌아옴 
                this.moveCoroutine = this.StartCoroutine(this.CoMove());
                //this.RotateShield(null);
            }
        }
        else //부딪힌게 enemy가 아님
        {
            dir = (this.lHandAnchor.position - this.pos.position).normalized;
        }
    }

    private void RotateShield(GameObject target)
    {
        if (target != null)
        {
            DOTween.Kill("rotateTween");
            //적 쳐다보기
            var dir = (target.transform.position - this.transform.position).normalized;
            this.transform.up = dir;
            
            if (this.transform.position.x < target.transform.position.x)
            {
                degrees = 270;
                Debug.LogFormat("<color=yellow>오른쪽에 있음 : {0}</color>", degrees);

            }
            else if (this.transform.position.x > target.transform.position.x)
            {
                degrees = 90;
                Debug.LogFormat("<color=yellow>왼쪽에 있음 : {0}</color>", degrees);
            }
            else
            {
                Debug.LogFormat("<color=yellow>같은 위치에 있음 : {0}</color>", degrees);
            }
            this.transform.rotation = this.transform.rotation * Quaternion.Euler(0, degrees, 0);
        }
        else if (target == null)
        {
            this.Dorotate();
        }
        
    }
    private GameObject FindNextTarget()
    {
        Collider[] enemyCols = Physics.OverlapSphere(this.pos.transform.position, this.detectRadius, 1 << 6);
        this.dic.Clear();
        for (int i = 0; i < enemyCols.Length; i++)
        {
            var col = enemyCols[i];
            this.dic.Add(col.gameObject, Vector3.Distance(col.transform.position, this.pos.transform.position));
        }

        if (this.dic.Count > 0)
        {
           // Debug.Log(dic.Count);
            var nearestDistance = this.dic.Values.Min();
            var target = this.dic.FirstOrDefault(x => x.Value == nearestDistance).Key;
            return target;
        }
        else
        {
            dir = (this.lHandAnchor.position - this.pos.position).normalized;
            return null;
        }

    }


    private Coroutine moveToEnemyRoutine;

    //두번째 부터 사용 
    private IEnumerator CoMoveToEnemy(Transform target)
    {
        Debug.Log("<color=yellow>=> CoMoveToEnemy</color>");

        while (true) {

            var dir = (target.transform.position - this.pos.position).normalized;

            DrawArrow.ForDebug(this.pos.transform.position, dir, 10f, Color.red, ArrowType.Solid);

            this.pos.transform.Translate(dir * this.moveSpeed * Time.deltaTime, Space.World);

            var dis = Vector3.Distance(this.pos.transform.position, target.transform.position);
            if(dis <= 0.1f)
            {
                break;
            }
            yield return null;
        }
        Debug.Log("<color=yellow>=> 이동완료</color>");

    }
    //private IEnumerator CoDetectEnemy()
    //{
    //    while (true)
    //    {
    //        Collider[] enemyCols = Physics.OverlapSphere(this.transform.position, this.detectRadius, 1 << 6);
    //        this.dic.Clear();
    //        for (int i = 0; i < enemyCols.Length; i++)
    //        {
    //            var col = enemyCols[i];
    //            this.dic.Add(col.gameObject, Vector3.Distance(col.transform.position, this.transform.position));
    //        }

    //        if (this.dic.Count > 0)
    //        {
                
    //            Debug.Log(dic.Count);
    //            var nearestDistance = this.dic.Values.Min();
    //            var target = this.dic.FirstOrDefault(x => x.Value == nearestDistance).Key;
    //            var dirTarget = (target.transform.position - this.pos.position).normalized;
    //            Ray ray = new Ray(this.pos.transform.position, dirTarget);
    //            Debug.DrawRay(ray.origin, ray.direction * 1000f, Color.red);

    //            this.pos.transform.LookAt(target.transform);
    //            Debug.Log(ray.direction);
    //            //this.pos.Translate(ray.direction * this.moveSpeed * Time.fixedDeltaTime, Space.World);
    //            this.pos.transform.position = Vector3.MoveTowards(this.pos.transform.position, target.transform.position, 10f * Time.fixedDeltaTime);
    //            this.pos.transform.rotation = Quaternion.LookRotation(target.transform.position - this.pos.transform.position,Vector3.right);
    //        }
    //        else
    //        {
    //            dir = (this.lHandAnchor.position - this.pos.position).normalized;
    //            break;
    //        }
    //        yield return null;
    //    }
    //}


    //------------------------- 방패 진동 -----------------------------------
    private void OnParticleCollision(GameObject other)
    {
        
        this.StartCoroutine(this.shakeRoutine);
        if (this.shakeRoutine != null) StopCoroutine(this.shakeRoutine);
    }

    public void Shake()
    {
        this.StartCoroutine(this.shakeRoutine);
    }
    public void StopShake()
    {
        this.StopCoroutine(this.shakeRoutine);
    }

    //방패 진동하는 코루틴 함수
    private IEnumerator CoShake(float magnitude)
    {
        while (true)
        {
            transform.localPosition = (Vector3)UnityEngine.Random.insideUnitSphere * magnitude + startPos;
            yield return null;
        }
    }
}

 

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;


public class Laser : MonoBehaviour
{
    private LineRenderer lr;
    [SerializeField] private Transform attackPos;

    public System.Action onGetHit;
    public System.Action onStopGetHit;
    private void Start()
    {
        this.lr = GetComponent<LineRenderer>();
    }

    void Update()
    {
        lr.SetPosition(0, this.attackPos.position);
        RaycastHit hit;

        Debug.DrawRay(this.attackPos.position, this.attackPos.forward * 50f, Color.red);
        if (Physics.Raycast(this.attackPos.position, this.attackPos.forward * 50f, out hit))
        {
            if (hit.collider.CompareTag("Shield"))
            {
                lr.SetPosition(1, hit.point);
                Quaternion rot = Quaternion.LookRotation(-hit.normal);
                this.onGetHit();
            }
            else //쉴드 말고 다른거에 부딪힐 때
            {
                lr.SetPosition(1, hit.point);
                Quaternion rot = Quaternion.LookRotation(-hit.normal);
                //방패 진동 멈추기
                this.onStopGetHit();
            }
        }
        onStopGetHit();
    }
    
}
using Oculus.Interaction.HandGrab;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class EnemyAttackMain : MonoBehaviour
{ 
    [SerializeField]
    private Shield shield;
    [SerializeField]
    private GameObject aerialEnemyPrefab;
    [SerializeField]
    private Transform[] points;
    [SerializeField]
    private Transform playerTrans;
    private GameObject[] enemyGo;
    private int enemyNum=0;
    Dictionary<GameObject, float> mainDic = new Dictionary<GameObject, float>();
    private float detectEnemyRadius=20;


    private void Update()
    {
        this.enemyGo = GameObject.FindGameObjectsWithTag("Enemy");
        this.CreateEnemy();
        foreach (var enemy in enemyGo)
        {
            var laser=enemy.GetComponentInChildren<Laser>();
            laser.onGetHit = () =>
            {
               this.shield.Shake();
            };
            laser.onStopGetHit = () =>
            {
                this.shield.StopShake();
            };
        }

        this.FindShield();
    }

    private void CreateEnemy()
    {
        if (this.enemyGo.Length == 0)
        {
            if (enemyNum < 6)
            {
                //적 3마리 생성
                for (int i = 0; i < 3; i++)
                {
                    Debug.Log("적 생성해라");
                    Instantiate(this.aerialEnemyPrefab, this.points[i].position, Quaternion.identity);
                    enemyNum++;
                }
            }
            else if (enemyNum >= 6 && enemyNum < 8)
            {
                //2마리 생성
                for (int i = 0; i < 2; i++)
                { 
                    Instantiate(this.aerialEnemyPrefab, this.points[i].position, Quaternion.identity);
                    enemyNum++;
                }
            }
            else
            {
                //더이상 생성하지 X
                //인디케이터 생성
                return;
            }
        }
    }

    private void FindShield()
    {
        var shieldGo = GameObject.FindWithTag("Shield");
        var dis = Vector3.Distance(this.playerTrans.position, shieldGo.transform.position);
        if (dis > 20f&& OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))
        {
            this.shield.Init();
        }
    }

    public GameObject FindEnemyDir()
    {
        Collider[] enemyCols = Physics.OverlapSphere(this.playerTrans.position, detectEnemyRadius, 1 << 6);
        this.mainDic.Clear();
        for (int i = 0; i < enemyCols.Length; i++)
        {
            var col = enemyCols[i];
            Vector3 mainDir = (col.transform.position - this.playerTrans.position).normalized;
            var dot = Vector3.Dot(this.shield.pos.forward, mainDir);
            //Debug.LogFormat("<color=lime>손의 앞방향과 적의 앞 방향 내적 값 !{0}</color>",dot);
            this.mainDic.Add(col.gameObject,dot );
        }

        if (this.mainDic.Count > 0)
        {
           Debug.Log(mainDic.Count);
            var nearestDir = this.mainDic.Values.Max();//가장 방향이 비슷한 적
            var target = this.mainDic.FirstOrDefault(x => x.Value == nearestDir).Key;
            //Debug.LogFormat("<color=red>가까운 적 이름!{0}</color>", target.name);
            return target;
            
        }
        else
        {
           Debug.Log("반경안에 적이 없습니다.");
           return null;
        }
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(this.playerTrans.position, 20);
    }
}
using Palmmedia.ReportGenerator.Core.Reporting.Builders;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using static UnityEngine.GraphicsBuffer;

public class AerialEnemy : MonoBehaviour
{
    [SerializeField]
    private SphereCollider childCollider;
    [SerializeField]
    private GameObject laserStaticEffect;
    [SerializeField]
    private Laser laser;
    [SerializeField]
    private GameObject getHitEffect;
    private Coroutine coroutine;
    private Rigidbody rBody;
    private SphereCollider parentCollider;
    private float time=0f;
    private void Start()
    {
        this.rBody = this.gameObject.GetComponent<Rigidbody>();
        this.parentCollider = this.gameObject.GetComponent<SphereCollider>();
        this.rBody.useGravity = false;
        this.Move();
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Shield"))
        {
            Destroy(this.gameObject, 2f);
            this.rBody.useGravity = true; //바닥으로 떨어지게 
            this.parentCollider.enabled = false;
            this.childCollider.enabled = true;

            var contact = collision.GetContact(0);
            this.rBody.AddForce(contact.point * 25f);
            this.getHitEffect.SetActive(true);

            this.laserStaticEffect.SetActive(false);
            this.laser.enabled = false;
            this.StopCoroutine(this.coroutine);
        }
    }

    //생성되고 랜덤 위치로 이동
    private void Move()
    {
        if (this.coroutine != null) StopCoroutine(this.coroutine);
        this.coroutine = this.StartCoroutine(this.CoMove());
    }

    private IEnumerator CoMove()
    {
        var position = this.transform.position+ new Vector3(Random.Range(-0.6f, 0.6f), Random.Range(-0.5f, 1.0f), Random.Range(-8f, -4f));
        this.laserStaticEffect.SetActive(false);
        this.laser.enabled = false;
        while (true)
        {
            this.transform.LookAt(position);
            this.transform.Translate(Vector3.forward * Random.Range(1f,15f) * Time.deltaTime);
            var dis = Vector3.Distance(position, this.transform.position);
            if (dis < 0.2f)
            {
                this.coroutine=this.StartCoroutine(this.CoAttackAndMove());
                break;
            }

            yield return null;
        }
    }

    //공격-> 랜덤이동-> 공격-> 랜덤이동 ..
    private IEnumerator CoAttackAndMove()
    {
        var position = this.transform.position + new Vector3(Random.Range(-0.8f, 1.2f), Random.Range(-1f, 0.8f), Random.Range(-1f, 1.2f));
        Debug.Log(position);
        while (true)
        {
            this.time += Time.deltaTime;
            if (Vector3.Distance(position, this.transform.position)<0.2f)
            {
                //Debug.Log("목표 위치 변경 ");
                if (this.time > 0.5f)
                {
                    this.laserStaticEffect.SetActive(true);
                    this.laser.enabled = true;
                    this.time = 0;
                }
                yield return new WaitForSeconds(0.7f);
                position = this.transform.position + new Vector3(Random.Range(-0.7f, 0.7f), Random.Range(-0.7f, 0.8f), Random.Range(-0.6f, 1f));
            }
            else
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, position, 0.05f);
                this.laserStaticEffect.SetActive(false);
                this.laser.enabled = false;
            }

            yield return null;
        }
    }
}