At first I did this:
public SpaceCanvas(){
new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
int fcount = 0;
#Override
public void run() {
System.out.println("Update thread started!");
while(!Thread.interrupted()){
fcount++;
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
}
while(entities.iterator().hasNext()){
entities.iterator().next().update(fcount);
}
System.out.println("About to paint");
repaint();
System.out.println("Done with paints");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
in the initializer of a thing I call a SpaceCanvas.
However, that doesn't allow the canvas, and therefore the applet it is within, to be created, because the Thread doesn't actually run asynchronously. Then, I replaced ".start()" with ".run()" and the thread only ran once, but the SpaceCanvas initialized perfectly.
What did I do wrong, and how do I fix this?
I'm not sure this sort of code works the way you expect it to:
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
players.iterator() gets a new iterator for the players collection. If there are 0 items in the collection then it will be false but if there are any items, you will be in an infinite loop, creating a new iterator each time. The iterator() call inside of players generates another new iterator object as well.
I think you should doing something like:
Iterator iterator = players.iterator();
while (iterator.hasNext()) {
iterator.next().update(fcount);
}
This is the same with your entities loop as well. A better pattern (as of Java 5) is to use the for loop:
for (Player player : players) {
player.update(fcount);
}
Also, if multiple threads are accessing these collections, they have to be somehow synchronized. You can either use a concurrent collection or you have to make sure every access (read and write) is within a synchronized block.
synchronized (players) {
for (Player player : players) {
player.update(fcount);
}
}
...
// down in the outer thread
synchronized (players) {
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
Obviously the entities will need to be synchronized in the same manner.
In this millennium, use Swing (JApplet/JPanel) rather than AWT (Applet/Canvas)
When using Swing, establish a Swing Timer that calls repaint() every 500 msec.
(When using Swing/Timer) Don't call Thread.sleep(n) on the EDT (Event Dispatch Thread).
..can you draw on a JPanel?
Sure thing. To do so, override the paintComponent(Graphics) method. You might also extend a JComponent and do the same, but there are some quirks to dealing with a JComponent that make the JPanel the better choice to extend.
On the other hand, there is another approach entirely.
Create a BufferedImage of the size required for whatever custom graphic is needed.
Add the image to an ImageIcon.
Add the icon to a JLabel.
Add the label to the GUI.
On each Timer action.
Call image.getGraphics() to obtain the drawing surface.
Replicate what you might have done in paint() or paintComponent()
(If needed) erase all previous drawing.
Draw the current custom rendering.
dispose() of the Graphics instance of the image.
call label.repaint()
Related
Is there a way to make my 2048 game run faster?
I made a setting called high speed mode so that if moves were made really fast I would just skip the spawning, combining and moving animations, however even with that I am still usually one or two moves behind when I spam a bunch of keys at once.
Right now I have a tilePanel class to handle displaying my tiles, and use a timer(very basic code) with paintComponent(drawing the tiles constantly) to make sure it continually updates the board.
public void doAnimation() {
System.nanoTime();
Timer timer = new Timer(2, this);
timer.start();
}
The way I have structured my game is that I have an ArrayList of commands(ie pressing the right key adds "right" to the arraylist and eventually the arraylist gets to it and executes) I receive to make sure that it always does a move, spawns before doing the next move in the sequence.
To make sure the board continually updates itself, i made a very basic run thread:
public void run(){
while(true) {
if(canDoNewMove&&commands.size()>0&&parent.spawnsLeft==0) {
move(commands.get(0));
commands.remove(0);
canDoNewMove=false;
}
if(commands.size()>=2) {
board.isBehind=true;
}
else {
board.isBehind=false;
}
if(totalMovements==0&&moveDone) {
moveDone=false;
if(parent.changed) {
parent.spawn(parent);
}
canDoNewMove=true;
}
//moveDone=false;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}};
Thread sampleThread = new Thread(backGroundRunnable);
sampleThread.start();
}
Would reducing method calls produce a noticeable enough difference that the actions would finish right after I press the keys or is the problem within the tilePanel class that draws the board?
thanks guys
I have got the following animator class that implements Runnable (mentioned in JUNG documentation).
How can tell the thread , if some condition was true pause for some time and then start running?
switch (args[0])
{
case "agent":
int size=nodeAttributes.size();
int i;
for(i=0;i<size;i++)
{
if(args[1].equals(nodeAttributes.get(i).nodeName))
{
VertexCollider vtxCol = new VertexCollider(layout, panel,args[1], args[2] , args[1] , nodeAttributes.get(i));
vtxCol.setMaximumIterations(1000);
vtxCol.setDesiredPrecision(1);
vtxCol.initialize();
Animator animator = new Animator(vtxCol);
animator.start();
if(nodeAttributes.get(i).isMoving)
{
animator.stop();
animator.wait(10000);
System.out.println("stopped");
}
nodeAttributes.get(i).isMoving = true;
break;
}
}
break;
}
According to the documentation you referenced, an Animator can be paused for a certain amount of time between iteration loops.
animator.setSleepTime(10000);
And then you could set the sleep time to a much shorter interval when your pause condition ended.
However, it seems like you want your Animator to stop entirely when the pause condition is true. In that case, I recommend you stop() the animator at that time (as your code is doing), and then start() it again when the pause condition ends. It appears you can call the stop and start methods repeatedly.
Place wherever you want the program to sleep: (inside an if statement?)
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
this will tell the thread to sleep however many milliseconds you want it to.
in do-while:
do{
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(something() == true);
this will keep on checking the value, until it is false.
If you want to pause the the animator you must first move the animator object and vtxCol object Initialization to another Thread.Because even if the Thread.sleep() function or wait() function are about to work for your purpose they will stop the function Initializing the animator too which may not fit your needs.
After moving the animator object creation to another separate Thread you must consider creating some LinkedList , Array or some kind of Collection for holding your movement data in order to Initialize the vtxCol and animator object by them , And pass the data to the thread. Then in the Thread.sleep() function can answer your need in that separate thread created.
One of my applications paints objects to a screen by reading an array List:
simple code summary:
#Override
public synchronized void paintComponent(Graphics g) {
for(Object gO:paintList) {
g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
}
}
The problem is I add more objects every time the user clicks the mouse, so if if the user clicks fast enough, I can cause the program painting to stutter since it cannot read while it is writing (the arrayList is synchronized). What is the common practice developers use to deal with this concurrency issue?
edit: here is the code that calls the repaint:
byte ticks = 0;
while(true) {
currentTime = System.nanoTime();
if(ticks == 25) {
drawPanel.repaint();
ticks = 0;
} else if (ticks%5 == 0) {//if ticks is a multiple of 5 (5,10,15,...)
drawPanel.operations();
ticks++;
} else if(ticks < 25) {
ticks++;
}
try {
/*
Refer to: 'http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep'
on differences between Thread.sleep() and wait()
*/
wait(1);//old timings: (long)(refreshRate*1000)
} catch (InterruptedException ex) {
Logger.getLogger(DeathWish.class.getName()).log(Level.SEVERE, null, ex);
}
//Debugging
//System.out.println(ticks);
currentTime = System.nanoTime();
*where operations() calculates changes in 'paintable' object's properties, removes objects that meet certain conditions and adds new objects to the paint list. Logically to me, the adding and writing should be separated?
I can post the operations() method, if there isn't enough information, but I'm trying not to post huge sections of code so it is easier to interpret.
I guess you're getting things a bit wrong with synchronization :
ArrayList is a list implemented without synchronization
A synchronized method means that only 1 Thread at a time can access the method, but the variables inside your function are not synchronized at all
What you want, is to have your list temporary synchronized.
You could do something like that :
#Override
public void paintComponent(Graphics g) {
synchronized(paintList) {
for(Object gO:paintList) {
g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
}
}
}
and in the code adding objects yo your list do somewhat the same.
EDIT from here :
If you want to remove all the concurrency problems between the add thread and the paint Thread, here's how you could do :
in the method to add images :
public synchronized void addImage(...) {
Something newImage = .....
List<Something> newPaintList = new ArrayList<>(paintList.size() + 1);
newPaintList.addAll(paintList);
newPaintList.add(newImage);
paintList = newPaintList;
}
And in the paint method, remove the synchronization part.
#Override
public void paintComponent(Graphics g) {
for(Object gO:paintList) {
g.drawImage( gO.getObjImage(), gO.getXLoc(), gO.getYLoc(), outer.getTransparent(), null);
}
}
With this, you won't have any concurrency between the reads and the writes, since the only operation done on paintList is reads.
The addImage should be synchronized to avoid two different Threads adding images at the same time, which could make one addImage ignored.
Trying to draw something every ms on single canvas. I mean only adding details to canvas, not redrawing it all every frame. So this code gives me three different canvases. Third, then first again. Why?
public void run() {
this.run = true;
Canvas canvas = null;
while (run) {
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (this.surfaceHolder) {
Thread.sleep(delay);
draw(new Img(canvas, size));
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (canvas != null) {
this.surfaceHolder.unlockCanvasAndPost(canvas);
}
}
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) {}
}
}
}
}
If it is android triple buffering - how to turn it off, or do something with it?
Android 4.2.1
If you like to preserve your previous draw you should draw them in an off-screen canvas and draw them to the canvas you got from lock canvas.
The puesd-code to illustrate the idea:
Bitmap offScreenBitmap = Bitmap.createBitmap(100,200,Bitmap.ARGB_8888);
Canvas offScreenCanvas = new Canvas(offScreenBitmap);
onScreenCanvas = this.surfaceHolder.lockCanvas();
//always draw to te offScreenCanvas
offScreenCanvas.drawXxxx
//copy the data to on-screen canvas you got from the lock
onScreenCanvas.drawBitmap(offScreenBitmap);
unlockAndPost(onScreenCanvas)
That should get your task done. Right?
Then, a little bit under the hood stuff:
Yes, android view (surface IS A view) has multiply buffers: one is used by apps for drawing and one is used by system for rendering and sometimes there is a third one when if the app can not finish drawing timely. No way to turn it off and you won't want to. And it is the reason you get different canvas when lock as you have already observed.
I would recommend against naming a boolean field, "run" in a Runnable implementation (in which the method returns void). Even if problems don't surface from the conflict, it's confusing. Maybe "running", or something (anything), would make more sense - easier to debug.
Don't use Object.wait when you are multi-threading. It won't always (generally, will not) act as you might expect.
You are most likely getting multiple instances of your Canvas member because somewhere (maybe in the Android framework, or maybe in your code... hard to tell), "new Canvas(args)" is being called while what you believe to be your only Canvas instance is out on another thread. While you have only one reference, more than one instance can be created.
I wouldn't recommend using synchronized(whatever) unless you are sure you need to do so.
Hang in there. This problem is very confusing - I worked through it last Spring and it wasn't easy or fun.
Hope any of the above helps in some way.
-Brandon
I’m writing a Tetris-like game for Android and I’m trying to implement the “real-time part”. I have something which seems to work, but I want to be sure that my implementation is correct.
What I want is:
The shapes are going down at a fixed rate (say that I want to wait n milliseconds each time the y of the shape is decremented)
The player can drop the shape at any time and the timer waiting for the n milliseconds must then be immediately interrupted and start again only for the next shape
When the shape is droped or when the shape cannot go down anymore, the game waits m milliseconds before creating another shape
The system have to be able to stop the thread at any time
What I am doing is the following (the system can stop the thread with interrupt()):
class TetrisThread extends Thread {
private int n = 3000; // for testing purposes, in the real game n will be smaller ;)
private int m = 1000;
#Override
public void run() {
doDraw();
while(!interrupted())
{
try {
synchronized (this) {
wait(n);
}
doPhysics();
doDraw();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
// This method is the one which will drop the shape, it is called from another thread
synchronized public boolean onTouch([…]) {
[…]
// The shape has to be dropped
dropShape();
notify();
[…]
}
private void doPhysics() throws InterruptedException {
[…]
// The shape cannot go down or has been dropped
sleep(m);
createNewShape();
[…]
}
}
In particular, the part synchronized(this) { wait(n); } looks funny because if I understand correctly this will take a lock on this and release it immediately.
But wait() requires to be used in a synchronized(this) block (why?) and I cannot either synchronize the whole run() method, because then if I try to drop three times the shape during the sleep(m) call, then the three next shapes will be automatically dropped (which is not what I want).
Does this seem correct to you?
Do you have any correction, advice, or remark?
Thank you :-)
The wait() method is used to make the current running thread to wait the object invoking wait() invoke notify() (in this case this). The synchronized(this) part needed to make sure only one thread at that time accessing this.
You can't synchronize the whole run() method, because the run() is from the parent (Thread) class and the parent didn't use synchonized in the declaration.
I don't know how to solve your other problem because I don't get how your program works right now.