我需要使用什么来制作一个对每个对象都有不同作用的交互方法? Unity3D

What do I need to use in order to make an interact method that acts differently for each object? Unity3D

对不起,如果这看起来像一个白痴问题,但我很不擅长编程。

基本上,我想制作一个脚本,其中包含一个 Interact 方法,该方法根据对象是什么来执行不同的操作。

如果您玩过 Max Payne 2 之类的游戏,您可能已经注意到您可以如何打开门、与水槽和马桶互动,并且它们会做一些不同的事情。

我所做的是将显示按钮提示的脚本附加到我将与之碰撞的对象上,但我不知道如何继续。一旦玩家与对象发生碰撞,哪个脚本应该检查“E”按钮是否按下,以及如何根据我碰撞的对象定义 Interaction() 方法而不为每个对象制作脚本? (除非你就是这样制作这种交互系统的?)

抱歉,如果我说的不太清楚,英语不是我的主要语言。提前致谢。

public class Interactable : MonoBehaviour {

public GameObject canvas;

void Update()
{

}

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.tag == "Player")
    {
        Debug.Log("enabled");
        canvas.SetActive(true);
    }
}
void OnCollisionExit(Collision collision)
{
    if (collision.gameObject.tag == "Player")
    {
        Debug.Log("exit");
        canvas.SetActive(false);
    }
}

欢迎来到Stack-overflow和编程

你要找的是Inheritance
它允许你创建一个'base' class来使用和引用。

在这种情况下,您可以class将这些对象定义为Interactable,并创建另一个脚本来进一步描述它们的用法,如下所示:

public abstract class Interactable : MonoBehaviour {
    // ...

    public abstract void Interact();

    void OnCollisionEnter(Collision collision) {
        if (collision.gameObject.tag == "Player") {
            // EXAMPLE: Now it will interact dynamically whenever player enters it's range
            Interact();
        }
    }
}

// ......

public class Door : Interactable {
    public  override void Interact() {
        Debug.Log("Open Door");
    }
}

// ......

public class Toliet : Interactable {
    public  override void Interact() {
        Debug.Log("Flush Toliet");
    }
}

// Or maybe on the player's POV

public class Player : MonoBehaviour {
    void OnCollisionEnter(Collision collision) {
        if (collision.gameObject.tag == "Interactable") {
            // We only have to concern if its an interactable, 
            // no need to concern what type of interactable it is
            gameObject.GetComponent<Interactable>().Interact();
        }
    }
}

如果还是觉得不明白可以去网上查一些教程

You may also want to look at Interfaces. Nearly identical to Inheritance.

处理该问题的最佳方法之一是使用 interface。当然,请记住,避免为交互对象创建不同的脚本会使播放器代码随着项目的扩展而失控。因此,您可以在播放器外部创建如下所示的界面 class:

public interface IInteractable
{
    void OnAction(Player player);
}

您也可以按如下方式分配此接口。这里的门将是一个可交互的 Monobehavior。其他游戏对象如灯、书等可以定义如下。

public class Door : MonoBehaviour, IInteractable // for e.g
{
    public void OnAction(Player player)
    {
        // Play Open door animation
    }
}
public class Book : MonoBehaviour, IInteractable // for e.g
{
    public void OnAction(Player player)
    {
        // Read the book
    }
}
public class Agent : MonoBehaviour, IInteractable // even you can use this for agents that can interact with them
{
    public void OnAction(Player player)
    {
        Debug.Log(player.name + " is talking with " + name);
    }
}

最后,您需要在播放器中编写的唯一代码是光线投射。因为对撞机仅在您的玩家在体内时才起作用,但是交互模式(例如天际或最大佩恩)通过光线投射或球形投射起作用。下面的代码可以涵盖任何受益于 Interactable 的对象。不仅可以访问播放器,而且随着项目的扩展,不再需要为不同的对象定义多个if。另请记住,这是解决此问题的标准方法。

public LayerMask interactLayer; // interact layer for avoiding ray detection mistakes
public void Update()
{
    if (Physics.Raycast(transform.position, transform.forward, out var hit, 2f, interactLayer.value))
    {
        if (Input.GetKeyDown(KeyCode.E))
        {
            var _interactable = hit.transform.GetComponent<IInteractable>();

            _interactable?.OnAction(this);
        }
        else
        {
            Debug.Log("Press E Key to interact with "+ hit.transform.name);
        }
    }
}