Libgdx中Actor动作传递问题:装饰Button时原有动作不生效
Hey there! Let's break down why your original Button's SequenceAction isn't firing, and how to fix it.
The Root of the Problem
When you copied the original Button's actions into your Shake decorator, you missed a key detail about LibGDX Actions: each Action holds a reference to the Actor it was added to. Those copied Actions were still targeting the original Button, not your decorator. Since you're using the decorator in place of the original Button (and probably didn't add the original to the Stage), its act() method never gets called—so its actions never run.
The Correct Decorator Approach
Instead of copying actions, your decorator should wrap the original Button as a child Actor, ensuring its full lifecycle (including action updates) is preserved. Here's how to adjust your code:
First, update your base ButtonDecorator to properly proxy the decorated Button:
public class ButtonDecorator extends Actor { protected Button decoratedButton; public ButtonDecorator(Button buttonToBeDecorated) { decoratedButton = buttonToBeDecorated; // Add the original button as a child so it's rendered and updated addActor(decoratedButton); // Sync size and position to match the original button setSize(decoratedButton.getWidth(), decoratedButton.getHeight()); decoratedButton.setPosition(0, 0); } @Override public void act(float delta) { super.act(delta); // Run the decorator's own actions first decoratedButton.act(delta); // Ensure the original button's actions are updated } // Proxy hit detection to the original button so clicks work correctly @Override public Actor hit(float x, float y, boolean touchable) { return decoratedButton.hit(x, y, touchable); } @Override public void draw(Batch batch, float parentAlpha) { super.draw(batch, parentAlpha); decoratedButton.draw(batch, parentAlpha); // Render the original button } }
Then simplify your Shake decorator to focus on adding its own effect:
public class Shake extends ButtonDecorator { public Shake(Button buttonToBeDecorated) { super(buttonToBeDecorated); // Add the shake action to the decorator itself—this will move the entire wrapped button addAction(Actions.forever(new SequenceAction( Actions.moveBy(10, 0, 0.5f), Actions.moveBy(-10, 0, 0.5f) ))); } }
Why This Works
- The original Button is now a child of the decorator, so its
act()method gets called every frame—meaning its original SequenceAction will run as expected. - The shake action applies to the decorator, which moves the entire container (including the child Button), creating the desired visual effect without breaking the original button's behavior.
- All input and rendering logic is proxied to the original Button, so clicks and appearance remain unchanged.
内容的提问来源于stack exchange,提问作者JohnnyGat

