조퇴로 인한 지금 업로드 ,, 크흠 ^_^
void RayCastFire()
{
...
GameObject go = Instantiate(trailPrefab);
Vector3[] pos = new Vector3[] { firingPosition.position, hitPosition };
go.GetComponent<LineRenderer>().SetPositions(pos);
//방법 1 Invoke()
//방법 2
StartCoroutine(DestroyTrail(go));
//방법 3
Destroy(go, 0.1f);
}
IEnumerator DestroyTrail(GameObject obj)
{
yield return new WaitForSeconds(0.5f);
Destroy(obj);
}
}
사용 이유
비동기 작업을 처리하면서도 게임 루프의 제어를 유지할 수 있기 때문에 사용한다.
사용 방법
IEnumerator 메소드이름()
{
yield return new WaitForSeconds(초);
}
StartCoroutine(메소드이름());
파티클이 끝난 후 어떤걸 불러올지 정할 수 있음(None, Disable, Destroy, Callback(함수 불러오기))
총알이 맞은 방향 수직으로 파티클이 튀도록
void RayCastFire()
{
Camera cam = Camera.main;
RaycastHit hit;
Ray r = cam.ViewportPointToRay(Vector3.one / 2); //카메라 정 중앙으로 발사
Vector3 hitPosition = r.origin + r.direction * 200; //아무곳에도 부딪히지 않았다면 카메라 방향에서 200정도 떨어져있는 곳
if (Physics.Raycast(r, out hit, 1000)) //어딘가에 빛이 부딪혔으면 true
{ //레이 r의 정보를 가지고 1000의 최대거리 만큼 레이를 쏜다. out : 변수를 넣었을때 변수가 변할 수 있다는 것(out을 안 쓰면 오류남)
hitPosition = hit.point; //빛이 부딪힌 부분이 총알의 종착점
//총알이 부딪힌 지점의 수직으로 파티클이 튀도록
GameObject particle = Instantiate(particlePrefab);
particle.transform.position = hitPosition;
particle.transform.forward = hit.point;
}
총과 같은 위치에 수류탄 에셋을 가져와서 두기
상속
0,0,0에 수류탄을 하나 만들어서 콜라이더를 넣어줌
얘가 projectilePrefab이 될 예정
상속되어서 인스펙터창에 다 나옴
각각 알맞은 곳에 넣어준다
using UnityEngine;
public class ProjectileWeapon : Weapon
{
public GameObject projectilePrefab;
public float projectileAngle = 30;
public float projectileForce = 10;
public float projectileTime = 5;
protected override void Fire()
{
ProjectileFire();
}
public void ProjectileFire()
{
//30도 올린 각도 만들기
Camera cam =Camera.main;
Vector3 forward = cam.transform.forward; //카메라가 주시하는 방향 벡터
Vector3 up = cam.transform.up; //y축 벡터
Vector3 direction = forward + up * Mathf.Tan(projectileAngle * Mathf.Deg2Rad);
//주시방향+(y축 * 라디안으로 치환한 발사각의 탄젠트값)
direction.Normalize(); //벡터값 정규화
direction *= projectileForce; //발사 방향에 발사 힘 곱해서
GameObject go = Instantiate(projectilePrefab); //수류탄 인스턴스 생성
go.transform.position = firingPosition.position; //생성한 수류탄 초기 위치 지정
go.GetComponent<Rigidbody>().AddForce(direction, ForceMode.Impulse); //생성한 수류탄을 지정한 벡터로 투척
}
}
public class Weapon : MonoBehaviour
{
public void FireWeapon()
{
if (animator != null)
{
if (animator.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
{
animator.SetTrigger("Fire");
Fire();
}
}
else
{
Fire();
}
}
protected virtual void Fire()
{
RayCastFire();
}
폭발하는 애니메이션 생성
using UnityEngine;
public class Bomb : MonoBehaviour
{
public float time;
private void Update()
{
time -= Time.deltaTime;
if (time < 0)
{
GetComponent<Animator>().SetTrigger("Explode");
Destroy(gameObject, 2f);
}
}
}
using UnityEngine;
public class Bomb : MonoBehaviour
{
public float time;
private void Update()
{
time -= Time.deltaTime;
if (time < 0)
{
GetComponent<Animator>().SetTrigger("Explode");
Destroy(gameObject, 2f);
}
}
}
수류탄 프리팹에 추가
public class ProjectileWeapon : Weapon
{
public float projectileTime = 5;
public void ProjectileFire()
{
go.GetComponent<Bomb>().time = projectileTime;
}
}
인풋 추가
Listen누르고 원하는 버튼 누르면 쉽게 가능
PlayerController 스크립트 수정
public List<Weapon> weapons;
int currentWeaponIndex;
void OnChangeWeapon()
{
weapons[currentWeaponIndex].gameObject.SetActive(false);
currentWeaponIndex++;
if(currentWeaponIndex > weapons.Count-1)
{
currentWeaponIndex = 0;
}
weapons[currentWeaponIndex].gameObject.SetActive(true);
}
public class Weapon : MonoBehaviour
{
public GameObject trailPrefab;
public Transform firingPosition;
public GameObject particlePrefab;
public TextMeshProUGUI bulletText;
public int currentBullet = 8;
public int totalBullet = 32;
public int maxBulletMagazine = 8;
Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
bulletText.text = currentBullet + "/" + totalBullet;
}
public void FireWeapon()
{
if (currentBullet > 0) //현재 잔탄이 남아있을때
{
if (animator != null)
{
if (animator.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
{
animator.SetTrigger("Fire");
currentBullet--;
Fire();
}
}
else
{
currentBullet--;
Fire();
}
}
}
protected virtual void Fire()
{
RayCastFire();
}
public void ReloadWeapon()
{
if (totalBullet > 0) //탄약이 있으면
{
if (animator != null)
{
if (animator.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
{
animator.SetTrigger("Reload");
Reload();
}
}
else
{
Reload();
}
}
}
void Reload()
{
if (totalBullet >= maxBulletMagazine - currentBullet)
//탄약수가 (탄창 탄약 - 잔탄)보다 같거나 많으면
{
//꽉 채우기
totalBullet -= maxBulletMagazine - currentBullet;
currentBullet = maxBulletMagazine;
//잔탄을 탄창 탄약으로 설정
}
else
//탄약수가 (탄창 탄약 - 잔탄)보다 적으면
{
//남은 탄창 + 채울거
currentBullet += totalBullet;
totalBullet = 0; //탄약을 비움
}
}
적으로 지정해줘서 콜라이더 넣어주기
Nav Mesh Surface 추가후 Bake
Enemy에 Nav Mesh Agent를 추가
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
GameObject player;
NavMeshAgent agent;
void Start()
{
player = GameObject.FindWithTag("Player");
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
agent.destination = player.transform.position;
}
}
내가 가있던 자리로 쫓기
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
GameObject player;
NavMeshAgent agent;
void Start()
{
player = GameObject.FindWithTag("Player");
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
//destination까지 남은 거리(흔적쫓기)
if (agent.remainingDistance<1f)
{
agent.destination = player.transform.position;
}
}
}