如何通过旋转改变游戏对象上的material?

How to change material on a gameobject by rotation?

我想在 2 material 秒之间切换,具体取决于平台(游戏对象)的旋转。 这是我到目前为止所做的:

public class PlatformSpawner : MonoBehaviour
{
    public GameObject platform;
    public Material[] platformMaterial;
    Material currentMaterial;
    Renderer _renderer;
}

    void Start()
    {
        _renderer = this.GetComponent<Renderer>();
    }

我也写了这个,但我不想通过按钮更改 materials:

    public void LeftTurn()
    {
        _renderer.material = platformMaterial[0];
        currentMaterial = _renderer.material;
    }
    public void RightTurn()
    {
        _renderer.material = platformMaterial[1];
        currentMaterial = _renderer.material;
    }
}

这是平台向左或向右随机旋转 90 度的位置:

    public struct SpawnPoint
    {
        public Vector3 position;
        public Quaternion orientation;

        public void Step(float distance)
        {
            if (Random.value < 0.5)
            {
                position.x += distance;
                orientation = Quaternion.Euler(0, 90, 0); //change to one of the materials
            }
            else
            {
                position.z += distance;
                orientation = Quaternion.Euler(0, 0, 0); //change to the other of the materials.
             //This is where I want to material to switch.
             //When the objects position changes, the material changes too.
            }
        }
    }

有游戏画面。我想把所有转角平台的material改成漂亮的曲线视图

任何人都可以帮助我在这种情况下做什么以及如何做?我有点迷路了。 非常感谢您的帮助!

编辑:新代码看起来像那样。唯一的问题是 Unity 给我 15 个错误(见下图),即使 Visual Studio 说没有发现问题。错误与开关有关。

public class PlatformSpawner : MonoBehaviour
{
    public GameObject platform;
    public Transform lastPlatform;
    SpawnPoint _spawn;
    bool stop;

    public Material straightMaterial;
    public Material turnLeftMaterial;
    public Material turnRightMaterial;
    public Renderer roadPrefab;

    [System.Serializable]

    public struct SpawnPoint
    {
       public Vector3 position;
        public Quaternion orientation;
        public RoadType type;

        public enum RoadType
        {
            Straight,
            LeftTurn,
            RightTurn
        }

        private enum Direction
        {
            Z,
            X,
        }

        private Direction lastDirection;

        public void Step(float distance)
        {
            type = RoadType.Straight;

            if (Random.value < 0.5f)
            {
                position.x += distance;
                orientation = Quaternion.Euler(0, 90, 0);
                if (lastDirection == Direction.Z)
                {
                    type = RoadType.RightTurn;
                }
            }
            else
            {
                position.z += distance;
                orientation = Quaternion.Euler(0, 0, 0);
                if (lastDirection == Direction.X)
                {
                    type = RoadType.LeftTurn;
                }

                lastDirection = Direction.Z;
            }
        }
    }

    void Start()
    {
        _spawn.position = lastPlatform.position;
        _spawn.orientation = transform.rotation;

        StartCoroutine(SpawnPlatforms());
    }

    IEnumerator SpawnPlatforms()
    {
        while (!stop)
        {
            var _spawn = new SpawnPoint();

            for (var i = 0; i < 20; i++)
            {
                var newPlatform = Instantiate(roadPrefab, _spawn.position, _spawn.orientation);

                _spawn.Step(1.5f);

                var roadMaterial = _spawn.type switch
                {
                    SpawnPoint.RoadType.LeftTurn => turnLeftMaterial,
                    SpawnPoint.RoadType.RightTurn => turnRightMaterial,
                    _ => straightMaterial
                };

                newPlatform.GetComponent<Renderer>().material = roadMaterial;

                yield return new WaitForSeconds(0.1f);
            }
        }
    }
}

这会让您开始使用 Quaternion.Dot

using UnityEngine;

[RequireComponent(typeof(Renderer))]
public class NewBehaviourScript : MonoBehaviour
{
    public Material Material1;
    public Material Material2;
    public Vector3 Euler = new(90, 0, 0);
    private Renderer _renderer;

    private void Start()
    {
        _renderer = GetComponent<Renderer>();
        _renderer.material = Material1;
    }

    private void Update()
    {
        var dot = Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler));

        if (Mathf.Approximately(dot, 1.0f))
        {
            _renderer.material = Material2;
        }
        else
        {
            _renderer.material = Material1;
        }
    }
}

对 N、E、S、W 角使用不同的 material:

using UnityEngine;

[RequireComponent(typeof(Renderer))]
public class NewBehaviourScript : MonoBehaviour
{
    public Material Material1;
    public Material Material2;
    public Material Material3;
    public Material Material4;
    public Vector3 Euler1 = new(0, 0, 0);
    public Vector3 Euler2 = new(0, 90, 0);
    public Vector3 Euler3 = new(0, 180, 0);
    public Vector3 Euler4 = new(0, 270, 0);
    private Renderer _renderer;

    private void Start()
    {
        _renderer = GetComponent<Renderer>();
        _renderer.material = Material1;
    }

    private void Update()
    {
        if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler1)), 1.0f))
        {
            _renderer.material = Material1;
        }

        if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler2)), 1.0f))
        {
            _renderer.material = Material2;
        }

        if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler3)), 1.0f))
        {
            _renderer.material = Material3;
        }

        if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler4)), 1.0f))
        {
            _renderer.material = Material4;
        }
    }
}

确保旋转超过 360 度,否则它看起来总是黄色的(第 4 个 material)。

听起来你基本上有一个工作系统来切换材质和生成你的道路部件和材质已经根据你的旋转看起来正确 - 现在你只需要识别曲线。

其实这很简单:

  • 当前部分为X方向,下一个为Z->Left Turn
  • 是Z方向的当前部分,下一个将在X -> RightTurn
  • 任何其他情况都是直的

所以你可能会做类似的事情

public struct SpawnPoint
{
    public Vector3 position;
    public Quaternion orientation;
    public RoadType type;

    public enum RoadType
    {
        Straight,
        LeftTurn,
        RightTurn
    }

    private enum Direction
    {
        // since your orientation by default equals the Z direction use that as default value for the first tile
        Z,
        X, 
    }
    private Direction lastDirection;

    public void Step(float distance)
    {
        type = RoadType.Straight;

        if (Random.value < 0.5f)
        {
            position.x += distance;
            orientation = Quaternion.Euler(0, 90, 0);

            if(lastDirection == Direction.Z)
            {
                type = RoadType.RightTurn;
            }

            lastDirection = Direction.X;
        }
        else
        {
            position.z += distance;
            orientation = Quaternion.Euler(0, 0, 0); 

            if(lastDirection == Direction.X)
            {
                type = RoadType.LeftTurn;
            }

            lastDirection = Direction.Z;
        }
    }
}

而且你没有显示生成代码,但我会假设类似

public class Example : MonoBehaviour
{
    public Material straightMaterial;
    public Material turnLeftMaterial;
    public Material turnRightMaterial;

    public Renderer roadPrefab;

    private void Awake()
    {
        var spawnPoint = new SpawnPoint();
        
        for(var i = 0; i < 20; i++)
        {
            var roadTile = Instantiate(roadPrefab, spawnPoint.position, spawnPoint.orientation);

            // do the Step after spawning the current tile but before assigning the material
            // -> we want/need to know already where the next tile is going to be
            spawnPoint.Step(1f);
            
            var roadMaterial = spawnPoint.type switch
            {
                SpawnPoint.RoadType.LeftTurn => turnLeftMaterial,
                SpawnPoint.RoadType.RightTurn => turnRightMaterial,
                _ => straightMaterial
            };

            roadTile.GetComponent<Renderer>().material = roadMaterial;
        }
    }
}

看我的绘画技巧 ;)