我想与Unity中的游戏对象互动。这些对象可能是钥匙,门,箱子,...
比方说桌子上有钥匙。玩家靠近时,应使用着色器勾勒轮廓,并显示“拾取键”文字。
我创建了可交互游戏对象的界面。
public interface IInteractable
{
string InteractabilityInfo { get; }
void ShowInteractability();
void Interact();
}
这样做,我可以将接口组件添加到我的Key
脚本中
public class Key : MonoBehaviour, IInteractable
{
public string InteractabilityInfo { get { return "some text here"; } }
public void ShowInteractability()
{
// Outline Shader maybe?
}
public void Interact()
{
// Do something with the key
}
}
当涉及检查某些事物是否可交互的脚本时,我创建了一个脚本,该脚本创建了一个检查可交互对象的光线投射。 (我将此脚本附加到FPS相机上)
public class InteractabilityCheck : MonoBehaviour
{
private const int RANGE = 3;
private void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
{
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
if (interactable != null)
{
interactable.ShowInteractability();
if (Input.GetKeyDown(KeyCode.E))
{
interactable.Interact();
}
}
}
}
}
此脚本尝试获取接口组件,如果不为null,则从中调用方法。
此代码可以正常工作,但我不喜欢Raycast每帧触发一个。还有另一种实现交互性的方法吗?
答案 0 :(得分:1)
是的,光线投射是“昂贵的”,将其称为每一帧都不酷,有许多方法可以避免这种情况。在您的情况下,您可以像这样简单地重组代码:
private void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
{
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
if (interactable != null)
{
interactable.ShowInteractability();
interactable.Interact();
}
}
}
}
另外一个好主意是采用一种分离的方法来获得游戏逻辑,以便您以后可以更轻松地修改它并避免使用spaggeti xaxa。像这样:
public void interactWithYourObject()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
{
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
if (interactable != null)
{
interactable.ShowInteractability();
interactable.Interact();
}
}
}
,然后在您的更新中,只要您的条件是真的,就调用它:
private void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, RANGE))
{
interactWithYourObject()
}
}
答案 1 :(得分:1)
另一种方法是将球形触发器放置在可交互对象上,然后您可以通过球形触发器的radius
控制范围。
这类似于我刚刚回答的另一个问题,所以我重新编写了代码。
using UnityEngine;
[RequireComponent(typeof(SphereCollider))]
internal abstract class CollisionTrigger : MonoBehaviour
{
private bool _isPlayerInsideTrigger = false;
private void Awake()
{
if(!GetComponent<SphereCollider>().isTrigger)
{
Debug.LogError("Please set the sphere collider to a trigger.");
enabled = false;
return;
}
}
private void Update()
{
if(_isPlayerInsideTrigger)
{
FakeOnTriggerStay();
}
}
private void OnTriggerEnter(Collider collider)
{
if(!collider.CompareTag("Player")) return;
_isPlayerInsideTrigger = true;
}
public abstract void FakeOnTriggerStay();
private void OnTriggerExit(Collider collider)
{
if(!collider.CompareTag("Player")) return;
_isPlayerInsideTrigger = false;
}
}
这是一个示例,用于演示使用上面提供的类的Key
类的外观。
internal class Key : CollisionTrigger
{
public override void FakeOnTriggerStay()
{
// Show the user they can now interact with it.
// Outline Shader maybe?
if(Input.GetKeyDown(KeyCode.E))
{
// Do something with the key.
}
}
}