更改多个相同GameObject之一的颜色

时间:2018-08-16 02:02:59

标签: c# unity3d

我有一个太空射击游戏,玩家可以为飞船选择一种颜色,这也适用于飞船射击的子弹。这些飞船使用相同的子弹预制件,因此我想在游戏中创建子弹后更改其颜色。我最初使用以下代码更改颜色。

Material bulletMat = this.GetComponent<MeshRenderer>().sharedMaterial;
if (bulletMat != null)
{
   bulletMat.SetColor("_TintColor", color);
}

但是,我发现这会改变材料的颜色,并且在创建每个项目符号时,项目符号会在颜色之间切换。经过更多研究之后,我遇到了 MaterialPropertyBlock 变量和以下教程http://thomasmountainborn.com/2016/05/25/materialpropertyblocks/。因此,我遵循了本教程并设置了以下代码。

public Renderer renderer;
public MaterialPropertyBlock matBlock;
public Color color;
public bool colorSet = false;
void Awake()
{
    renderer = this.GetComponent<Renderer>();
    matBlock = new MaterialPropertyBlock();
}
public void ColorSet(Color color)
{
    this.color = color;
    this.colorSet = true;           

}

void Update()
{
    if (this.colorSet)
    {
        renderer.GetPropertyBlock(matBlock);
        matBlock.SetColor("_Color", this.color);
        renderer.SetPropertyBlock(matBlock);
    }
}

但是,发生了与先前解决方案相同的问题。...

有人可以帮我弄清楚如何为每个子弹设置颜色吗?

2 个答案:

答案 0 :(得分:2)

仅在真正要使用此材料更改每个对象的材料的地方使用sharedMaterial。那就是你不想做的。相反,您必须使用material,因此您只需更改材料的“克隆”实例。


如果这样做,Unity实际上只会自动为该对象实例化当前材料的本地副本。

public class ColorChanger : MonoBehavior
{
    private MeshRenderer meshRenderer;

    private void OnEnable()
    {
        meshRenderer = GetComponent<MeshRenderer>();
    }

    public void SetColor(Color newColor)
    {
        renderer.material.color = newColor;
    }
}

或使用SetColor,就像我猜得到的一样

public void SetColor(Color newColor)
{
    renderer.material.SetColor("_TintColor", newColor);
}

我个人比较容易找到以前提到的一种。但是第二个可以给你更多的控制权,因为你可以还可以更改其他方式无法实现的emitColor。


现在,当实例化子弹时,请确保首先实例化预制件,然后使用上面的组件更改颜色:

public GameObject bulletPrefab;
public Color myColor;
public GameObject Hand;

private void Shoot()
{
    // There are various ways for Instantiate e.g. providing start position and rotation or also the parent object
    // Since it shall be fired from the player I'll assume here there is a "Hand" object from which you want to fire
    // and that you want to add the bullet directly to the hierarchy without a parrent
    GameObject newBullet = Instantiate(bulletPrefab, Hand.position, Hand.rotation);
    // Now we get the color change component
    ColorChanger colorChanger = newBullet.GetComponent<ColorChanger>();
    // And set the color
    colorChanger.SetColor(myColor);
}

注意:
如果是多人游戏,则子弹应仅在服务器上实例化,因此您必须首先让服务器知道子弹应为哪种颜色,然后Network.Spawn后再将此信息提供给所有玩家他们。

答案 1 :(得分:1)

您不需要继续更新属性块。一次就够了。您还必须确保材质允许实例化,并且着色器支持实例化“ _Color”。在标准材质和精灵材质上,您会在材质的检查器窗口的底部找到它。

因此,您可以在Update中删除测试,并修改ColorSet方法。实际上,在Bullet类型的对象上,我倾向于使其尽可能精简(最好将所有功能移至中央Bullet Manager,但这不在主题之列。)

public void ColorSet(Color color)
{
  renderer.GetPropertyBlock(matBlock);
  matBlock.SetColor("_Color", color);
  renderer.SetPropertyBlock(matBlock);       
}

如果这没有帮助,您是否正在从已经在对象上设置颜色的水池中抓弹?只是在没有为已实例化的对象设置正确的颜色的情况下?

我也在质疑为什么renderer.material不起作用(或者您是否尝试过?)。但是,根据我的理解/猜测,设置新材料实际上会破坏实例化。因此,无论如何设置属性块,实际上可能会获得更好的性能。