HeroShoot-Stage1: 범위내의 몬스터 자동공격
-코루틴 함수로 상태를 체크하는 함수를 작성했다. DetectMonster()메서드는 몬스터를 감지하는 메서드이다.
-distance는 플레이어의 위치와 추출한 오브젝트의 위치 사이의 거리이다.
-공격 사정거리 내에 들어왔을때 가까이에 있는 몬스터를 찾아 this.shortDistanceGo 게임 오브젝트에 저장한다.
-Physics.OverlapSphere를 사용하기 위해 몬스터의 레이어를 Monster로 변경해준다.
공격 구현
-현재는 애니메이션만 넣은 상태이므로 총에서 총알이 나가 몬스터를 공격하도록 수정한다.
-bulletGo에 BulletController.cs 를 부착한다. bullet의 각도는 자식의 각도를 조절한다.
-총알의 collider를 붙인후 태그를 바꿔주고, 몬스터 프리팹에 스크립트를 추가한다.
-몬스터가 존재하지 않으면 문을 열리게 하기 위해서 floorController.cs를 추가하였다.
-quad의 이름을 target으로 변경 후 비활성화 한 뒤 코드를 수정하였다.
-PlayerController의 코드를 다음과 같이 수정하였는데(85~86라인) 동작은 하는데 child 범위가 벗어났다고 오류가 떠서..
어떻게 해결하는게 맞는지 아직 모르겠다.
name을 찍어보면 오류나지않고 이름 잘 출력하는데 음 비활성화된 상태에서 접근하는거라 그런건지..?
나오는데..오류난다.
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.EventSystems;
public class PlayerController : MonoBehaviour
{
//[SerializeField] private VariableJoystick joystick;
public enum eState
{// 상태 정의
IDLE, MOVE, ATTACK, DIE
}
public eState state = eState.IDLE;//Player의 현재 상태
private bool isDie;//Player의 사망 여부
// [SerializeField] private float traceDistance = 10.0f;//추적 사거리
[SerializeField] private float attackDistance = 8.0f;//공격 사거리
[SerializeField] private float moveSpeed = 3f;
[SerializeField] GameObject bulletGo;//총알 오브젝트
[SerializeField] Transform FirePos;//총알 발사 transform
private float distance;
private float minDistance = 20f;
private GameObject shortDistanceGo;
private float monsterCount;
private TutorialMain tutorialMain;
private Stage1Main stage1;
private Transform monsterTrans;
private SceneLoad sceneLoad;
private Collision collision;
public bool isMove = false;
private List<MonsterController> monsterList = new List<MonsterController>();
// private Vector3 downPosition;
//private bool isDown = false;
public Animator anim;
// Start is called before the first frame update
void Start()
{
this.tutorialMain = FindObjectOfType<TutorialMain>();
this.stage1 = FindObjectOfType<Stage1Main>();
//this.monsterGenerator = FindObjectOfType<MonsterGenerator>();
this.sceneLoad = FindObjectOfType<SceneLoad>();
this.monsterList = this.stage1.monsterList;//stage1의 몬스터를 저장
// StartCoroutine(this.CoMonsterLoad());
StartCoroutine(this.CheckState());//상태확인
StartCoroutine(this.PlayerAction());//상태에따라 플레이어 동작
}
// Update is called once per frame
void Update()
{
}
private IEnumerator CoMonsterLoad()
{
yield return null;
//this.monsterTrans = this.stage1.monsterList[0].gameObject.transform;
this.monsterTrans = this.monsterList[0].gameObject.transform;
Debug.Log(this.monsterTrans);
}
private IEnumerator CheckState()
{//상태 갱신 코루틴 함수: 일정 간격으로 Player의 행동상태 체크
while (!isDie)
{
//yield return null;
yield return new WaitForSeconds(0.3f);//0.3초마다 상태 갱신
//yield return new WaitForSeconds(0.3f);
this.DetectkMonster();//가장 가까운 몬스터 감지
if (this.isMove)
{
this.state = eState.MOVE;
}
else
{
if (shortDistanceGo != null)
{//몬스터 존재시
if (this.distance < this.attackDistance)
{
//string name = this.shortDistanceGo.transform.GetChild(2).gameObject.name;
//Debug.Log(name);
GameObject go = this.shortDistanceGo.transform.GetChild(2).gameObject;
go.SetActive(true);
this.transform.LookAt(this.shortDistanceGo.transform.position);
this.state = eState.ATTACK;//공격상태로 변경
this.Fire();//총알 발사
// Debug.Log(this.distance);
}
else //공격범위를 벗어나면
{
// this.shortDistanceGo = null;
yield return null;
this.state = eState.IDLE;
}
}
else//몬스터가 존재하지 않으면
{
this.state = eState.IDLE;
}
}
}
}
private IEnumerator PlayerAction()
{
while (!isDie)
{
yield return new WaitForSeconds(0.3f);
if (this.state == eState.MOVE)
{
Debug.Log("Move");
this.anim.SetInteger("State", 1);
}
else if(this.state == eState.ATTACK)
{
Debug.Log("Attack Monster!");
this.anim.SetInteger("State", 2);
}
else
{
this.anim.SetInteger("State", 0);
}
}
}
public void movePlayer(Vector3 dir)
{
float angle = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg;
this.transform.Translate(dir.normalized * this.moveSpeed * Time.deltaTime, Space.World);
this.transform.localRotation = Quaternion.AngleAxis(angle, Vector3.up);//축으로 회전
//this.anim.SetInteger("State", 1);//run forward animation
}
private void Fire()
{
// Vector3 rotation = this.FirePos.rotation.eulerAngles;
// Quaternion rotation = this.FirePos.rotation +Quaternion(0,0,0)
Instantiate(this.bulletGo,this.FirePos.position,this.FirePos.rotation);
//go.transform.rotation = Quaternion.identity;
// go.transform.position = this.FirePos.position;
}
private void DetectkMonster()
{//주변에 있는 몬스터 추출
Collider[] colls = Physics.OverlapSphere(this.transform.position, this.attackDistance, 1 << 3);
foreach (Collider coll in colls)
{
// Debug.Log(coll);
this.distance = Vector3.Distance(this.transform.position, coll.gameObject.transform.position);
if (this.minDistance >= this.distance)//거리 측정
{//distance가 더 작을때 shorDistanceGo에 게임 오브젝트를 저장
this.minDistance = this.distance;
this.shortDistanceGo = coll.gameObject;
Debug.LogFormat("가장 가까운 몬스터:{0}", coll.gameObject.name);
}
}
}
private void OnCollisionEnter(Collision collision)
{
this.collision = collision;//매개변수를 멤버변수에 저장
if (collision.collider.CompareTag("Portal"))
{
Debug.Log("Portal");
Destroy(collision.gameObject);
this.tutorialMain.OpenGate();
}
else if (collision.collider.CompareTag("Stage1"))
{
this.SceneLoad(this.collision.gameObject.tag);
}
else if (collision.collider.CompareTag("Stage2"))
{
this.SceneLoad(this.collision.gameObject.tag);
}
}
private void SceneLoad(string sceneName)
{
this.sceneLoad.imgDim.gameObject.SetActive(true);
StartCoroutine(this.sceneLoad.CoFadeOut(sceneName));
}
private void OnDrawGizmos()
{
if(this.state == eState.ATTACK)
{
Gizmos.color = Color.yellow;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RemoveBullet : MonoBehaviour
{
[SerializeField] private float hp = 10;
private void OnCollisionEnter(Collision collision)
{
Debug.Log(collision);
if (collision.collider.CompareTag("Bullet"))
{
this.hp -= 1;
Destroy(collision.gameObject); //총알 삭제
if (this.hp <= 0)
{
Destroy(this.gameObject);//monster 사망
Debug.Log("몬스터 사망");
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FloorController : MonoBehaviour
{
//private List<Collider> colls = new List<Collider>();
private Collider[] colls;
public bool isOpen;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
this.DetectkMonster();
// Debug.Log(this.count);
if (this.colls.Length == 0)
{
this.isOpen = true;
// Debug.Log("문이 열려요");
}
}
private void DetectkMonster()
{// 몬스터 추출
this.colls = Physics.OverlapSphere(this.transform.position, 30f, 1 << 3);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Stage1Main : MonoBehaviour
{
[SerializeField] private GameObject gateLeftGo;
[SerializeField] private GameObject gateRightGo;
[SerializeField] private GameObject npcGo;
[SerializeField] private GameObject speechGo;
[SerializeField] private MyJoyStick joystick;
private Text text;
private bool isDown;
private float openDamping = 1f;
private float timeCount;
private float monsterCount;
private PlayerController playerController;
private MonsterGenerator monsterGenerator;
private FloorController floorController;
public List<MonsterController> monsterList = new List<MonsterController>();//생성된 몬스터를 관리
// Start is called before the first frame update
void Start()
{
this.monsterGenerator = FindObjectOfType<MonsterGenerator>();
this.playerController = FindAnyObjectByType<PlayerController>();
this.floorController = FindAnyObjectByType<FloorController>();
MonsterController beholderController1 = this.monsterGenerator.GenerateMonster(GameEnums.eMonsterType.BeholderMonster, new Vector3(3f, -2f, 20));
//리스트에 추가
this.monsterList.Add(beholderController1);
//Debug.Log(this.monsterList[0]);
this.joystick.onDown = () => {
this.isDown = true;
};
this.joystick.onUp = () => {
this.isDown = false;
//this.playerController.anim.SetInteger("State", 0);
this.playerController.state = PlayerController.eState.IDLE;
};
//시작시 안내 UI Active.
this.npcGo.SetActive(true);
this.speechGo.SetActive(true);
this.text = this.speechGo.GetComponentInChildren<Text>();
this.text.text = "조이스틱에서 손을 놓으면 적팀에게 공격합니다.";
}
// Update is called once per frame
void Update()
{
if (this.isDown)
{
float h = this.joystick.Direction.x;
float v = this.joystick.Direction.y;
Vector3 moveDir = (Vector3.forward * v) + Vector3.right * h;
//조이스틱으로 입력받아 방향 바라보게함
if (moveDir != Vector3.zero)
{//이동
this.playerController.movePlayer(moveDir);
}
this.playerController.isMove = true;
}
else
{
this.playerController.isMove = false;
}
if (this.floorController.isOpen)
{
this.OpenGate();
}
}
public void OpenGate()
{
//Debug.Log("OpenGate");
StartCoroutine(this.CoOpenGate());
}
private IEnumerator CoOpenGate()
{
//this.gateLeftGo.transform.Rotate(0,90,0);
var left = Quaternion.Euler(new Vector3(0, 90, 0));
var right = Quaternion.Euler(new Vector3(0, -90, 0));
var leftRotation = this.gateLeftGo.transform.rotation;
var rightRotation = this.gateRightGo.transform.rotation;
while (true)
{
this.gateLeftGo.transform.rotation = Quaternion.Slerp(leftRotation, left, this.timeCount * this.openDamping);
this.gateRightGo.transform.rotation = Quaternion.Slerp(rightRotation, right, this.timeCount * this.openDamping);
this.timeCount += Time.deltaTime;
if (this.gateLeftGo.transform.localRotation == left)
{
break;
}
yield return null;
}
this.text.text = "좋습니다! 문을 통해 계속 이동하세요.";
}
}
'3d 콘텐츠 제작' 카테고리의 다른 글
HeroShoot-TitleScene(로딩화면) (0) | 2023.08.31 |
---|---|
HeroShoot-Stage1 오류 수정: 자식 오브젝트 받기(GetComponentInChildren/GetChild) (0) | 2023.08.28 |
HeroShoot- Stage1, 씬 로드 변경 (0) | 2023.08.24 |
HeroShoot-튜토리얼 씬 수정(조이스틱, fadeOut,Gate에 Slerp) (0) | 2023.08.23 |
HeroShoot-1. 튜토리얼 씬(캐릭터 이동/회전, 특정 위치 도달시 포탈 오픈) (0) | 2023.08.22 |