스테이지 1
1. 마우스를 뗐을 때 총을 한발씩 딜레이 (0.5초) 주고 발사하기 [모르겠는데 발사는 함/ 애매한 완성]
2. 몬스터 피 설정하기 [완]
3. 몬스터 피격애니메이션 설정하기 [완]
4. 몬스터 피 0 이하면 2초뒤 죽기 [완]
5. 텍스트 변경 및 문 열기 [완]
6. 몬스터 밀치면 밀쳐지기 [미완]
7. 플레이어 죽으면 회색화면 및 죽어도 게임오버되지않고 살아남[미완]
8. 스킬 선택창 [미완]
9. 이동할 때 캐릭터 앞에 DrawArrow가 조그마한게 생기는거같음 [미완]
--- 고민 ---
총알 나가는 방식을 오브젝트 풀링으로 바꿀지 고민이다.
총을 어떻게 딜레이 주고 발사하는지 잘 모르겠다.
elapsedTime으로 하고있긴하지만 발사하기전에 마우스로 움직여버리면
elapsedTime은 조금 가있어서 공격애니메이션과 eapsedTime에 간격이 생겨버려서
애니메이션효과랑 총알이 나가는게 달라진다
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 BulletController bulletController;
//조이스틱
[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.playerController.reachDoor = () =>
{
//씬 전환하기
//this.FadeOutAndSceneManager();
};
//공격실행
this.playerController.onAttack = (target) => {
if (moveDir == Vector3.zero)
{
this.playerController.Attack();
//공격했을 때 바라보기
this.playerController.transform.LookAt(target.transform.position);
}
};
//몬스터가 공격 당했을 때
this.target.onHit = () => {
this.target.GetHit(this.bulletController.Damage);
if(this.target.Hp <= 0)
{
//피가 0이하라면 죽는다
this.target.Die();
//죽으면 문 열기
this.OpenDoor();
//텍스트 변경하기
this.text.text = "좋습니다! 문을 통해서 계속 이동하세요.";
}
};
}
// 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;
}
}
private void OpenDoor()
{
//문 열기
this.leftDoorController.OpenDoor();
this.rightDoorController.OpenDoor();
}
}
MonsterController
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterController : MonoBehaviour
{
[SerializeField]
private GameObject targetQuad;
//체력
private int hp = 5;
public int Hp
{
get
{
return this.hp;
}
}
//최대체력
private int maxHp;
//애니메이션
private Animator anim;
//피격 대리자
public Action onHit;
// 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;
this.PlayAnimation(EnumState.eMonsterState.GetHit);
}
public void Die()
{
this.PlayAnimation(EnumState.eMonsterState.Die);
Destroy(this.gameObject, 2f);
}
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);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "Bullet")
{
this.onHit();
}
}
}
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;
}
}
}
}
'유니티 심화 > 복습' 카테고리의 다른 글
[복습] HeroShooter - 몬스터 밀쳐지는거 (0) | 2023.08.29 |
---|---|
[복습] HeroShooter - 총알 CollisionEnter or TriggerEnter (0) | 2023.08.29 |
[복습] SpaceShooter2D - 적 비행기 피격시 애니메이션, 총알 삭제 (0) | 2023.08.29 |
[복습] SpaceShooter2D - CollisionEnter2D[오류] (0) | 2023.08.29 |
[복습] SpaceShooter2D - 오브젝트 풀링, 총알 나가기 (0) | 2023.08.29 |