Hello Guest

Author Topic: Change the material of each sprite in SpriteDefinition at run time.  (Read 6868 times)

eklavyaa

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 20
    • View Profile
Hi,

I have a sprite collection for torso of bear.This collection have frames for running of bear. Now I want to have bear in some other colored shirt say yellow. I don't want to create running frames of bear  in yellow shirt. So I am thinking of :-

1] Create a copy of the green shirt's atlas0.png, which is created inside the sprite collection data of green shirt sprite collection.
2] Create its own material.

Then at run time depending on which shirt Player selects, I will change the material and atlas in the sprite definitions.But I will be accessing sprite collection data via the tk2dSprite. Like this:-

Code: [Select]
tk2dSpriteCollectionData torso = transform.FindChild ("Torso").GetComponent<tk2dSprite> ().Collection;
I did it manually as of now, it works fine.

My question is :-

1] Is this approach can break the things, as I am not updating "Source texture GUID" ? but changing the source atlas and material directly.
2] What may be the better way of achieving what I am trying.



unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #1 on: March 24, 2015, 09:05:55 am »
1. You can do that, its not really a problem if you're messing about with it at runtime.
2. You could probably do it without multiple atlases by using shaders, but how to do it will require a ton of explaining and is completely out of scope. The basic gist is, somehow identify the parts that need to change color, and replace that color in the shader.

eklavyaa

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 20
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #2 on: March 30, 2015, 07:32:54 am »
I am able to change the sprite collection data at runtime. But the change is reflected in once I close the game and start again. So all I need is to refer the latest updated sprite collection at ru time . So I did following but it is not working, it doesnot refer to the latest sprite collection.I have marked the collection as loadable

Code: [Select]
tk2dSpriteCollectionData collectionData = animatorObject.gameObject.GetComponent<tk2dSprite> ().Collection;
SetAtlasAndMaterialAsPerClothsSelected (collectionData); // here I have updated the material and atlas as per my need
animatorObject.GetComponent<tk2dBaseSprite>().
SetSprite(tk2dSystem.LoadResourceByName<tk2dSpriteCollectionData>("Boy_Mid_Torso1_SpriteCollection"),
                                                                                                "boy_mid_jump_torso"
                                                                                               );




EDIT : I have been able to do it using following code , I had to strip away the tk2dSprite and tk2dSpriteAnimator to add it at run time : -


      
Code: [Select]
tk2dSpriteCollectionData scData = Resources.Load("Temp/Boy_Mid_Torso1_SpriteCollection",typeof(tk2dSpriteCollectionData)) as tk2dSpriteCollectionData ;


SetAtlasAndMaterialAsPerClothsSelected (scData);

part.gameObject.AddComponent<tk2dSprite>();

animatorObject = part.gameObject.AddComponent<tk2dSpriteAnimator> ();

part.gameObject.GetComponent<tk2dSprite>().SetSprite(scData,"Home_idle_torso");

EDIT 2: I just found that above way of setting the collection doesnot actually set the sprite collection. The tk2dSprite is not referencing any sprite collection when I check in inspector, but some how animation is playing. What might be wrong ?

Although it plays the animation but before playing it it throws NullReferenceException at line following function Bold Line

Code: [Select]
public void SetSprite(tk2dSpriteCollectionData newCollection, int newSpriteId) {
bool switchedCollection = false;
if (Collection != newCollection) {
collection = newCollection;
[b] collectionInst = collection.inst; [/b] // throws NullReferenceException.
_spriteId = -1; // force an update, but only when the collection has changed
switchedCollection = true;
}

spriteId = newSpriteId;

if (switchedCollection) {
UpdateMaterial();
}
}

My concern is If its not able to get the reference then how animation is playing ?

Edit 3: I just found that the sprite collection I am messing up with that is Boy_Mid_Torso1_SpriteCollection, cannot be found by the system. While setting this sprite collection for in animation editor, It keeps on Scanning the project folder forever for Rebuilding the indexes and throws error "Sprite Collection cannot be found : this is serious problem" . What went wrong ? How to fix it ?
« Last Edit: March 31, 2015, 03:31:58 pm by eklavyaa »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #3 on: March 31, 2015, 10:37:05 pm »
I don't know what went wrong = you will need to debug this. But from your description all you really needed to do is change the textures on the material, why aren't you doing that?

The animator will have direct links to things there too. In your second code snippet, is anything null? Looks like scData is null.

eklavyaa

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 20
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #4 on: April 01, 2015, 05:29:20 am »
Quote
all you really needed to do is change the textures on the material, why aren't you doing that?
I tried it, it changes the texture for a second, then change it back to the original one. I think its happening because as soon as animation is played it refers the one to which sprite collection points. For a proof I didn't play the animation and the new texture was there.

 What you think ?

Also this line

Code: [Select]
scData = tk2dSystem.LoadResourceByName<tk2dSpriteCollectionData>("Boy_Mid_Torso1_SpriteCollection");

returns null. The sprite collection is marked loadable.
« Last Edit: April 01, 2015, 05:36:18 am by eklavyaa »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #5 on: April 01, 2015, 07:36:45 am »
Regarding that line - I don't know why it isn't working. The tk2dSystem stuff isn't public API simply because it hasn't been tested outside the internal use case, which is to load platform sprite collections.

If you want to change materials at runtime, use the tk2dSprite.SpriteChanged callback to change the material every time the sprite changes. Basically, when the material changes, you find your own equivalent copy of the material and switch that. http://2dtoolkit.com/forum/index.php/topic,4877.msg22563.html#msg22563

eklavyaa

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 20
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #6 on: April 01, 2015, 09:31:04 am »
Thanks for the link.

I found an idea from one of your answers  here http://2dtoolkit.com/forum/index.php?topic=356.0#msg_1529  :P

So now I am doing following.

1] Keep the tk2dsprite already added to the gameobject and set the expected sprite collection. , earlier I was adding it at run time.
2] Now at run time decide upon which animation to play and set its animation library.
3] Now, on this gameobject's tk2dSprite do following :-

Code: [Select]
sprite.GetCurrentSpriteDef ().material.SetTexture ("_MainTex", Resources.Load (pathForShirt + "atlas0") as Texture);
One most important thing its doing is getting "current" sprite definitions. and that is all I wanted. Directly modifying the sprite definitions which are currently loaded in memory. It works like charm.

my only concern now is that : Whether this approach can break things ? as I am not changing the material any where but only textures.My earlier approach corrupted the sprite collection and I had to create sprite collection again. Once you confirm this I am good to go :)


unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Change the material of each sprite in SpriteDefinition at run time.
« Reply #7 on: April 02, 2015, 03:54:08 pm »
This will work, but be careful about the definition of "currently loaded in memory". In Unity the object thats in your project folder is the same thing thats loaded in memory, so changing data there may change the actual asset (if it gets saved). If you're only changing the texture - worst case, it ends up bound to the wrong images...

The approach I suggested will change the material on the instance that is rendering it, so is definitely way safer.