PlayerController
onAttack 대리자만 추가해줘서 몬스터가 인식할 때 대리자를 Main쪽에 부를 수 있게 해주었다.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
//캐릭터 움직임 속도
[SerializeField]
private float moveSpeed = 5f;
//애니메이션
private Animator anim;
//포탈태그했을 때
public Action reachPortal;
//문에 닿았을 때
public Action reachDoor;
//rayOffsetY
private float rayOffsetY = 0.5f;
//공격대리자
public Action onAttack;
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
public void Move(Vector3 moveDir)
{
//달리는 애니메이션 실행
this.PlayAnimation(EnumState.ePlayerState.RunF);
//Mathf.Atan2와 Mathf.Rad2Deg를 이용해서 회전시키기
float angle = Mathf.Atan2(moveDir.x, moveDir.z) * Mathf.Rad2Deg;
//AngleAxis를 이용하기
Quaternion q = Quaternion.AngleAxis(angle, Vector3.up);
//캐릭터에 회전 적용
this.transform.rotation = q;
//캐릭터 움직이기
this.transform.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);
}
public void PlayAnimation(EnumState.ePlayerState state)
{
this.anim.SetInteger("State", (int)state);
}
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Door")
{
//대리자 사용해서 씬 전환하기
this.reachDoor();
}
else if (collision.collider.tag == "Portal")
{
//대리자 사용해서 문 열고, 포탈 제거하기
this.reachPortal();
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(this.transform.position, 30f);
}
public void MonsterRay(Vector3 dir, MonsterController target)
{
//레이로 플레이어의 살짝 위에서 몬스터까지의 거리 찍기
Ray ray = new Ray(this.transform.position + (Vector3.up * this.rayOffsetY), dir);
//그려보기
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.green);
//layerMask.NameToLayer로 레이어 구별해주기
var layerMask = 1 << LayerMask.NameToLayer("Monster") | 1 << LayerMask.NameToLayer("Car") | 1 << LayerMask.NameToLayer("Wall");
RaycastHit hit;
if(Physics.Raycast(ray, out hit, 100f, layerMask))
{
Debug.Log(hit.collider.tag);
if(hit.collider.CompareTag("Monster"))
{
if(target != null)
{
target.HideIndicator();
}
var monsterController = hit.collider.gameObject.GetComponent<MonsterController>();
monsterController.ShowIndicator();
this.onAttack();
target = monsterController;
}
else
{
MonsterController[] monsterContorllers = GameObject.FindObjectsOfType<MonsterController>();
Debug.Log(monsterContorllers.Count());
foreach (MonsterController monster in monsterContorllers)
{
monster.HideIndicator();
}
target = null;
}
}
}
}
Stage1SceneMain
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class Stage1SceneMain : MonoBehaviour
{
//플레이어
[SerializeField]
private PlayerController playerController;
//몬스터
[SerializeField]
private MonsterController target;
//조이스틱
[SerializeField]
private CJoystick joystick;
//왼쪽 문
[SerializeField]
private DoorController leftDoorController;
//오른쪽 문
[SerializeField]
private DoorController rightDoorController;
//페이드인
[SerializeField]
private Image dim;
//NPC 텍스트
[SerializeField]
private Text text;
//TargetQuad
[SerializeField]
private GameObject targetQuadGo;
//반지름
private float radius = 30f;
//딕셔너리
private Dictionary<GameObject, float> dic = new Dictionary<GameObject, float>();
//캐릭터가 움직이는 좌표
private Vector3 moveDir;
// Start is called before the first frame update
void Start()
{
//씬 전환시 페이드인
this.StartCoroutine(this.CoFadeInAndSceneManager());
//포탈에 닿았을 때
this.playerController.reachPortal = () =>
{
//포탈 삭제하고
//Destroy(this.portalGo.gameObject);
//문 열기
//this.leftDoorController.OpenDoor();
//this.rightDoorController.OpenDoor();
};
//문에 닿았을 때
this.playerController.reachDoor = () =>
{
//씬 전환하기
//this.FadeOutAndSceneManager();
};
//공격실행
this.playerController.onAttack = () => {
if (moveDir == Vector3.zero)
{
this.playerController.PlayAnimation(EnumState.ePlayerState.Attack);
}
};
}
// Update is called once per frame
void Update()
{
//수평, 수직 좌표 구하고 moveDir에 넣기
float h = this.joystick.Horizontal;
float v = this.joystick.Vertical;
this.moveDir = new Vector3(h, 0, v);
//moveDir이 Vector3.zero일 경우
if (moveDir == Vector3.zero)
{
//정지 애니메이션 실행
this.playerController.PlayAnimation(EnumState.ePlayerState.Idle);
}
else // (0,0,0)이 아닐 경우
{
//this.IsAttack = false;
this.playerController.Move(moveDir);
}
//OverlapSphere로 몬스터 인식하기
int layerMask = 1 << LayerMask.NameToLayer("Monster");
Collider[] hitColliders = Physics.OverlapSphere(this.playerController.transform.position, this.radius, layerMask);
this.dic.Clear();
foreach (Collider cols in hitColliders)
{
//딕셔너리에 거리차이와 게임오브젝트 추가
this.dic.Add(cols.gameObject, Vector3.Distance(cols.transform.position, this.playerController.transform.position));
}
//만약 dic.Count가 0보다 크다면
if (dic.Count > 0)
{
//작은 값을 short_distance에 넣기
float short_distance = this.dic.Values.Min();
//몬스터한 키값 넣어주기
var target = this.dic.FirstOrDefault(x => x.Value == short_distance).Key;
//dir에 몬스터와 플레이어의 거리 빼준 값 넣기
Vector3 dir = this.target.transform.position - this.playerController.transform.position;
this.playerController.MonsterRay(dir, this.target);
}
}
private IEnumerator CoFadeInAndSceneManager()
{
Color color = this.dim.color;
while (true)
{
color.a -= 0.01f;
this.dim.color = color;
if (color.a <= 0)
{
break;
}
yield return null;
}
}
}
Start쪽에 공격애니메이션을 실행시켜주었다.
남은 할 일 :
LookAt으로 공격애니메이션할 때 가까운 몬스터 바라보기
카메라 버그 수정하기 [ z축으로 -6.8f 오면 멈추고 플레이어가 뒤로 와도 카메라가 이동안함 ]
Stage1Scene에 text추가해주기
Stage1Scene문 통과하면 다음챕터가기
'유니티 심화' 카테고리의 다른 글
절대강좌 유니티 - 싱글톤, Invoke, CancelInvoke, DontDestroyonLoad (0) | 2023.08.28 |
---|---|
[주말과제/미완] HeroShooter - 총알나가고 삭제 (0) | 2023.08.28 |
절대강좌 유니티 - Button, Hpbar, TestMesh pro (0) | 2023.08.25 |
절대강좌 유니티 - UI (0) | 2023.08.25 |
HeroShooter - 가까운 거리 몬스터 선 그리기 (0) | 2023.08.24 |