Home > OS >  How to change material on a gameobject by rotation?
How to change material on a gameobject by rotation?

Time:12-09

I want to change between 2 materials, depending on the platforms (gameobject) rotation. Here is what I've done so far:

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

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

I also wrote this, but I don't want to change materials by buttons:

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

And this is where the platform rotates randomly 90 degrees to the left or to the right:

    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.
            }
        }
    }

There is a picture of the gameplay. I want to change the material of all the corner platforms to have a nice curve line view.

Picture

Can anyone help me what and how to do in this case? I am a bit lost there. Every help is highly appreciated!

CodePudding user response:

This will get you started using Quaternion.Dot.

enter image description here

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;
        }
    }
}

Using different materials for N, E, S, W corners:

enter image description here

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;
        }
    }
}

Make sure to wrap the rotation past 360 degrees, else it'll always look yellow (4th material).

CodePudding user response:

So it sounds like you basically have a working system for switching the materials and spawning you road parts and materials already look correctly according to your rotations - now you only need to identify the curves.

Actually this is pretty simple:

  • is the current part in X direction and the next will be in Z -> Left Turn
  • is the current part in Z direction and the next will be in X -> RightTurn
  • any other case is straight

So you could probably do something like

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;
        }
    }
}

And you didn't show your spawn code but I would assume something like

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;
        }
    }
}

Behold my Paint skills ;)

enter image description here

  • Related