playMaker

Author Topic: Specify Gameobject  (Read 6625 times)

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Specify Gameobject
« on: February 11, 2014, 07:59:54 AM »
Hi I made a custom action for Spine (Its a skeletal animation system, esotericsoftware.com)
The action picks a hashtable of colors from ArrayMaker and tint the Slots(where attachments and colors are stored). The action also needs to specify a gameobject with the Spine component and other with the arraymaker component.

The problem starts when I create a FsmGameObject variable to specify the gameobject with the Spine component and reuse It.
Reusing the same variable makes that every time the action is called, also tint the past gameobject used for this variable.

So if you have 3 gameobjects to tint and the 3 were used for this variable. The 3 gameobject will be tinted with the same color at the same time, no matter what gameobject is selected for this variable.

Here is the custom action.
Quote
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Spine;
namespace HutongGames.PlayMaker.Actions
{
    [ActionCategory("2D Spine")]
    [Tooltip("Set color")]
   public class SpineSetColor : HashTableActions
  {
     [RequiredField]
     [Tooltip(The Game Object must have a SkeletonAnimation component attached.")]
     
      [CheckForComponent(typeof(SkeletonAnimation))]
        public FsmOwnerDefault gameObject;

      [RequiredField]
      [Tooltip("The gameObject with the PlayMaker HashTable Proxy component")]
      [CheckForComponent(typeof(PlayMakerHashTableProxy))]
      public FsmOwnerDefault gameObject2;

      [Tooltip("Author defined Reference of the PlayMaker HashTable Proxy component ( necessary if several component coexists on the same GameObject")]
      [UIHint(UIHint.FsmString)]
      public FsmString reference;


private SkeletonAnimation skeletonAnimation;
private Slot slot;


private void _getSkeletonAnimation()
       {
          GameObject go = Fsm.GetOwnerDefaultTarget(gameObject);
            if (go == null)
               {
                return;
               }

         skeletonAnimation = go.GetComponent<SkeletonAnimation>();
       }


public override void Reset()
       {
          gameObject = null;
         gameObject2 = null;
         reference = null;
         
       }

public override void OnEnter()
       {
         if (SetUpHashTableProxyPointer(Fsm.GetOwnerDefaultTarget(gameObject2),reference.Value))
         
          _getSkeletonAnimation();

         skeletonAnimation.UpdateBones += SetColor;

                  
         Finish ();
         
       }
   


void SetColor(SkeletonComponent skeletonAnimation)

       {
           if (skeletonAnimation == null)
              {
               LogWarning("Missing skeletonAnimation component");
               return;
              }

          else
              {

            foreach (DictionaryEntry entry in proxy.hashTable)
              {
               string slotName = entry.Key as string;

               slot = skeletonAnimation.skeleton.FindSlot(slotName);
               Color color = (Color)entry.Value;

               slot.R = 1;
               slot.G = 1;
               slot.B = 1;
               slot.A = 1;
                slot.R *= color.r;
                slot.G *= color.g;
                slot.B *= color.b;
                slot.A *= color.a;
         

              }


           }

       }
  }

}

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Specify Gameobject
« Reply #1 on: February 11, 2014, 01:17:33 PM »
Hi,

 can you share a working scene? I'll test it.

bye,

 Jean

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Specify Gameobject
« Reply #2 on: February 12, 2014, 01:35:18 PM »
Hi,

 the problem is elsewhere, basically, you are not using the right method to update the skeleton.

using a delegate for the update is not what you want, you need to manually set the color once, not when the skeleton updates itself. So instead, call SetColor once.

 Does that make sense?

Also, I refactored your public variables, "gameobject2" is not a nice naming convention... :)

Bye,

 Jean

Code: [Select]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Spine;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory("2D Spine")]
[Tooltip("Add Animation. \nNOTE: The Game Object must have a SkeletonAnimation attached.")]
public class SpineSetColor : HashTableActions
{
[ActionSection("HashTable")]

[RequiredField]
[Tooltip("The gameObject with the PlayMaker HashTable Proxy component")]
[CheckForComponent(typeof(PlayMakerHashTableProxy))]
public FsmOwnerDefault gameObject;

[Tooltip("Author defined Reference of the PlayMaker HashTable Proxy component ( necessary if several component coexists on the same GameObject")]
[UIHint(UIHint.FsmString)]
public FsmString reference;

[ActionSection("Target")]

[RequiredField]
[Tooltip("The Game Object to work with. NOTE: The Game Object must have a SkeletonAnimation component attached.")]
     
[CheckForComponent(typeof(SkeletonAnimation))]
public FsmOwnerDefault skeleton;
private SkeletonAnimation skeletonAnimation;
private Slot slot;

private void _getSkeletonAnimation ()
{
GameObject go = Fsm.GetOwnerDefaultTarget (skeleton);
if (go == null) {
return;
}

skeletonAnimation = go.GetComponent<SkeletonAnimation> ();
}

public override void Reset ()
{
gameObject = null;
skeleton = null;
reference = null;
         
}

public override void OnEnter ()
{
if (SetUpHashTableProxyPointer (Fsm.GetOwnerDefaultTarget (gameObject), reference.Value))
{
_getSkeletonAnimation ();
}

SetColor(skeletonAnimation);
//skeletonAnimation.UpdateBones  += SetColor;

         
Finish ();

}

void SetColor (SkeletonComponent skeletonAnimation)
{
if (skeletonAnimation == null) {
LogWarning ("Missing skeletonAnimation component");
return;
} else {

foreach (DictionaryEntry entry in proxy.hashTable) {
string slotName = entry.Key as string;

slot = skeletonAnimation.skeleton.FindSlot (slotName);
Color color = (Color)entry.Value;

slot.R = 1;
slot.G = 1;
slot.B = 1;
slot.A = 1;
slot.R *= color.r;
slot.G *= color.g;
slot.B *= color.b;
slot.A *= color.a;


}


}

}
}

}

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Re: Specify Gameobject
« Reply #3 on: February 12, 2014, 09:51:43 PM »
Hi,

 the problem is elsewhere, basically, you are not using the right method to update the skeleton.

using a delegate for the update is not what you want, you need to manually set the color once, not when the skeleton updates itself. So instead, call SetColor once.

 Does that make sense?

Also, I refactored your public variables, "gameobject2" is not a nice naming convention... :)

Bye,

 Jean

Code: [Select]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Spine;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory("2D Spine")]
[Tooltip("Add Animation. \nNOTE: The Game Object must have a SkeletonAnimation attached.")]
public class SpineSetColor : HashTableActions
{
[ActionSection("HashTable")]

[RequiredField]
[Tooltip("The gameObject with the PlayMaker HashTable Proxy component")]
[CheckForComponent(typeof(PlayMakerHashTableProxy))]
public FsmOwnerDefault gameObject;

[Tooltip("Author defined Reference of the PlayMaker HashTable Proxy component ( necessary if several component coexists on the same GameObject")]
[UIHint(UIHint.FsmString)]
public FsmString reference;

[ActionSection("Target")]

[RequiredField]
[Tooltip("The Game Object to work with. NOTE: The Game Object must have a SkeletonAnimation component attached.")]
     
[CheckForComponent(typeof(SkeletonAnimation))]
public FsmOwnerDefault skeleton;
private SkeletonAnimation skeletonAnimation;
private Slot slot;

private void _getSkeletonAnimation ()
{
GameObject go = Fsm.GetOwnerDefaultTarget (skeleton);
if (go == null) {
return;
}

skeletonAnimation = go.GetComponent<SkeletonAnimation> ();
}

public override void Reset ()
{
gameObject = null;
skeleton = null;
reference = null;
         
}

public override void OnEnter ()
{
if (SetUpHashTableProxyPointer (Fsm.GetOwnerDefaultTarget (gameObject), reference.Value))
{
_getSkeletonAnimation ();
}

SetColor(skeletonAnimation);
//skeletonAnimation.UpdateBones  += SetColor;

         
Finish ();

}

void SetColor (SkeletonComponent skeletonAnimation)
{
if (skeletonAnimation == null) {
LogWarning ("Missing skeletonAnimation component");
return;
} else {

foreach (DictionaryEntry entry in proxy.hashTable) {
string slotName = entry.Key as string;

slot = skeletonAnimation.skeleton.FindSlot (slotName);
Color color = (Color)entry.Value;

slot.R = 1;
slot.G = 1;
slot.B = 1;
slot.A = 1;
slot.R *= color.r;
slot.G *= color.g;
slot.B *= color.b;
slot.A *= color.a;


}


}

}
}

}
Hi,

Its a bit complex why I use a delegate.
My animations(not the animation used in the repro) have keys that override colors, so if you just set the color, the animation will override it in the first keyframe. So I need to call updateBones in SkeletonAnimation in order to maintain the setting color.

Here is the thread with the explanation:
http://esotericsoftware.com/forum/viewtopic.php?f=3&t=1852

And here you have a json with key colors that work with the repro


Thank you

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Specify Gameobject
« Reply #4 on: February 13, 2014, 02:29:45 AM »
Hi,

Can you send me a repro with an actual character that has this feature?

bye,

 Jean

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Re: Specify Gameobject
« Reply #5 on: February 13, 2014, 03:21:36 AM »
Hi,

Can you send me a repro with an actual character that has this feature?

bye,

 Jean

Just change the json You have in the repro with the json I posted. It will change the head to orange and green.

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Re: Specify Gameobject
« Reply #6 on: February 18, 2014, 01:06:43 AM »
Bump this!

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Re: Specify Gameobject
« Reply #7 on: February 19, 2014, 12:22:52 AM »
Hi Jean I think there is a problem with this line of code:

void SetColor (SkeletonComponent skeletonAnimation)

Also tried
void SetColor (SkeletonAnimation skeleton)

Its come from SkeletonAnimation:

public delegate void UpdateBonesDelegate(SkeletonAnimation skeleton);

Here is the complete code:

Code: [Select]
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using Spine;

/** Extends SkeletonComponent to apply an animation. */
[ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class SkeletonAnimation : SkeletonComponent {
public bool loop;
public Spine.AnimationState state;

public delegate void UpdateBonesDelegate(SkeletonAnimation skeleton); public UpdateBonesDelegate UpdateBones;

public String _animationName;
public String animationName {
get {
TrackEntry entry = state.GetCurrent(0);
return entry == null ? null : entry.Animation.Name;
}
set {
if (_animationName == value) return;
_animationName = value;
if (value == null || value.Length == 0)
state.ClearTrack(0);
else
state.SetAnimation(0, value, loop);
}
}

override public void Initialize () {
if (Initialized) return;

base.Initialize();

state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData());
if (_animationName != null && _animationName.Length > 0) state.SetAnimation(0, _animationName, loop);
}

override public void UpdateSkeleton (float deltaTime) {
// Apply the animation.
state.Update(deltaTime * timeScale);
state.Apply(skeleton);

if (UpdateBones != null) UpdateBones(this);

// Call overridden method to call skeleton Update and UpdateWorldTransform.
base.UpdateSkeleton(deltaTime);
}
}

Maybe its a reference problem? Like the delegate don't know who is the gameobject to work it?

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Specify Gameobject
« Reply #8 on: February 24, 2014, 03:18:50 AM »
Hi,

 It's simply that you shoudl always remove a delegate link, in your action you add you method to the delegate, but when the action finished you should remove that link as well.

Code: [Select]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Spine;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory("2D Spine")]
[Tooltip("Add Animation. \nNOTE: The Game Object must have a SkeletonAnimation attached.")]
public class SpineSetColor : HashTableActions
{
[ActionSection("HashTable")]

[RequiredField]
[Tooltip("The gameObject with the PlayMaker HashTable Proxy component")]
[CheckForComponent(typeof(PlayMakerHashTableProxy))]
public FsmOwnerDefault gameObject;

[Tooltip("Author defined Reference of the PlayMaker HashTable Proxy component ( necessary if several component coexists on the same GameObject")]
[UIHint(UIHint.FsmString)]
public FsmString reference;

[ActionSection("Target")]

[RequiredField]
[Tooltip("The Game Object to work with. NOTE: The Game Object must have a SkeletonAnimation component attached.")]
     
[CheckForComponent(typeof(SkeletonAnimation))]
public FsmOwnerDefault skeleton;
private SkeletonAnimation skeletonAnimation;
private Slot slot;

private void _getSkeletonAnimation ()
{
GameObject go = Fsm.GetOwnerDefaultTarget (skeleton);
if (go == null) {
return;
}

skeletonAnimation = go.GetComponent<SkeletonAnimation> ();
}

public override void Reset ()
{
gameObject = null;
skeleton = null;
reference = null;
         
}

public override void OnExit()
{
skeletonAnimation.UpdateBones  -= SetColor;
}

public override void OnEnter ()
{
if (SetUpHashTableProxyPointer (Fsm.GetOwnerDefaultTarget (gameObject), reference.Value))
{
_getSkeletonAnimation ();
}

//SetColor(skeletonAnimation);
skeletonAnimation.UpdateBones  += SetColor;

         
Finish ();

}

void SetColor (SkeletonComponent skeletonAnimation)
{
if (skeletonAnimation == null) {
LogWarning ("Missing skeletonAnimation component");
return;
} else {

foreach (DictionaryEntry entry in proxy.hashTable) {
string slotName = entry.Key as string;

slot = skeletonAnimation.skeleton.FindSlot (slotName);
Color color = (Color)entry.Value;

slot.R = 1;
slot.G = 1;
slot.B = 1;
slot.A = 1;
slot.R *= color.r;
slot.G *= color.g;
slot.B *= color.b;
slot.A *= color.a;


}


}

}
}

}

Bye,

 Jean

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Re: Specify Gameobject
« Reply #9 on: February 24, 2014, 10:14:03 AM »
Hi Jean, I tried your code but when you remove the delegate link, you are also removing the colors. I think I need to stay with this delegate in order to keep the colors.

What I don't understand is why affect all instances. If I have a skeletonAnimation component for each instance, why the delegate works like if were only one instance.

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Specify Gameobject
« Reply #10 on: February 24, 2014, 01:01:17 PM »
Hi,

 I think that garbage collection can not do its job because this action instance that assigned itself to that delegate is therefore in use and can not be destroyed and released from memory, therefore the ghost bug of an action that seems not there anymore.

 I think you are approching the wrong way, you can't expect a behavior to carry on having an effect if it's not "active" any more, hence if your character keep changing color and you want to overide this, you have a problem, it has to be ALWAYS overriding. So you need one fsm on each character each responsible for overriding its own color, and your random system would simply send a global event to the character to tell it its color, that's all,

bye,

 Jean

spiral

  • Playmaker Newbie
  • *
  • Posts: 18
Re: Specify Gameobject
« Reply #11 on: February 24, 2014, 02:13:53 PM »
Yes, right now I put this action in each gameobject to get it works. I was searching for a global way, like a color manager that tint all the game objects.

So the best way is a exclusive fsm with one state(with the action), so when the gameobject is not active, the delegate will be removed?

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Specify Gameobject
« Reply #12 on: February 25, 2014, 02:42:07 AM »
Hi,

 yes, when the action is deactivated the delegate will be removed ( when the state is left for example).

bye,

 Jean