c# - 奇怪,为什么在更改门颜色时会更改所有门而不是每个门的颜色?
问题描述
此脚本使用 ExecuteAlways 附加到空 GameObject,因此它也可以在编辑模式和运行时模式下工作:
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();
}
}
解决方案
您正在编辑所有门之间共享的 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 将在运行时编辑材质时创建材质实例)
有两种方法可以解决此问题:
- 使用两种不同的材料(一种红色,一种绿色)并将材料换成所需的材料。
- 获取 GameObjects 的 Renderer 而不是(共享)材质,并改为使用
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()
andCloseDoor()
方法中)。
推荐阅读
- linux - 使用带有 Bash 脚本 Linux 的 SSH 克隆 Bitbucket 存储库
- java - Spring boot - 使用内存数据库启动应用程序
- rust - 安装 cargo-generate 失败
- python - 自动从网站下载 excel 文件
- python - pandas:在每组中按复杂条件选择子数据集
- embedded-linux - 有没有关于如何在 Linux 中使用 DMA 切换 AVNET Zynq 7000 用户 LED 的示例?
- php - 仅显示第一个字母或段落
- java - 如何从字节数组制作文件并从这些文件制作 zip 并将 zip 发送到服务器而不在 Android 的存储中创建文件?
- javascript - 如何将字符串的一部分更改为 JSX 元素?
- python - 比较 Python 中的两个字典列表。返回不匹配