https://www.youtube.com/watch?v=-47pjK-P888&list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x&index=14
1. 아이템 데이터 만들기
데이터를 체계적으로 관리하기위해 스크립터블 오브젝트 제공
아이템 데이터 생성을 담당할 스크립트 생성 : ItemData.cs
[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 Info")]
public float baseDamage;
public int baseCount;
public float[] damages;
public int[] counts;
[Header("# Weapon")]
public GameObject projectile;
}
Monobehavior 지우고 ScriptableObject로 대체
아이템의 각종 속성들을 변수로 작성하기
- enum으로 아이템 종류 편하게 구분(ItemType)
CreateAssetMenu : 커스텀 메뉴를 생성하는 속성
[CreateAssetMenu(fileName ="Item",menuName ="Scriptble Object/ItemData")]
스크립트블 오브젝트를 담을 폴더 생성(Data)
***Create 메뉴에서 코드로 지정한 Scriptble Object > ItemData클릭으로 에셋 생성
스크립트블 오브젝트 : 다양한 데이터를 저장하는 에셋
나머지도 복사 후 기타 값들을 넣어준다. (Icon, Projectile도 변경)(Item 0 ~ Item 4)
2. 레벨업 버튼 제작
Canvas > Create Empty : 레벨업 버튼을 묶어줄 부모 오브젝트 생성(Level Up)
앵커및 크기조정
자식 오브젝트로 버튼 추가(Item 0)
background = panel
자식 오브젝트 Text를 폰트변경, 크기 0,0 ,Horizontal&Vertical Overflow로 변경
Image의 Source Image를 변경(Select 0)
크기가 크기 때문에 Set Native Size클릭해서 원본크기로 돌려 놓는다. //안되서 직접 썻습니다.
Pos Y = 3
업그레이드 버튼을 담당할 스크립트 생성 : Item.cs
아이템 관리에 필요한 변수들 선언
using UnityEngine.UI;
using static Cinemachine.DocumentationSortingAttribute;
public class Item : MonoBehaviour
{
public ItemData data;
public int level;
public Weapon weapon;
public Gear gear;
Image icon;
Text textLevel;
}
using UnityEngine.UI; 해주어야 Image와 Text 사용 가능
자식 오브젝트의 컴포넌트가 필요하므로 GetComponentsInChildren<Image>[1];
- 자기 자신도 포함되서 두번째 값으로 가져오기
Text는 여러개를 가져올것이기 때문에 배열 선언
LateUpdate에서 레벨 텍스트 갱신
private void LateUpdate()
{
textLevel.text = "Lv." + (level + 1);
}
버튼에 작성한 스크립트 추가 후 스크립트블 오브젝트 넣어두기
완성된 버튼은 Ctrl + D로 복사하여 다른 데이터 넣기
Level Up(Empty,부모)에게 Vertical Layout Group 컴포넌트를 추가
버튼을 데이터 개수에 맞게 복사하고 각각 스크립트블 오브젝트 연결
버튼 클릭 이벤트와 연결할 함수 추가
public void OnClick()
{
switch (data.itemType)
{
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
break;
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
break;
case ItemData.ItemType.Heal:
break;
}
level++;
if (level == data.damages.Length)
{
GetComponent<Button>().interactable = false;
}
}
아이템 타입을 통해 switch case문 작성해두기
여러 개의 case를 붙여서 로직을 실행하게 할 수 있어요
이후 level 값 하나 더하기
level이 최대값이면 올라가지 않게 interactable = false 설정
- interactable = false : 클릭 비활성화
나와서 인스펙터 창에서 Button 컴포넌트의 On Click () 에 각각의 (Script)Item의 OnClick() 메서드 연결
오작동을 방지하기 위해 모든 버튼의 Navigation을 None으로 변경
3. 무기 업그레이드
과거에 작성하였던 Player의 자식 Weapon1,2를 삭제
무기를 만드는 코드를 작성
switch (data.itemType)
{
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
if(level == 0)
{
GameObject newWeapon = new GameObject();
weapon = newWeapon.AddComponent<Weapon>();
weapon.Init(data);
}
break;
새로운 게임오브젝트를 코드로 생성
AddComponent<T> : 게임 오브젝트에 T 컴포넌트를 추가하는 함수
- AddComponent 함수 반환 값을 미리 선언한 변수에 저장
weapon.Init으로 초기화
(Init) Ctrl + 마우스 클릭으로 함수를 클릭하면 해당 함수 내용으로 바로 이동
Weapon의 Init 메소드
public void Init(ItemData data)
{
// Basic Set
name = "Weapon " + data.itemId;
transform.parent = player.transform;
transform.localPosition = Vector3.zero;
// Property Set
id=data.itemId;
damage = data.baseDamage;
count = data.baseCount;
for(int index = 0; index < GameManager.instance.pool.prefabs.Length; index++)
{
if(data.projectile== GameManager.instance.pool.prefabs[index])
{
prefabId = index;
break;
}
}
switch (id)
{
case 0:
speed = 150;
Batch();
break;
default:
speed = 0.3f;
break;
}
player.BroadcastMessage("ApplyGear",SendMessageOptions.DontRequireReceiver);
}
Weapon 초기화 함수에 스크립트블 오브젝트를 매개변수로 받아 활용
Basic set(기본적인 사항)과 Property set()으로 나눠서 초기화
//Basic set
transform.parent = player.transform : 부모를 player로 지정
transform.localPosition = Vector3.zero : 지역 위치인 localPosition을 원점으로 변경
- 플레이어 안에서 (0,0,0)이여아 하기 때문이다.
//Property set
각종 무기 속성 변수들을 스크립트블 오브젝트 데이터로 초기화
프리펩 아이디는 풀링 매니저의 변수에서 찾아서 초기화
for(int index = 0; index < GameManager.instance.pool.prefabs.Length; index++)
{
if(data.projectile== GameManager.instance.pool.prefabs[index])
{
prefabId = index;
break;
}
}
- Data에서 프리팹 아이디를 숫자로 직접 넣어도 되지만 꼬일 수 있기 때문에
- 스크립트블 오브젝트의 독립성을 위해서 인젝스가 아닌 프리펩으로 설정
Start 함수 로직은 삭제하고
더 이상, 이 Weapon은 부모의 자식이 아님으로, Awake 함수에서의 플레이어 초기화는 게임매니저 활용으로 변경
private void Awake()
{
//player = GetComponentInParent<Player>();
player = GameManager.instance.player;
}
Item에 OnClick에 LevelUp 로직 추가
switch (data.itemType)
{
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
if(level == 0)
{
GameObject newWeapon = new GameObject();
weapon = newWeapon.AddComponent<Weapon>();
weapon.Init(data);
}
else
{
float nextDamage = data.baseDamage;
int nextCount = 0;
nextDamage += data.baseDamage * data.damages[level];
nextCount += data.counts[level];
weapon.LevelUp(nextDamage, nextCount);
}
level++;
break;
- 처음 이후의 레벨업은 데미지와 횟수를 계산
- Weapon의 작성된 레벨업 함수를 그대로 활용
4. 장비 업그레이드
장비를 담당하는 새로운 스크립트 생성(Gear.cs)\
장비의 타입과 수치를 저장할 변수 선언
Weapon과 동일하게 초기화 함수 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gear : MonoBehaviour
{
public ItemData.ItemType type;
public float rate;
public void Init(ItemData data)
{
// Basic Set
name = "Gear " + data.itemId;
transform.parent = GameManager.instance.player.transform;
transform.position = Vector3.zero;
// Property Set
type = data.itemType;
rate = data.damages[0];
ApplyGear();
}
}
public void Levelup(float rate)
{
this.rate = rate;
ApplyGear();
}
void ApplyGear()
{
switch (type)
{
case ItemData.ItemType.Glove:
RateUp();
break;
case ItemData.ItemType.Shoe:
SpeedUp();
break;
}
}
void RateUp()
{
Weapon[] weapons = transform.parent.GetComponentsInChildren<Weapon>();
foreach(Weapon weapon in weapons)
{
switch (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;
}
Weapon과 동일하게 레벨업 함수 작성
RateUp() : 장갑의 기능인 연사력을 올리는 함수 작성
transform.parent.GetComponentsInChildren<Weapon>() : 플레이어로 올라가서 모든 Weapon을 가져오기
foreach문으로 하나씩 순회하면서 타입에 따라 속도 올리기
SpeedUp() : 신발의 기능인 이동 속도를 올리는 함수 작성
ApplyGear를 실행하는게 관건인데, 언제 사용하느냐?
1. 처음에 기어가 생성될 때 (Init)
2. 기어가 업데이트 될 때 (LevelUp)
Item으로 돌아가서 Gear 변수 선언
public class Item : MonoBehaviour
{
public ItemData data;
public int level;
public Weapon weapon;
public Gear gear;
//...
}
- 버튼 스크립트에서 새롭게 작성한 장비 타입의 변수 선언
public void OnClick()
{
switch (data.itemType)
{
//...
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
if(level == 0){
GameObject newGear = new GameObject();
gear = newGear.AddComponent<Gear>();
gear.Init(data);
}
else
{
float nextRate = data.damages[level];
gear.Levelup(nextRate);
}
level++;
break;
//...
}
- 무기 로직과 마찬가지로 최초 레벨업은 게임오브젝트 생성 로직을 작성
- 나중에 생성된 무기가 기어에 영향을 받지 않는 문제 발생
BroadcastMessage : 특정 함수 호출을 모든 자식에게 방송하는 함수
player.BroadcastMessage("ApplyGear",SendMessageOptions.DontRequireReceiver);
- SendMessageOptions.DontRequireReceiver : 이 옵션은 받는 대상이 없어도 오류를 출력하지 않는다.
Weapon.cs의 BroadcastMessage를 초기화, 레벨업 함수 마지막 부분에서 호출(Init,LevelUp)
치료 기능의 음료수 로직은 case문에서 바로 작성
case ItemData.ItemType.Heal:
GameManager.instance.health = GameManager.instance.maxHealth;
break;
레벨 값을 올리는 로직을 무기, 장비 case 안쪽으로 이동 //이미 하였음
깃허브 올리기
Commit : ver 1.11
Description : Ability implement
https://github.com/mekain80/CloneCode_Undead_Survivor
'게임개발 > 언데드서바이벌_골드메탈_클론코딩' 카테고리의 다른 글
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 12 (레벨업🥳시스템) (0) | 2023.05.10 |
---|---|
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 11+ (플레이어 무기 장착 표현하기) (0) | 2023.05.10 |
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 10 (HUD📐제작하기) (0) | 2023.05.06 |
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 9 (타격감🌟있는 몬스터 처치 만들기) (0) | 2023.05.06 |
[클론코딩_유니티_골드메탈] 뱀서라이크 따라만들기 8 (자동🎯원거리 공격 구현) (0) | 2023.04.10 |