728x90
지난 금요일에 배운 LoadAndSave 프로젝트가 Sourcetree에 잘 안올라가진 것 같다,,,ㅜㅜ
내일 다시 해봐야겠다!
주말에 그동안 HeroShooter 오류났던 것들 수정을 했다.
- Hero가 Monster 감지할 때 Ray가 이상하게 나갔던 것
- 총알 발사할때 방향이 이상하게 나갔던 것
- 애니메이션 추가 등..
그렇지만 역시나 이번에도 새로운 걸 하려보니 오류가 나
네^^,,
오류에 늪에서 벗어나려면 연습을 더 해야함을 느낀다...
**오늘의 오류
- 총알 무한발사 (지난 번에 했던 코루틴 무한반복 방지 방법을 쓴 거 같은데도 무한 발사를 한다ㅜ )
Player
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Player : MonoBehaviour
{
private Transform playerTrans;
public float moveSpeed = 5f;
private Animator anim;
public float turnSpeed = 80f;
private Rigidbody rBody;
[SerializeField]
private float radius = 15.0f;
[SerializeField]
private float rayOffsetY = 0.5f; //Ray 오프셋
[SerializeField]
private Monster target;
[SerializeField]
private BulletGenerator bulletGenerator;
[SerializeField]
private Bullet bullet;
private Coroutine attackCoroutine;
//Stage2의 몬스터 2마리
private Collider[] monsterColl = new Collider[2];
void Start()
{
this.playerTrans = this.GetComponent<Transform>();
this.anim = this.GetComponent<Animator>();
this.rBody = this.GetComponent<Rigidbody>();
}
//몬스터 게임오브젝트를 사전에 넣어서 관리
Dictionary<GameObject, float> dic = new Dictionary<GameObject, float>();
void Update()
{
this.SearchMonster();
if(target != null)
{
this.Attack();
}
}
//이동 메서드
public void Move(Vector3 dir)
{
//애니메이션
this.anim.SetInteger("State", 1);
//회전하기
float angle = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg;
this.playerTrans.localRotation = Quaternion.AngleAxis(angle, Vector3.up);
//이동하기
this.playerTrans.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);
}
//정지 메서드
public void Idle()
{
this.anim.SetInteger("State", 0);
}
//거리를 구해서 몬스터 검색하는 메서드
public void SearchMonster()
{
//layMask를 이용
Collider[] targetCols = Physics.OverlapSphere(this.playerTrans.position, this.radius, 1 << LayerMask.NameToLayer("Monster"));
this.dic.Clear(); //사전에 있는 정보 초기화
//for문을 돌며 GameObject를 키값으로 거리 정보를 dic에 저장
for(int i = 0; i < targetCols.Length; i++)
{
Collider col = targetCols[i];
//거리 구하기
float distance = Vector3.Distance(col.transform.position, this.playerTrans.position);
//거리 정보를 dic에 저장
this.dic.Add(col.gameObject, distance);
}
//공격 사거리 안에 몬스터가 있다면
if(this.dic.Count > 0)
{
//가장 작은 값(가까운 거리)을 저장
float nearestDistance = this.dic.Values.Min();
//
GameObject target = this.dic.FirstOrDefault(x => x.Value == nearestDistance).Key;
//player로부터 타겟의 방향
Vector3 dir = target.transform.position - this.playerTrans.position;
//Ray 생성
Ray ray = new Ray(this.transform.position + (Vector3.up * this.rayOffsetY), dir);
//Ray 그리기
Debug.DrawRay(ray.origin, ray.direction * 1000f, Color.red);
int layerMask = 1 << LayerMask.NameToLayer("Monster") | 1 << LayerMask.NameToLayer("Wall") | 1 << LayerMask.NameToLayer("Tree");
RaycastHit hit;
//layMask를 이용하여 몬스터, 벽, 나무 구분하기
if (Physics.Raycast(ray, out hit, 1000f, layerMask))
{
//tag가 몬스터라면
if(hit.collider.CompareTag("Monster"))
{
if(this.target != null)
{
this.target.HideIndicator();
//몬스터를 바라보기
//this.playerTrans.LookAt(this.target.transform.position);
}
Monster monster = hit.collider.gameObject.GetComponent<Monster>();
monster.ShowIndicator();
this.target = monster;
}
else
{
Monster[] monsters = GameObject.FindObjectsOfType<Monster>();
//몬스터 수 출력
Debug.Log(monsters.Count());
foreach(Monster monster in monsters)
{
monster.HideIndicator();
}
this.target = null;
}
}
}
}
//공격 메서드
void Attack()
{
if(this.attackCoroutine != null)
{
this.StopCoroutine(CoAttack());
}
//타겟 몬스터 바라보기
this.playerTrans.LookAt(this.target.transform.position);
//
this.StartCoroutine(CoAttack());
}
IEnumerator CoAttack()
{
while (true)
{
//공격 애니메이션 실행
this.anim.SetInteger("State", 2);
//총알 발사 타이밍 맞추기
yield return new WaitForSeconds(0.03f);
//총알 생성
this.bulletGenerator.CreateBullet();
Debug.Log("총알 발사");
yield return new WaitForSeconds(0.2f);
if(bullet == true)
{
break;
}
}
yield return null;
}
private void OnDrawGizmos()
{
Gizmos.color = Color.white;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
}
}
Bullet
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
private Rigidbody rBody;
[SerializeField]
private float force = 1000;
void Start()
{
this.rBody = this.GetComponent<Rigidbody>();
//월드좌표 기준으로 힘 가해짐
this.rBody.AddForce(this.transform.forward * this.force);
}
}
BulletGenerator
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletGenerator : MonoBehaviour
{
[SerializeField]
private GameObject bulletPrefab;
[SerializeField]
private Transform firePos;
//총알 생성
public void CreateBullet()
{
Instantiate(this.bulletPrefab, this.firePos.position, this.firePos.rotation);
}
}
총알 발사를 코루틴 하기 전에 봤던 블로그 글인데 코루틴 이해에 조금 더 도움이 됐다!!
https://m.blog.naver.com/cdw0424/221624274241
유니티(Unity) - 코루틴(Coroutine)과 yield에 대하여
코루틴을 설명하는 글은 많이 봤지만 대부분 매우 함축되어 있어서 쉽게 이해할 수 있는 글은 정말 정말 찾...
blog.naver.com
'KDT > 유니티 심화' 카테고리의 다른 글
23/09/04 LearnUGUI 버튼2 (배열로 관리) (0) | 2023.09.04 |
---|---|
23/09/04 LearnUGUI 버튼 (0) | 2023.09.04 |
23/08/31 Input System 연습 (0) | 2023.08.31 |
23/08/30 HeroShooter 타이틀 (비동기 씬 전환) (0) | 2023.08.30 |
23/08/29 TestAreaMask (0) | 2023.08.29 |