1
votes

I am trying to create particles emission for my objects which are actually pawns in a chess game. I changed particles material using Inspector for particle system and it works fine, however, when I try to change it with a script, nothing happens (particles stay pink for the black pawn).

I am not sure what is wrong with the script, whether it's a change of material problem or maybe I need to set the path for material. I would be glad if someone suggested a solution!

Here is the script:

public class BlackPawnParticleSystem : MonoBehaviour 
{
    private Material m_Material;
    private ParticleSystemRenderer psr;

    private void Start() 
    {
        var ps     = GetComponent<ParticleSystem>();
        m_Material = GetComponent<Renderer>).material;
        psr        = GetComponent<ParticleSystemRenderer>);

        psr.material = Resources.GetBuiltinResource<Material>("BlackBishop.mat");
    }

This is how it looks like:

enter image description here

EDIT:

Changes in code:

public class BlackPawnParticleSystem : MonoBehaviour 
{
    private Material m_Material;
    private ParticleSystemRenderer psr;

    private void Start() 
    {
        var ps       = GetComponent<ParticleSystem>();
        m_Material   = GetComponent<Renderer>().material;
        psr          = GetComponent<ParticleSystemRenderer>();
        psr.material = Resources.Load<Material>("BlackBishop");
    }

Location of my materials: enter image description here

Inspector for the material:

enter image description here

Script attached to the object:

enter image description here

2
I'd guess it's something to do with setting the material on an object that doesn't actually point to the ParticleSystem. The way Unity exposes the ParticleSystem objects is quite strange, I would look into it.Douglas Dwyer
I would also check whether GetBuiltinResource returns null, which would result in pink particles.Douglas Dwyer

2 Answers

4
votes

The problem is this line: Resources.GetBuiltinResource<Material>("BlackBishop.mat")

It is returning null. The Resources.GetBuiltinResource function is used to load resources that are built-in into Unity not ones created by you. For example, "Sprites-Default.mat". There is no build-in material named "BlackBishop.mat" so it returns null.


To load material you created, use rhe Resources.Load function.

First, create a folder called "Resources" then put your "BlackBishop.mat" material there. You can now load it as below:

Resources.Load<Material>("BlackBishop");

Notice how I did not include ".mat" in the name. You don't include the extension name when using the Resources.Load function. If you do, it will not find it.

EDIT:

But still nothing happens on my game scene

Please carefully:

1.Like I said in my original answer, you must create a folder named "Resources" and must put the "Black Bishop" material inside that folder. You have not done this and it should not work. The spellings of thisfolder must be correct so copy it directly from this answer. Again, it should be named "Resources".

2.Your material is named "Black Bishop" not "BlackBishop" . See the space. Please fix this in the code. That should be Resources.Load<Material>("Black Bishop"); not Resources.Load<Material>("BlackBishop");.

3.Your material is currently using the "Standard" shader. Change that to Particle shader. You can do that by selecting the Material and changing the shader from "Standard" to "Particles/Alpha Blended Premultiply". That's it. Your problem should now be solved.

Extra:

I noticed you are using folders to organize your resources. Your "Black Bishop.mat" is inside Arcane Cyber --> Chess --> Materials --> Pieces --> Plastic. I suggest you move the "Materials" folder to the "Resources" folder created in #1 above.

Now, your "Black Bishop.mat" should be inside Assets --> Resources --> Materials --> Pieces --> Plastic.

You can now load it as:

Resources.Load<Material>("Materials/Pieces/Plastic/Black Bishop");

If you still have problems, please update your code and new Inspector images again. Remember that spellings count.

0
votes

Why not just make a SerializedField with the Materials you need? If you don't want materials and trails to be random, set them to the exact spot in the array you need for the situation.

I did it like this:

using UnityEngine;

public class CorrectParticles : MonoBehaviour
{
    private static ParticleSystem correctPart;
    private static ParticleSystemRenderer correctRend;

    public static CorrectParticles Instace;

    [SerializeField] Material[] mainMaterials;
    [SerializeField] Material[] trailMaterials;

    private void Awake()
    {
        Instace = this;
    }

    void Start()
    {
        correctPart = GetComponent<ParticleSystem>();
        correctRend = GetComponent<ParticleSystemRenderer>();
        correctPart.Stop();
    }

    public void StartParticles()
    {
        int mainMaterial = Random.Range(0, mainMaterials.Length);
        correctRend.material = mainMaterials[mainMaterial];

        int trailMaterial = Random.Range(0, trailMaterials.Length);
        correctRend.trailMaterial = trailMaterials[trailMaterial];
        
        correctPart.Play();
    }

    public void StopParticles()
    {
        correctPart.Stop(withChildren: true, stopBehavior: ParticleSystemStopBehavior.StopEmittingAndClear);
    }
}

Then I can start and stop the particle system as needed on other scripts.

CorrectParticles.Instace.StartParticles();

or

CorrectParticles.Instace.StopParticles();