代号一个动画麻烦(也在纸牌演示中)?
Posted
技术标签:
【中文标题】代号一个动画麻烦(也在纸牌演示中)?【英文标题】:Codename One Animation Trouble (also in Solitaire demo)? 【发布时间】:2016-01-12 12:35:17 【问题描述】:代号一号动画发生了什么?我使用了很多,截至 12 月,我的应用程序不再工作。当我在 6 月份离开时,一切都很好(一年多以来一直如此)。
我的应用程序是一个草稿(跳棋)游戏,自 2013 年起在应用程序商店中提供。在看到 CN1 Poker 演示后,我完全重写了我的 GUI,因为我想将这些动画添加到我的应用程序中。现在发生的事情是我突然让 index out of bound 异常。我将其缩小到以下情况:
cont.addComponent(comp);
...
...
cont.getComponent(0); <-- index out of bound exception: 0 out of 0
我在 6 月份已经使用了 newVM=true,我相信这是现在的默认设置。我试图通过添加一个
来解决问题cont.animateLayoutAndWait(100);
在 addComponent 调用之后。这修复了索引超出范围的异常,但现在应用程序在短时间内正常工作后随机崩溃。我试过了,但一直找不到问题的根源。 CN1 发生了一些变化,因此我的代码不再有效。 (另请参阅旧论坛,搜索“草稿”,我在其中发布了我的基本设计的完整列表。)
我研究了新的 Solitaire 演示,它具有我需要的大部分动画功能。 Solitaire 的应用商店版本在我所有的 ios/android 设备上运行良好。一个小错误是可以拖动一组卡片,包括一些面朝下的卡片,这些卡片在拖动操作期间面朝上。也很难拿起正确数量的卡片。拖动一组卡片也会在屏幕上留下一条白色的痕迹,看起来不太好看。这也发生在模拟器中。
作为一个实验,我重新设计了我的 GUI 布局,使其与 Solitaire 代码完全相似:两层按钮,唯一的区别是我使用 GridLayout(10,10),而 Solitaire 使用 SolitaireLayout()。这是有效的,除了一件事:如果棋子在棋盘上向下移动,它会正确地移动到其他棋子上方,但如果棋子在棋盘上移动,它会在其他棋子下方移动。
我的代码如下所示:
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);
所以按钮似乎总是按它们的 GridLayout 顺序绘制,而我希望动画(移动)按钮将在最后/顶部绘制,就像纸牌中的移动卡片一样。
这是在 SolitaireLayout 和 GridLayout 中处理动画的区别吗?如果是这样,这可以在动画逻辑中改变吗?否则我必须添加一个额外的动画层和大量开销。
在 Android 上,动画(运动)无法正常工作。因此,我决定使用当前 CN1 版本(插件 3.2.6,libs 2016-01-11)在我的设备上自行构建和测试 Solitaire 演示。我将动画更改为慢 10 倍,以便更好地了解正在发生的事情。在模拟器中,布局和动画大部分都可以正常工作,但在我的 iOS 和 Android 设备上却有很多问题。
模拟器(Windows 7、NetBeans 8.0.2): - 我用文本替换了字体图标,因为它们丢失了。 - 但是如何访问汉堡菜单?我没有看到 3 个点,甚至没有空间。 - 有时可以拖动一组卡片,其中包含一些向下的卡片;拖动时,它们会暂时朝上翻转。 - 自动播放似乎并不总是有效。 (并非所有的动作都被播放。)
在 iOS 9.2 (iPad 4)、iOS 8.4 (iPhone 4) 上: - [?] 显示在汉堡菜单复选框中。 - 启动后,画面背景卡背跳到容器/屏幕的底部。 - 有时,在发牌动画中,最右边画面中的牌暂时朝上,而已经朝上的牌则翻转为朝下。然而,最终的交易状态是正确的。 - 撤消/重做:有时会导致牌组 0 上的牌面朝上,牌组 1 上的牌面朝下。 - 重做有时会“跳转”到新布局而不是动画。 仅限 iPhone: - 一系列自动播放动作留下了不一致的基础状态:顶牌红心-J、梅花-10、梅花-K、方块-Q;即,不同基础堆栈上的 2 张俱乐部卡。
在 Android 5.1.1 (Nexus 7) 上存在更多问题。 - 甲板上的交易动画不是一个漂亮的景象。卡片插入(滑动到)画面堆栈的底部,因此它们在其他卡片下方滑动。移动的牌应该面朝下,但通常面朝上,总是显示发给画面 1 的第一张牌。最右边画面中的牌暂时面朝上。最后,已经面朝上的牌被翻面朝下然后再翻过来。然而,最终的交易状态是正确的。 - 当连续有几个动作时,自动播放也不正确。在动画期间,几张面朝上的基础卡会暂时改变其卡值(正面)。移动的牌也会滑到基础牌下(有时会滑过,但这是个例外)。 - 完成游戏后,由于文本似乎没有叠加显示,而是显示在卡片下方(在一个大的空白区域中),而在屏幕顶部的一小部分中仅部分可见,因此完成游戏后,完成的屏幕已损坏。 - 开始新游戏经常失败,因为没有开始发牌;屏幕上显示了一个甲板和四个国王在地基上,而画面是空的。当敲击牌组时,会发一张牌并显示做得好的顺序。有时重复此操作会成功开始新游戏。
所有这一切已经花费了很多时间,但我的应用程序仍然无法再次运行,这非常令人沮丧。在这个话题上遇到了很多麻烦,即使下载了演示应用程序,使用 Codename One 构建这种类型的应用程序感觉就像在流沙上构建。请帮忙!
【问题讨论】:
【参考方案1】:一旦遇到麻烦,您可能应该只是问一下,而不是在帖子上如此努力。是的,作为长期存在的动画问题(并行运行的动画可能发生冲突)的错误修复的一部分,我们确实进行了重大的兼容性破坏性更改。
这引入了一些冲突,但减少了设备/模拟器之间的不一致,这总是一件好事。
我们在这里宣布了这一点:https://www.codenameone.com/blog/new-animation-manager.html
现在创建便携式动画实际上要简单得多,因为所有内容都会同步以避免动画冲突,例如如果您在动画正在进行时执行Component.removeComponent()
,它将被隐式添加到动画队列中,并在动画完成后执行,而不是立即执行。
将您的下一个动作推迟到我们拥有的动画之后:
form.getAnimationManager().flushAnimation(() -> doThisAfterAnimation());
更简单,没有特殊情况的全局锁。
将代码直接“移植”到新方法有点困难,但看起来您的动画逻辑依赖于耗时 1000 毫秒的动画,并且在方法返回时它完全完成,这可能并非总是如此(如 add/删除调用或其他逻辑可能会妨碍)。
过去,确保动画完成的唯一方法是将它们分开,但现在您可以使用flushAnimation
来确保所有动画都已完成。请记住,一些不是明确的动画的东西现在可能会意外地变成动画,例如如果在调用它们时正在运行动画,则添加/删除组件将变为动画...
【讨论】:
【参考方案2】:很抱歉,我错过了 12 月 16 日关于新动画管理器的博文。纸牌演示日期为 10 月 8 日,我查看了 12 月 31 日的开发人员指南,所以我认为我是最新的。尽管如此,我还不清楚如何使用新的动画管理器。 Januari 11 的新开发人员指南没有说明该主题,您的答案/博客文章也不是很详细。
如果将 Solitaire 演示更新为与新的动画管理器一起使用,也会有很大帮助。
现在我的问题是:
1) 如何重写以下代码以使用新的动画管理器?这是一个真实的场景,因为我有多个步骤的动画应该连续执行。
// 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) 重写这个是否也解决了一个棋子(棋子)在其他棋子下方而不是在其他棋子上移动的问题?
3) 如何在两次 testAnimation 调用之间暂停? (显然不是睡觉。)
2016-01-14 更新(另见评论部分):
我用flushAnimations尝试了两件事:
1) 使用这样的函数:
private void flushAnimations(Form f)
f.getAnimationManager().flushAnimation(() -> );
并在连续动画之间调用它。这不起作用。
2) 嵌套的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);
);
);
);
这似乎适用于 iOS,但不适用于我的 Android 设备:通常在第二个动画之后屏幕闪烁并跳转到下一个状态而不是动画。除此之外,这不是一个好的解决方案。
然后我尝试了 UITimer 解决方案:
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)
...
这可行,但也不是一个非常理想的解决方案。我有一个“自动播放”功能,可以重播由 >100 个动作组成的整个游戏,每个动作由 1 个或多个动画步骤组成。用户可以通过按下停止按钮来中断这个过程。
我非常想看看如何使用新的动画处理对扑克和纸牌(自动游戏!)演示进行编码。
请花一点时间点击这个链接,看看我在说什么类型的功能:http://toernooibase.kndb.nl/opvraag/applet.php?taal=1&kl=46&Id=4579&r=10&jr=16&wed=845502。只需按下板下方的自动播放按钮 ('>')。 (我的应用也可以玩游戏,您可以将其设置为每次移动思考 1 分钟,在此期间 GUI 被阻止。)
我看到开发者指南于 1 月 13 日更新,现在有一个关于休闲游戏编程的章节/附录。这很好,尽管它列出的 CN1Poker 版本仍然不能在 Android 设备上正常工作:发牌动画显示牌大多在跳跃,有时会滑到它们的位置。 (它在模拟器和 iOS 设备上运行良好。)
你怎么能说“现在创建便携式动画实际上要简单得多”?我认为就我而言,它实际上变得更加困难。对于扑克和纸牌演示中也使用的旧方法,我需要一种替代方法:使用 animateLayoutAndWait 并且在动画期间没有添加/删除操作(也由程序逻辑确保)。
作为一个基本订阅者(3 年了),我必须使用最新的 CN1 版本,但是对于当前的 CN1 版本,我不再知道如何编码。我认为这是一个非常基本的问题,因为所有游戏都使用这样的功能。
【讨论】:
它不能解决 2,因为这与 Z 排序有关。只需将组件“稍后”放在组件列表中即可。您可以像往常一样使用UITimer
来延迟下一次通话。我稍微修改了我的答案。请注意,您不应将更新作为答案,而应使用更多详细信息编辑您的原始问题(不更改其“核心问题”),或者只是提交一个完全可以的新问题。
我不明白如何解决 Z 排序问题。 '将组件“稍后”放在组件列表中'是什么意思?该组件是最后添加的(及时),但它当然不能在 GridLayout 顺序中最后添加,因为它的位置具有意义:它是一个棋盘。 (为什么这在旧的 Solitaire 演示中有效?)我更新了我的第二篇文章,尝试使用 flushAnimation 和 UITimer 提出您的建议。
它需要有最后一个组件索引,因此网格布局在这个意义上有点问题,因为它不是为 z 排序而设计的。我不确定是否有网格布局的解决方案。您可能可以使用TableLayout
,它在与约束一起使用时对 z 排序不敏感。尽管对于某些复杂的用法来说它更加“不稳定”。
Solitaire 应该如何解决 Z 排序问题?它在旧动画设置中有效,但在新动画设置中无效。你忽略了我最后一个问题的大部分内容,我像你问的那样编辑了我的第二个问题(参见“更新 2016-01-14”),关于同步动画和程序逻辑。这一切都非常令人失望。炫耀一些非常好的演示(我的设计基于这些演示)对用户是不公平的,这些演示由于兼容性破坏而不再起作用,而且你不能告诉我如何解决这个问题。
我只看到了一个解决方案:我敦促您尽快更新 Poker & Solitaire 演示和文档以使用新的动画管理器。请给我一个时间表!当我看到演示使用当前 CN1 再次工作时,我会从那里研究代码。以上是关于代号一个动画麻烦(也在纸牌演示中)?的主要内容,如果未能解决你的问题,请参考以下文章
如何用CSS3做过渡效果(transition)与动画(animation)麻烦告诉我