왜.... 오셨나요?

부끄러워요

연구노트

[슬라임랜처] 슬라임건 기능구현-3(완)

와피했는데 2026. 2. 20. 15:48

개요


설명

 

2일차에 슬라임건의 흡입과 인벤토리 그리고 UI까지 구현했는데 이번에는 나머지 배출기능 구현과 사운드를 적용할 예정임


기능 구현


슬라임건 배출


> 배출 코드(Controller)

    [Header("배출")]
    [Tooltip("배출력")]
    [SerializeField] private float ejectImpulse = 8f;
    [Tooltip("배출간격")]
    [SerializeField] private float ejectInterval = 0.15f; // 0.15초마다 1개
    
	private InputAction releaseAction;
    
   private void Awake()
    {
        releaseAction = playerInput.actions["Release"];
    }
    
    private void Update()
	{
    CheckButtons();
    Release(); 
	}
    
  //============= 입력 처리 ================
  private void CheckButtons()
  {
      isRelease = releaseAction.IsPressed();
  }
  
  //============= 배출 기능 ================
private void Release()
{
    if(!isRelease) return;
    if (isLookOff) return;
    if (Time.time < nextEjectTime) return;
    if (GameManager.Unit.game1Player.inventory.TryEject(selectedSlot, muzzle.position, muzzle.forward, ejectImpulse))
        nextEjectTime = Time.time + ejectInterval;
    else
        nextEjectTime = Time.time + 0.05f; // 배출 실패 시 재시도 간격 (조정 가능)
}

> 배출 코드(Game1Inventory)

    public bool TryEject(int slotIndex, Vector3 spawnPos, Vector3 dir, float impulse = 8f)
    {
        if ((uint)slotIndex >= (uint)slots.Length) return false;
        if (slots[slotIndex].IsEmpty) return false;

        int id = slots[slotIndex].id;
        if (!defById.TryGetValue(id, out var def) || def == null) return false;
        if (string.IsNullOrEmpty(def.prefabPath)) return false;

        Vector3 fwd = (dir.sqrMagnitude < 1e-6f) ? Vector3.forward : dir.normalized;
        Quaternion rot = Quaternion.LookRotation(fwd);

        GameObject go = GameManager.Resource.Instantiate<GameObject>(def.prefabPath, spawnPos, rot);
        if (go == null) return false;

        if (go.TryGetComponent<Rigidbody>(out var rb))
        {
#if UNITY_6000_0_OR_NEWER
            rb.maxLinearVelocity = Mathf.Max(rb.maxLinearVelocity, impulse);
            rb.linearVelocity = fwd * impulse;
#else
            rb.velocity = fwd * impulse;
#endif
        }

        slots[slotIndex].count--;
        if(slots[slotIndex].count > 0) GameManager.Sound.PlaySFX("Game1/EjectSFX");
        if (slots[slotIndex].count <= 0) slots[slotIndex].Clear();

        RaiseChanged(slotIndex);
        return true;
    }
    
    
        private void RaiseChanged(int i)
    {
        defById.TryGetValue(slots[i].id, out var def);
        GameManager.Event.Publish(EventType.SlotChanged, i, slots[i], def);
    }

 

 

설명
- 배출시 Slot에 있는 Slime이 Rigidbody의 힘을 받아 배출되어 날아간다 그리고 한번에 배출되지 않게 하나씩 방출되면서 일정 간격 시간을 주어 머신건처럼 연사로 빠르게 배출되지 않게 설정함
- 슬롯에 Slime이 0보다 클시 배출 바운드가 출력됨

> 슬롯 선택 코드(Controller)

    // 인벤토리 슬롯 선택 (0~3)
    private int selectedSlot = 0; // 0~3
    private float nextEjectTime = 0f;
    
      private void Update()
  {
      CheckButtons();
      HandleSlotHotkeys();
  }
  
 //============= 인벤토리 슬롯선택 기능 ================
 private void HandleSlotHotkeys()
 {
     var kb = Keyboard.current;
     if (kb == null) return;

     if (kb.digit1Key.wasPressedThisFrame || kb.numpad1Key.wasPressedThisFrame)selectedSlot = 0;
     else if (kb.digit2Key.wasPressedThisFrame || kb.numpad2Key.wasPressedThisFrame)selectedSlot = 1;
     else if (kb.digit3Key.wasPressedThisFrame || kb.numpad3Key.wasPressedThisFrame) selectedSlot = 2;
     else if (kb.digit4Key.wasPressedThisFrame || kb.numpad4Key.wasPressedThisFrame) selectedSlot = 3;

     GameManager.Event.Publish(EventType.SelectSlot, selectedSlot); // 슬롯 선택 이벤트 발행
 }

> 슬롯 선택 코드(InventoryUI)

 private void OnEnable()
 {
     GameManager.Event.Subscribe<int>(EventType.SelectSlot, SelectUIAnime);
 }
 private void OnDisable()
 {
     GameManager.Event.Unsubscribe<int>(EventType.SelectSlot, SelectUIAnime);
 }

 // =========  UI 애니메이션 ==========
 private void SelectUIAnime(int i) 
 {
     switch (i)
     {
         case 0:
             slot1.transform.DOScale(new Vector3(1.2f, 1.2f, 1),0.1f);
             slot2.transform.localScale = new Vector3(1f, 1f, 1);
             slot3.transform.localScale = new Vector3(1f, 1f, 1);
             slot4.transform.localScale = new Vector3(1f, 1f, 1);
             break;
         case 1:
             slot2.transform.DOScale(new Vector3(1.2f, 1.2f, 1), 0.1f);
             slot1.transform.localScale = new Vector3(1f, 1f, 1);
             slot3.transform.localScale = new Vector3(1f, 1f, 1);
             slot4.transform.localScale = new Vector3(1f, 1f, 1);
             break;
         case 2:
             slot3.transform.DOScale(new Vector3(1.2f, 1.2f, 1), 0.1f);
             slot2.transform.localScale = new Vector3(1f, 1f, 1);
             slot1.transform.localScale = new Vector3(1f, 1f, 1);
             slot4.transform.localScale = new Vector3(1f, 1f, 1);
             break;
         case 3:
             slot4.transform.DOScale(new Vector3(1.2f, 1.2f, 1), 0.1f);
             slot2.transform.localScale = new Vector3(1f, 1f, 1);
             slot3.transform.localScale = new Vector3(1f, 1f, 1);
             slot1.transform.localScale = new Vector3(1f, 1f, 1);
             break;
     }
 }
● 설명
- 키보드 숫자패드 1,2,3,4 버튼에 바인딩하여 숫자버튼을 누를시 selectedSlot 변수에 0~3까지(총4개) 변수가 선택되며 선택된 변수에 따라 슬롯이 결정됨
- 선택된 슬롯을 DOtween 애니메이션을 통해 스케일이 변경되는 애니메이션이 출력됨

 


버그수정


 

> Case1

발생 몬스터 새로운 프리펩 모델 적용이후 흡입이 되질 않음
문제 몬스터 프리펩의 자식오브젝에 Collider가 있는데 하위 오브젝트는 물리접촉 적용이 되질않음
해결 Collider를 최상위 부모오브젝트에 옮기고 수정해서 접촉가능하게 만듬

> Case2

발생 배출시 슬롯에는 슬라임이 없는데 사운드가 계속 출력됨
문제 슬롯의 슬라임이 없을때에 대한 사운드 출력 조건 자체가 없었음
해결 슬롯에 슬라임이 0보다 많은시에만 출력되도록 if조건문을 추가하여 해결함

> Case3

발생 EventManager를 통해 이벤트 등록하려는데 매개변수 에러가 남
문제 기존 EventManager를 사용시 매개변수가 두개이상은 등록이 되질 않음
해결 제네릭 변수를 추가로 하는 Overloading으로 함수를 추가적으로 생성해서 해결함

마치며.


플레이어 움직임은 없고 슬라임 또한 움직임은 없고 오로지 '슬라임건'만 핵심적으로 분석해서 기능구현을 3일동안 치뤘는데

개인적으로 설정한 구현성공여부를 살펴보며 이번 슬라임랜처_슬라임건 기능 구현을 성공적으로 마무리 하도록 하겠음