[ 능력 업그레이드 구현 ] --> 능력 업그레이드 UI를 만들고 로직 작성
- C# 스크립트 생셩(ItemData)
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "Item", menuName = "Scriptble Object/ItemData")] // 커스텀 메뉴 생성
public class ItemData : ScriptableObject
{
public enum ItemType { Melee, Range, Glove, Shoe, Heal } // 타입 종류
[Header("# Main Info")] // 헤더를 통해 이쁜이 작업
public ItemType itemType; // 타입
public int itemId; // 번호
public string itemName; // 이름
public string itemDesc; // 설명
public Sprite itemIcon; // 아이콘
[Header("# Level Data")]
public float baseDamage; // 기본데미지
public int baseCount; // 기본개수
public float[] damages; // 레벨에 따른 데미지
public int[] counts; // 레벨에 따른 개수
[Header("# Weapon")]
public GameObject projectile; // 투사체
}
- Undead Survivor 폴더에 새로운 폴더 생성(Data)
- Data 폴더에서 우클릭 --> Create --> Scriptble Object --> ItemData 생성
- Inspector에서 아이템이 가진 속성들 설정 (Type, Id, Name, Icon, Base Damage, Base Count)
- Damages, Counts = 5 설정 (레벨 개수)
- Damages Element에는 레벨업 할 때마다, 데미지 증가율 넣어주기 ex) 0.5(50%) | 1 (100%) | ...
- Counts Element에는 레벨업 할 때마다, 추가 할 개수 넣어주기 ex)1(1개 추가) | 1(1개 추가) | ...
- Projectile에 Prefabs의 Bullet 0 넣어주기(드래그&드랍) - 작성한 Item 0를 Ctrl + D 하여 5가지 모두 설정해주기(Melee, Range, Glove, Shoe, Heal)
- Bullet 1에서의 Counts는 관통을 의미
- Glove와 Shoe에서 Counts는 모두 0으로, Projectile의 프리펩은 None으로 설정
- Heal은 # Main Info를 제외한 모든 값을 0으로 설정 - 캔버스 아래에 빈 오브젝트 추가
- Width = 22, Height = 150으로 설정 - 자식 오브젝트로 UI --> Legacy --> Button 추가 (Item 0)
- Source Source를 Panel로 변경
- 이름을 Text Level로 변경
- 앵커 선택 후 Shift + Alt 입력 후 정 중앙 이미지 선택
- Width = 0, Height = 0 선택
- Horizontal Overflow, Vertical Overflow 모두 Overflow로 설정
- Font를 Fonts 폴더에서 설정(드래그&드랍)
- Font Size = 5로 설정
- Text = Lv.00으로 설정
- Pos Y = -9로 설정 - Item 0 의 자식 오브젝트로 UI --> Image 추가
- Source Image를 Sprite의 Select 0 로 변경
- Set Native Size 버튼 클릭 - C# 스크립트 생성(Item)
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // Image를 입력받기 위해 import
public class Item : MonoBehaviour
{
public ItemData data; // ItemData 변수
public int level; // 레벨
public Weapon weapon; // Weapon 변수
public Gear gear; // Gear 변수
Image icon; // Image 변수
Text textLevel; // Text 변수
private void Awake()
{
icon = GetComponentsInChildren<Image>()[1]; // 자식 오브젝트의 컴포넌트를 다룸
icon.sprite = data.itemIcon; // 초기화
Text[] texts = GetComponentsInChildren<Text>(); // 자식 오브젝트의 컴포넌트를 다룸
textLevel = texts[0]; // 초기화
}
private void LateUpdate()
{
textLevel.text = "LV." + (level + 1); // 레벨을 화면에 표현
}
public void OnClick() // 버튼 클릭 시그널 함수
{
switch(data.itemType) // Type별로 다르게 작성
{
case ItemData.ItemType.Melee: // Weapon
case ItemData.ItemType.Range: // Weapon
if(level == 0){
GameObject newWeapon = new GameObject(); // 처음 눌렀을 때 게임 오브젝트 생성
weapon = newWeapon.AddComponent<Weapon>(); // 게임 오브젝트에 Weapon 컴포넌트 추가
weapon.Init(data); // Weapon data 초기화
}
else{
float nextDamage = data.baseDamage; // nextDamage 초기화
int nextCount = 0; // nextCount 초기화
nextDamage += data.baseDamage * data.damages[level]; // baseDamage + 레벨에 따라 증가된 damages
nextCount += data.counts[level]; // baseCount + 레벨에 따라 증가된 Counts
weapon.LevelUp(nextDamage, nextCount); // LevelUp 함수 호출
}
level++;
break;
case ItemData.ItemType.Glove: // Gear
case ItemData.ItemType.Shoe: // Gear
if (level == 0){
GameObject newGear = new GameObject(); //최초 레벨업시 게임 오브젝트 초기화
gear = newGear.AddComponent<Gear>(); // gear에 게임 오브젝트 생성
gear.Init(data); // gear 초기화
}
else{
float nextRate = data.damages[level]; // nextRate 변수
gear.LevelUp(nextRate); // LevelUp 함수 호출
}
level++;
break;
case ItemData.ItemType.Heal:
GameManager.instance.hp = GameManager.instance.maxHp; // 현재 hp를 maxHp로 채움
break;
}
if(level == data.damages.Length) // Damages의 레벨 개수와 같아짐(현재는 5개)
{
GetComponent<Button>().interactable = false; // 버튼 상호작용 비활성화
}
}
}
- Item 0에 Add Component
- Item(Script) - LevelUp 오브젝트에 Add Component
- Vertical Layout Group - Item 0를 5개 복사 후 각각 Data 폴더의 Scriptble Object 연결
- 5개의 Item 오브젝트 이름 변경(Item 0~4)
- Item 0~4 오브젝트에 On Click()에 자신의 스크립트 넣어주기(드래그&드랍)
- Item 0~4 On Click()의 Function을 Item --> OnClick으로 변경
- Item 0~4의 Navigation = None 설정
- Hierachy의 Player 자식오브젝트인 Weapon 0,1 삭제
- 기존의 Weapon 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
using UnityEngine;
public class Weapon : MonoBehaviour
{
public int id;
public int prefabId;
public float damage;
public int count;
public float speed;
float timer;
Player player;
void Awake(){
player = GameManager.instance.player; // GameManager 활용으로 변경
}
// Start 함수 로직은 삭제
void Update(){
switch (id){
case 0:
transform.Rotate(Vector3.back * speed * Time.deltaTime);
break;
default:
timer += Time.deltaTime;
if(timer > speed){
timer = 0f;
Fire();
}
break;
}
// .. Test Code ..
if (Input.GetButtonDown("Jump")){
LevelUp(10, 1);
}
}
public void LevelUp(float damage, int count)
{
this.damage += damage;
this.count += count;
if(id == 0){
Batch();
}
player.BroadcastMessage("ApplyGear",SendMessageOptions.DontRequireReceiver); // ApplyGear 함수를 가진 모든 오브젝트에 실행 명령을 내림
}
public void Init(ItemData data) // 매개변수 추가
{
// Basic Set
name = "Weapon " + data.itemId; //오브젝트 이름
transform.parent = player.transform; // player의 자식 오브젝트로 생성
transform.localPosition = Vector3.zero; // player의 안쪽에서 위치 초기화
// Property Set
id = data.itemId; // Scriptble Object Id 초기화
damage = data.baseDamage; // Scriptble Object Damage 초기화
count = data.baseCount; //Scriptble Object Count 초기화
for(int index=0; index<GameManager.instance.pool.prefabs.Length; index++){
if (data.projectile == GameManager.instance.pool.prefabs[index]){ // Prefab Id는 PoolManager의 변수에서 찾아서 초기화
prefabId = index;
break;
}
}
switch(id){
case 0:
speed = 150; // (+) --> 반시계방향
Batch();
break;
default:
speed = 0.3f;
break;
}
player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver); // ApplyGear 함수를 가진 모든 오브젝트에 실행 명령을 내림
}
void Batch(){
for(int index=0; index < count; index++) {
Transform bullet;
if(index < transform.childCount){
bullet = transform.GetChild(index);
}
else{
bullet = GameManager.instance.pool.Get(prefabId).transform;
bullet.parent = transform;
}
bullet.localPosition = Vector3.zero;
bullet.localRotation = Quaternion.identity;
Vector3 rotVec = Vector3.forward * 350 * index / count;
bullet.Rotate(rotVec);
bullet.Translate(bullet.up * 1.5f, Space.World);
bullet.GetComponent<Bullet>().Init(damage, -1, Vector3.zero); // -1 is Infinity Per.
}
}
void Fire()
{
if (!player.scanner.nearestTarget){
return;
}
Vector3 targetPos = player.scanner.nearestTarget.position;
Vector3 dir = targetPos - transform.position;
dir = dir.normalized;
Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
bullet.position = transform.position;
bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);
bullet.GetComponent<Bullet>().Init(damage, count, dir);
}
}
- C# 스크립트 생성(Gear)
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gear : MonoBehaviour
{
public ItemData.ItemType type; // ItemType 변수
public float rate; // 수치 변수
public void Init(ItemData data) // 초기화 함수
{
// Basic set
name = "Gear " + data.itemId; // 오브젝트 이름
transform.parent = GameManager.instance.player.transform; // player의 자식 오브젝트로 설정
transform.localPosition = Vector3.zero; // player의 안에서 위치 초기화
// Property set
type = data.itemType; // ItemType 초기화
rate = data.damages[0]; // 수치 초기화
ApplyGear(); // ApplyGear 함수 호출
}
public void LevelUp(float rate) // Weapon과 동일한 LevelUp 함수
{
this.rate = rate;
ApplyGear(); // ApplyGear 함수 호출
}
void ApplyGear() // Gear 관리 함수
{
switch (type)
{
case ItemData.ItemType.Glove:
RateUp();
break;
case ItemData.ItemType.Shoe:
SpeedUp();
break;
}
}
private void RateUp() // 수치 증가 함수
{
Weapon[] weapons = transform.parent.GetComponentsInChildren<Weapon>(); // Weapon 가져옴
foreach(Weapon weapon in weapons) // Weapon에 하나씩 접근
{
switch (weapon.id) // Weapon의 id별로 나누어 작성
{
case 0: // 근접
weapon.speed = 150 + (150 * rate);
break;
default: // 원거리
weapon.speed = 0.5f * (1f - rate);
break;
}
}
}
void SpeedUp() // 이동속도 증가 함수
{
float speed = 3;
GameManager.instance.player.speed = speed + speed * rate;
}
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
★Slow and Steady★
'Unity 공부 > Unity_2D' 카테고리의 다른 글
| [Day 11] 레벨업 시스템 (0) | 2023.07.17 |
|---|---|
| [Day 10] 무기 장착 표현 (0) | 2023.07.16 |
| [Day 8] HUD 제작 (0) | 2023.07.14 |
| [Day 7] 타격감 있는 몬스터 처치 구현 (0) | 2023.07.13 |
| [Day 6] 자동 원거리 공격 구현 (0) | 2023.07.12 |