I have problem with Android. I'm trying make project where I draw circles on a random position. After touch on this circle you will get a score and the circle will disappear. But I have a problem, my object is spawned then disappears without touch and spawns in another location.
Here is my spawner code.
protected void spawner(Canvas canvas,int timer){
System.out.println(myThread.timer);
if (myThread.timer>100) {
int x = 200 - generator.nextInt() % (myThread.screenDimX / 2);
int y = 200 - generator.nextInt() % (myThread.screenDimY / 2);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
paint.setColor(Color.parseColor("#800000"));
canvas.drawCircle(x, y,50, paint);
myThread.timer=0;
}
}
myThread is my game loop thread.
Can anyone help me with this?
You're only drawing that circle for the instant myThread.timer is greater than 100. What you need to do is add it to an ArrayList, or whatever data structure you want, and then constantly loop over that ArrayList and draw all the circles.
One thing I can tell you in general, and I don't know if that's why you have a problem or not, is all UI components manipulation should happen on the UI thread, and not on your other thread.
It's unclear if you call this method on a callback from the timer thread or on the UI thread. If you're calling it from the UI thread then it might be that both the UI thread and the Timer thread write to myThread.timer, concurrently and the way it seems, you're not guarding it.
Related
Is LibGDX SpriteBatch draw() smart enough not to redraw 100% exactly same sprite at each render() call?
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (shallFadeOut) { // becomes true when sound message finishes
doFadingOut();
showNextScreen();
dispose();
} else {
batch.begin();
// introSprite is a static image - it never changes a pixel (splash screen)
// I need to paint it once and then just wait until sound message finishes
// DON'T NEED TO REDRAW IT EVERY render() cycle 60 times/sec (~60 fpm)
introSprite.draw(batch);
batch.end();
}
}
In OpenGL, you typically redraw the whole screen on every frame. It doesn’t make sense to wonder if the batch is smart enough to avoid redrawing the same thing, because it has to redraw it to prevent it from disappearing.
If you want to avoid redrawing anything on the screen for a while to save battery on the device, you can use GDX.graphics.setContinuousRendering(false) but that means your render() method will stop getting called so you must set it back to true using a timer or input callback.
You could alternatively use a Boolean to decide whether to clear the screen with glClear and draw stuff, but under the hood, LibGDX will still be requesting OpenGL to copy the screen buffer data between the back buffer and the screen buffer.
Not that drawing a single sprite is super trivial and probably not worth a second of thought about optimizing it.
I am afraid that I do not think any accounting is done by the Batch between batching render steps to see if a texture was already loaded and is ready to be rendered, but the texture itself might.
The batching is intended for cases where you are drawing duplicates of the same thing in the same render step so that you are not unnecessarily context switching between sprites and having to reload data to your graphics card.
The batch is as I am sure you know defined by the begin and end calls you are using, and it depends on you actually rendering all of the sprites of a particular type one after the other without jumping to render something else. This can be seen int he batch draw code here, but for readability the relevant lines are below:
Texture texture = region.texture;
if (texture != lastTexture) {
switchTexture(texture);
} else if (idx == vertices.length) {
flush();
}
To take advantage of the batch - you should be grouping the rendering of all your sprite types, and between steps, the batch does not offer any efficiencies by design as far as I can tell.
But, between batching steps or game loops, when a texture is bound, it uses a fixed target and handle as can be seen here. This means that if all you are drawing is a single sprite for several render loops, libgdx should be using your memory and graphics card as efficiently as can be expected.
I am trying to accomplish having the android canvas flash from blue to red. I would like to control the flashing to be adjustable. For example change colors every 100 milliseconds for 3 seconds.
I have tried using Timer and Threads how ever the application seems to crash. I tried with and without invalidate(). I am assuming my logic is off or that i do not fully understand how its executing. Possibly it happens to fast I cant see and crashes or creates too many threads that crash the app.
Pseudo code
// canvas change color to blue
// wait 100 milliseconds
// canvas change color to red
// wait 100 milliseconds
// canvas change color to blue
// execute for 3 seconds
I would put code but since I tried multiple solutions each having the same crash or hanging effect I am assuming they won't be that helpful.
I know I can either create a rectangle shape drawable to fill the screen or just color the whole canvas which is probably the better approach.
I have two paint objects created and if I fill the canvas regularly they both work of course.
Paint paint2 = new Paint();
paint2.setColor(Color.RED);
paint2.setStyle(Style.FILL);
canvas.drawPaint(paint2);
Paint paint1 = new Paint();
paint1.setColor(Color.BLUE);
paint1.setStyle(Style.FILL);
canvas.drawPaint(paint1);
Just to sum up: I would like the canvas to flash between blue and red every 100 milliseconds for 3 seconds. But would also like both the delay (100 milliseconds) and the duration (3 seconds) to be adjustable so I can increase or decrease them.
I have tried using:
Timers
Threads
Shape drawable
System.currentTimeMillis()
I started playing with someone's else code and came across an interesting experiment. The program will work fine with the if statement. But I found out if I change the if statement into a while loop, the program runs but I could not close the program with the X button instead I had to press Eclipse terminate button. I am guessing this is a sign of an infinite loop or is it the fact that Java cannot repeatedly draw the same images over and over again?
// if you want to draw graphics on the screen, use the paintComponent method
// it give you a graphic context to draw on
public void paintComponent(Graphics g){
super.paintComponent(g);
// when the player is still in the game
if(inGame){
g.drawImage(apple, apple_x, apple_y, this);
for (int z = 0; z < dots; z++) {
if (z == 0)
g.drawImage(head, collisionX[z], collisionY[z], this);
else g.drawImage(tail, collisionX[z], collisionY[z], this);
}
Toolkit.getDefaultToolkit().sync();
// dispose graphics and redraw new one
g.dispose();
}
else gameOver(g);
}
Changing this line into a while statement
if (inGame) {
will not allow the variable to be reset to false, resulting in the infinite loop. Having while loops or any resource-heavy calls in paintComponent is a bad idea in general. Swing has concurrency mechanisms to deal with these.
If you want your UI to remain responsive, event handlers and repaints should finish within a reasonable amount of time. This means you shouldn't loop inside paintComponent() at all; instead you have to repeatedly trigger a repaint from somewhere else, like an animation timer.
Changing the if to a while, ie:
while(inGame){
will loop forever if inGame is true, because there would be only two ways to exit the loop:
inGame is set to false within the loop
the is a break statement in the loop
neither of which is found in the code.
fyi, the code pattern while(true) is a common way to create an infinite loop, which is needed for things like web services waiting for requests
I'm not quite sure how to phrase this, so bear with me.
I have two JPanels in a container JPanel with an OverlayLayout. Both JPanels in the container override paint(Graphics).
The bottom JPanel is opaque and draws some fairly complicated graphics, so it takes a "long" time (10s or 100s of milliseconds) to render.
The top JPanel is transparent and just draws a rectangle or line or simple shape based on mouse input, so it's really quick.
Is there a way to set things up so when I change the simple shape in the upper panel, it doesn't redraw the bottom panel? (e.g. it somehow caches the bottom panel)
I'm vaguely familiar w/ concepts like bitblt, double-buffering, and XOR-drawing but not really sure what to apply here.
You'd be best off using a single JComponent and creating a BufferedImage to store the bottom image. When the paintComponent operation happens on the JComponent, you just blit the bottom image and use the Graphics object to do any further drawing on top of that (from a stored state). Should be fairly efficient.
You'll want to do the complex drawing operations for the bottom BufferedImage in another thread, as the other poster mentions (omitted this by accident, sorry :)). However, you don't want to cause contention on this image, so you must store an additional BufferedImage for this, and blit it synchronously to the other image at the very moment the drawing operations are complete on it.
Focusing on the complicated panel, the key is factoring everything out of paintComponent() except drawImage(). Put everything else in another thread that continually updates an offscreen buffer. Periodically update the screen at some rate that keeps the simple panel responsive. The only hard part is synchronizing, but SwingWorker is a good choice. There's more here.
What's sure is that if the upper panel is target for a full repaint(), then the lower one will be also.
Maybe you can try to optimize the region to repaint on the upper panel in order to avoid repainting all the lower one. But if the painted rectangle in the upper panel covers the whole area, then you end up with full repaint() once again.
Normally, Swing tries to optimize the regions that need a repaint, but it also aggregates these regions when several repaint are performed in a short time, and if I remember well, the aggregated region is just a rectangle that is the union of all repaint rectangles, which is not always optimized but allows for fast computation of repaint events creation.
Now, I think you should follow the advices given in previous replies; indeed, you should really avoid having a paint() method that can perform computations that can be that long (a few 10s of ms should be the real maximum). Painting should be as fast as possible if you don't want to have a GUI that looks unresponsive to the end user. Hence, favour performing the computation only once (and outside the EDT if possible) store the result in a BufferedImage that you just simply draw later on in the paint() method.
EDIT: added other sources of reflection
If you want to optimize the update of the list of points but still keep it in the paint() method, then you can use the clipping region of the passed Graphics to limit the calls to drawing methods, something like:
Rectangle clip = g.getClipBounds();
for (Point p: allPoints) {
if (clip.contains(p)) {
// draw p with g graphics
}
}
You can even try to optimize the list of points to draw by using a QuadTree instead of a simple List, but you'll have to code it yourself (or find some free implementations, there are probably a few of them out there). With a quadtree, you can optimize the time to find the list of all points that have to be redrawn (based on the Graphics clipping rectangle) and only redraw those points.
Addenda for answer by trashgod and jfpoilpret
1/ OverlayLayout is strange way how to layout JPanels, are you same output with once JPanel (without OverlayLayout and Translucentcy)
2/ (10s or 100s of milliseconds) is maybe small value because there is Native OS Latency (45-75ms for today OS and PC)
3/ synchronizations would be managed by using SwingWorker on BackGround Task and with order, directions and synchronizations for painting processes to the JPanel, maybe your paints are too fast/quickly
4/ you didn't describe more about how, where and which about paint()/paintComponent()
if (SwingUtilities.isEventDispatchThread()) {
paintImmediately(int x, int y, int w, int h) // or Rectangle r
} else {
Runnable doRun = new Runnable() {
#Override
public void run() {
repaint(long tm, int x, int y, int width, int height) // or Rectangle r
}
};
SwingUtilities.invokeLater(doRun);
}
I'm making a frame which contains a round rectangle. This rectangle is constantly (re)painting
itself with smaller values.
The plan is, First the rectangle decreases in width(x), after that the rectangle decreases in height(y).
But for now I just want to get the width decreasing done with. But I'm having troubles here already.
Please note, i'm only drawing the rectangle's borders, so I don't want to fill it.
I made a for loop as follows:
for (rectWidth = 470; rectWidth >= 0; --rectWidth) {
try {
//simply made to represent rectWidth's value, not really relevant
System.out.println("rectWidth is: " + rectWidth);
//draw the rectangle with it's new width, ignore the "rectHeight" for now.
g.drawRoundRect(5, 5, rectWidth, rectHeight, 10, 10);
//this Thread.sleep is messing up my frame which has an instance of this class added
//to it also, my program is uninterruptable when adding this Thread.sleep
Thread.sleep(500);
} catch (Exception ex) {
//rectangle's value will be returned here when interrupted.
}
}
My question is, how can I add a 'sleep' in my for loop in order to make the drawing not go all too fast,
withouth messing my frame. This thread.sleep is messing my frame up in a way that I don't even see
the rectangle anymore.
I want to achieve a smooth (re)painting of the rectangle. (And yes I know as this piece of code is now
it isn't repainting the rectangle but constantly painting a slightly smaller rectangle in the frame.)
The reason that the rectangle isn't getting displayed is that the display is updated on the EventDispatchThread which is probably the same one your loop is on. That is it can't paint the rectangle because it's too busy sleeping.
The solution is to use a Swing Timer which will run and happily sleep sending tasks to the EventDispatchThread when updating.
Also you can start drawing thread
#Override
public void run(){
while(shouldDraw())
this.wait(500);
yourCalculations(); // maybe setting fields in runnable object
SwingUtilities.invokeAndWait(yourRunnableObject); // or invokeLater if you prefer non blocking version
}
This code shows only conception (I've skipped synchronization and exception handling). SwingTimer looks more elegant but I've never used it.