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 float turnSpeed = 10.0f;
private void Start()
{
targetPosition = transform.position;
heroAnimator = GetComponent<Animator>();
}
private void Update()
{
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);
heroAnimator.SetInteger("state", 1);
}
else
{
heroAnimator.SetInteger("state", 0);
}
}
public void SetTargetPosition(Vector3 position)
{
targetPosition = position;
}
public void CollectItem(ItemController item)
{
EquipItem(item);
onItemCollected?.Invoke(item);
}
private 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:
// 체력 회복 로직 or 다른 액션
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 System.Collections.Generic;
using UnityEngine;
namespace Test_Portal
{
public class ItemController : MonoBehaviour
{
public string itemName;
public GameEnums.eItemType itemType;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Hero"))
{
HeroController hero = other.GetComponent<HeroController>();
if (hero != null)
{
hero.CollectItem(this);
}
}
}
}
}
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;
private Transform monsterTarget;
[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));
hero = this.heroGenerator.Generate(heroPrefab, new Vector3(3, 0, 3));
//만들어진 개체들을 그룹화 관리
//배열, 컬렉션
//동적 배열
this.monsterList.Add(turtle);
this.monsterList.Add(slime);
Debug.LogFormat("this.monsterList.Count: {0}", this.monsterList.Count);
//리스트의 요소를 출력
foreach (MonsterController monster in this.monsterList)
{
Debug.LogFormat("monster: {0}", monster);
monster.OnMonsterDied += (position, itemType) => HandleMonsterDied(position, itemType);
}
}
private void Update()
{
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)
{
monsterHit.Die(); // 몬스터 죽음 메서드 호출
monsterList.Remove(monsterHit);
//Destroy(monsterHit.gameObject,2.5f);
if (this.monsterList.Count == 0)
{
this.potalObject.SetActive(true);
}
}
// 아이템이 클릭된 경우
else if (itemHit != null)
{
// 히어로를 해당 아이템 위치로 이동
HeroController hero = FindObjectOfType<HeroController>();
if (hero != null)
{
hero.SetTargetPosition(itemHit.transform.position);
}
}
//바닥이나 기타 오브젝트가 클릭된 경우
else
{
// 히어로를 클릭한 위치로 이동
HeroController hero = FindObjectOfType<HeroController>();
if (hero != null)
{
Vector3 targetPos = hit.point;
targetPos.y = hero.transform.position.y; // 현재 히어로의 Y축 값을 유지
hero.SetTargetPosition(targetPos);
}
}
}
}
}
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);
}
public void GenerateItem(GameEnums.eItemType itemType, Vector3 position)
{
itemGenerator.Generate(itemType, position);
}
}
}
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 UnityEngine;
namespace Test_Portal
{
public class ItemGenerator : MonoBehaviour
{
[SerializeField]
private List<GameObject> itemPrefabs; // 아이템 프리팹들의 리스트
// Start is called before the first frame update
void Start()
{
for (int i = 0; i < this.itemPrefabs.Count; i++)
{
GameObject prefab = this.itemPrefabs[i];
Debug.LogFormat("index: {0}, prefab: {1}", i, prefab);
}
}
/// <summary>
/// 아이템 생성
/// </summary>
/// <param name="itemType">생성하려는 아이템의 타입</param>
/// <param name="initPosition">생성된 아이템의 초기 월드좌표</param>
public ItemController Generate(GameEnums.eItemType itemType, Vector3 initPosition)
{
Debug.LogFormat("itemType: {0}", itemType);
int index = (int)itemType;
Debug.LogFormat("index: {0}", index);
GameObject prefab = this.itemPrefabs[index];
Debug.LogFormat("prefab: {0}", index);
GameObject go = Instantiate(prefab);
go.transform.position = initPosition;
ItemController itemController = go.GetComponent<ItemController>();
itemController.itemType = itemType; // itemType 설정
return itemController;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test_Portal
{
public class MonsterGenerator : MonoBehaviour
{
[SerializeField]
private List<GameObject> prefabList; //동적 배열 (컬렉션 사용전 반드시 인스턴스화)
// Start is called before the first frame update
void Start()
{
for (int i = 0; i < this.prefabList.Count; i++)
{
GameObject prefab = this.prefabList[i];
Debug.LogFormat("index: {0}, prefab: {1}", i, prefab);
}
}
/// <summary>
/// 몬스터 생성
/// </summary>
/// <param name="monsterType">생성 하려고 하는 몬스터의 타입</param>
/// <param name="initPosition">생성된 몬스터의 초기 월드좌표</param>
public MonsterController Generate(GameEnums.eMonsterType monsterType, Vector3 initPosition)
{
Debug.LogFormat("monsterType: {0}", monsterType);
//몬스터 타입에 따라 어떤 프리팹으로 프리팹 복사본(인스턴스)를 생성할지 결정 해야 함
//몬스터 타입을 인덱스로 변경
int index = (int)monsterType;
Debug.LogFormat("index: {0}", index);
//프리팹 배열에서 인덱스로 프리팹 가져옴
GameObject prefab = this.prefabList[index];
Debug.LogFormat("prefab: {0}", index);
//프리팹 인스턴스를 생성
GameObject go = Instantiate(prefab); //위치를 결정 하지 않은 상태이기때문 (프리팹의 설정된 위치에 생성됨)
//위치를 설정
go.transform.position = initPosition;
return go.GetComponent<MonsterController>();
}
}
}
using System.Collections;
using UnityEngine;
namespace Test_Portal
{
public class MonsterController : MonoBehaviour
{
// Delegate 및 Event 수정
public delegate void MonsterDied(Vector3 position, GameEnums.eItemType itemType);
public event MonsterDied OnMonsterDied;
public GameEnums.eItemType dropItemType;
private Animator anim;
private void Start()
{
anim = GetComponent<Animator>();
}
public void Die()
{
anim.SetInteger("state", 3);
StartCoroutine(DieCoroutine());
}
IEnumerator DieCoroutine()
{
yield return new WaitForSeconds(2.5f); // 2.5초 기다림 (애니메이션 재생 시간)
OnMonsterDied?.Invoke(transform.position, dropItemType); // 이벤트 발생
Destroy(this.gameObject); // 몬스터 파괴
}
}
}
using System.Collections;
using System.Collections.Generic;
using Test_Portal;
using UnityEngine;
namespace Test_Portal
{
public class HeroGenerator : MonoBehaviour
{
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)
{
heroPrefab = Instantiate(prefab);
heroPrefab.transform.position = initPosition;
return heroPrefab.GetComponent<HeroController>();
}
}
}

반응형
'KDT > 유니티 기초' 카테고리의 다른 글
[SimpleRPG] 보스전 구현 (1) (0) | 2023.08.14 |
---|---|
[SimpleRPG] 보스 씬 전환 + 보스 탐지 범위와 공격 범위 구현 (0) | 2023.08.14 |
[SimpleRPG] 몬스터 피격시 피격 이펙트 입히기 (0) | 2023.08.10 |
[SimpleRPG] 플레이어 이동과 공격 + 몬스터 공격시 피격 구현 (0) | 2023.08.09 |
[Apple Catch] High Score 구현 (0) | 2023.08.07 |