[Unity / C#] 손전등 기능 및 아이템 모션 구현

주예성·2025년 7월 14일

📋 목차

  1. 손전등 구현
  2. 중간 결과
  3. 애니메이션
  4. 스크립트에서 애니메이션 제어
  5. 오브젝트 맞추기
  6. 최종 결과
  7. 오늘의 배운 점
  8. 다음 계획

🔦 손전등 구현

1. 빛 추가

손전등 구현은 이미 Scanner에서 대부분 구현했기 때문에, 간단하게 하고 넘어가겠습니다. 먼저 손전등 프리팹에서 PointLight를 자식으로 추가하고, 설정을 맞춰주세요.

2. 입력으로 끄고 켜기

지금 현재 손전등이 켜져있는지 꺼져있는지의 변수를 추가하고, 빛을 끄고 켜고를 표현합시다.

// ItemInstance.cs

 void IntializeProperties()
 {
 	// 기존 코드...
    
    if (itemData.itemName = "손전등")
    {
    	properties["IsFlashlightOn"] = false;
    }
}

public void SetFlashLightOn(bool isOn)
{
    if (itemData.itemName != "손전등") return;
    properties["isFlashlightOn"] = isOn;
    GetComponentInChildren<Light>().enabled = isOn;
}

// UseItem.cs

private void Update()
{
    if (playerItemHandler.currentItem)
    {
        ReloadCharge(playerItemHandler.currentItem);
    }
    UseScannerInUpdate();
    UseFlashlightInUpdate();
}

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)) UseFlashlight(item);
            break;
        default:
            return;
    }
}

private void UseFlashlightInUpdate()
{
    if (!playerItemHandler.currentItem) return;
    if (playerItemHandler.currentItem.itemData.itemName != "손전등") return;

    bool isBattery = CanUseBatteryProduct();

	// 켜져있는중 배터리가 모두 소모하면 자동으로 꺼
    if (!isBattery)
    {
        playerItemHandler.currentItem.gameObject.GetComponentInChildren<Light>().enabled = false;
        return;
    }
    
    if (playerItemHandler.currentItem.Get<bool>("isFlashlightOn"))
    {
        UseBattery();
    }
}
private void UseFlashlight(ItemInstance item)
{
    if (!inventory || !item || chargeUIOpen || GameState.IsUIOpen || !CanUseBatteryProduct()) return;
    if (item.gameObject.GetComponentInChildren<Light>().enabled)
    {
        Debug.Log("손전등을 끕니다.");

    }
    else
    {
        Debug.Log("손전등을 켭니다.");
    }
    item.gameObject.GetComponentInChildren<Light>().enabled = !item.gameObject.GetComponentInChildren<Light>().enabled;
    item.Set<bool>("isFlashlightOn", item.gameObject.GetComponentInChildren<Light>().enabled);
}

3. UI 업데이트

R키로 배터리 교체창을 만들었었는데, 실시간으로 몇%인지 업데이트 하는 로직도 넣습니다.

// UseItem.cs

private void UseBattery()
{
    ItemInstance battery = playerItemHandler.currentItem.Get<ItemInstance>("Battery");
    float rate = battery.Get<float>("batteryUsageRate");
    rate -= Time.deltaTime;
    battery.Set<float>("batteryUsageRate", rate);
    uiManager.SetChargeText();
}

// UIManager.cs

public void SetChargeText()
{
    ItemInstance item = playerItemHandler.currentItem.GetComponent<ItemInstance>();
    ItemInstance charge = null;
    switch (item.itemData.productType)
    {
        case ProductType.BatteryUsing:
            charge = item.Get<ItemInstance>("Battery");
            break;
        case ProductType.FuelUsing:
            charge = item.Get<ItemInstance>("Fuel");
            break;
        default:
            return;
    }

    int displayCharge = Mathf.Max(0, (int)charge.Get<float>("batteryUsageRate"));

    if (!chargeSlotPanel) return;
    // 현재 쓰고 있는 배터리는 무조건 0 인덱스로 처음 것만 값이 변하도록 함
    if (!chargeSlotPanel.GetComponentInChildren<TextMeshProUGUI>()) return;
    chargeSlotPanel.GetComponentInChildren<TextMeshProUGUI>().text = displayCharge.ToString() + "%";
}

🎮 중간 결과

우클릭으로 껐다 켰다 할 수 있으며 배터리 교체도 가능합니다.


🎞️ 애니메이션

물건을 사용하고 쥐고 있을때의 애니메이션을 넣겠습니다. 전 이미 만들어진 애니메이션 에셋을 수정하여 사용했습니다.

1. 만들기

Window -> Animation -> Animation을 들어가면 Animation창이 뜹니다. 거기서 드롭다운을 선택, Create New Clip으로 새로운 Anim파일을 만듭니다.
왼족 상단에 녹화버튼이 있죠? 그 버튼을 누르면 이제 편집할 수가 있게 됩니다.

2. 편집

편집은 간단하지만 매우 번거롭습니다. 만들고 싶은 애니메이션을 직접 제작하는 것인데요. 무언가를 쥐고 있는 애니메이션을 만들기 위해 Player의 스켈레톤을 직접 조작합니다. 원하는 프레임에서 스켈레톤을 바꾸면 Key가 생겨 해당 지점에서는 그 위치로 옮겨가는 애니메이션을 진행합니다.
먼저 칼을 들고, 칼을 쓰는 애니메이션을 보여드리겠습니다.

3. Animator Controller

Project창에서 Create -> Animator Controller을 하고 이름을 PlayerAnimator로 합시다. 들어가면 그래프같은 창이 뜰겁니다.
이 각 노드들은 현재 캐릭터가 취하고 있는 행동을 말합니다. 지금은 아무것도 없으니, 캐릭터가 아무것도 하지 않는 가만히 있는 상태를 뜻하는 Idle를 추가합시다. 해당 창에서 create State -> Empty를 선택해주세요.
생성된 New State의 이름을 Idle로 바꾸고, Motion에는 가만히 서 있는 포즈 애니메이션을 넣습니다.

물건을 드는 것과 쓰고 있는 것 또한 `HoldingItem`과 `OnUseKnife`로 이름을 설정하여 Empty 두 개를 생성합니다. 그리고 똑같이 Motion에 만든 애니메이션을 넣습니다.

4. 노드 연결하기

이젠 여기선 다음을 연결하기 위한 조건이 필요합니다.
물건을 들게 되면 Idle에서 HoldingItem으로 바뀌고, 나이프를 쓰면 HoldingItem에서 OnUseKnife로 행동이 바뀌겠죠?
그 반대로도 행동이 바껴야하니 노드에서 우클릭을 하고 Make Transition을 선택하여 나온 화살표를 다음에 행동할 노드에 연결합시다.

5. 조건 걸기

이제 조건을 추가합시다. Idle에서 HodingItem을 가려면 현재 아이템을 들고 있다는 Bool값이 필요하고, HodingItem에서 OnUseKnife를 하려면 나이프를 들고 있으며 현재 쓰는 중 이라는 Trigger가 필요합니다.
Trigger는 단발성 행동에 좋습니다. 한 번만 하고 끝내거든요.

왼쪽의 Parameters창에서 +버튼을 눌러 Bool과 Trigger 파라미터를 추가합시다.

그 다음 Idle->HoldingItem 화살표를 클릭하여 Conditions에 Holding을 True로 설정하여 추가합니다.
HoldingItem->OnUseKnife는 DoUseKnife를 추가해주세요.
HoldingItem->Idle은 Holding을 False로 설정하여 추가합니다.

각 화살표의 Inspector에 Has Exit Time이 있는데요. 이것은 애니메이션 전환 타이밍을 결정하는 중요한 설정입니다.

  • 체크 시: 애니메이션이 일정 시간 재생된 후에 전환하고 Exit Time까지 기다린 후 조건 확인함. 애니메이션이 자연스럽게 끝나고 전환. 공격, 스킬, 점프 등 완료되어야 하는 애니메이션에 사용.
  • 체크 해제 시: 조건이 맞으면 즉시 전환하며 애니메이션 중간에도 바로 전환 가능. 이동, 방향 전환 등 즉시 반응해야 하는 애니메이션에 사용.

OnUseKnife -> HoldingItem 의 Has Exit Time만 체크하고 나머지는 해제해주세요.


🎞️ 스크립트에서 애니메이션 제어

이제 우리에겐 아이템을 들었다아이템을 쓴다라는 코드를 찾아가는 일만 남았습니다.

// PlayerItemHandler.cs

private Animator animator;

private void Start()
{
	animator = GetComponent<Animator>();
}

public void ClearHolding()
{
    // 기존 코드...
    animator.SetBool("Holding", false);
}

private void SetHoldingItem(ItemInstance item, Transform transform)
{
	// 기존 코드...
    animator.SetBool("Holding", true);
    // 기존 코드...
}

// UseItem.cs

private void UseKnife(float damage)
{
	playerController.animator.SetTrigger("DoUseKnife");
    // 기존 코드...
}

🛠️ 오브젝트 맞추기

이대로 그냥 실행하게 되면 물건이 어색하게 손에 쥐어집니다. 그러니 물건을 쥐고 있는 Player를 Scene창에서 자연스럽게 쥐게끔 해당 오브젝트를 조정해줍니다.
그리고 조정 후, Inspector에 있는 Transform정보를 Prefab에 적용하면 자연스럽게 쥐게 됩니다.

다른 방법이 있기는 하나...!! 전 이게 더 자연스러워서 이 방법으로 했습니다.


🎮 최종 결과

이제 물건을 쥐고 사용해보세요! 다른 물건들도 만들어 보세요.


📚 오늘의 배운 점

  • 손전등 구현
  • Animation 및 Animator Controller 활용

🎯 다음 계획

다음 글에서는:

  1. 모듈형 방어구 구현
profile
Unreal Engine & Unity 게임 개발자

0개의 댓글