FPS서바이벌 디펜스
X.레이어마스크 해결
ruripanda
2025. 5. 28. 14:57
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class GunController : MonoBehaviour
{
//활성화 여부
public static bool isActivate = false;
//현재 장착된 총
[SerializeField]
private Gun currentGun;
//연사속도 계산
private float currentFireRate;//정조준 위치를 위한 값
//상태변수
private bool isReload = false;
[HideInInspector]//인스팩터에세 숨김
public bool isFineSightMode = false;//정조준 위치 bool 값
// 본래 포지션 값.
[SerializeField]
private Vector3 originPos;//원래 조준위치
//효과음
private AudioSource audioSource;
//레이져 충돌 정도 받아옴
private RaycastHit hitInfo;
[SerializeField]
private LayerMask layerMask;
//필요한 카메라 컴포넌트
[SerializeField]
private Camera theCam;
private Crosshair theCrosshair;
//피격 이팩트
[SerializeField]
private GameObject hit_effect_prefab;
void Start()
{
originPos = Vector3.zero;
audioSource = GetComponent<AudioSource>();
theCrosshair = FindAnyObjectByType<Crosshair>();
}
// Update is called once per frame
void Update()
{
if (isActivate)
{
GunFireRateCalc();
TryFire();
TryReload();
TryFineSight();
}
}
//연사속도 재계산
private void GunFireRateCalc()
{
if (currentFireRate > 0)
currentFireRate -= Time.deltaTime;
}
//발사시도
private void TryFire()
{
if (Input.GetButton("Fire1") && currentFireRate <= 0 && !isReload)
{
Fire();
}
}
//발사전 계산
private void Fire()
{
if (!isReload)
{
if (currentGun.currentBulletCount > 0)
Shoot();
else
{
CancelFineSight();
StartCoroutine(ReloadCoroutine());
}
}
}
//발사 후 계산
private void Shoot()
{
theCrosshair.FireAnimation();
currentGun.currentBulletCount--;
currentFireRate = currentGun.fireRate; // 연사 속도 재계산.
PlaySE(currentGun.fire_Sound);
currentGun.muzzleFlash.Play();
Hit();
StopAllCoroutines();
StartCoroutine(RetroActionCoroutine());
}
private void Hit()
{
if (Physics.Raycast(theCam.transform.position, theCam.transform.forward +
new Vector3(Random.Range(-theCrosshair.GetAccuracy() - currentGun.accuracy, theCrosshair.GetAccuracy() + currentGun.accuracy),
Random.Range(-theCrosshair.GetAccuracy() - currentGun.accuracy, theCrosshair.GetAccuracy() + currentGun.accuracy),
0), out hitInfo, currentGun.range, layerMask))
{
GameObject clone = Instantiate(hit_effect_prefab, hitInfo.point, Quaternion.LookRotation(hitInfo.normal));
Destroy(clone, 2f);
//Debug.Log(hitInfo.transform.name);
}
}
//재장전 시도
private void TryReload()
{
if (Input.GetKeyDown(KeyCode.R) && !isReload && currentGun.currentBulletCount < currentGun.reloadBulletCount)
{
CancelFineSight();
StartCoroutine(ReloadCoroutine());
}
}
public void CancelReload()
{
if (isReload)
{
StopAllCoroutines();
isReload = false;
}
}
//재장전
IEnumerator ReloadCoroutine()
{
if (currentGun.carryBulletCount > 0)
{
isReload = true;
currentGun.anim.SetTrigger("Reload");
currentGun.carryBulletCount += currentGun.currentBulletCount;
currentGun.currentBulletCount = 0;
yield return new WaitForSeconds(currentGun.reloadTiem);
if (currentGun.carryBulletCount >= currentGun.reloadBulletCount)
{
currentGun.currentBulletCount = currentGun.reloadBulletCount;
currentGun.carryBulletCount -= currentGun.reloadBulletCount;
}
else
{
currentGun.currentBulletCount = currentGun.carryBulletCount;
currentGun.carryBulletCount = 0;
}
isReload = false;
}
else
{
Debug.Log("소유한 총알이 없습니다.");
}
}
//정조준 시도
private void TryFineSight()
{
if (Input.GetButtonDown("Fire2") && !isReload)
{
FineSight();
}
}
//정조준 취소
public void CancelFineSight()
{
if (isFineSightMode)
FineSight();
}
//정조준 로직가동
private void FineSight()
{
isFineSightMode = !isFineSightMode;
currentGun.anim.SetBool("FineSightMode", isFineSightMode);
theCrosshair.FineingAnimation(isFineSightMode);
if (isFineSightMode)
{
StopAllCoroutines();
StartCoroutine(FineSightActivateCoroutine());
}
else
{
StopAllCoroutines();
StartCoroutine(FineSightDeactivateCoroutine());
}
}
//정조준 활성화
IEnumerator FineSightActivateCoroutine()
{
while (currentGun.transform.localPosition != currentGun.fineSightOriginPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, currentGun.fineSightOriginPos, 0.2f);
yield return null;
}
}
//정조준 비활성화
IEnumerator FineSightDeactivateCoroutine()
{
while (currentGun.transform.localPosition != originPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, originPos, 0.2f);
yield return null;
}
}
//총 반동
IEnumerator RetroActionCoroutine()
{
Vector3 recoilBack = new Vector3(currentGun.retroActionForce, originPos.y, originPos.z);
Vector3 retroActionRecoilBack = new Vector3(currentGun.retroActionFineSightForce, currentGun.fineSightOriginPos.y, currentGun.fineSightOriginPos.z);
if (!isFineSightMode)
{
currentGun.transform.localPosition = originPos;
// 반동 시작
while (currentGun.transform.localPosition.x <= currentGun.retroActionForce - 0.02f)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, recoilBack, 0.4f);
yield return null;
}
// 원위치
while (currentGun.transform.localPosition != originPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, originPos, 0.1f);
yield return null;
}
}
else
{
currentGun.transform.localPosition = currentGun.fineSightOriginPos;
// 반동 시작
while (currentGun.transform.localPosition.x <= currentGun.retroActionFineSightForce - 0.02f)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, retroActionRecoilBack, 0.4f);
yield return null;
}
// 원위치
while (currentGun.transform.localPosition != currentGun.fineSightOriginPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, currentGun.fineSightOriginPos, 0.1f);
yield return null;
}
}
}
//사운드 재생
private void PlaySE(AudioClip _clip)
{
audioSource.clip = _clip;
audioSource.Play();
}
public Gun GetGun()
{
return currentGun;
}
public bool GetFineSightMode()
{
return isFineSightMode;
}
public void GunChange(Gun _gun)
{
if(WeaponManager.currentWeapon != null)
WeaponManager.currentWeapon.gameObject.SetActive(false);
currentGun = _gun;
WeaponManager.currentWeapon = currentGun.GetComponent<Transform>();
WeaponManager.currentWeaponAnim = currentGun.anim;
currentGun.transform.localPosition = Vector3.zero;
currentGun.gameObject.SetActive(true);
isActivate = true;
}
}
using System.Collections;
using UnityEngine;
public abstract class CloseWeaponController : MonoBehaviour//abstract 자식클레스에서 완성시키는 추상클레스
{
//현재 장착된 Hand형 타입 무기
[SerializeField]
protected CloseWeapon currentCloseWeapon;
//공격중??
protected bool isAttack = false;
protected bool isSwing = false;
protected RaycastHit hitInfo;
[SerializeField]
protected LayerMask layerMask;
protected void TryAttack()
{
if (!Inventory.inventoryActivated)
{
if (Input.GetButton("Fire1"))
{
if (!isAttack)
{
StartCoroutine(AttackCoroutine());
}
}
}
}
protected IEnumerator AttackCoroutine()
{
isAttack = true;
currentCloseWeapon.anim.SetTrigger("Attack");
yield return new WaitForSeconds(currentCloseWeapon.attackDelayA);
isSwing = true;
StartCoroutine(HitCoroutine());
yield return new WaitForSeconds(currentCloseWeapon.attackDelayB);
isSwing = false;
yield return new WaitForSeconds(currentCloseWeapon.attackDelay - currentCloseWeapon.attackDelayA - currentCloseWeapon.attackDelayB);
isAttack = false;
}
protected abstract IEnumerator HitCoroutine();//abstract 미완성 = 추상코루틴, 자식스크립트에서 완성예정
protected bool CheckObject()
{
if (Physics.Raycast(transform.position, transform.forward /*transform.TransformDirection(Vector3.forward)은 같은 뜻*/, out hitInfo, currentCloseWeapon.range, layerMask))
{
return true;
}
return false;
}
//virtual, 완성 함수이지만 추가 편집이 가능한 함수
public virtual void CloseWeaopnChange(CloseWeapon _closeWeapon)
{
if (WeaponManager.currentWeapon != null)
WeaponManager.currentWeapon.gameObject.SetActive(false);
currentCloseWeapon = _closeWeapon;
WeaponManager.currentWeapon = currentCloseWeapon.GetComponent<Transform>();
WeaponManager.currentWeaponAnim = currentCloseWeapon.anim;
currentCloseWeapon.transform.localPosition = Vector3.zero;
currentCloseWeapon.gameObject.SetActive(true);
}
}
이번시간에는 플레이어에게서 레이어마스크가 잡히는 문제를 해결할 것이다
무슨 소리냐면 플레이어가 곡괭이로 공격을 하면 플레이어 자신이 콘솔에서 잡히는 문제점이다
GunController 스크립트를 열어서 밑줄친 부분을 작성해주자
그리고 Hit부분에 layerMask 를 받아올 부분을 추가해주자
다음은 CloseWeaponController 스크립트를 열어서 밑줄 친 부분을 추가해주자
그뒤 함수에 밑줄친 부분을 추가해주자
그러면 이렇게 표시한 부분이 추가되는데 이 부분이 감지할 객체를 선택해주는 것이다
Everything를 누른 다음 Ignore Raycaast와 Player부분의 체크를 해제해서 체크한 부분만 적중되게 하자
이번 강좌는 이것으로 끝이다