Description:
I have a StackPane as parent container (display) and my components are extending Region and kept in a ConcurrentLinkedQueue. The display of the components are not a problem, even the animation work as I wanted in sync with a timeline (the timeline records the whole process. E.g. min 2 -> Circle pop's up and does some fading + transition, etc.). All nice until now.
Now my problem comes: first of all I want after I consume and play this component to delete it from the display and from the Queue.
Second thing, now when I run this and I have two components that they are at the same time they run together in parallel, even though they are polled from queue (that I don't understand). So I need something that delays or waits until the first component was played, after this delete this component and play the next.
Any suggestion will be awesome!
//show message
public void showMessages() {
while(!messageQueue.isEmpty()) {
playMessage(messageQueue.poll());
}
}
/**
* Searches for the source and target component, finds the connection points and prepares the message to be played
* #param mess Visual message node, that will appear on dashboard
* If no source and target component will be found this will return without doing anything
*/
public void playMessage(MessageNodeVGT mess) {
//get the source and the target of the message
CompNodeVGT source=getComponent(mess, SOURCE);
CompNodeVGT target=getComponent(mess, TARGET);
if(source==null || target == null) {
return;
}
Point2D sourcePoint=get2DPoint(source.impl_getShape(),target.impl_getShape());
Point2D targetPoint=get2DPoint(target.impl_getShape(),source.impl_getShape());
mess.setSourceCoordinates(sourcePoint);
mess.setTargetCoordinates(targetPoint);
instance.getChildren().add(mess.createPath());
instance.getChildren().add(mess);
mess.play();
}
Due to the fact that I have two timelines (one general for the whole application and one local for the animation/s) the lock or other technique didn't help. Here it's why:
1st local animation ~ 3seconds (duration)
2nd local animation ~ 3seconds (duration)
general timeline: |-----10s----20s---x-x2---..
let's say x=22s =2200 millis, this is when the 1st animation pops up if the second animation will be at x2 and if this x2 is in between 1 millis - 1000 millis (even more) I will see this as a parallel event, even this is not completely true.
What I did? I just paused the general timeline until the 1st animation finishes, then on setOnFinish I just resume the general timeline.
This is not a perfect answer, because actually with this Pause you lose some time in the case if you are trying to follow some event in Real time.
I'm open to other solutions, hope this helps others too.
Related
When loading in a new FXML and setting the center of a BorderPane there is a brief 'freeze' of the application where existing animation, whether from a Timeline, or from a gif in an image view, will stop. I'm using this code to change the centerView:
#FXML
public void handleChangeView(ActionEvent event) {
Task<Parent> loadTask = new Task<>() {
#Override
public Parent call() throws IOException {
String changeButtonID = ((ToggleButton) event.getSource()).getId();
Parent newOne = getFxmls().get(changeButtonID);
if (newOne == null) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/" + changeButtonID + ".fxml"));
newOne = loader.load();
getFxmls().put(changeButtonID, newOne);
}
return newOne ;
}
};
loadTask.setOnSucceeded(e -> {
getMainUI().setCenter(loadTask.getValue());
});
loadTask.setOnFailed(e -> loadTask.getException().printStackTrace());
Thread thread = new Thread(loadTask);
thread.start();
}
And while this does the job in keeping the UI responsive in the load time, when the center stage displays for the first time there is a noticable lag. Looking at a CPU profile:
I'm not sure if the delay is from the initialize function running, or the loading of the elements. Here's a gif of the program, you can see the visible delay:
By loading it up in VLC and progresing frame-by-frame the delay looks to be 5 or 6 frames in a 30 fps video, meaning about a 200ms delay which implies the animation freezes for more than the 50ms or so initialize method. (Maybe the entire load method freezes the animation?)
The question is, is it possible to keep the animation smooth during this?
//********* EDIT **********//
So I went through the project and cut out as many methods and classes as possible, reducing the entire game to 6 minimal classes. I STILL have the delay in pressing the character button ('you' button). With such a minimal example I'm lost to what could be wrong. I've uploaded this to google drive for anyone to take a look.
https://drive.google.com/open?id=17A-PB2517bPJc8Dek-yp2wGXsjTyTj1d
There is nothing "wrong" with your code (at least in regards to this issue).
The issue you are experiencing also has nothing to do with the loading of the FXML (which is very slow and you have correctly handled off FX-Thread).
The stutter happens for These reasons:
relativly large hierarchy in character.fxml
lots of CSS (delete the main.css and you will notice; the stutter is slightly less prominent)
dynamically changing the scene graph (adding/removing Nodes during runtime)
Every time you replace the center of the mainView with some large Node, it causes the JavaFx runtime to completely re-layout and re-style (at least) that node. This happens on the FX-Thread, hence you notice the stutter.
One possible mitigation is a classic game dev technique: Pre-allocating as much as possible.
Simply load all necessary FMXLs once during startup and put them into the scene graph. In your click handlers then, change the visibility or (Z-)position of the Nodes you want to show/hide.
This is a good use case for a StackPane for example.
I adapted your code a little to demonstrate what I mean:
Prototype
Check out these ressources to learn more:
http://gameprogrammingpatterns.com/
https://stackoverflow.com/a/26537688/1271937
https://www.javaworld.com/article/2074652/core-java/javaone-2012-javafx-graphics-tips-and-tricks.html
My game takes around a minute to load in android till the first screen appears. Till the time its loading, jmonkey’s input manager seems to queue all inputs which results in nasty behavior(automatic button clicks) as soon as my first nifty screen loads.
Same happens when the scene loads(which again takes a while on pressing the appropriate nifty button). This happens despite the fact that I set mappings and listeners in the last App State which loads.
Is there a way to flush all previous input which I can call just before and after adding listeners to input manager?
I dont do much work in update() and initialize of my appstates but some functions (reinitialize()) which I call on nifty's OnClick(), loads all the scene and models in the scene garph so it takes a while. Here is a pseudo code of my application
In Main.java {
// Nothing in SimpleUpdate()
// This app state contains
stateManager.attach(new MainMenuAppState());
}
In MainMenuAppState.java implements ScreenController {
initialize() {
niftyDisplay = new NiftyJmeDisplay(app.getAssetManager(), app.getInputManager(), app.getAudioRenderer(), app.getGuiViewPort());
// Create a new nifty GUI object
nifty = niftyDisplay.getNifty();
// attach a couple of more app states which also has nothing significant in update loop
// do some good computation
// attach 5 new APP STATES which does not have anything significant in update()
display the appropriate screen of nifty
}
onClick() {
nifty.gotoScreen(“loadScreen”);
// appstate previously attached. they dont have anything significant in update.
// They have significant initialize methods.
app.enqueue(
rgas.reInitialize(time,cameraLoc,cameraRot);
maes.reInitialize(qId); // loads all the scene and models on screen
nifty.gotoScreen(“hudScreen”);
nifty.getScreen(“hudScreen”).findElementByName(“ConfirmModuleButton”).setFocus();
ppes.reInitialize(); // this contains input mappings
);
}
}
If there is a way to do this it will be on the InputManager so you could check out the API for that. Your problem may be though that the queue isn't really a queue in the way you are thinking. Potentially it is not a queue of input events but a queue of actions being taken in response to the events. Since events don't process until the update loop runs them then if the upload loop is stalled they will keep building up.
You could simply not add the listeners until the application has finished loading, then any events will get ignored automatically. You could also try breaking the scene loading up using a queue or similar of your own to load things a bit at a time while not completely stalling the system.
You may get a better response on this question if you try the jME3 forums. There are more monkeys active there than here including people with more detailed knowledge of the input system than me :)
I guess what Tim B said is your best bet.
However you could try calling nifty.setIgnoreMouseEvents(true) and nifty.setIgnoreKeyboardEvents(true) at some appropriate time to shut-off handling of any events that might reach Nifty and enable it later again.
I am creating a game where the user must tap the screen faster to allow them to go faster in game, however I have encountered some problems. I have made the game so it calculates the amount of taps per minute from the users last tap and their current tap, however this method seems to be jerky and does not work too well. I also cannot work out another way to do it, so that the when they don't tap at all, it slows down.
How would I go about creating this mechanism for the game where the faster the user taps, the faster the game goes, and if they don't tap at all it slows to a stop.
Thanks
Here is a snippet of what I have so far, calculating the Taps Per Minute (TPM) of the user. (This is in the on touch method). I am currently passing the TPM into an update method which moves the background by TPM/100 each time it updates (it's running at 30FPS)
if (thisTouch == 0 || lastTouch == 0) {
Log.d("info","First Touch");
thisTouch = lastTouch = System.currentTimeMillis();
} else {
Log.d("d","touch");
thisTouch = System.currentTimeMillis();
long difference = thisTouch - lastTouch;
TPM = (int)((1000*60)/difference);
lastTouch = thisTouch;
}
I would like to know how I can change this so that the game speeds up when they click faster, and then slows when they do not touch the screen.
Maybe you could do something like this:
Create a PriorityQueue< Long>
Whenever the user taps the screen, add (currentTime + someTimeOut) to the queue
Whenever you are going to check the current speed (eg size of queue), first remove all elements > currentTime.
Don't forget to add appropriate thread safety measures if you do something like this of course.
Not to be "that guy" but it sounds like your current plan of taps per minute is pretty good but just implemented badly. However, I would strongly recommend a smaller time quantity such as taps per three seconds since games are usually fast paced and having to wait a whole minute to see your character speed up or slow down may produce a sense of delayed lag.
Alternatively, you could could use some form of acceleration that is increased up to a maximum limit every time the screen is tapped and decreases over the time as the screen is not tapped.
Now that I see you updated your question with some code, I'd like to point out that a tap is a touch and release from the screen not necessarily a touch. I honestly don't know from your code whether or not you're compensating for this so this may be the source of some of your problems.
Lastly, for game development algorithms and theory you may want to see this StackExchange site: https://gamedev.stackexchange.com/
It sounds like you're very close to getting your game to feel the way you want it to, good luck!
Your general approach is pretty much the only way to do it, it just needs some fine tuning.
Keep a general TapsPerTime variable. With each new tap you register, do not replace the TapsPerTime, but calculate a new, weighted value:
TapsPerTime = (TapsPerTime * X) + (MeasureTapsPerTime * (1-X))
The factor X you need to find empirically (by trying out what works best for you). The general idea here is that each measurement will only nudge the used value a bit into the right direction.
Also, if you do not detect a tap for a set amount of time, simply update the TapsPerTime with the same formula, but use 0 (zero) for MeasureTapsPerTime. So if the user does not do anything the value goes down.
I'm currently making a game of Reversi for my programming class and I wanted to try and implement a computer into the game. I got this working successfully, but the computer makes their move instantly so you can't see how your move worked.
I tried solving this by using the following method:
public void wait (int n) {
long t0, t1;
t0 = System.currentTimeMillis();
do {
t1 = System.currentTimeMillis();
} while ((t1-t0) < n);
}
I then called this method after the player made their move, right before it called my computerAI() method.
However, it didn't work quite right and it seems like it hit the wait before it changes the colors of the board, because the player clicks, the background changes to the default light gray, and then after it waits a second, it performs the color changes of your move and the computers.
Anyone have any suggestions for fixing this?
Use:
Thread.sleep(5000);
This causes the current thread to sleep for 5 seconds.
You may need not only change button's color property, but also call its .repaint() or even .update() method often enough, e.g. every 100 ms. That is, you need to make the button actually redraw itself on the screen when you need it, not when the system determines it has time to render the accumulated changes.
In my application I fetch data if component is resized. I want to delay the fetch till user completes resize operation. ComponentListener event componentResized fires every time the window is resized.
I'd say you are propably writing a mapping application of some kind? :-)
You can use the swing Timer class to wait until a specified amount of time passed without any events. Here's the code :
/** Time to wait */
private final int DELAY = 1000;
/** Waiting timer */
private javax.swing.Timer waitingTimer;
/**
* Handle resize event.
*/
public void componentResized(ComponentEvent e)
{
if (this.waitingTimer==null)
{
/* Start waiting for DELAY to elapse. */
this.waitingTimer = new Timer(DELAY,this);
this.waitingTimer.start();
}
else
{
/* Event came too soon, swallow it by resetting the timer.. */
this.waitingTimer.restart();
}
}
/**
* Actual resize method
*/
public void applyResize()
{
//...
}
/**
* Handle waitingTimer event
*/
public void actionPerformed(ActionEvent ae)
{
/* Timer finished? */
if (ae.getSource()==this.waitingTimer)
{
/* Stop timer */
this.waitingTimer.stop();
this.waitingTimer = null;
/* Resize */
this.applyResize();
}
}
This isn't possible via conventional means, I'm afraid. componentResized() will be called for every intermediate sizing change, and there is no way to determine if the current call will be the last.
Strictly speaking, what you are attempting isn't a conventional thing to do. Data loads can be expensive IO operations and are usually best performed when the user is expecting them after a more direct UI operation such as a button press, when appropriate feedback can be displayed as a result of their action. The size of a component can change for innocent reasons such as the frame being maximised or arranged as a result of an operation elsewhere, such as the new Aero operations in Windows 7.
Some applications do perform IO as a result of sizing. Google Reader, for instance, can load older posts from RSS feeds as a result of moving the scrollbar on the browser window. This is a nice feature, and does away with the need for an explicit load button, but it is directly driven by the user seeking the older posts; a conscious action, not an unconscious one.
I guess my point is that you need to be very careful about how you make this work. Punishing a user with a slow IO operation that makes them wait simply because they dared resize the window is not a user-friendly approach!
You give precious little information in your question about what your UI looks like, or what the component is or how it gets resized - even, where you are loading data from, so it's kind of difficult to answer. Here are a couple of suggestions: I hope they help.
1. Load the data into memory beforehand, and just display it
If the data model isn't too big you could just load it into memory, and redraw it quickly with every resize event. The Event-Dispatch-Thread will combine resize events together so your listener is not overwhelmed by requests. This might be a non-starter for you, but it's worth mentioning.
2. Be eager to load
Load more data than you need on the first resize event, and then either reject or cache the data you don't use. If you're populating the rows of a table or a list this might be the better approach; tabular data is usually straight-forward to load and parse.
3. Allow a reasonable time to pass for resizing to stop
The first resize event starts a Timer with a 1 second countdown. Any subsequent resize events reset the 1 second countdown. At some point there will be a final resize event after which no subsequent resize events reset the countdown so it is allowed to expire. At this point the Timer does your load for you.
Three is the safest, most accurate approach, in my opinion. You can make your application feel responsive by visibly indicating that data is loading on the first resize event, and adjust the countdown of the timer to get the feel of your application right.
This is not possible. But you can use SingleWorkerThread to minimalize the number of events processed.