#Weird Material null thing
1 messages ยท Page 1 of 1 (latest)
Fair
๐
Try this:
Let's log the ID in the following places:
- On startup, on
particlePrefab - On the objects that are initialized from
ParticlePrefabthe first time they are spawned - When
Preloadis called - When
Useis called
okay "So, where do you actually call Instantiate on the ParticlePrefab?" let me track this down
Will do
I just renamed all particlePrefabs into particleInstances because that is what the component is and its confusing me that I named them differently
the five preloaded particles do not match the use ID
but the game object the use is being run on, is one of those five
So, Preload is 3 Use is 4 I'm assuming On Startup is 1. What are the results of 2?
When they're first instantiated
"On the objects that are initialized from ParticlePrefab the first time they are spawned"
My brain is getting rigid, I'm struggling to understand that
they are spawned by the pool at start
the five preloads are they
this never gets called though for some reason
or wait it is, once, at the end
it should be being called 5 times I think?
Im going to set it to not make 5 but I was getting even weirder behaviour when I did that before
which was only making it harder to dialognose
there is only a single one in the entire scene
sceratch that there's two for some reason
let me see if I can see why
I think its because my pool is only 1 big, and it always tries to have extras when being used
so that it never has nothing to spawn from the pool
okay
I removed the code that widens the pool
there is only one instance of the particle
@daring perch
the reason i asked if different components can have different IDs
is because when I click the error ID, it takes me to this component
which is a component separate from the particle instance, but on the same game object
aw fuck maybe this is a Reference vs Value problem
im getting it from my global game manager
I want to instantiate unique ones though
could that be whats wrong??
Sorry, I had to step away for a bit. I'll read through this real quick
Start is called at the beginning of the first Update loop this object is enabled for. If you enable it, then do a bunch of stuff to it in that same function, it'll all run before start
Is this genericDamageParticle a Prefab or an object in the scene?
its a prefab in project
Okay, so, somewhere you're calling Instantiate on that, right?
Yes
Can you show that snippet?
private void Start()
{
InitializePool(itemPoolCount);
ParticlePoolInstanceManager.Instance.CreateDamageInstance(1, genericDamageParticle); //temp just one instance.
}
global game manager's start
right, sorry
the global game manager is making the POOL manager, who then makes the instances within the pool
let me find that part
public ParticlePool CreateInstance(int poolsize, ParticleInstance particleInstance)
{
if (FindInstance(particleInstance) == null)
{
ParticlePool thisInstance = Pool.ExpandPool(this.transform, instanceList, basePrefab); // make one instance of the list.
thisInstance.gameObject.SetActive(true);
thisInstance.Initialize(poolsize, particleInstance);
return thisInstance;
}
else
{
Debug.LogWarning("Attempted to create particle pool and failed. Did you forget to set a particle instance?");
return null;
}
}
I wish the thread screen wasnt so narrow, making it hard to read code
You can click the thread on the left side in the channel index to open it in the main window
Oh, thanks, that worked
I still don't see an Instantiate there
oh sorry you're right I was misreading initialize
here we go
public static T ExpandPool<T>(Transform parent, List<T> pool, T poolObject) where T : UnityEngine.Component
{
T instance = Instantiate(poolObject, Vector3.zero, Quaternion.identity);
instance.gameObject.SetActive(false);
instance.transform.SetParent(parent);
pool.Add(instance);
return instance;
}
actually come to think of it I think you helped me write this function originally
like a few months ago, when I was learning about <T>
Okay, so, this is the single most core bit of code. The closest to Unity's nervous system. Let's start here. Add this right before the return statement:
Debug.Log($"Spawing a copy of {nameof(T)} prefab {poolObject.GetInstanceID()} as new instance {instance.GetInstanceID()}");
Oh, hang on
Let's make this more useful. Editing.
Okay ๐
I think that'll print out what type T is
so we can see what class it's instantiating as
run it after instantiate?
Yeah, that'll do
Dang. It didn't give us the actual type. Well, we can still see the values. Is this the only place that line runs in your console?
oh right ExpandPool has overload methods
It might be a wholly different pool object. I was hoping nameof(T) would get us what T actually was, but I don't know the syntax for that
Ill add it to the overload thats probably getting used
public static void ExpandPool<T>(Transform parent, List<T> pool, T poolObject, int size) where T : UnityEngine.Component
{
for (int i = 0; i < size; i++)
{
T instance = Instantiate(poolObject, Vector3.zero, Quaternion.identity);
Debug.Log($"Spawing a copy of {nameof(T)} prefab {poolObject.GetInstanceID()} as new instance {instance.GetInstanceID()}");
instance.gameObject.SetActive(false);
instance.transform.SetParent(parent);
pool.Add(instance);
}
}
public static T ExpandPool<T>(Transform parent, List<T> pool, T poolObject) where T : UnityEngine.Component
{
T instance = Instantiate(poolObject, Vector3.zero, Quaternion.identity);
Debug.Log($"Spawing a copy of {nameof(T)} prefab {poolObject.GetInstanceID()} as new instance {instance.GetInstanceID()}");
instance.gameObject.SetActive(false);
instance.transform.SetParent(parent);
pool.Add(instance);
return instance;
}
I dont remember why the overload exists
hm it appears to return a value and takes different arguments
thats probably a stupid mistake on my part ill make a note to make it not two functions
or at least clarify why the same thing is there mostly twice
It looks like one is for expanding it by many, which is fair, but you should probably just call the second overload inside the loop of the first
oh right one is a single
Riiiiiight its all coming back now
the lower one makes the single Pool
the upper one makes all the Pool's child instances
Ill make a note to clarify that
Ah yeah I see what you mean, run the lower one within the loop of the upper one
yeah that is smart
Ill do it right now
well it looks slightly non-trivial so I wont
public static void ExpandPool<T>(Transform parent, List<T> pool, T poolObject, int size) where T : UnityEngine.Component
{
for (int i = 0; i < size; i++)
{
T instance = Instantiate(poolObject, Vector3.zero, Quaternion.identity);
Debug.Log($"Spawing a copy of {nameof(T)} prefab {poolObject.GetInstanceID()} as new instance {instance.GetInstanceID()}");
instance.gameObject.SetActive(false);
instance.transform.SetParent(parent);
pool.Add(instance);
}
}
public static T ExpandPool<T>(Transform parent, List<T> pool, T poolObject) where T : UnityEngine.Component
{
T instance = Instantiate(poolObject, Vector3.zero, Quaternion.identity);
Debug.Log($"Spawing a copy of {nameof(T)} prefab {poolObject.GetInstanceID()} as new instance {instance.GetInstanceID()}");
instance.gameObject.SetActive(false);
instance.transform.SetParent(parent);
pool.Add(instance);
return instance;
}
running this those logs
I dont understand why the ID's dont match
Ah, I figured out something, instead of nameof(T) do typeof(T).FullName
That'll let us know what object these are the IDs of
Okay, and ParticleInstance is the offending class, right?
wait so how is a particle instance running on awake, let me move to a scene with NOTHING in it
okay here is starting the scene, and then prompting the error
the selected log is where scene-start ends
let me change the code that is returning 18832 to output the name
Okay, a few things leap out at me:
- I have no idea why none of those match -131854
- 18832 is still the same even on a new scene. I'm pretty sure that means this is not in the scene
I think you're calling Use on a prefab somewhere
I don't know how to update your code
it was based on T before
public void Use(Texture texture)
{
//Debug.Log("Use Instance ID is " + this.gameObject.GetInstanceID());
Debug.Log($"Use Function called on {nameof(T)} prefab");
internalMat.SetTexture("_MainTex", texture);
}
You wouldn't need to do that bit. That was just to tell us what T was. In this case, we know what type it is since it's in a script with a name
So we could see what class it was instantiating
okay
You'd want Use Function Called on {this.GetInstanceID()}
I didn't actually make a new scene, I just cleaned out the existing scene and made a copy of the old scene
Which, now that I think about it, we were calling that on the gameObject, right?
so I will try to make an actual new scene?
Maybe that's why the numbers don't match
I think so maybe?
No, try running it with that new updated string
Okay
Change out that one debug, and change the other one to use this. instead of gameObject.
Change both the use and Preload, then run it
it changed, but it still doesnt match anything
public void PreloadMaterials()
{
internalMat = new Material(matTemplate);
for (int i = 0; i < systems.Length; i++)
{
systems[i].material = internalMat;
}
Debug.Log("Preload Instance ID is " + this.GetInstanceID());
}
public void Use(Texture texture)
{
//Debug.Log("Use Instance ID is " + this.gameObject.GetInstanceID());
Debug.Log("Use Instance ID is " + this.GetInstanceID());
//Debug.Log($"Spawing a copy of {typeof(T).FullName} prefab {poolObject.GetInstanceID()} as new instance {instance.GetInstanceID()}");
internalMat.SetTexture("_MainTex", texture);
}
So, where are you calling Use again?
Show the snippet
okay
public static void InstantiateDamageEffect(ITargetable target, DynamicParticleDamageSprite particle, int ammount)
{
InstantiateEffect(target, particle.myInstance, ammount);
if (particle != null && target.gameObject.TryGetComponent(out ItemComponent itemComponent))
{
Texture2D tex = Utils.textureFromSprite(itemComponent.sprite.sprite);
particle.Use(tex);
}
}```
public static void InstantiateEffect(ITargetable target, ParticleInstance particle, int ammount)
{
if (particle != null)
{
//REFACTOR: create already runs findInstance inside of itself.
ParticlePool pool = ParticlePoolInstanceManager.Instance.FindInstance(particle);
if (pool == null)
{
pool = ParticlePoolInstanceManager.Instance.CreateInstance(ammount, particle); // MAGIC NUMBER: 5 is random arbitary atm.
}
pool.InstantiateEffect(target);
}
}```
Where do you call InstantiateDamageEffect?
private static void DoExecuteAction(ScriptableActionPackage package)
{
bool succeeded = package.action.ExecuteAction(package.target, package.activator);
if (succeeded)
{
ParticlePool.InstantiateEffect(package.target, package.action.OnActionVFX, package.action.OnActionPoolCount);
}
else if (!succeeded && package.target != null && package.target.gameObject.TryGetComponent(out Actor actor) && package.activator.gameObject.TryGetComponent(out ItemComponent itemComponent))
{
ParticlePool.InstantiateDamageEffect(package.target, GameGlobalManager.Instance.genericDamageParticle, 5);
actor.TakeDamage(itemComponent.useAction.damage);
}
}```
There!
ParticlePool.InstantiateDamageEffect(package.target, GameGlobalManager.Instance.genericDamageParticle, 5);
That second parameter
I should probably rename Instantiate because it's not actually instantiating it
its just using from the pool
No, it's using the prefab
uhh
So I take it "GameGlobalManager.Instance.genericDamageParticle" was afuckup, because of some unity internal reason I failed to grasp
Follow the thread, let's swap in the values in the code:
public static void InstantiateDamageEffect(ITargetable target, DynamicParticleDamageSprite particle, int ammount)
{
InstantiateEffect(package.target, GameGlobalManager.Instance.genericDamageParticle.myInstance, ammount);
if (GameGlobalManager.Instance.genericDamageParticle!= null && target.gameObject.TryGetComponent(out ItemComponent itemComponent))
{
Texture2D tex = Utils.textureFromSprite(itemComponent.sprite.sprite);
GameGlobalManager.Instance.genericDamageParticle.Use(tex);
}
}
See how in InstantiateEffect you're getting GameGlobalManager.Instance.genericDamageParticle.myInstance
but you're calling Use directly on GameGlobalManager.Instance.genericDamageParticle?
Yep
why did I do that, what did I think I was doing
I think what I thought I was doing was looking in the pool for that prefab, and if its not present, make more of it
Oh wait this is a thread not a DM I should probably remove that gif
hhrmm okay so why did that not work, but the copy paste version does work
haha
so this entire mess happened because I couldnt use my existing method
because I needed to run code in the thing
that line is the line I copied over
which does work (maybe?)
and that thing is using "package.action.OnActionVFX"
which is just a reference to a prefab in the project
so why is my reference to a prefab now not working but that one is working
right you sent me a code snippet let me look at that
I just dropped in your actual variables for the parameters
to demonstrate what was happening
I think you just need to change particle.use to particle.myInstance.use
L:ets rewind to here
What type is myInstance?
What is that block of code
ParticleInstance
ParticleInstance doesnt run Use
That block of code is the InstantiateDamageEffect code, but with the values you passed to it instead of the parameter name
What does?
DynamicParticleDamageSprite, which is a component on the instantiated ParticleInstance prefab
So, you might need to do another getcomponent
they arent the same component because I dont want this code to exist on every single particle instance
particle.myInstance.GetComponent<DynamicParticleDamageSprite>().Use
I'm getting really confused now
particle is already a DynamicParticleDamageSprite
why would I have to get itself?
oh wait because its not itself, its the prefab from project?
You aren't. Unless myInstance is just a reference to itself
If it is, then your problems go very deep
public static void InstantiateDamageEffect(ITargetable target, DynamicParticleDamageSprite particle, int ammount)
{
InstantiateEffect(target, particle.myInstance, ammount);
if (particle != null && target.gameObject.TryGetComponent(out ItemComponent itemComponent))
{
Texture2D tex = Utils.textureFromSprite(itemComponent.sprite.sprite);
particle.Use(tex);
}
}
particle is "DynamicParticleDamageSprite particle"
thats how Im able to run use on it
Basically, right now, particle is the exact instance you have in GameGlobalManager
You want it to be one of the pooled thingies spawned from it
Yes ๐ค
I am utterly lost as to why this is happening but doesnt happen every other time I do the exact same thing
Well, you seem to be doing something right in InstantiateEffect
which uses the myInstance property of the thing in GameGlobalManager
Hence why I suggested using that for this one instead
Let me see InstantiateEffect again?
I only made the GlobalGameManager thing as a hack
the instance that is
because i didnt know how to tell it THIS PREFAB
let me get that code for you
public void InstantiateEffect(ITargetable target) // wont do effect without target.
{
if (target != null)
{
ParticleInstance thing = Pool.Use(effectPool); // pool.use is the culprit for weird clone issue.
thing.transform.position = target.gameObject.transform.position;
}
if (effectPool.Count == 0)
{
Pool.ExpandPool(this.transform, effectPool, particleInstance, poolIteration);
poolIteration += 1;
for (int i = 0; i < effectPool.Count; i++)
{
effectPool[i].parentPool = this;
}
}
}
Do you have an overload for that with 3 arguments?
oh, yes
public static void InstantiateEffect(ITargetable target, ParticleInstance particle, int ammount)
{
if (particle != null)
{
//REFACTOR: create already runs findInstance inside of itself.
ParticlePool pool = ParticlePoolInstanceManager.Instance.FindInstance(particle);
if (pool == null)
{
pool = ParticlePoolInstanceManager.Instance.CreateInstance(ammount, particle); // MAGIC NUMBER: 5 is random arbitary atm.
}
pool.InstantiateEffect(target);
}
}
Aha, I see
ParticlePool pool = ParticlePoolInstanceManager.Instance.FindInstance(particle);
Right here, particle is the prefab in the game manager
And you're getting an instance of it from the pool
๐
But you're not doing that step in InstantiateDamageEffect before calling Use
You need to make an instance of particle like you did here, and call Use on that
okay so...
Im calling the working one, and then I tried to run the extra new code after it
but.. right
right the working one is changing what "Particle" when it does its thing
but the code outside of that is still using the prefab and not the instance
I think I understand it but I would never have solved this on my own
You have been invaluable ๐ฆ
right it stops using particle and starts using pool
Pools are tricky to keep straight. You really want to make sure you have a good system in place before using it ever, retroactively adding one to code that already exists is a fine tightrope act
You run into weird edge cases like this one
Yeah up until this moment the pool was ship shape, it only broke because I tried to expand on it for a SPECIFIC edge case
and also didnt understand how it worked obviously
or I did once, and forgort
Okay so the fix is particle.Use(tex); needs to be run on ParticlePoolInstanceManager.Instance.FindInstance(particle); finding an instance matching that prefab