【问题标题】:Strange, Why when changing the doors colors it's changing it for all the doors and not each door individual?奇怪,为什么在更改门颜色时会更改所有门而不是每个门的颜色?
【发布时间】:2020-05-02 00:51:06
【问题描述】:

此脚本使用 ExecuteAlways 附加到空游戏对象,因此它也可以在编辑模式和运行时模式下工作:

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

[ExecuteAlways]
public class DoorsLockManager : MonoBehaviour
{
    public List<HoriDoorManager> Doors = new List<HoriDoorManager>();
    public List<bool> DoorsLockState = new List<bool>();

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Doors.Count == 0 || DoorsLockState.Count == 0)
        {
            Doors = FindObjectsOfType<HoriDoorManager>().ToList();
            DoorsLockState = new bool[Doors.Count].ToList();
        }

        for (int i = 0; i < DoorsLockState.Count; i++)
        {
            Doors[i].lockState = DoorsLockState[i];
        }
    }
}

这个脚本也附加到每个门上,在这个脚本中我使用的是 ExecuteAlways 属性:

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

[ExecuteAlways]
public class HoriDoorManager : MonoBehaviour
{
    public DoorHori door1;
    public DoorHori door2;
    public bool lockState;

    private List<Material> doorsRenderers = new List<Material>();

    private void Start()
    {
        doorsRenderers.Add(door1.transform.GetChild(0).GetComponent<Renderer>().sharedMaterial);
        doorsRenderers.Add(door2.transform.GetChild(0).GetComponent<Renderer>().sharedMaterial);
        doorsRenderers[0].shader = Shader.Find("Unlit/ShieldFX");
        doorsRenderers[1].shader = Shader.Find("Unlit/ShieldFX");
    }

    void OnTriggerEnter()
    {
        if (lockState == false)
        {
            if (door1 != null)
            {
                door1.OpenDoor();
            }

            if (door2 != null)
            {
                door2.OpenDoor();
            }
        }
    }

    private void Update()
    {
        if(lockState == false)
        {
            doorsRenderers[0].SetColor("_MainColor", Color.green);
        }
        else
        {
            doorsRenderers[0].SetColor("_MainColor", Color.red);
        }
    }
}

问题是,当我在 List DoorsLockState 的第一个脚本中更改标志的状态时,它不会更改门的颜色,只有一个标志会更改所有门的颜色。

它确实会改变锁定状态,但我希望每扇门也会根据锁定状态改变颜色。锁定 = 红色 解锁 = 绿色。

DoorHori 类:

using UnityEngine;
using System.Collections;

public class DoorHori : MonoBehaviour {

    public float translateValue;
    public float easeTime;
    public OTween.EaseType ease;
    public float waitTime;

    private Vector3 StartlocalPos;
    private Vector3 endlocalPos;

    private void Start(){
        StartlocalPos = transform.localPosition;    
        gameObject.isStatic = false;
    }

    public void OpenDoor(){
        OTween.ValueTo( gameObject,ease,0.0f,-translateValue,easeTime,0.0f,"StartOpen","UpdateOpenDoor","EndOpen");
        GetComponent<AudioSource>().Play();
    }

    private void UpdateOpenDoor(float f){       
        Vector3 pos = transform.TransformDirection( new Vector3( 1,0,0));
        transform.localPosition = StartlocalPos + pos*f;

    }

    private void UpdateCloseDoor(float f){      
        Vector3 pos = transform.TransformDirection( new Vector3( -f,0,0)) ;

        transform.localPosition = endlocalPos-pos;

    }

    private void EndOpen(){
        endlocalPos = transform.localPosition ;
        StartCoroutine( WaitToClose());
    }

    private IEnumerator WaitToClose(){

        yield return new WaitForSeconds(waitTime);
        OTween.ValueTo( gameObject,ease,0.0f,translateValue,easeTime,0.0f,"StartClose","UpdateCloseDoor","EndClose");
        GetComponent<AudioSource>().Play();
    }
}

【问题讨论】:

  • door1 & door2 是 2 扇门?你也可以展示 DoorHori Class 吗?
  • @Frenchy 已将其添加到我的问题中。
  • 可能是因为门共用材料

标签: c# unity3d


【解决方案1】:

您正在编辑所有门之间共享的 sharedMaterial

doorsRenderers.Add(door1.transform.GetChild(0).GetComponent<Renderer>().sharedMaterial);
//Notice the ".shadredMaterial" at the end here

而不是材质的实例。

通过使用doorsRenderers[0].shader = Shader.Find("Unlit/ShieldFX");,您还可以直接访问着色器,这意味着对其所做的任何更改都将反映在该材质的每个实例上。

doorsRenderers[0].SetColor("_MainColor", Color.green); 也直接访问材质和底层着色器,而不是材质实例(默认情况下,Unity 会在运行时编辑材质时创建一个材质实例)

有两种方法可以解决这个问题:

  • 使用两种不同的材料(一种红色,一种绿色)并将材料换成所需的材料。
  • 获取游戏对象的渲染器而不是(共享)材质,并改用Renderer.material.color 属性应用颜色更改。这将创建一个材质实例,仅更改该实例的颜色。

解决方案二看起来像这样:

private List<Renderer> doorsRenderers = new List<Renderer>();

private void Start()
{
    doorsRenderers.Add(door1.transform.GetChild(0).GetComponent<Renderer>());
    doorsRenderers.Add(door2.transform.GetChild(0).GetComponent<Renderer>());
}

private void ChangeDoorColour()
{
    if(lockState == false)
    {
        doorsRenderers[0].material.color = Color.green;
    }
    else
    {
       doorsRenderers[0].material.color = Color.red;
    }
}

顺便说一句:您通过在更新循环中设置门的每一帧的材质颜色,这不是一件好事,只能在门的状态发生变化时进行。所以我把它放在一个单独的函数ChangeDoorColour() 中,只有在门的状态发生变化时才应该调用它(所以可能在OpenDoor()CloseDoor() 方法中)。

【讨论】:

  • 问题是我不想在门打开或关闭时更改门的颜色,但是当我根据门锁状态更改第一个脚本 DoorsLockManager 中的标志时。例如,如果在检查器中,我在运行时或编辑模式中将门 7 标志设置为 false,则实时更改锁定状态和门颜色。这个想法是根据锁定状态而不是门是打开还是关闭来设置门的颜色。
  • @AbrahamKrim 更改颜色的代码将保持不变doorsRenderers[0].material.color = Color.&lt;your colour&gt;;,然后在标志更改时调用该代码
【解决方案2】:

如果您共享相同的材质并更改着色器中的颜色,它将全部更改,最好有两种材质并相应地应用它们。

有两种材料一种用于锁定一种用于解锁。 在脚本中引用这些颜色,即(在检查器中设置)

public Material greenMat, redMat;

何时解锁

door.GetComponent<MeshRenderer>().material = greenMat;

锁定

door.GetComponent<MeshRenderer>().material = redMat;

【讨论】:

  • 感谢 Remy 的编辑,今天早上我在手机上发了这篇文章,但没有格式化代码的选项耸耸肩
猜你喜欢
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
  • 2012-06-27
  • 2018-08-13
  • 2014-11-19
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多