제트팩은 등 뒤에 장착하겠습니다.
Player에게 BackSocket이라는 빈 오브젝트를 등에 달아줍니다. 그리고 PlayerItemHandler에서 관리합시다.
// PlayerItemHandler.cs
[HideInInspector] public ItemInstance backSocketItem;
[Header("Socket")]
public Transform backSocket;
public void SetBackSocket(ItemInstance item)
{
if (!item || item == backSocketItem) return;
backSocketItem = item;
SetActiveCurrentItem(backSocketItem, backSocket);
}
// 본래 있던 함수를 변형함
// 다른 Bone에도 붙일 수 있게끔 item과 해당 위치의 transform을 인수에 둠
private void SetHoldingItem(ItemInstance item, Transform transform)
{
if (!item) return;
item.transform.position = transform.position;
item.transform.rotation = transform.rotation;
item.transform.SetParent(transform);
item.transform.localPosition = Vector3.zero;
item.transform.localRotation = Quaternion.identity;
Rigidbody rb = item.GetComponent<Rigidbody>();
if (rb) rb.isKinematic = true;
Collider[] colliders = item.GetComponents<Collider>();
foreach (Collider collider in colliders)
{
collider.enabled = false;
}
item.gameObject.SetActive(true);
}
// UseItem.cs
public void UseItems(ItemInstance item)
{
switch(item.itemData.itemName)
{
case "스캐너":
if (Input.GetMouseButtonDown(1)) UseScanner();
break;
case "나이프":
if (Input.GetMouseButtonDown(0)) UseKnife(item.itemData.attackPower);
break;
case "제트팩":
if (Input.GetMouseButtonDown(1)) UseJetPack(item);
break;
default:
return;
}
}
private void UseJetPack(ItemInstance item)
{
if (chargeUIOpen) return;
playerItemHandler.SetBackSocket(item);
}
우클릭을 누르면 플레이어의 등에 장착하게 됩니다.
이 게임에서 제트팩의 효과는 점프가 더 높이되며, 내려올때 천천히 내려와 낙하데미지를 입지 않는 것입니다. JetpackController 스크립트를 생성합시다.
// JetpackController.cs
using UnityEngine;
public class JetpackController : MonoBehaviour
{
[Header("Jetpack Settings")]
public float jetpackForce = 15f; // 제트팩 추진력
public float maxAltitude = 50f; // 최대 고도
public float gravityScale = 1f; // 중력 영향
private ItemInstance jetPack;
private Rigidbody rb;
private float groundLevel; // 지면 높이
private bool isUsingJetpack;
private GameObject player;
private float foolPowerTime = 5f; // 허공에 머물러 있을 수 있는 시간
private float currentPowerTime;
void Start()
{
player = GameObject.Find("Player");
jetPack = GetComponent<ItemInstance>();
rb = player.GetComponent<Rigidbody>();
groundLevel = player.transform.position.y; // 시작 지점을 지면으로 설정
currentPowerTime = foolPowerTime;
}
void Update()
{
Debug.Log($"현재 제트팩 가능 게이지 : {currentPowerTime}");
bool isCan = false;
if (Input.GetKey(KeyCode.Space))
{
// 허공에 있을 수 있는 게이지가 모두 닳아버릴 경우 천천히 떨어짐
if (currentPowerTime > 0)
{
currentPowerTime -= Time.deltaTime; // 누르고 있을 때는 게이지가 줄어듬
isCan = CanUseFuelProduct(jetPack);
}
isUsingJetpack = isCan;
}
else // 누르고 있지 않을 때는 게이지가 느리게 채워짐
{
if (currentPowerTime <= foolPowerTime)
{
currentPowerTime += Time.deltaTime / 3;
}
isUsingJetpack = false;
}
}
private void FixedUpdate()
{
if (isUsingJetpack)
{
UseJetpack();
}
}
private bool CanUseFuelProduct(ItemInstance jetPack)
{
ItemInstance fuel = jetPack.Get<ItemInstance>("Fuel");
if (!fuel)
{
Debug.Log("현재 연료통이 존재하지 않습니다!");
return false;
}
float rate = fuel.Get<float>("fuelUsageRate");
if (rate <= 0)
{
Debug.Log("연료가 모두 소진되었습니다!");
return false;
}
rate -= Time.deltaTime;
fuel.Set<float>("fuelUsageRate", rate);
return true;
}
void UseJetpack()
{
// 현재 고도
float currentAltitude = player.transform.position.y - groundLevel;
if (currentAltitude < maxAltitude)
{
// 만약 있을 수 있는 고도면 위로 날 수 있게
rb.AddForce(Vector3.up * jetpackForce, ForceMode.Force);
}
else
{
// 아니라면 더이상 올라가지 못함
rb.AddForce(Vector3.up * (jetpackForce * 0.3f), ForceMode.Acceleration);
}
}
}
플레이어가 공중에서 잠시 뜰 수 있게 됩니다. 고도 제한과 시간 등의 설정은 나중에 밸런스를 맞추도록 합시다.
제트팩은 현재 연료량과 날 수 있는 제한 시간에 대한 UI 표시가 필요합니다. HUD_Panel에서 JetpackBar의 빈 오브젝트를 생성하고, 다른 HUD와 비슷하게 설정할겁니다.
Background_Bar(Image), Fill_Bar(Image, FuelRate(Text)란 자식 오브젝트를 생성합시다.
UIManager에서 편집하도록 합시다.
// UIManager.cs
[Header("Bar")]
public GameObject jetpackBar;
public Image jetpackGaugeBar;
[Header("Text")]
public Text jetPackRateText;
private UseItem useItem;
void Start()
{
// 기존 코드...
if (player)
{
useItem = player.GetComponent<UseItem>();
}
// 기존 코드...
}
public void UpdateJetpackUI(ItemInstance jetpack, float time, float foolTime)
{
if (!jetpackBar || !jetpackGaugeBar || !jetpackRateText || !jetpack) return;
JetpackController jetpackController = jetpack.GetComponent<JetpackController>();
jetpackBar.SetActive(true);
jetpackGaugeBar.fillAmount = time / foolTime;
ItemInstance fuel = jetpack.Get<ItemInstance>("Fuel");
int displayRate = 0;
if (fuel)
{
displayRate = Mathf.Max(0, (int)fuel.Get<float>("fuelUsageRate"));
Debug.Log(jetpack.Get<float>("fuelUsageRate"));
jetpackRateText.text = displayRate.ToString() + "%";
}
else
{
jetpackRateText.text = "None";
}
}
// JetpackController.cs
void Update()
{
// 기존 코드...
if (uiManager)
{
uiManager.UpdateJetpackUI(jetPack, currentPowerTime, foolPowerTime);
}
// 기존 코드...
}
다음 글에서는: