Java call method on a different thread - java

I'm making a Minecraft 1.8 client, and I'm trying to create a loading screen animation.
I know that updating the screen every time Minecraft loads something would make the animation choppy, so I tried making it run asynchronously, updating the screen every 10 milliseconds. The following code runs in Minecraft.java when the game starts:
CompletableFuture.runAsync(() -> {
int xPosition = // calculation of the value
// draw the rectangle
try {
TimeUnit.MILLISECONDS.sleep(10L);
}
catch (InterruptexException ignored) {
}
this.updateDisplay(); // render the rectangle
});
However, due to CompletableFuture running the code in a different thread, LWJGL can't find the rendering context (it can be found in the Minecraft thread), and can't update the screen (an IllegalStateException is thrown).
Is it possible to call the updateDisplay (or any) method on a different thread instead of the current thread?

Related

JavaFX window is not opened immediately

I've created a visualizer in JavaFX for a problem I'm solving, and currently I can get it to show up after the calculations in my application are done, but I would like the window to first be opened and then run the calculations, so I can animate the visualization during the computations.
This is the code for creating an instance of the problem, showing the visualizer and performing the calculations:
public static void run(Visualizer v) {
readInput();
if (v != null) {
v.resizeCanvas(rectangles);
v.drawAllRectangles(rectangles);
v.show();
}
calculateArea();
System.out.println(totalArea);
}
The Visualizer class extends javafx.application.Application and utilizes a JavaFX Canvas. calculateArea() simply runs a static method which performs some calculations.
What currently happens when I run my program is:
It waits for input on stdin
The computations are run
The visualization is displayed
What I want:
It waits for input on stdin
The visualization is displayed
The computations are run
So for some reason the displaying of the visualization is delayed even though I call v.show() before calculateArea().
My first hunch would be to run the calculations in a new thread, but according to
the documentation "The JavaFX scene graph, which represents the graphical user interface of a JavaFX application, is not thread-safe and can only be accessed and modified from the UI thread also known as the JavaFX Application thread."
I tried putting a Thread.sleep(3000) right after v.show(), and what happened was that my program just waited 3 seconds before running calculateArea() followed by the window being displayed.
Thanks for any input!
You should call your calculation method in a separate thread (as suggested by #Selim) launched in the applications start() method.
If your calculation method directly changes graphical content on screen (which it should not do BTW...) you need to pass this graphics code (not the calculation itself) to Platform.runLater().

Java graphics not updating correctly

In my program, a the graphics on my screen are supposed to move across the screen. I have a loop that calls the draw function(the draw function is display.draw()), but whenever the amount of times the loop runs is greater than one, the display doesn't update after each time like it should. Instead, it waits until the loop finishes to update the display.
below is the refreshing function that only apparently runs at the end.
public void refresh()
{
myPanel.removeAll();
myPanel.add(display.draw());
myPanel.validate();
myPanel.repaint();
}
And here's the loop. I added a 1 second sleep after each iteration to make sure it just wasn't moving faster than I could see.
for(int i = 0; i < 2; i++)
{
myGraphics.rearrange();
this.refresh();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
}
myGraphics.rearrange() simply changes the values of the variables which the drawing function uses,
changing the x and y variables for the positions of all the objects.
What is happening that it's not updating?
You're calling Thread.sleep(...) in a Swing program on the Swing event thread. What this does is put the entire application to sleep and so is not something that you should be doing. Instead use a Swing Timer to drive your animation.
For example:
Similar question 1
Similar question 2
Similar question 3
For more specific help, consider posting more code, preferably an mcve.

UI not updating smoothly due to a background Thread

I am writing an android game and here is what i have:
Game loop is implemented as:
I have made a custom view which extends the view.Then inside my onDraw() method, i call invalidate();
MainActivity:
Here i make an instance of a custom view and use setContentView() to set that as my current view.
I also use OnTouch() method to get touch events
Everything was working fine and smoothly till i did this:
I made a new class Graphthread and inside the run method, i created a loop.
public class Graphthread extends Thread
{
#Override
public void run() {
while(true)
{
}
}
}
Then i created an instance of this in my MainActivity
Graphthread gth = new Graphthread();
and used gth.start() in my onCreate method.
Now following happened:
The game did not run smoothly.Or i should say it was like..run for sometime..freeze for a few milliseconds...run again ...freeze again and so on.
What is happening?
Slight jitters like that sounds like garbage collection. If your background thread (or something else) is consuming a very large amount of memory, the GC may need to run more often then expected. That would cause momentary jitters such as you described.
Try more suitable approach for games: use SurfaceView and background thread to draw on it. This should free you from stuttering, cased by irregular message processing by main thread.
onDraw hack, from my point of view, suitable only if you want to animate something inside a regular app (not game), and animation framework has little use for you. Panning and scaling image for example.

Android game engine design: how to synchronize game loop and canvas updating thread?

I wanted to rewrite my simple game engine to run on Android and I am wondering how can I synchronize two running threads. Right now I have the following:
Runner is the main activity, entry point for this game;
CanvasView is just a canvas on which drawing is being made;
GameWorld is - as the name suggests - class which stores the current information about the state of the game. For now, lets just say that it also contains a Level.
GameLoop is a separate thread which is updating the game state;
CanvasThread is a separate thread, which is being run to draw the current Level on CanvasView.
As the level is just a simple array, CanvasThread just iterates through the array and draws it on screen. And I have few questions regarding this:
is there a possibility to run the onDraw() method of CanvasThread on demand? In current state of the engine it is just being relaunched when the execution of previous one is finished.
I want to implement some kind of three way handshake between GameLoop and CanvasThread, something similar to:
GameLoop -> CanvasThread: please stop updating
Canvas -> GameLoop: ok, stopped
GameLoop -> CanvasThread: ok, you may resume.
What is the best way to do so? I am a total Java / Android newbie so my way of setting the engine is most probably not the best / optimal one. If you have any suggestions to the design, I will gladly appreciate them.
Thank you.
PS: If I had violated all best practices while creating the diagram above, please forgive me.
Android has an easy way to handle thread communication. You can use a Looper and a Handler to send messages, or complete Runnables, between the Threads.
Look at Android Guts: Intro to Loopers and Handlers on mindtherobot.com for an introduction.
You can send an "empty" message to signal something, or supply some arguments. You can send the message immediately, or with some delay.
If you design your game loop by sending messages to itself, it would be easy to inject messages from other threads.
What I created long long time ago. Maybe it helps a little
http://code.google.com/p/candroidengine/
I believe you'll find it a lot easier if they don't communicate.
Instead, put a couple constraints on to keep yourself sane:
Make a very tight game loop. If you're going to be updating your canvas at, let's say, 30 fps (about 33 ms) make your game loop take no longer than 10 or 20 ms.
Put a lock on your game loop and canvas update. Now, each one will wait for the other to finish before doing their thing. You won't end up with a canvas that has the half the screen representing before the loop and the other half of the screen after the loop.
Example:
class GameLoop extends Thread {
public void run() {
while(true) {
synchronized(theGameWorldObject) {
// update game info here
}
}
}
}
class Canvas {
updateCanvas() { // or whatever you call it
synchronized(theGameWorldObject) {
// update canvas here
}
}
}

Call repaint from another class in Java?

I'm probably doing this wrong, so please be nice.
I'm developing a Java game, and I'm at the stage of testing character movement / animation.
The "person" can move up down left and right on a grid.
The class the grid is drawn in is the gamePanel class.
The buttons are in the gameControlPanel class.
I have a button which spawns a person on the grid.
I then have a button to move the person up down left and right.
When the move up button is pressed, it calls the move up method from the person class.
(At the moment, I'm only testing one "person" at a time.)
In that method is the following code...
int move = 10;
while(move!=0)
{
setTopLeftPoint(new Point((int)getTopLeftPoint().getX(),
(int)getTopLeftPoint().getY() - 3));
try
{
Thread.sleep(300);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
move-=1;
}
The problem is that I can't seem to call the repaint method for the gamePanel class from within the Person class.
To get around this, I created a timer in the gamePanel class which repaints every 20ms.
When I press the up button after the person is spawned, the button remains pressed down until the cycles of the while loop have been completed, and then the circle representation of the person is displayed in the grid square above.
I will try to answer any questions regarding this.
repaint() does not immediately repaint the GUI. Rather, it posts a message to the AWT thread telling it to paint at the next convenient opportunity. When it gets the chance, it will repaint your app. However, if you do this in an event handler, then the AWT thread is already busy and you need to exit the handler to give control back to the AWT handler.
As a general rule of thumb, you don't want to do any long-running calculations on the AWT thread (including in event handlers) since these will stop the app from responding to other events until your calculations are done. This will often appear to the user as stuck buttons like you described. To get around this, use a SwingWorker which can do the calculations on a separate thread.
Finally, something to be aware (but not necessarily to change) is that timers and sleeps do not guarantee when they will awaken. Rather, they guarantee that they will not waken before the amount of time elapses, but can theoretically sleep indefinitely. Also, not all machines have 1 ms timer resolution. In particular, on many windows machines the timers only have 55 ms resolution, so a 20 ms timer may give weird results.
If you want to repaint at a certain interval, javax.swing.Timer is probably the class for you. In the specific case of repaint you can call it from a non-EDT thread, but you may get yourself into difficulty as you are now dealing with multiple threads.
I don't have much experience making games but having a loop to control all animation is a fundamental aspect of game programming. Most simple 2d games only have 1 loop to render most of its animation.
In my experience a good way to render a whole bunch of stuff is to have a collection of all the entities in your game in one place and just loop over this collection passing the Graphics object to each entity.
This will allow each entity to draw itself onto the graphics object. Although this is just one way to do it.
synchronized ( entities ) {
for ( Entity e : entities ) {
e.draw( g );
e.doAction();
}
}
Is the button press handled by the event-dispatch thread of your GUI?
If this is a case, then the repaint method on the GUI will not fire until the event dispatch thread ends (i.e. when the button is released and it breaks out of the loop). I had this problem recently, and the best solution I can suggest is to make the class with the movement algorithm threadable and fire off a thread when the keypress is detected. This allows the event-dispatch thread to finish and therefore allows the gui to repaint.
For more information on threading see Starting a thread.

Categories

Resources