InteractSystem
클래스 구조 변경
InteractSystem
의 추가로 캐릭터가 상호작용 시 주변 오브젝트들 중 우선순위에 따라 상호작용이 진행되는 기능이 생겼다.
유저가 현 시점에서 상호작용 할 오브젝트가 뭔지 알 수 있도록 상호작용할 오브젝트에 아웃라인으로 하이라이트 효과를 주기로 했다.
하이라이트 효과를 적용하기 위해선 현재 InteractSystem
의 구조를 살짝 바꿀 필요성이 있다.
InteractSystem.cs
public void TryInteractSequence()
{
SearchAllObject(_transform.position);
var tool = GetCurrentTool();
var isWeapon = tool is WeaponItemData;
// # 1. 타게팅 공격
if (isWeapon)
{
if (TryWeaponInteract(tool))
return;
}
// # 2. 도구 상호작용
if (tool != _emptyHand)
{
// # 2-1. 파괴
if (TryToolDestruct(tool))
return;
// # 2-2. 벌목, 채광
if (TryToolInteract(tool))
return;
}
// # 3. 구조물 상호작용
if (TryArchitectureInteract(_emptyHand))
return;
// # 4. 채집 상호작용
if (TryToolInteract(_emptyHand))
return;
// # 5. 허공에 공격
if (isWeapon)
{
if (TryWeaponInteract(tool, true))
return;
}
}
PlayerBaseState.cs
protected virtual void OnInteractStarted(InputAction.CallbackContext context)
{
if (_stateMachine.IsFalling) return;
_stateMachine.InteractSystem.TryInteractSequence();
}
기존의 구조는 PlayerBaseState
에서 상호작용 입력을 받으면, InteractSystem
에게 우선순위에 따라 상호작용을 진행할 것을 요청한다.
InteractSystem
은 요청을 받았을 때 주변 오브젝트를 탐색하여 순차적으로 상호작용을 시도한 다음, event를 날리는 구조이다.
하지만, 지금 상호작용을 눌렀을 때 어떤 오브젝트에게 상호작용될지 보여주는 하이라이트 효과
를 적용하기 위해서는, InteractSystem
은 항상 어떤 오브젝트에게 상호작용 될지 알고 있어야한다.
InteractSystem.cs
private Action _onInteract;
public void TryInteract()
{
_onInteract?.Invoke();
}
public void SearchInteractableObjectsSequence()
{
var tool = GetCurrentTool();
var isWeapon = tool is WeaponItemData;
SearchAllObject(_transform.position);
// # 1. 타게팅 공격
if (isWeapon)
{
if (SearchWeaponInteract(tool))
return;
}
// # 2. 도구 상호작용
if (tool != _emptyHand)
{
// # 2-1. 파괴
if (SearchToolDestruct(tool))
return;
// # 2-2. 벌목, 채광
if (SearchToolInteract(tool))
return;
}
// # 3. 구조물 상호작용
if (SearchArchitectureInteract(_emptyHand))
return;
// # 4. 채집 상호작용
if (SearchToolInteract(_emptyHand))
return;
// # 5. 허공에 공격
if (isWeapon)
{
if (SearchWeaponInteract(tool, true))
return;
}
}
private bool SearchToolInteract(ToolItemData tool)
{
foreach (var target in _targets)
{
if (!target.CompareTag(tool.targetTagName) || (1 << target.gameObject.layer & tool.targetLayers) == 0)
continue;
if (target.distance > tool.range * tool.range)
break;
if (target.TryGetComponent<IInteractable>(out var interactable))
{
_onInteract = () => OnToolInteract?.Invoke(interactable, target.tag, target.transform.position);
HighlightTarget(target);
//OnToolInteract?.Invoke(interactable, target.tag, target.transform.position);
return true;
}
}
return false;
}
우선 InteractSystem
에서는 이벤트 호출 구조와 메서드의 이름을 살짝 바꿨다.
이제 요청을 받으면 바로 상호작용 이벤트를 호출하는게 아니라, 오브젝트 탐색과 이벤트 호출부를 나눴다.
검색을 진행하면 _onInteract
Action에 플레이어가 상호작용 버튼을 눌렀을 때 호출될 이벤트를 담아둔다.
TryInteract()
메서드가 호출되면, 담고 있던 이벤트를 호출한다 !
이에 맞춰 PlayerBaseState
의 구조도 바꿨다.
PlayerBaseState.cs
public virtual void Update()
{
Move();
_stateMachine.InteractSystem.SearchInteractableObjectsSequence();
}
protected virtual void OnInteractStarted(InputAction.CallbackContext context)
{
if (_stateMachine.IsFalling) return;
_stateMachine.InteractSystem.TryInteract();
}
기존엔 OnInteractStarted()
에서 검색과 이벤트호출을 모두 담당하는 TryInteractSequence()
를 호출했지만, InteractSystem
이 담아두고 있던 이벤트를 호출하는 TryInteract()
를 호출하도록 했고, 오브젝트의 탐색은 매 프레임 호출되는 Update()
에서 SearchInteractableObjectsSequence()
를 호출하도록 했다.
테스트용으로 아웃라인 하이라이트를 적용해봤는데, 나무 오브젝트의 경우 버텍스 수가 6천개쯤 돼서 다가가면 0.5초 ~ 1초 정도 게임이 멈춘다.
우선은 잡 시스템으로 스무스노말을 계산하는 로직을 적용해보고,
상호작용할 수 있는 오브젝트, 즉 하이라이트가 적용될 수 있는 오브젝트들을 선별해서 해당 오브젝트들이 스무스 노말이 적용된 메시를 미리 알고 있게 해주는게 좋을 것 같다.