using System.Collections;
using UnityEngine;
public class BossController : MonoBehaviour
{
public float detectionRange = 3f;
public float attackRange = 2f;
public float moveSpeed = 1f;
private GameObject Hero;
private int state = 0;
private Animator animator; // 애니메이터 컴포넌트 참조 추가
private void Start()
{
animator = GetComponent<Animator>(); // 애니메이터 컴포넌트 초기화
StartCoroutine(LateStart());
}
IEnumerator LateStart()
{
yield return new WaitForSeconds(0.1f);
Hero = GameObject.FindGameObjectWithTag("Hero");
}
private void Update()
{
if (Hero == null)
{
Hero = GameObject.FindGameObjectWithTag("Hero");
if (Hero == null)
{
Debug.LogError("Hero not found in the scene.");
return;
}
else
{
Debug.Log("Hero found.");
}
}
switch (state)
{
case 0:
Idle();
break;
case 1:
Chase();
break;
case 2:
Attack();
break;
}
animator.SetInteger("state", state); // 애니메이터에 상태값 전달
}
void Idle()
{
float distance = Vector3.Distance(transform.position, Hero.transform.position);
if (distance <= detectionRange)
state = 1;
}
void Chase()
{
float distance = Vector3.Distance(transform.position, Hero.transform.position);
if (distance <= attackRange)
{
state = 2;
return;
}
Vector3 moveDirection = (Hero.transform.position - transform.position).normalized;
// 플레이어와의 거리와 다음 프레임에서의 이동 거리를 비교
float nextStepDistance = moveSpeed * Time.deltaTime;
if (distance > nextStepDistance) // 만약 이동 거리가 플레이어와의 거리보다 짧으면 이동
{
transform.position += moveDirection * nextStepDistance;
}
else // 그렇지 않다면, 플레이어 바로 앞에서 멈춤
{
transform.position = transform.position + moveDirection * distance;
}
}
void Attack()
{
float distance = Vector3.Distance(transform.position, Hero.transform.position);
if (distance > attackRange)
state = 1;
return;
}
public void SetHero(GameObject newHero)
{
Hero = newHero;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossScene
{
public class BossGenerator : MonoBehaviour
{
private GameObject bossPrefab; //hero 프리팹
// Start is called before the first frame update
void Start()
{
}
public BossController Generate(GameObject prefab, Vector3 initPosition)
{
bossPrefab = Instantiate(prefab);
bossPrefab.transform.position = initPosition;
return bossPrefab.GetComponent<BossController>();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test_Portal
{
// 히어로의 움직임과 행동을 제어하는 클래스
public class HeroController : MonoBehaviour
{
public float moveSpeed = 5.0f; // 히어로의 움직임 속도
private Vector3 targetPosition; // 히어로의 이동 대상 위치
public static event Action<ItemController> onItemCollected; // 아이템 수집 시 발생하는 이벤트
private Animator heroAnimator; // 히어로의 애니메이터 컴포넌트
private bool isInAttackAnimation = false;
private float turnSpeed = 10.0f; // 회전 속도
public GameObject hitParticlePrefab;
// 공격 대상이 되는 몬스터
private MonsterController attackTarget = null;
public float attackRange = 2f; // 공격 가능한 거리
private void Start()
{
targetPosition = transform.position; // 시작 위치 초기화
heroAnimator = GetComponent<Animator>(); // 애니메이터 컴포넌트 초기화
StartCoroutine(HeroMovementUpdate());
}
private IEnumerator HeroMovementUpdate()
{
while (true)
{
if (attackTarget != null)
{
float distance = Vector3.Distance(transform.position, attackTarget.transform.position);
if (distance <= attackRange)
{
if (!isInAttackAnimation) // 이미 공격 중이 아니라면 공격을 시작합니다.
{
isInAttackAnimation = true;
heroAnimator.SetInteger("state", 2);
yield return new WaitForSeconds(0.5f); // 공격 애니메이션 지속 시간
isInAttackAnimation = false;
continue;
}
}
}
// 움직임 로직 (공격 애니메이션 중에도 실행되도록 변경)
if (Vector3.Distance(transform.position, targetPosition) > 0.1f)
{
Quaternion targetRotation = Quaternion.LookRotation(targetPosition - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
// 움직이는 중이며 공격 애니메이션 중이 아닐 때만 움직임 애니메이션을 플레이
if (!isInAttackAnimation)
{
heroAnimator.SetInteger("state", 1);
}
}
else
{
if (!isInAttackAnimation)
{
heroAnimator.SetInteger("state", 0);
}
}
yield return null; // Yield every frame
}
}
public void TriggerAttack()
{
if (attackTarget)
{
// 파티클 생성
GameObject hitParticle = Instantiate(hitParticlePrefab, attackTarget.transform.position, Quaternion.identity);
Destroy(hitParticle, 3f); // 파티클 애니메이션 끝나면 3초 후에 파괴 (3초는 예시로 설정한 값이며 필요에 따라 조절)
attackTarget.Die();
isInAttackAnimation = false;
attackTarget = null; // 공격 대상 초기화
targetPosition = transform.position;
}
}
// 공격 대상을 설정하는 메서드
public void SetAttackTarget(MonsterController monster)
{
attackTarget = monster;
Vector3 directionToMonster = (monster.transform.position - transform.position).normalized;
Vector3 attackPosition = monster.transform.position - directionToMonster * (attackRange * 0.9f);
SetTargetPosition(attackPosition);
}
// 히어로의 이동 대상 위치 설정
public void SetTargetPosition(Vector3 position)
{
targetPosition = position;
}
// 아이템을 수집하는 메서드
public void CollectItem(ItemController item)
{
EquipItem(item);
onItemCollected?.Invoke(item);
}
// 아이템을 장착하는 메서드
public void EquipItem(ItemController item)
{
GameEnums.eItemType itemType = item.itemType;
switch (itemType)
{
case GameEnums.eItemType.Sword:
EquipToSlot(item.gameObject, "Weapon");
break;
case GameEnums.eItemType.Shield:
EquipToSlot(item.gameObject, "Shield");
break;
case GameEnums.eItemType.Potion:
// 추가적인 로직(체력 회복 등)을 여기에 구현
break;
}
}
// 특정 슬롯에 아이템을 장착하는 메서드
private void EquipToSlot(GameObject item, string slotName)
{
Transform slotTransform = FindChildWithName(this.transform, slotName);
if (slotTransform == null)
{
Debug.LogError("Cannot find slot with name: " + slotName);
return;
}
foreach (Transform child in slotTransform)
{
Destroy(child.gameObject); // 이전에 장착되어 있던 아이템 제거
}
Destroy(item.GetComponent<BoxCollider>());
item.transform.SetParent(slotTransform); // 아이템을 해당 슬롯에 부착
item.transform.localPosition = Vector3.zero;
item.transform.localRotation = Quaternion.identity;
}
// 이름을 기반으로 자식 오브젝트를 찾는 메서드
private Transform FindChildWithName(Transform parent, string name)
{
foreach (Transform child in parent)
{
if (child.name == name)
{
return child;
}
Transform found = FindChildWithName(child, name);
if (found != null)
{
return found;
}
}
return null;
}
}
}
using System.Collections;
using UnityEngine;
namespace Test_Portal
{
// 몬스터를 제어하는 클래스
public class MonsterController : MonoBehaviour
{
// 몬스터가 죽었을 때 호출될 이벤트와 대리자(delegate) 선언
public delegate void MonsterDied(Vector3 position, GameEnums.eItemType itemType);
public event MonsterDied OnMonsterDied;
// 죽는 애니메이션 시간
private float deathAnimationTime = 2f;
// 몬스터가 드롭할 아이템의 종류
public GameEnums.eItemType dropItemType;
// 애니메이션 컨트롤러
private Animator anim;
private void Start()
{
// 시작할 때 애니메이터 컴포넌트를 가져옵니다.
anim = GetComponent<Animator>();
}
// 몬스터가 죽을 때 호출될 함수
public void Die()
{
anim.SetInteger("state", 3);
StartCoroutine(DieCoroutine());
}
// 죽는 애니메이션 후 몬스터를 파괴하는 코루틴
private IEnumerator DestroyAfterAnimation()
{
yield return new WaitForSeconds(deathAnimationTime);
Destroy(this.gameObject);
}
// 몬스터가 죽을 때 이벤트를 호출하고 몬스터를 파괴하는 코루틴
IEnumerator DieCoroutine()
{
yield return new WaitForSeconds(deathAnimationTime);
OnMonsterDied?.Invoke(transform.position, dropItemType);
Destroy(this.gameObject);
yield return null;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace Test_Portal
{
public class PortalController : MonoBehaviour
{
private FadeOutEffect fadeOut;
public string nextSceneName;
public Image fadeOutImage;
private void Start()
{
fadeOut = FindObjectOfType<FadeOutEffect>();
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Hero"))
{
StartCoroutine(fadeOut.FadeOutRoutine(fadeOutImage));
GameManager.SetPlayer(other.gameObject);
SceneManager.LoadScene(nextSceneName);
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test_Portal
{
public class GameEnums
{
public enum eMonsterType
{
Turtle, Slime
}
public enum eItemType
{
Potion,Sword,Shield
}
}
}
using System.Collections;
using System.Collections.Generic;
using Test_Portal;
using UnityEngine;
using UnityEngine.SocialPlatforms.Impl;
using UnityEngine.UI;
namespace Test_Portal
{
// 씬의 모든 객체들을 관리하는 클래스(컴포넌트)
public class Test_CreatePortalMain : MonoBehaviour
{
// 변수 선언 영역
[SerializeField]
private MonsterGenerator monsterGenerator; // 몬스터 생성 클래스
[SerializeField] private GameObject heroPrefab; // 히어로 프리팹
[SerializeField] private HeroGenerator heroGenerator; // 히어로 생성 클래스
[SerializeField] private HeroController hero; // 히어로 컨트롤러
[SerializeField]
private ItemGenerator itemGenerator; // 아이템 생성 클래스
private Camera camera; // 메인 카메라
private List<MonsterController> monsterList; // 현재 씬에 있는 몬스터 리스트
public GameObject potalObject; // 포탈 오브젝트
[SerializeField]
private Text txtMonsterCount; // 화면에 보여지는 몬스터 카운트
[SerializeField]
private Text txtGetItem; // 아이템 획득 시 화면에 보여지는 텍스트
private void Awake()
{
camera = Camera.main; // 카메라 초기화
hero = FindObjectOfType<HeroController>(); // 히어로 컨트롤러 찾기
HeroController.onItemCollected += HandleItemCollected; // 아이템 획득 이벤트 바인딩
}
void Start()
{
// 초기 몬스터와 히어로 생성 로직
this.monsterList = new List<MonsterController>();
// 몬스터 생성
MonsterController turtle = this.monsterGenerator.Generate(GameEnums.eMonsterType.Turtle, new Vector3(-3, 0, 0));
MonsterController slime = this.monsterGenerator.Generate(GameEnums.eMonsterType.Slime, new Vector3(0, 0, 3));
// 히어로 생성
if (!hero)
{
hero = this.heroGenerator.Generate(heroPrefab, new Vector3(3, 0, 3));
}
// 생성된 몬스터를 리스트에 추가
this.monsterList.Add(turtle);
this.monsterList.Add(slime);
// 이벤트 바인딩
foreach (MonsterController monster in this.monsterList)
{
monster.OnMonsterDied += HandleMonsterDied; // 바인딩 부분 수정
}
}
private void Update()
{
// UI 업데이트 및 마우스 입력 처리
this.UpdateScoreUI();
if (Input.GetMouseButtonUp(1)) // 마우스 오른쪽 클릭 검사
{
RaycastHit hit;
// 마우스 위치에서 레이캐스트 발사
if (Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
{
MonsterController monsterHit = hit.collider.GetComponent<MonsterController>();
ItemController itemHit = hit.collider.GetComponent<ItemController>();
// 몬스터 클릭 시 처리
if (monsterHit != null)
{
hero.SetAttackTarget(monsterHit);
if (this.monsterList.Count == 0)
{
this.potalObject.SetActive(true);
}
}
// 아이템 클릭 시 처리
else if (itemHit != null)
{
hero.SetTargetPosition(itemHit.transform.position);
}
// 그 외 영역 클릭 시 처리
else
{
Vector3 targetPos = hit.point;
targetPos.y = hero.transform.position.y; // Y축 값 유지
hero.SetTargetPosition(targetPos);
}
}
}
}
// 몬스터 카운트 UI 업데이트
public void UpdateScoreUI()
{
this.txtMonsterCount.text = string.Format("남은 몬스터 수: {0}", this.monsterList.Count);
}
// 아이템 획득 시 텍스트 출력 후 일정 시간 후 숨기기
private IEnumerator DeactivateTextAfterSeconds(float seconds)
{
yield return new WaitForSeconds(seconds);
txtGetItem.gameObject.SetActive(false);
}
// 아이템 획득 이벤트 핸들러
private void HandleItemCollected(ItemController item)
{
txtGetItem.text = "획득한 아이템: " + item.itemName;
txtGetItem.gameObject.SetActive(true);
StartCoroutine(DeactivateTextAfterSeconds(5));
}
// 몬스터 사망 이벤트 핸들러
void HandleMonsterDied(Vector3 position, GameEnums.eItemType itemType)
{
GenerateItem(itemType, position);
// 몬스터 리스트에서 제거
MonsterController monster = monsterList.Find(m => m.transform.position == position);
if (monster != null)
{
monsterList.Remove(monster);
}
UpdateScoreUI();
// 포탈 활성화 조건
if (monsterList.Count == 0)
{
potalObject.SetActive(true);
}
}
// 아이템 생성 함수
public void GenerateItem(GameEnums.eItemType itemType, Vector3 position)
{
itemGenerator.Generate(itemType, position);
}
}
}
using System.Collections;
using System.Collections.Generic;
using Test_Portal;
using UnityEngine;
namespace Test_Portal
{
public class HeroGenerator : MonoBehaviour
{
private Vector3 savedPosition = Vector3.zero;
private GameObject heroPrefab; //hero 프리팹
// Start is called before the first frame update
void Start()
{
//Debug.Log(heroPrefab.gameObject.name + "생성!");
}
/// <summary>
/// 히어로 생성
/// </summary>
/// <param name="initPosition">생성된 몬스터의 초기 월드좌표</param>
public HeroController Generate(GameObject prefab, Vector3 initPosition)
{
GameObject heroInstance = Instantiate(prefab);
heroInstance.transform.position = initPosition;
return heroInstance.GetComponent<HeroController>();
}
}
}
반응형
'KDT > 유니티 기초' 카테고리의 다른 글
[SimpleRPG] 보스전 구현(2) 탐지 범위 수정 (0) | 2023.08.14 |
---|---|
[SimpleRPG] 보스전 구현 (1) (0) | 2023.08.14 |
[SimpleRPG] 몬스터 클릭시 사망, 사망+이동 애니메이션, 아이템 드롭과 장착 (0) | 2023.08.10 |
[SimpleRPG] 몬스터 피격시 피격 이펙트 입히기 (0) | 2023.08.10 |
[SimpleRPG] 플레이어 이동과 공격 + 몬스터 공격시 피격 구현 (0) | 2023.08.09 |