Codename One Animation Trouble (also in Solitaire demo)?

做~自己de王妃 提交于 2019-12-05 17:17:23

You should have probably just asked once you ran into trouble instead of working so hard on the post. Yes we did make a major somewhat compatibility breaking change as part of a bug fix for long standing animation issues (where animations running in parallel could collide).

This introduced some collisions but reduced inconsistencies between devices/simulator which is always a good thing.

We announced this here: https://www.codenameone.com/blog/new-animation-manager.html

It is actually MUCH simpler to create a portable animation now as everything will get synchronized to avoid animation collisions e.g. if you do Component.removeComponent() while an animation is in progress it will be implicitly added to the animation queue and performed after the animation completes instead of immediately.

To postpone your next action until after the animations we have:

form.getAnimationManager().flushAnimation(() -> doThisAfterAnimation());

Much simpler and no special case global locks.

Its a bit hard to "port" code directly to the new approach but it looks like your animate logic relies on the animation taking 1000ms and that it completely finished when the method returns which might not always be the case (as add/remove calls or other logic might get in the way).

In the past the only way to guarantee an animation was complete was to distance them apart but now you can just use flushAnimation to make sure all animations have completed. Keep in mind that some things that aren't explicitly an animation can now become an animation by accident e.g. an add/remove component will become an animation if there is an animation in progress when you call them...

I'm sorry I missed the blog post on the new animation manager of December 16. The Solitaire demo dates October 8 and I checked the Developer Guide of December 31, so I thought I was up to date. Still, it is not clear to me how to use the new animation manager. The new Developer Guide of Januari 11 says nothing on the topic and your answer/blog post are not very elaborate.

It would also help a lot if the Solitaire demo would be updated to work with the new animation manager.

Now my questions are:

1) How do I rewrite the following code to use the new animation manager? This is a realistic scenario because I have animations with multiple steps that should be performed consecutively.

// simplified code (background layer omitted)
public void start() {
    if(current != null){
        current.show();
        return;
    }

    Form form = new Form("Draughts 2");
    Container piecesCnt = new Container(new GridLayout(10, 10));
    for (int i=0; i<100; i++) {
        piecesCnt.addComponent(createPieceButton(piece(i), true));
    }
    form.addComponent(piecesCnt);
    form.show();

    new UITimer(() -> {
        testAnimation(piecesCnt, 0,9 , 9,0);    // moves UNDER other pieces
        testAnimation(piecesCnt, 9,0 , 0,9);    //   "   OVER    "     "
        testAnimation(piecesCnt, 1,0 , 9,8);    //   "   OVER    "     "
        testAnimation(piecesCnt, 9,8 , 1,0);    //   "   UNDER   "     "
    }).schedule(1500, false, form);
}

private void testAnimation(Container piecesCnt, int x1,int y1, int x2,int y2) {
    int a1 = 10 * y1 + x1;
    int a2 = 10 * y2 + x2;        
    Button pc = (Button)piecesCnt.getComponentAt(a1);
    Button to = (Button)piecesCnt.getComponentAt(a2);
    piecesCnt.removeComponent(pc);
    piecesCnt.addComponent(a1, createPieceButton(Piece.EMPTY_PIECE, true));
    piecesCnt.removeComponent(to);
    piecesCnt.addComponent(a2, pc);
    piecesCnt.animateLayoutAndWait(1000);
}

2) Does rewriting this also solve the problem of a piece (checker) moving under instead of over other pieces?

3) How do I pause between two testAnimation calls? (Not by sleeping, obviously.)


Update 2016-01-14 (see also the Comment section):

I tried two things with flushAnimations:

1) Use a function like this:

private void flushAnimations(Form f) {
    f.getAnimationManager().flushAnimation(() -> {});
}

and call this between successive animations. This doesn't work.

2) Nested flushAnimations:

testAnimation(piecesCnt, 0,9 , 9,0);
f.getAnimationManager().flushAnimation(() -> {
    testAnimation(piecesCnt, 9,0 , 0,9);
    f.getAnimationManager().flushAnimation(() -> {
        testAnimation(piecesCnt, 1,0 , 9,8);
        f.getAnimationManager().flushAnimation(() -> {
            testAnimation(piecesCnt, 9,8 , 1,0);
        });
    });
});

This does seem to work on iOS but not on my Android device: usually after the second animation the screen flickers and jumps to the next state instead of animating. Apart from that it is not a nice solution.

Then I tried the UITimer solution:

blockUI(piecesCnt);
new UITimer(() -> { testAnimation(piecesCnt, 0,9 , 9,0); }).schedule(2000, false, f);
new UITimer(() -> { testAnimation(piecesCnt, 9,0 , 0,9); }).schedule(3500, false, f);
new UITimer(() -> { testAnimation(piecesCnt, 1,0 , 9,8); }).schedule(5000, false, f);
new UITimer(() -> { testAnimation(piecesCnt, 9,8 , 1,0); }).schedule(6500, false, f);
new UITimer(() -> { 
    unblockUI(piecesCnt); 
}).schedule(8000, false, f);

private boolean blocked = false;    
private void blockUI(Container piecesCnt) {
    blocked = true;
    int n = piecesCnt.getComponentCount();
    for (int i=0; i<n; i++) {
        piecesCnt.getComponentAt(i).setDraggable(false);
    }
}
private void unblockUI(Container piecesCnt) {
    ...
}

This works but is also not a very desirable solution. I have a function 'autoplay' that replays an entire game consisting of >100 moves, each move consisting of 1 or more animation steps. The user can interrupt this process by pressing a stop button.

I would very much like to see how the Poker and Solitaire (Autoplay!) demos should be coded with the new animation handling.

Please take a minute to follow this link to see what kind of functionality I am talking about: http://toernooibase.kndb.nl/opvraag/applet.php?taal=1&kl=46&Id=4579&r=10&jr=16&wed=845502. Just press the autoplay button ('>') below the board. (My app can also play the game, and you can set it to think for say 1 minute per move, during which the GUI is blocked.)

I saw that the Developer Guide was updated Jan 13, and now has a chapter/appendix on Casual Game Programming. This is nice, although the CN1Poker version it lists still doesn't properly work on an Android device: the dealing cards animation shows the cards mostly jumping and sometimes sliding to their positions. (It works fine in the Simulator and on iOS devices.)

How can you say it is 'actually MUCH simpler to create a portable animation now'? I think in my case it actually just became much harder. I need an alternative for the old approach which is also used in the poker and solitaire demos: use animateLayoutAndWait and have no add/remove actions during an animation (also made sure by program logic).

As a basic subscriber (for 3 years now) I have to use the latest CN1 version, but with the current CN1 version I no longer know how to code this. I think this is a quite fundamental issue as all games use functionality like this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!