What happened to Codename One animations? I use a lot of them and as of december my app is no longer working. When I left things in June everything was fine (and was so for more than a year).
My app is a draughts (checkers) game and is available in the app stores since 2013. After seeing the CN1 Poker demo, I completely rewrote my GUI as I wanted to add those kind of animations to my app. What happens now is that I suddenly get index out of bound exceptions. I narrowed this down to the following situation:
cont.addComponent(comp);
...
...
cont.getComponent(0); <-- index out of bound exception: 0 out of 0
I already used newVM=true in June, which is now the default, I believe. I tried to fix things by adding a
cont.animateLayoutAndWait(100);
after the addComponent call. This fixed the index out of bound exceptions, but now the app just crashes at random moments after working fine for a short time. I tried but have been unable to find the source of the problem. Something has changed in CN1 so that my code no longer works. (See also the old forum, search for "draughts", where I posted a complete listing of my basic design.)
I studied the new Solitaire demo, which has most of the animation functionality I need. And the app store versions of Solitaire run fine on all my iOS/Android devices. A minor bug is that it is possible to drag a group of cards including some that are facing down, which are facing up during the drag operation. Also it is pretty hard to pick up exactly the right amount of cards. Dragging a group of cards also leaves a white trail on the screen, which doesn't look very nice. This also happens in the Simulator.
As an experiment, I redesigned my GUI layout to exactly resemble that of the Solitaire code: two layers of buttons, the only difference being that I use GridLayout(10,10) where Solitaire uses SolitaireLayout(). This works, except for one thing: if a checker moves DOWN the board it correctly moves OVER other checkers, but if a checker moves UP the board it moves UNDER the other checkers.
My code looks like this:
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);
So it seems that the buttons are always drawn in their GridLayout order, while I hoped that the animated (moving) button would be drawn last/on top, just like the moving cards in Solitaire.
Is this a difference between handling animation in SolitaireLayout vs. GridLayout? If so, can this be changed in the animation logic? Otherwise I have to add an extra animation layer and a lot of overhead.
And on Android, the animation (movement) is not working properly. So I decided to also self-build and test the Solitaire demo on my devices with the current CN1 version (plugin 3.2.6, libs 2016-01-11). I changed the animations to be 10x slower, to better see what is happening. In the Simulator, the layout and animations work mostly fine but on my iOS and Android devices there are a lot of problems.
Simulator (Windows 7, NetBeans 8.0.2):
- I replaced the font icons by text since they are missing.
- But how to access the hamburger menu? I don't see the 3 dots and there is even no space for it.
- Sometimes it is possible to drags a groups of cards with some downfacing cards taken; while dragged they are temporarily flipped facing up.
- Autoplay doesn't always seem to work. (Not all moves are played.)
On iOS 9.2 (iPad 4), iOS 8.4 (iPhone 4):
- [?] is shown in the hamburger menu check boxes.
- After startup, the tableau background card-backs jump to the bottom of the container/screen.
- Sometimes, in the deal-from-deck animation, cards in the rightmost tableau are temporarily facing up, and cards already facing up are flipped facing down. The final deal-state is correct, however.
- Undo/Redo: sometimes results in a facing-up card on deck 0 and a facing-down on deck 1.
- Redo sometimes 'jumps' to the new layout instead of animating.
iPhone only:
- A sequence of autoplay moves left an inconsistent foundation state: top cards heart-J, club-10, club-K, diamond-Q; i.e., 2 club-cards on different foundation stacks.
On Android 5.1.1 (Nexus 7) there are more problems.
- The deal-from-deck animation is not a pretty sight. Cards are inserted (slide to) at the bottom of the tableau stacks, so they slide under the other cards. The moving cards should be facing down but are usually facing up, always showing the first card dealt to tableau 1. The cards in rightmost tableau are temporarily facing up. Finally, cards already facing up are flipped facing down and back again. The final deal-state is correct, however.
- Autoplay is also not correct when there are several moves in a row. During the animations, several foundation cards facing up change their card value (front) temporarily. Also the moving cards slide under the foundation card (and sometimes over, but this is the exception).
- After finishing the game, the well-done screen is corrupted since the text seems to be displayed not overlayed but below the cards (in a big white space), which are only partly visible in a tiny portion at the top of the screen.
- Starting a new game often fails because deal-from-deck is not started; the screen shows a deck and four kings on the foundations with the tableau empty. When tapping the deck, a card is dealt and the well done sequence is show. Sometimes repeating this results in successfully starting a new game.
All this has taken a lot of time already and I still don't have my app working again, which is very frustrating. Having so much trouble with this topic, even with a downloaded demo app, building this type of app with Codename One feels like building on quicksand. Please help!
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.
Related
Hello everyone,
I am quite new to Flutter and wanted to build an application that detects multiple touches and if that touch lasts longer sets a circle there for example.
Similar to this there is the app "Chwazi Finger Chooser" in the PlayStore. This is how the whole thing should look like in the end.
Can you help me and tell me which components I need? Or if possible suggest some code?
I have not found an answer through my research so far and am hoping for you now!
Please help me :)
check the GestureDetector widget
and those available events https://flutter.dev/docs/development/ui/advanced/gestures
however Using OnGestureListener to detect multitouch gestures does not seem to be implemented by default.
The first thing you may have tried is reading event.pointerCount to get the count of fingers on the screen. However, this will be equal to 1. This is because you will (quite likely) never be able touch the screen with both fingers in exactly the same millisecond.
Fixing it
You have to buffer pointerCount (the amount of fingers on screen). First add those variables somewhere in the context that you intend to track gestures in:
// track how many fingers are used
var bufferedPointerCount = 1
var bufferTolerance = 500 // in ms
var pointerBufferTimer = Timer()
Then, in the onTouchEvent(event: MotionEvent) function, you add this:
// Buffer / Debounce the pointer count
if (event.pointerCount > bufferedPointerCount) {
bufferedPointerCount = event.pointerCount
pointerBufferTimer = fixedRateTimer("pointerBufferTimer", true, bufferTolerance, 1000) {
bufferedPointerCount = 1
this.cancel() // a non-recurring timer
}
}
Essentially this tracks the maximum amount of fingers on the display and keeps it valid for bufferTolerance milliseconds (here: 500).
I am making a game for Android and I encountered a problem while working on my next update. Game is set to work from API 19 upwards. I am using ObjectAnimator class to animate little bouncing arrows pointing buttons in tutorial. Nothing fancy.
Yellow arrow - Screenshot 1
Code:
//Animate minestone clicker button arrow
b1_animator = ObjectAnimator.ofFloat(button_minestone_pointer,"translationX",0,-100);
b1_animator.setDuration(500);
b1_animator.setRepeatMode(ValueAnimator.REVERSE);
b1_animator.setRepeatCount(Animation.INFINITE);
b1_animator.start();
Problem is, animations are smooth on ALL virtual devices provided by Android Studio (API 19 - API 27) and on all newer APIs, but on my phone (Sharp SH-01G), which is running Android 4.4, automatic scrolling or these arrows simply jump from one position to another creating blurred image.
Did not have a chance to check it on another pre-API21 device yet.
Feeling like it does not respect the ".setDuration();" bit. Scrolls are jumping immediately to the desired position but not smoothly at all.
This is the scroller code:
ObjectAnimator.ofInt(scroller_clickers, "scrollX", 800).setDuration(777).start();
So the question is, what is causing such a behaviour? I tried using view.animate() instead too, but it didn't help either. Clue is, when I tried to lookup the "getAnimatedFraction();" value, emulators were showing various fractions - smooth transition between 0.0 and 1. My phone was always showing 0.0 or 1.0 in somehow random order (Stuffed this into a TextView and refreshed with a Runnable). Assigning "AccelerateDecelerateInterpolator()" did not work either. I don't want to show a faulty game to the public :(
Any ideas?
Fixed.
Turns out my phone had animations switched off from 1.0x to off in developer options which the ObjectAnimator class did not like. Works good now
I am building a program that records a "kill feed" in the top right of a full-screen game and performs two actions as a result:
Update a counter I've painted to the screen with an always-on-top, transparent window that represents the number of players alive on each team (in the style of "2 v 1"), and
render a "hitmarker" graphic when my in-game username appears in the killfeed, indicating that I've killed my opponent
I've been programming in Java for three years, but I still don't know how to achieve this. I am able to use Graphics2D to paint graphics such as a "hitmarker" and draw strings such as the player count I mentioned above. However, I do not know how to recognize colors or text on screen, aside from Java's built-in Java's built-in Robot's getPixelColor() method (which I've never used before).
My best guess is to use java.util.Robot's createScreenCapture() method to save an image of the screen 60 times per second and do some OCR magic to recognize my username, then perform the two actions I detailed above.
Because I'm relatively inexperienced, specific and detailed answers would be much appreciated.
EDIT: I know it's not feasible to save the screen 60 times a second. My intention was for another method to be proposed. Also, as clarification, I am drawing over a game, and reading a killfeed that is a part of the game, not my program. I'm not rendering the feed, just the player counter and hitmarker (killmarker) because it's not a feature of the game like the killfeed is.
Basically I have a game where I want to play an explosion gif whenever the player (or an enemy) dies, but I want the gif to just play once.
I have everything set up in a class and I have an ArrayList that gets explosions added to it when I need it to, and I currently have it set up to remove them once the gif's duration has been reached (using System.currentTimeMillis()). The only problem there is that it isn't exact, and sometimes the gif stops early and disappears, and sometimes it rolls over, both situations causing the next one to start where the other one left off.
Is there some sort of method, class, listener of some sort, or anything I can use to tell what frame my gif is on, or how many times it has looped? My code can do the rest of the work, I just need something better to put in my if statement than this:
g2D.drawImage(explosion, x - 150, y - 150, null);
if(System.currentTimeMillis() - startingTime > 520){
System.out.println(System.currentTimeMillis());//for testing accuracy
Game.explosions.remove(this);
explosion = null;
}
The usual solution to this is to not use a gif :)
Most games will store each 'frame' of the gif separately, and display them in order, instead of trying to get gif rendering to work.
System.currentTimeMillis() is not terribly accurate, plus there can be tons of stuff going on in the background between calls to your draw function (all of which affects the framerate) so I would recommend against relying on that in general.
For those of you who have played Madness Interactive, one of the most frustrating things is when the cursor leaves the game area, and you accidentally click. This causes the game to defocus and your character dies in a matter of seconds. To fix this, I'd like to make a java application that I can run in the background that will hold the cursor inside the screen until I press a key, like ESC or something.
I see two ways of implementing this, but I don't know if either of them are workable.
Make an AWT frame that matches the size of Madness Interactive's render area, and control the cursor using that.
Use some out-of-context operating system calls to keep the cursor in a given area.
Advantage of approach #1: Much easier to implement resizing of the frame so that user can see the shape and position of the enclosed area.
Potential Problems with approach #1: The AWT Frame would likely need to steal focus from the browser window the game is running in, making the whole solution pointless.
My question is, are either of these approaches viable? If not, is there a viable option?
EDIT: I am willing to use another programming language if necessary.
EDIT2: I might develop a browser plugin for this, but I've never done that kind of development before. I'll research it.
If you're still interested in working in Java, here's a possible solution for you.
First, in order to limit the cursor within an area, you could use the Java Robot class.
mouseMove(int x, int y);
Then, you could use AWT's MouseInfo to get the position of the mouse cursor.
PointerInfo mouseInfo = MouseInfo.getPointerInfo();
Point point = mouseInfo.getLocation();
int x = (int) point.getX();
int y = (int) point.getY();
Then, whenever the x and y value of the mouse cursor go beyond a certain point, move them back using the Java Robot class.
If this is for a browser-based game, consider writing a greasemonkey script, which acts as a browser extension that can be filtered to only run on the game's site.
In the simplest case, assume the clickable regions are (0,0) - (300,400), then you can add the following event handler to the page:
$(document).on('click', function(event) {
if (event.pageX > 300 || event.pageY > 400) {
return false;
}
});
You can further refine your script to do the following:
resize the browser to be the perfect size for playing the game
instead of checking the absolute x,y coords of the click, check if it is inside an element of the page that you don't want to receive the click
add custom key bindings to umm.. help you at the game
write a javascript bot that can play the game itself