【问题标题】:Overriding virtual function not get called in Unity C# script在 Unity C# 脚本中未调用覆盖虚函数
【发布时间】:2017-10-10 07:10:41
【问题描述】:

我在 Unity 3D 中编写了以下 2 个脚本,PhysicsObjectPlayerPlatformerController(接下来是 tutorial)。 PlayerPlatformerController 脚本附加到游戏对象。

PhysicsObject.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicsObject : MonoBehaviour {
    void Update () {
        ComputeVelocity ();
    }

    protected virtual void ComputeVelocity() {

    }
}

PlayerPlatformerController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerPlatformerController : PhysicsObject {
    void Update () {

    }

    protected override void ComputeVelocity() {

    }
}

代码看起来很简单,但是PlayerPlatformerController 中的ComputeVelocity() 没有被调用(通过添加Debug.Log() 来证明)。为什么?

如果我更改为以下代码,该功能可以完美运行:

PhysicsObject.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicsObject : MonoBehaviour {
    void Update () {
        //ComputeVelocity ();
    }

    /*protected virtual void ComputeVelocity() {

    }*/
}

PlayerPlatformerController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerPlatformerController : PhysicsObject {
    void Update() {
         ComputeVelocity();
    }

    void ComputeVelocity() {

    }
}

我错过了什么?

【问题讨论】:

  • ComputeVelocity 方法是否在 PhysicsObject 中被调用?
  • 嗨,史蒂夫,是的,ComputeVelocity() 可以在PhysicsObject 内调用(也由Debug.Log() 证明)
  • 尝试将PhysicsObject 中的ComputeVelocity 更改为抽象方法,看看它是否在PlayerPlatformerController 中被调用。我来自 .Net 视图,但除非 Mono 有不同的行为,否则它应该可以按您的预期工作。
  • 谢谢。通过将virtual 更改为abstract,它要求PhysicsObject 类也必须是abstract 类。因为我在PhysicsObject 类中有其他代码,所以我不能这样做。我开始认为这是 Unity 的一个小故障,因为无论从 .NET 还是 Mono 框架的角度来看,我的代码看起来都很好。
  • 如果您不直接使用“PhysicsObject”,您应该可以将其抽象化。我只是建议它无论如何都要进行测试,看看是否调用了基本实现。

标签: c# unity3d


【解决方案1】:

我碰巧有两个脚本: 健康.cs HealthModified.cs -> 这是 Health.cs 的覆盖函数

在我的游戏对象中,我正在测试 HealthModified(启用),并且我在游戏对象中也有 Health.cs,但已禁用。

代码也在使用 Halth.cs 组件,当它被禁用时,我不得不从游戏对象中删除该组件以获得 HealthModified 行为。

【讨论】:

  • 我的游戏对象只有PlayerPlatformerController 脚本组件; PhysicsObject 不包含在游戏对象的组件列表中。
【解决方案2】:

这可能是因为您在子类 (PlayerPlatformerController) 中使用了 Update 方法。如果为真,您会将更新标记为受保护和虚拟,并在子类中覆盖它。它可能看起来像这样:

public class PhysicsObject : MonoBehaviour
{
    protected virtual void Update()
    {
        ComputeVelocity();
        Debug.LogFormat("PhysicsObject Update");
    }

    protected virtual void ComputeVelocity()
    {
        Debug.LogFormat("PhysicsObject ComputeVelocity");
    }
}


public class PlayerPlatformerController : PhysicsObject
{
    protected override void Update()
    {
        base.Update();
        Debug.LogFormat("PlayerPlatformerController Update");
    }

    protected override void ComputeVelocity()
    {
        base.ComputeVelocity();
        Debug.LogFormat("PlayerPlatformerController ComputeVelocity");
    }
}

【讨论】:

    【解决方案3】:

    我终于找到了问题所在。在PlayerPlatformerController 类中,如果我删除Update() 方法,覆盖ComputeVelocity() 将开始工作。

    感谢大家对我的帮助。

    【讨论】:

      【解决方案4】:

      当您有一个从另一个类继承的类时,您需要警惕意外覆盖父类的方法。

      在这种情况下,创建空的 Start() 和 Update() 方法将替换来自父级的方法。这是一个容易犯的错误,因为默认情况下通常使用这些方法创建新类。

      从子类中删除方法将确保调用父类。或者,如果您想在调用父方法的同时保留子方法,可以使用 base.Start()(或您要覆盖的任何方法)。

      【讨论】:

        猜你喜欢
        • 2015-06-17
        • 2016-02-29
        • 1970-01-01
        • 2020-08-21
        • 1970-01-01
        • 1970-01-01
        • 2014-05-22
        • 2020-12-16
        相关资源
        最近更新 更多