유튜브 <골드메탈> 영상 시청 및 따라 만들기 - 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.자동회전방지
이 버그의 원인은 Player <> 총알탄피 의 물리충돌로 인하여 Player의 Rigidbody에 회전속력이 추가되기에 발생되는 것이다.
Player.cs
void FreezeRotation()
{
//rigid.angularVelocity : 물리회전속도
rigid.angularVelocity = Vector3.zero;
}
해당 코드를 FixedUpdate()에서 호출하여 회전속도를 강제로 0으로 만들어 처리하였다.
2.충돌레이어 설정
위 그림과 같이 탄피(BulletCase)와 플레이어 총알(PlayerBullet)의 레이어를 설정하고 충돌 관계를 설정하여
충돌을 방지했다.
1,2 번으로 문제점을 해결한 결과
3.벽 관통 방지
해당 프로젝트에서 캐릭터가 벽을 관통하는 버그가 있었다. 실제로 3D프로젝트를 진행하면 자주 겪는 버그다.
이 버그를 대처하기 위해서는 RayCast기능을 활용하였다.
해당 코드는 인게임에서는 보이지 않고 에디터에서만 보이는 레이저다.
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가 충돌시 문제가 발생한다.
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와의 충돌을 방지하였다.
'내일배움캠프_Unity_6기 > TIL(Today I Learend)' 카테고리의 다른 글
TIL : 2024-09-10(화) :: Class 내부 변수 이름으로 호출하기, (0) | 2024.09.10 |
---|---|
TIL : 2024-09-09(월) :: GitHub 기초 (0) | 2024.09.09 |
TIL : 2024-09-06(금) (0) | 2024.09.06 |
TIL : 2024-09-05(목) (0) | 2024.09.05 |
TIL : 2024-09-04(수) (0) | 2024.09.04 |