1

Ok so basically I'm trying to decorate a Libgdx Actor class with other actions

 public Shake(Button buttonToBeDecorated) extends ButtonDecorator {
      super(buttonToBeDecorated);
      Array<Action> actions = buttonToBeDecorated.getActions();

      for (Action action : actions)
            addAction(action);

      addAction(Actions.forever(new SequenceAction(
             Actions.moveBy(10, 0, 0.5f),
             Actions.moveBy(-10, 0, 0.5f)))
      );

 }

however actions from toBeDecorated class (which are also wrapped in SequenceAction) doesn't apply to instance of Shake. I'm sure that actions are passed properly because I am able to print them out. But I'm not getting combined effect, maybe some of you would know why ? Thanks

EDIT: (based on new response from @DHa)

I believe I have understood this Group-Workaround that you presented. However I still can't manage to make it work. For this instance let's assume that we decorate button object with Shake action and then with FadeOut action (Both of these classes have "Group" variable extended from parent class ButtonDecorator). So creating this type of object would look like this:

Button button = new Decorators.FadeOut(new Decorators.Shake(new Buttons.PlayButton()));

And classes:

//Shake class - we just simply add Shake actor to group and then add a specific action
//this works perfectly fine by itself - new Decorators.Shake(new Buttons.PlayButton())
public static class Shake extends ButtonDecorator {
    public Shake(Button buttonToBeDecorated) {
        super(buttonToBeDecorated);
        group.addActor(this);
        group.addAction(Actions.forever(new SequenceAction(
                Actions.moveBy(10, 0, 0.5f),
                Actions.moveBy(-10, 0, 0.5f))));

    }
}

//In FadeOut we are trying to decorate Shake object with another Action
public static class FadeOut extends ButtonDecorator {
    public FadeOut(Button buttonToBeDecorated) {
        super(buttonToBeDecorated);
        Array<Action> actions = buttonToBeDecorated.group.getActions(); //getting actions from Shake
        group.addActor(buttonToBeDecorated);
       /* I'm guessing that the whole workaround is in this line. We are adding
          Shake-actor to FadeOut group so Shake-actions should no longer apply
          to Shake-object and can be applied to our new FadeOut button */

        group.addActor(this); //Adding FadeOut to it's own group
        for (Action action : actions) 
            group.addAction(Actions.parallel(action,new SequenceAction(Actions.fadeOut(3), Actions.fadeIn(3)))) 
            //besides adding shake actions to FadeOut object we are also adding parallel fadeout action



    }
}

I don't know why but still only one action (fading out) is applied to created object

JohnnyGat
  • 325
  • 2
  • 13
  • Your new version doesn't copy the Action object. It copies the reference to that same Action object. Since the Action classes do not have copy constructors, the only way to copy them is to make a new one from scratch and manually copy each parameter. – Tenfour04 Apr 28 '18 at 19:38
  • I'm not following your questions. What does copying a method mean? It sounds like you aren't yet familiar with some of the basics of object-oriented programming, so you may need to go through the Java tutorials on Sun's web site. – Tenfour04 May 07 '18 at 00:09

2 Answers2

2

Use the Group actor to combine several actors. Actions applied to that group will be applied to all actors in the group.

Group group = new Group();

group.addActor(actor1);
group.addActor(actor2);

group.addAction(...);

However, one actor can only be part of one group, so you cannot mix and match actions between different actors.

For example:

Group group1 = new Group();

group1.addActor(actor1);
group1.addActor(actor2);

Group group = new Group();

group2.addActor(actor2);
group2.addActor(actor3);

group1.addAction(...); // will only apply to actor1 since actor2 left group1 when joining group2

I figured a much better answer than my previous, the other answer is still technically correct so I'll keep it around as well.

DHa
  • 659
  • 1
  • 6
  • 21
  • I have added another edit base on your response. Please take a look at it if you have a moment – JohnnyGat May 17 '18 at 12:39
  • @user3713267 Your new solution might work if using Actions.parallel(action1, action2) as several actions added to an actor will by default be used in sequence, not in parallel – DHa May 18 '18 at 18:58
  • unfortunately it doesn't. Maybe I did something wrong but even when I'm adding actions parallel it still only apply second action. I have edit the code accordingly – JohnnyGat May 22 '18 at 16:08
1

Each action has one actor target, so it should not be possible to assign one and the same action to multiple actors. You would have to copy the actions to achieve the intended effect.

What should happen when you assign an action to a second actor is that the action target switches to the second actor rather than both actors now being target of the action.

Actor

public void addAction (Action action) {
    action.setActor(this);

Action

public void setActor (Actor actor) {
    this.actor = actor;
    if (target == null) setTarget(actor);

MoveByAction (the one you are using)

protected void updateRelative (float percentDelta) {
    target.moveBy(amountX * percentDelta, amountY * percentDelta);
}

Response to edit:

The new solution wraps the action rather than copies it, it will make little difference compared to the original, the actions cannot be used on more than one target at a time. The basic problem is that actors do not have actions (except for bookkeeping), actions have singular targets that they act upon.

I can see some ways around this (in order of my recommendation):

  1. If the actions don't have to be exact copies, create copies of them from a factory method
  2. Create a middle-man actor which can contain multiple targets and then forwards all the calls actions make to it to all its targets (in the particular case it would receive moveBy calls)
  3. Make a soft copy of the action using the setters/getters of the action
  4. Make a hard copy of the action before you reassign it: deep copying objects
DHa
  • 659
  • 1
  • 6
  • 21
  • Hi I've added edit segment to my post based on your response, please take a look at it – JohnnyGat Apr 27 '18 at 19:17
  • Thinking about it a little bit more I figure that setting an new actor for given action is exactly what I wanted. I want to decorate button with different actions, which means adding more actions to an actor, wich means setting a same actor for different actions. I want all actions targets to be set to one particular button-actor so new Shaking( new Fading( new Button())) would take action from Fading decorator and set its target to a button which also has Shaking actions. So shouldn't my first solution work like that ? – JohnnyGat May 04 '18 at 15:46