I am programming a basic java game, but I am having an issue.
Everytime that I try it out, if I wait just for 10 seconds, the program stops working correctly. I've made a class called Drawable, which has a paint function. This paint function paints a rectangle on a certain area(given on the constructor).
And I have a thread that iterates over all drawables in an arraylist(added randomly, with another thread), and just substracts 1 to their x. When it stops working correctly, the character can jump and does all animations, but the drawables stop moving. At first I thought this might have given a ConcurrentModificationException error, but it didn't print it on the console.
So right now I don't really know what to do.
Here I add the Drawables:
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
while (Game.isPlayingGame) {
try {
Thread.sleep((long) (Math.random()*2000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
obstacles.add(new Drawable(
Constants.WIDTH,
(int) (Constants.HEIGHT / 2),
Constants.WIDTH - 100,
(int) (Constants.HEIGHT / 2) - 100,
Color.BLUE));
}
}
});
t2.start();
Here I move the Drawables:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while (Game.isPlayingGame) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (Drawable d : obstacles) {
d.x -= 1;
d.x2 -= 1;
if (d.x2 < 0) {
obstacles.remove(d);
}
}
}
}
});
t.start();
paint method:
#Override
public void paint(Graphics g) {
super.paint(g);
floor.paint(g);
Graphics2D g2d = (Graphics2D) g;
AffineTransform ant = g2d.getTransform();
g2d.rotate(Math.toRadians(rotation),
character.x - Constants.characterSize / 2,
character.y - Constants.characterSize / 2);
character.paint(g);
g2d.setTransform(ant);
for (Drawable d : obstacles) {
d.paint(g);
System.out.println(rotation_down);
if (!rotation_down) {
if (!character.onCollision(floor)) {
character.y += (int) gravityAccel; // gravity
character.y2 += (int) gravityAccel; // gravity
gravityAccel += 0.1;
} else {
Screen.canJump = true;
gravityAccel = 0;
}
}
}
repaint();
}
Thanks in advance.
The proper synchronization depends on the exact internals of your Drawable. Also use CopyOnWriteArrayList. For the Drawable class, decrement of x and x2 should be atomic and synchronized with at least paint() method:
synchronized moveToLeft() {
x-=1;
x2-=1;
}
However, it does not make sense to have an object with x2 < 0 but this is a separate discussion.
You would also want to have
synchronized getX2() {
return x2;
}
and in your second thread do something like this:
if (d.getX2 == 0) {
obstacles.remove(d);
}
else {
d.moveToLeft();
}
The reason to do the check first is that if you do it other way around, you can and up in a situation when x2 is already -1, obstacles.remove(d) has not been called yet, and d.paint() is called. This could cause issues unless your paint() method can handle negative coordinates.
Related
I'm using a Thread to scroll text in my application :
public void run() {
super.run();
while (!isInterrupted()) {
if (X >= -getPreferredSize().getWidth()) {
X -= 2;
} else {
decrementMessagesInList(getMessages());
addMessage(getMessages());
prepare();
X = getParentWidth();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
repaint();
}
}
However, see that with sleep my CPU usage is very high, I need to reduce that. Can anyone suggest how to do it ?
If I can make the assumption that your code only needs to scroll the text in response to some event (say a click or drag or something) then you should make your thread go into a wait state then have the code that triggers the update post a notification over to the thread which will then wake up and do the update. Something like this:
Object syncObj = new Object();
public void run() {
while (true) {
try {
syncObj.wait();
if (X >= -getPreferredSize().getWidth()) {
X -= 2;
} else {
decrementMessagesInList(getMessages());
addMessage(getMessages());
prepare();
X = getParentWidth();
}
repaint();
} catch (InterruptedException ie) {
// handle the exception
}
}
}
Then in the code which handles/generates the event that causes a need to scroll
public void onClick(..) {
syncObj.notifyAll();
}
You also need to guard against spurious wake ups of your thread to make sure the event you were waiting for actually happened. See Do spurious wakeups actually happen?.
I try to make a standard form for simple games, but every time I try to compile it on my mac, it says:
move.java:31: error: unreachable statement
repaint();
^
Note: move.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error
When I tried to compile it on a windows computer, it worked just fine! I can't find anything about fixing this, and according to the java website the repaint() method isn't deprecated! This is my code:
import java.awt.*;
public class move extends java.applet.Applet implements Runnable {
Image osI;
Graphics osG;
Thread runner;
char currkey;
int x;
int y;
public void init() {
x = 0;
y = 1;
setBackground(Color.yellow);
osI = createImage(size().width, size().height);
osG = osI.getGraphics();
}
public void start() {
if (runner == null) {
runner = new Thread(this);
runner.start();
}
}
public void run() {
while (true) {
y = 1;
}
repaint();
try { Thread.sleep(1000); }
catch (InterruptedException e) { }
}
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public boolean keyDown(Event evt, int key) {
switch (key) {
case Event.DOWN:
x = 1;
break;
}
repaint();
return true;
}
public void paint(Graphics g) {
if (x == 1) {
g.drawString("x is 1!!!", 150, 150);
} else {
g.drawString("x is geen 1!!!", 150, 150);
}
if (y == 1) {
g.drawString("y is 1!!!", 150, 175);
} else {
g.drawString("y is geen 1!!!", 150, 175);
}
g.drawImage(osI, 0, 0, this);
osG.setColor(getBackground());
osG.fillRect(0, 0, size().width, size().height);
osG.setColor(getForeground());
}
}
You error isnt saying repaint() is deprecated. In fact, using deprecated methods inst an error at all.
Its because of your infinite loop:
while (true) {
y = 1;
}
repaint();
The error is because you have unreachable code
while (true) {
y = 1;
}
means that the repaint() method will never be called as the loop never ends.
This while-loop...
while (true) {
y = 1;
}
repaint();
Will never exit, therefore, repaint can NEVER be called
Thread#stop is deprecated...
runner.stop();
You should never use it. Instead, create a AtomicBoolean flag which you can use in your while-loop and while it's value is true, keep looping. In your stop method, set the AtomicBoolean's value to false and the loop will exit.
See Java Thread Primitive Deprecation for reasons why stop (and other Thread methods are deprecated)
Applet#size is deprecated...
osG.fillRect(0, 0, size().width, size().height);
Use getWidth and getHeight
java.awt.Applet is 15+ years out of date. Seriously, instead, you should be, at the very least, using JApplet, but even then, I would recommend moving your core logic to a JPanel and simply adding that to what ever container you want to use, apart from gaining double buffering support without any extra work, you also gain the flexibility to decide how to use the component, as frankly, there are better approaches then using an applet now days.
I have a android that draws a mandelbrot image.
I have 16 threads that each draw 1/16 part of the image, they have their own bitmap.
for(int x=0;x<xw;x++) {
for(int y=0;y<yh;y++) {
c_real=realMin+((double)(x+x1)*scaleReal);
c_imag=imagMin+((double)(y+y1)*scaleImag);
tmp=cal_pixel(c_real, c_imag, mag);
while(pause[thread]) {
try{
Thread.sleep(5);
}catch(InterruptedException ie){
}
}
plot(x,y,c[tmp], thread);
active[thread]=true;
}
dirty=true;
}
public void plot(int x, int y, int c, int myId) {
bitmap[myId].setPixel(x, y, c);
}
The run method for each piece
public void run() {
int myId=id++;
Log.i("run","Starting thread "+myId);
while(true) {
if (redraw[myId]) {
Log.i("run","redraw");
calc(myId);
redraw[myId]=false;
}
try{
Thread.sleep(100);
}catch(InterruptedException ie) {
}
}
}
I have a separate thread that 10 times a second takes the bitmaps and draws them on the canvas.
image.pause(true);
for(int i=0;i<16;i++) {
c.drawBitmap(image.getBitmap(i), (i%4)*w/4, (i/4)*h/4, null);
}
image.pause(false);
This is the thread that draws them
public void run() {
Canvas c;
while (true) {
if (run) {
if (view.dirty()) {
c = null;
try {
c = holder.lockCanvas(null);
synchronized (holder) {
view.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
try{
Thread.sleep(100);
}catch(InterruptedException ie){
}
}else{
//Log.i("Waiting the night away","Waiting the night away");
try{
Thread.sleep(1000);
}catch(InterruptedException ie){
}
}
}
}
Sometimes one or several of these pieces gest screwed up and are not drawn to the canvas, any idea why that happense.
It worked better in android 2.3.x it almost never happened, but noww in android 4.x it happens qquite often, if you want to check the program out and experience the bug here is the link https://play.google.com/store/apps/details?id=se.klockar.mandelbrotmobile
I have got my custom widget that changes background when hover. It is working nice but I would like to have smooth transition between no background and hover background. It will work with GC.setAlpha(), but:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
for (int i=0;i<255;i++) {
setBG(BGHelper(imgHover,i)); //i - alpha
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
This code wait until i == 255, but it doesn't display a smooth transition. Why?
This can not work, because as long as you are in your Code SWT will not repaint or change the component.
You should do the work in a separate Thread and call Display.asyncExec for every change.
for (int i = 0; i < 255; i++) {
final int x = i;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
setBG(BGHelper(imgHover,x)); //x - alpha
}
});
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I've got a working Java program and I would like to draw an object on the display every X seconds. What is the best way to do this? I was thinking of using a for loop and some sleep statements, but I'm curious if there is an easier or more efficient way to go about this.
Thanks.
The simplest way would be to use a javax.swing.Timer
Timer timer = new Timer(X, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Update the variables you need...
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
You might also like to have a read through
The Event Dispatching Thread
Concurrency in Swing
So you can understand why you should never use a while (true) { Thread.sleep(X) } call in Swing (inside the EDT)
ScheduledExecutorService might help here. The Javadoc shows example usage. Don't forget to call the shutdown method when you're finished.
Using Thread, this will draw a rectangle on the screen every XMilSeconds. This will stop after 5 runs. Edit the xMilSeconds for slower runs, and j > 4 for how many runs before stoping. It does freeze though, that I can't fix.
int i = 0;
private long xMilSeconds = 300;
private boolean paint;
public boolean running = true;
public void paint(Graphics g)
{
super.paint(g);
if(paint)
{
for(;i < i+1;)
{
g.drawRect(i+49,i+49,i+299,i+99);
g.setColor(Color.RED);
g.fillRect(i+49,i+49,i+299,i+99);
}
paint = false;
}
}
public void run()
{
while(running)
{
try
{
Thread.sleep(xSeconds);
paint = true;
repaint();
i++;
j++;
if(j > 4)
{
running = false;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}