1. HUD (Head Up Display) 구현
-Exp, Level, Kill, Time, Health
<구현 목표>
- GameManger 스크립트에 Player Info 정보 추가하기
- HUD 스크립트 새로 생성하여 아래와 같이 입력
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HUD : MonoBehaviour
{
public enum eInfoType
{
Exp, Level, Kill, Time, Health
}
public eInfoType type;
//UI 타입들
private Text text;
private Slider slider;
void Awake()
{
this.text = this.GetComponent<Text>();
this.slider = this.GetComponent<Slider>();
}
1) Exp
Hierarchy - UI-Canvas 추가
아래와 같이 설정 맞추기
Slider 추가하고 아래와 같이 설정 하기
[Slider 주요 속성들]
- Interactable : 특정 슬라이더의 입력 수용 여부를 결정( false일 경우 비활성화)
- Transition(전환모드) : 각 상태의 슬라이더 모양과 상태간 전환 유형을 관리
- Navigation : 키보드나 컨트롤러 입력을 이용 할 때 UI 엘리먼트의 선택 방식을 설정
다 체크 해제 해주기!
- HUD 스크립트 Udate()에 아래와 같이 작성
- GameManager 스크립트에 Exp 갱신하는 메서드 추가하기
- Monster가 죽을때 Kill 증가 및 Exp 갱신 되어야 하므로
Monster 스크립트에서 몬스터 죽을때 로직에 아래와 같이 추가 작성하기
02. Level
Text UI 추가 후 아래와 같이 설정
- HUD 스크립트에 아래와 같이 case 추가
03. Kill
UI Image와 text 추가 후 아래와 같이 text 설정
HUD 스크립트에 아래와 같이 case 추가
** 새로 알게된 것
string.Format에서 F0 => 소수점자리 지정 & String 형식으로 반환
따라서
string.Format("{0:F0}", GameManager.instance.kill);
string.Format("{0}", GameManager.instance.kill.ToString());
둘 다 출력 값이 같음
04. Timer
UI Text 추가 후 아래와 같이 설정
HUD 스크립트에 아래와 같이 case 추가
**새로 알게 된 것
string.Format에서 D => 표시할 자릿수 지정
(EX) D2 -> 2자리수 , D5 -> 5자리수
05. Health
Exp 슬라이더 그대로 가져와 아래와 같이 변경
HUD 스크립트에 아래와 같이 case 추가
구현 결과
2. 몬스터 피격 액션 추가
몬스터가 피격 당할 때 좀 더 타격감을 주기 위해 피격 액션 추가해주자
기존에 Update()로 설정했던 몬스터 이동 부분을 FixedUpdate()로 변경 후 변수로 추가하기
Monster 스크립트에 KnockBack 코루틴 함수 추가
**yield return new WaitForFixedUpdate
: FixedUpdate()가 끝나면 yield return new WaitForFixedUpdate 밑에 있는 구문 실행!
몬스터가 공격 받는 시점에 코루틴 실행
실행 결과
피격시 살짝 뒤로 밀리는 모습
03. 능력 업그레이드
**ScriptableObject 란?
: 클래스 인스턴스와는 별도로 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너.
: 첨부된 MonoBehaviour 스크립트에 변경되지 않는 데이터를 저장하는 프리팹이 있는 프로젝트의 경우 유용
=> 즉, 메모리에 데이터 사본을 하나만 저장
**기능
- 에디터 세션 동안 데이터 저장 및 보관
- 데이터를 프로젝트의 에셋으로 저장하여 런타임 시 사용
- ItemData 스크립트 생성하고 아래와 같이 작성하기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "Item", menuName ="Scriptable Object/ItemData")]
public class ItemData : ScriptableObject
{
public enum eItemType
{
Melee, Range, Glove, Shoe, Heal
}
[Header("# Main Info")]
public eItemType 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;
}
Data폴더 생성 후 Scriptable Object -> ItemData 생성
- 생성한 Item Data(5개)들에 설정값 입력하기
item Button UI 갯수에 맞게 생성 후 Data에 해당하는 itemData 넣어주기
실행해 보면 입력해준 값들대로 변경되어 출력됨
- 무기 업그레이드 -
- Item 스크립트에 버튼 클릭 이벤트로 OnClick 메서드 추가, 아래와 같이 입력
//버튼 클릭 이벤트
public void OnClick()
{
switch (data.itemType)
{
case ItemData.eItemType.Melee:
break;
case ItemData.eItemType.Range:
break;
case ItemData.eItemType.Glove:
break;
case ItemData.eItemType.Shoe:
break;
case ItemData.eItemType.Heal:
break;
}
//level 증가
level++;
//...레벨 개수 넘기지 않게 로직 추가
//Damages의 배열길이:5 를 넘어가면 Button의 interactable 비활성화(투명하게)
if(level == data.damages.Length)
{
GetComponent<Button>().interactable = false;
}
}
Object에 각 item 스크립트를 넣어주고 function에 OnClick 입력
실행한 모습
-무기 업그레이드-
- 기존에 Player 자식으로 있던 무기 삭제하기
-Weapon 스크립트 수정
: Init()에 매개변수 ItemData data 입력후 아래와 같이 추가
Item 스크립트, OnClick()에 아래와 같이 추가
실행한 모습
- Item 스크립트에 OnClick()에 아래와 같이 추가 입력
//버튼 클릭 이벤트
public void OnClick()
{
switch (data.itemType)
{
//..2개 같이도 가능
case ItemData.eItemType.Melee:
case ItemData.eItemType.Range:
if(level == 0)
{
GameObject newWeapon = new GameObject();
this.weapon = newWeapon.AddComponent<Weapon>();
//Weapon 초기화
this.weapon.Init(data);
}
else
{
//...처음 이후의 레벨업은 데미지와 횟수를 계산
//새로운 무기이면 damage 올려줘야함
float nextDamage = data.baseDamage;
int nextCount = 0;
//damages가 백분률 값이므로 곱해준 다음 더해줌
nextDamage += data.baseDamage * data.damages[level];
nextCount += data.counts[level];
//Weapon 레벨업
weapon.LevelUp(nextDamage, nextCount);
}
break;
- Weapon 스크립트 Init()에 아래와 같이 추가 입력
Weapon 스크립트 LevelUp() 메서드
실행 결과
- 장비 업그레이드 -
[장비 기능]
장갑 : weapon의 speed 증가
장화 : player의 speed 증가
음료수: player의 health -> maxhealth 충전
Gear 스크립트 생성 후 아래와 같이 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gear : MonoBehaviour
{
public ItemData.eItemType type;
public float rate;
public void Init(ItemData data)
{
//...Basic Set
name = "Gear" + data.itemId;
//부모 transform 설정
this.transform.parent = GameManager.instance.player.transform;
this.transform.localPosition = Vector3.zero;
//...Property Set
type = data.itemType;
rate = data.damages[0];
//...장비가 생성되면 Gear의 기능을 적용시킴
this.ApplyGear();
}
//...레벨업
public void LevelUp(float rate)
{
//rate 값 갱신
this.rate = rate;
//...장비가 새롭게 추가 되거나 레벨업 할 때 로직적용 함수 호출
//플레이어의 weapon들에게 다시 적용
this.ApplyGear();
}
void ApplyGear()
{
switch (type)
{
case ItemData.eItemType.Glove:
this.RateUp();
break;
case ItemData.eItemType.Shoe:
this.SpeedUp();
break;
}
}
//...삽의 회전속도 증가
void RateUp()
{
Weapon[] weapons = transform.parent.GetComponentsInChildren<Weapon>();
foreach(Weapon weapon in weapons)
{
switch (weapon.id)
{
//id =0 -> 삽
case 0:
weapon.speed = 180 + (180 * this.rate);
break;
default:
weapon.speed = this.rate * (1f - this.rate);
break;
}
}
}
//...player의 이동속도 증가
void SpeedUp()
{
float speed = 5f;
GameManager.instance.player.speed = speed + speed * this.rate;
}
}
- Item 스크립트의 Init() 부분의 비워놨던 case 구문에 아래와 같이 작성 추가
여기서
Heal은 일회성 아이템 --> 맨 마지막에 써줬던 'level++' 구문을 weapon과 gear case 구문 내로 옮겨줌
//weapon : 삽, 엽총
case ItemData.eItemType.Melee:
case ItemData.eItemType.Range:
if(level == 0)
{
//...중략
}
else
{
//...중략
}
//level 증가
level++;
break;
//gear : 장갑, 장화
case ItemData.eItemType.Glove:
case ItemData.eItemType.Shoe:
if (level == 0)
{
//...중략
}
else
{
//...중략
}
//level 증가
level++;
break;
case ItemData.eItemType.Heal:
//heal : player 체력 -> 최대 체력으로
//1회성 아이템 => level++ 필요없음!!
GameManager.instance.health = GameManager.instance.maxHealth;
break;
- 새로운 weapon을 얻어도 똑같이 levelup 적용된 gear 값을 적용해야함.
Weapon 스크립트의 Init(), LevelUp() 메서드의 마지막 구문에
'BroadcastMessage("ApplyGear")' 추가하기!
**BroadcastMessage 란?
: 특정 함수 호출을 모든 자식에게 방송하는 함수
public void Init(ItemData data)
{
//...중략
//player가 가지고 있는 모든 장비에 ApplyGear 적용
//...특정 함수 호출을 모든 자식에게 방송하는 함수
this.player.BroadcastMessage("ApplyGear");
}
//레벨업 시 damage와 count 조절하기
public void LevelUp(float damage, int count)
{
this.damage = damage;
this.count += count;
//레벨 = 0 , 근접무기일 경우
if(id == 0)
{
//배치해아함
this.Batch();
}
//...BroadcastMessage 초기화
this.player.BroadcastMessage("ApplyGear");
}
실행해보니
BroadcastMessage에 no receiver 오류가 발생!!
=> BroadcastMessage에 SendMessageOptions.DontRequireReceiver 추가해주기
(receiver 반드시 필요 -> receiver 반드시 필요 X로 바뀜)
오류수정 후 실행 결과
'2D 콘텐츠 제작 > [언데드 서바이벌] 제작 일지' 카테고리의 다른 글
[언데드 서바이벌 07] 게임 시작, 종료 & Player 캐릭터 선택 (0) | 2023.09.19 |
---|---|
[언데드 서바이벌 06] 레벨업 시스템 구현 & 오류 수정 (0) | 2023.09.19 |
[언데드 서바이벌 04] 공격 구현(근거리, 원거리)&무기 장착 (0) | 2023.09.16 |
[언데드 서바이벌 03] 오브젝트 풀링으로 몬스터 생성 & 몬스터 레벨 적용 (0) | 2023.09.15 |
[언데드 서바이벌 02] 무한맵 생성 & 몬스터 생성 (0) | 2023.09.14 |