미완
- 총알을 한발씩 발사하고싶은데 어떻게 해야할지 모르겠음[야매로 만들어서 이상함]
- 총알맞으면 피격 애니메이션
- 총알 맞고 죽는 애니메이션
- 죽으면 몇초 후 사라지게하기
- 사라진 후 Text와 문 열리기
BulletController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
[SerializeField]
private float bulletSpeed = 500f;
private Rigidbody rBody;
private int damage = 1;
// Start is called before the first frame update
void Start()
{
this.rBody = this.GetComponent<Rigidbody>();
this.rBody.AddForce(this.transform.forward * this.bulletSpeed);
}
public void RemoveBullet()
{
Destroy(this.gameObject);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "Monster")
{
this.RemoveBullet();
}
}
}
PlayerController
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
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<MonsterController> onAttack;
//공격반복방지
private Coroutine attackRoutine;
//총알프리팹
[SerializeField]
private GameObject bulletPrefab;
//총알생성위치
[SerializeField]
private Transform bulletTr;
//총알
private GameObject bullet;
//경과시간
private float elapsedTime = 0f;
void Start()
{
this.anim = this.GetComponent<Animator>();
}
//공격
public void Attack()
{
if (this.attackRoutine != null)
{
this.StopCoroutine(this.attackRoutine);
}
this.StartCoroutine(this.CoAttack());
}
//공격 코루틴
private IEnumerator CoAttack()
{
while (true)
{
this.elapsedTime += Time.deltaTime;
//총쏘는 애니메이션
this.PlayAnimation(EnumState.ePlayerState.Attack);
//0.5초마다 총알 생성
if(this.elapsedTime >= 0.5f)
{
//총알소환
this.bullet = Instantiate(this.bulletPrefab, this.bulletTr.position, this.bulletTr.rotation);
this.elapsedTime = 0f;
}
if (bullet == true)
{
//마우스 떼면 바로 발사 안함
break;
}
}
yield return null;
}
//움직임
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);
target = monsterController;
}
else
{
MonsterController[] monsterContorllers = GameObject.FindObjectsOfType<MonsterController>();
Debug.Log(monsterContorllers.Count());
foreach (MonsterController monster in monsterContorllers)
{
monster.HideIndicator();
}
target = null;
}
}
}
}
MonsterController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterController : MonoBehaviour
{
[SerializeField]
private GameObject targetQuad;
//체력
private int hp = 5;
//최대체력
private int maxHp;
//애니메이션
private Animator anim;
// Start is called before the first frame update
void Start()
{
this.maxHp = this.hp;
this.anim = this.GetComponent<Animator>();
}
public void GetHit(int damage)
{
this.hp -= damage;
}
public void Die()
{
this.PlayAnimation(EnumState.eMonsterState.Die);
Destroy(this.gameObject, 3f);
}
public void HideIndicator()
{
this.targetQuad.SetActive(false);
}
public void ShowIndicator()
{
this.targetQuad.SetActive(true);
}
public void PlayAnimation(EnumState.eMonsterState state)
{
this.anim.SetInteger("State", (int)state);
}
}
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 = (target) => {
if (moveDir == Vector3.zero)
{
this.playerController.Attack();
//공격했을 때 바라보기
this.playerController.transform.LookAt(target.transform.position);
}
};
}
// 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;
}
}
}
'유니티 심화' 카테고리의 다른 글
절대강좌 유니티 - 오브젝트 풀링 (0) | 2023.08.28 |
---|---|
절대강좌 유니티 - 싱글톤, Invoke, CancelInvoke, DontDestroyonLoad (0) | 2023.08.28 |
HeroShooter - 몬스터를 발견하면 공격애니메이션 실행 (0) | 2023.08.25 |
절대강좌 유니티 - Button, Hpbar, TestMesh pro (0) | 2023.08.25 |
절대강좌 유니티 - UI (0) | 2023.08.25 |