유튜브 <골드메탈> 영상 시청 및 따라 만들기 - 3D 쿼터뷰 액션게임


추가 및 수정한 스크립트

Player.cs :: 물리 충돌시 각종 버그를 수정하기위헤 FixedUpdate를 추가

1.오브젝트와 충돌시 회전속력이 발생하는 버그를 없애기위해 FreezeRotation()함수 추가

2.벽을 관통하는 버그가 있어 StopToWall() 함수 추가

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    bool isBorder = false; //현재 벽과 충돌했는지 체크 유무

    private void Move()
    {
        //정규화를 하는 이유? : 대각선 이동시 빨라지기 때문에 크기(속도)를 1로 만들어서 속도를 똑같이 만들어줘야한다.
        //쉽게 말하면 방향값이 1로 보정되는 벡터라고 생각하면 된다.
        //왜 빨라짐? : hAxis = 1 , vAxis = 1 인경우 대각성 이동시 피타고라스의 법칙으로 root(1^2+1^2) = root(2) = 1.141... 때문이다.
        moveVec = new Vector3(hAxis, 0, vAxis).normalized;

        //무기 교체시 or 무기 공격시 or 재장전시 움직이지 못하게 설정
        if (isSwap || !isFireReady || isReload) moveVec = Vector3.zero;

        //회피 동작 중인경우 회피 방향벡터가 대입되어 방향전환을 못하게 막기 위한 코드
        if (isDodge) moveVec = dodgeVec;

        //transform 이동은 가끔 물리충돌을 무시하는 경우가 발생 함
        //Rigidbody 컴포넌트에서 CollisonDetection을 Continuos로 변경 
        //Cpu를 더 먹어 최적화는 떨어지지만 정확도는 올라가기 때문 

        //위의 조건과 같이 걸어버리면 회전할시에 moveVec에 영향을 받게 되서 캐릭터가 굳어버릴수 있다.
        if (!isBorder)
        { 
            if (!wDown) transform.position += moveVec * speed * Time.deltaTime;
            else transform.position += moveVec * speed * 0.3f * Time.deltaTime;
        }

        //SetXXXX("애니메이션 이름" , bool 변수) 를 넣어 조건문처럼 사용 할 수 있다.
        anim.SetBool("isRun", moveVec != Vector3.zero);
        anim.SetBool("isWalk", wDown);
    }

    private void Turn()
    {
        //지정된 벡터를 향해서 회전시켜주는 함수 - 3D기능
        //현재 플레이어 위치에 방향벡터를 더해서 우리가 나아가는 쪽으로 오브젝트를 회전한다는 뜻
        //#1.키보드에 의한 회전
        transform.LookAt(transform.position + moveVec);

        //#2.마우스에 의한 회전
        if (fDown)
        {
            //스크린 -> 월드로 Ray를 쏘는 함수
            Ray ray = followCamera.ScreenPointToRay(Input.mousePosition);
            RaycastHit rayHit;
            if (Physics.Raycast(ray, out rayHit, 100))
            {
                Vector3 nextVec = rayHit.point - transform.position;
                nextVec.y = 0; //마스크가 없기에 부피가 있는 콜라이더 물체를 클릭시 캐릭터가 빙빙 도는 현상을 막기위해 y =0 추가
                transform.LookAt(transform.position + nextVec);
            }
        }
    }

    void FreezeRotation()
    {
        //rigid.angularVelocity : 물리회전속도
        rigid.angularVelocity = Vector3.zero;
    }

    void StopToWall()
    {
        Debug.DrawRay(transform.position, transform.forward * 5, Color.green);
        //레이어마스크(Wall)과 5 거리 안에 충돌시 isBorder는 true가 될것이다.
        isBorder = Physics.Raycast(transform.position, transform.forward, 5, LayerMask.GetMask("Wall"));
    }

    private void FixedUpdate()
    {
        FreezeRotation();
        StopToWall();
    }


}

 

Item.cs :: 드랍 아이템들의 Player와의 물리충돌을 없애기 위해

1.Floor와 충돌시 Rigidbody를 Kinematic 처리 와 물리충돌을 담당하는 Collider을 비활성화

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

public class Item : MonoBehaviour
{
    Rigidbody rigid;
    SphereCollider sphereCollider;

    //열거형 변수 enum
    public enum Type
    {
        Ammo, Coin, Grenade, Heart, Weapon
    };

    public Type type; //아이템 종류 변수
    public int value; //아이템 값을 저장할 변수

    private void Awake()
    {
        rigid = GetComponent<Rigidbody>();

        //Item 오브젝트에는 2개의 스피어콜라이더가 있음
        //GetComponent 호출시 Inspector 제일 위에있는 컴포넌트를 호출하게됨
        sphereCollider = GetComponent<SphereCollider>();
    }

    void Update()
    {
        //Rotate(오일러 각도) : 오브젝트를 해당 각도(방향벡터)로 회전시키는 함수 
       transform.Rotate(Vector3.up * 10 * Time.deltaTime);
    }

    //물리효과 변경을 스크립트로 수정
    private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.CompareTag("Floor"))
        {
            //바닥에 충돌시 키네마틱(물리충돌연산x)로 변경
            rigid.isKinematic = true;
            sphereCollider.enabled = false;

        }
    }
}

수정된 물리연산들 & 유니티 기능 정리

1.자동회전방지

탄피에도 RigidBody와 Collider가 있어 탄피가 쌓이고 Player가 위로 올라가면 자동으로 회전하는 버그가 있었다.

이 버그의 원인은 Player <> 총알탄피 의 물리충돌로 인하여 Player의 Rigidbody에 회전속력이 추가되기에 발생되는 것이다.

 

Player.cs

  void FreezeRotation()
    {
        //rigid.angularVelocity : 물리회전속도
        rigid.angularVelocity = Vector3.zero;
    }

해당 코드를 FixedUpdate()에서 호출하여 회전속도를 강제로 0으로 만들어 처리하였다.

 

2.충돌레이어 설정

오브젝트의 레이어를 설정하여 충돌을 원하는데로 컨트롤 할 수 있다.

위 그림과 같이 탄피(BulletCase)와 플레이어 총알(PlayerBullet)의 레이어를 설정하고 충돌 관계를 설정하여 

충돌을 방지했다. 

 

1,2 번으로 문제점을 해결한 결과

1.탄피가 겹치지 않게 설정 완료 , 2.Player가 탄피위에 올라가도 충돌 발생 X

 

3.벽 관통 방지

해당 프로젝트에서 캐릭터가 벽을 관통하는 버그가 있었다. 실제로 3D프로젝트를 진행하면 자주 겪는 버그다.

이 버그를 대처하기 위해서는 RayCast기능을 활용하였다.

Unity Editer에서 확인하기 편하게 해당 코드를 적어준다.

해당 코드는 인게임에서는 보이지 않고 에디터에서만 보이는 레이저다.

    void StopToWall()
    {
        Debug.DrawRay(transform.position, transform.forward * 5, Color.green);
        //레이어마스크(Wall)과 5 거리 안에 충돌시 isBorder는 true가 될것이다.
        isBorder = Physics.Raycast(transform.position, transform.forward, 5, LayerMask.GetMask("Wall"));
    }

isBorder Bool변수를 만들어 레이저가 벽에 닿은 경우 true가 되게 만든뒤 

private void Move()
    {

        //무기 교체시 or 무기 공격시 or 재장전시 움직이지 못하게 설정
        if (isSwap || !isFireReady || isReload) moveVec = Vector3.zero;

        //위의 조건과 같이 걸어버리면 회전할시에 moveVec에 영향을 받게 되서 캐릭터가 굳어버릴수 있다.
        if (!isBorder)
        { 
            if (!wDown) transform.position += moveVec * speed * Time.deltaTime;
            else transform.position += moveVec * speed * 0.3f * Time.deltaTime;
        }

        //SetXXXX("애니메이션 이름" , bool 변수) 를 넣어 조건문처럼 사용 할 수 있다.
        anim.SetBool("isRun", moveVec != Vector3.zero);
        anim.SetBool("isWalk", wDown);
    }

Move()함수에 추가하여 transform에 영향을 안주게 막아버렸다. 이러면 애니메이션은 계속 재생하기에

플레이어가 키를 눌렀다는것을 인지함과 동시에 벽 관통 버그를 원천 봉쇄해버렸다.

 

4.아이템 물리 총돌 제거

물리 충돌을 담당하는 콜라이더와 Player가 충돌시 문제가 발생한다.

충돌시 아이템의 회전속도가 지멋대로 바뀌며 Player는 해당 아이템에 올라 탈 수 있다.

Item.cs

  private void Awake()
    {
        rigid = GetComponent<Rigidbody>();

        //Item 오브젝트에는 2개의 스피어콜라이더가 있음
        //GetComponent 호출시 Inspector 제일 위에있는 컴포넌트를 호출하게됨
        sphereCollider = GetComponent<SphereCollider>();
    }
    
    
    //물리효과 변경을 스크립트로 수정
    private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.CompareTag("Floor"))
        {
            //바닥에 충돌시 키네마틱(물리충돌연산x)로 변경
            rigid.isKinematic = true;
            sphereCollider.enabled = false;

        }
    }


Floor와 충돌할때, Rigid를 키네마틱 , 물리충돌 담당하는 콜라이더를 비활성화 시켜 Player와의 충돌을 방지하였다.


 

 

 

+ Recent posts