I am trying to draw increasing circles in a TextureView. The centre of all circles is the same. I then try to increase the drawn Circle until a specific limit is reached. Then I want to clear the canvas and start over again. However using my code (see below), the canvas seems to never be cleared. Actually it flashes white shortly when it should be cleared, but then when the first circle in the next cycle is drawn (after attempting to clear canvas), all previous circles reappear and the whole animation seems to go crazy. After letting it run for several seconds I am left with dozens of circles (some overlapping) instead of only approximately 4 per cycle. Furthermore they do not have the radius I gave them (basically my code ends up drawing numerous circles of random sizes). Spent several days trying different things, but nothing seems to help.
Here's my code:
paint.setColor(Color.argb(opac, 177, 177, 177));
stroke = 5;
paint.setStrokeWidth(stroke);
radius = 10;
Canvas canvas = new Canvas();
Boolean clear = false;
//Added these two lines following advice from a previous answer:
Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
while (mRunning && !Thread.interrupted()) {
canvas = mSurface.lockCanvas(null);
try {
if(clear){
canvas.drawPaint(clearPaint); //This line should clear the canvas.
clear = false;
}else{
canvas.drawCircle(circleX, circleY, radius, paint);
}
} finally {
mSurface.unlockCanvasAndPost(canvas);
}
if(radius+15 <= circleY-stroke/2){
radius+=15;
}else{
radius = 10;
clear = true;
}
try {
Thread.sleep(360);
} catch (InterruptedException e) {
// Interrupted
}
Would really appreciate it if someone could help me out here. I wasn't able to proceed with my project for several weeks now due to this problem.
Create a new Paint Instance for just clearing the canvas
Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
In your if() block for clearing the canvas, paint it with the above instance of Paint
if(clear){
canvas.drawPaint(clearPaint);
clear = false;
}
Related
I'm currently trying to draw an image to a JFrame (just a nonsense test image). In the code bite below, the image is drawn to the JFrame, but the area around the image that doesn't fill JFrame is black that rapidly flashes.
Here is the code below:
try {
myImage = ImageIO.read(ImagesMain.class.getResource("/Textures/TestImage.png"));
}catch(Exception e) {
e.printStackTrace();
}
BufferStrategy strategy = null;
while(strategy == null) {//I know this is terrible practice, just doing this way because its inside main
strategy = myCanvas.getBufferStrategy();
if(myCanvas.getBufferStrategy() == null) {
myCanvas.createBufferStrategy(3);
}
}
myFrame.setVisible(true);
//Rendering part
while(true) {
do {
do {
g = strategy.getDrawGraphics();
g.setColor(Color.WHITE);
g.drawImage(myImage, 20, 20, null);
g.dispose();
}while(strategy.contentsRestored());
strategy.show();
}while(strategy.contentsLost());
}
I've tested and retested my code several times to no avail. I should also add that this is all done in the main method (for testing purposes). Long story short, how do I display my image without the unnecessary black flashing around the image?
When this happens, it is because one is not clearing the Frame to which they are drawing. In this instance,
g.clearRect(x, y, height, width); is needed to clear the drawing frame and display a clear image.
Answer courtesy of #MadProgrammer above, in comments.
I am programming a simple game in which the ball should bounce when it hits the wall. I used JavaFX for the GUI, Canvas and GraphicsContext for drawing.
My code for drawing the Ball:
public void moving(){
gc.setFill(Color.BLACK);
gc.fillOval(ball.getCenterX()-15, ball.getCenterY()-15, 30,30);
if (ball.getCenterX()<285 && ball.getCenterX()>15) {
double xtemp = ball.getCenterX()+vektorx;
ball.setCenterX(xtemp);
} else {
vektorx = -vektorx;
double xtemp = ball.getCenterX()+vektorx;
ball.setCenterX(xtemp);
}
if (ball.getCenterY()<485 && ball.getCenterY()>15) {
double ytemp = ball.getCenterY()+vektory;
ball.setCenterY(ytemp);
} else {
vektory = -vektory;
double ytemp = ball.getCenterY()+vektory;
ball.setCenterY(ytemp);
}
gc.setFill(Color.AQUA);
gc.fillOval(ball.getCenterX()-15, ball.getCenterY()-15, 30,30);
}
Note that gc is the GraphicsContext I used. Everything works the way it's supposed to, but only one thing bothers me:
The ball leaves a trace of road its been taking and it bothers me very much. I tried the code for one move (draw it in blue and black again), it leaves no trace, but when I put it on a thread and let it run, this thing happens.
I don't know that much about JavaFX, I use a different system for graphics, but I think if you add this at the beginning, it may help a little:
gc.clearRect(0D, 0D, Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
A LinearGradientPaint object from java.awt may appear nice once painted, but there's a problem I'm having with it for painting an animated background in some kind of game model that's taking me long to build.
I want to paint an animated rainbow gradient on the background using the Graphics2D paint object, except that when I do so, I notice a lot of lag in repainting the panel. It should repaint itself at least 30 frames per second, which is only possible if the Paint object the graphics object uses is not a rainbow gradient.
Even running it as a separate thread will not do the trick. Below is the code for what I am trying to do at the end of each frame:
gamePanel.executor.execute(new Runnable(){
public void run()
{
while(true)
{
if (Background.selectedBackgroundIndex >= Background.SKY_HORIZON_GRADIENT_PAINT &&
Background.selectedBackgroundIndex < Background.SPACE_PAINT)
{
float displacementValue = 1.0f;
if (Background.backgroundShape.y < ((-2990.0f) + CannonShooterModel.gamePanel.getSize().height) && gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = false;
else if (Background.backgroundShape.y > (-10.0f) && !gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = true;
Point2D.Double startPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getStartPoint()),
endPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getEndPoint());
if (gamePanel.horizonGoingDown)
Background.backgroundShape.y -= displacementValue;
else
Background.backgroundShape.y += displacementValue;
startPoint.setLocation(0, Background.backgroundShape.y);
endPoint.setLocation(0, Background.horizonGradientPaintHeight + Background.backgroundShape.y);
// Should be done in another thread, particularly in arithmetic calculations.
Background.background = new LinearGradientPaint(startPoint, endPoint,
((LinearGradientPaint)Background.background).getFractions(),
((LinearGradientPaint)Background.background).getColors());
}
for (int a = 0; a < PlayerUnit.weapon.bullets.length; a++)
{
if (PlayerUnit.weapon.bullets[a] != null)
{
if (PlayerUnit.weapon instanceof Pistol &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0 &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x <= CannonShooterModel.gamePanel.getSize().width &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0)
{
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x +=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x -=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y -=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y +=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
}
else
PlayerUnit.weapon.bullets[a] = null;
}
}
//System.out.println(Background.backgroundShape.y);
repaint();
try
{
Thread.sleep(1000 / 60);
}
catch (InterruptedException ex)
{
}
}
}
});
The classes Background, PlayerUnit, and CannonShooterModel are important to my game model. It's an upright shooting game supposed to be designed with various weapons and enemies.
This rainbow gradient I have uses an array of eight different Color objects. For every frame passed through, I change the y-coordinate for both Point2D.Float objects required for the gradient paint as desired. In order for the animation to work, I have to actually instantiate another object of LinearGradientPaint again, with some of the previous properties from the previous object, and have it be referenced by the variable background of type Paint.
Problem is, LinearGradientPaint does not have a method to where you can do a translate on the two end points, and the get methods do not return the actual object that LinearGradientPaint object contains. (what I mean is, the get methods return a new object of Point2D with the same values as those part of the LinearGradientPaint object.)
For every frame passed, I have to change not only the y-coordinate property of the shape that's associated with the gradient, but also set the locations of the two Point2D objects that are needed to instantiate LinearGradientPaint once again.
I would love to re-explain this much simpler, because I can have trouble with some knowledge of English, even though this is my primary language. Please let me know if you need re-explanation.
There are a couple of solutions you might try.
Instead of filling the entire paintable area, you could create a BufferedImage whose width is 1 pixel and height equal to the area you want to fill (assuming you are fill vertically). You would then apply the LinearGradientPaint to this BufferedImage's Graphics2D and fill it (don't forget to dispose of the Graphics context when your done).
Then, you would simply use Graphics#drawImage(Image, x, y, width, height, ImageObserver) to actually paint the image. Generally speaking, it appears that it's faster to rescale an image then it is to fill it with a LinearGradientPaint, especially when you consider you are only stretching the image horizontally.
The other choice would be to generate a basic BufferedImage which had the LinearGradientPaint already applied and you would simply paint this offset as required. This would probably require you to paint it at least twice to allow it to "stitch" toegther...
If you are just making the background gradient move up and down, could you write it to an image at initialization and then move and wrap the image vertically?
I searched google for this problem, but i can't really resolve them.
More info on code below.
Here are the two snippets of code, relevant:
//prepare
g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0,0,getWidth(),getHeight());
for(ListIterator<Chunk> it = chunkvector.listIterator();it.hasNext();){
Chunk r = it.next();
r.drawChunk(g);
}
for(ListIterator<Entity> it = vectorpainter.listIterator();it.hasNext();){
Entity r = it.next();
r.drawObjects(g);
}
//Chat
if(coni.getVerified()){
try {
chat.update(g);
} catch (IOException e) {
println("I/O Exception while updating chat! "+e.toString());
}
//Framerate Anzeige
if(fps_on){
g.setColor(Color.red);
g.drawString("FPS: "+fps, 20, 20);
}
//Tickberechnung & Anzeige
tick++;
if(tick>=65536)
tick=0;
if(tick_on){
g.setColor(Color.red);
g.drawString("Tick: "+tick,80,20);
}
//end drawing
g.dispose();
strategy.show();
interesting about that:
Chunks, Entities are painted, white rect also, but fps and tick NEVER (both are true, of course), i even wrote System.out.print("..."); into the if-clauses, and it is executed! :S
I think it is something about GPU acceleration, so i added the second code block, how images are loaded. One entity does also drawString, (showing playername above head) and it works, but in the main thread not? :(
second:
public Image[] loadPics(String path, int cnt){
Image[] anim = new Image[cnt];
BufferedImage source = null;
BufferedImage temp;
URL pic_url = getClass().getResource(path);
if (pic_url == null) {
fail("Can't find ref: "+path);
}
try{
source = ImageIO.read(pic_url);
}catch(IOException e){
fail("Failed to load: "+path);
}
// create an accelerated image of the right size to store our sprite in
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
for(int x=0;x<cnt;x++){
temp = source.getSubimage(x*source.getWidth()/cnt, 0,
source.getWidth()/cnt, source.getHeight());
anim[x]= gc.createCompatibleImage(temp.getWidth(), temp.getHeight(), Transparency.BITMASK);
anim[x].getGraphics().drawImage(temp,0,0,null);
}
System.out.println(pic_url+" - loaded.");
return anim;
}
second one i copied from a tutorial, maybe a bit edited.Before that i"ve painted with paintComponent(Graphics g) ... this worked, tutorial have said i could get better performance using this method, so i tried, and want to manage it somehow.
Now it is drawing in a run loop, when i copy everything to paintComponent, no Images are drawn.
For those who managed to get past all the text a little bit of extra work:
The program runs fine on a university pc - not that good hardware ^^ , and bit of laggy at mine, which should be more than double the computationpower. Any ideas? :(
Java(c) 1.7
Many thanks, even you just read that! :)
Okay, this can be closed. My drawing problem had nothing to do with the code above.
Problem was, that things i wanted to paint were not in the picture. That I achieved through giving statements like:
fillRect(50,50,2/3*frame.getHeight(),130);
the 2/3 resolves to 0, multiplied with frameHeight...
Trick was to write (int)(2./3.*frame.getHeight())
and one time I also tried to draw a String into the panel section, where closing , maximize buttons are, that wont work too , of course.
THanks anyway!
I'm fairly new to Android programming. I'm trying to create an animation of a bitmap image using Canvas in Android. I am using setAlpha() to manipulate the opacity of the bitmap. My drawFrame() method includes the following bit:
c = holder.lockCanvas();
drawScene(c, paint);
holder.unlockCanvasAndPost(c);
My drawScene() includes this bit:
Paint transparencyValue = new Paint();
transparencyValue.setAlpha(paint);
canvas.drawBitmap(boom.getImage(), logoToBoom.getX(), logoToBoom.getY(),
transparencyValue);
I imagine I have to insert a loop to modify paint from 0 to 255 and back down. So far it hasn't worked, but I am probably doing something wrong. Could anyone please recommend something?
EDIT: Here is my code for the Runnable. paint is a private double set to 255. boom_activated is a boolean that becomes true if the onTouchEvent enabled it. It should stay true until the Runnable disables it (setBoomState(false);). For some reason it's still not drawing the bitmap at the decreasing opacity. Is the code below valid, or am I missing something?
private final Runnable DrawSceneThread = new Runnable() {
public void run() {
if (boom_activated && paint <= 0) {
paint = 0;
drawFrame();
setBoomState(false);
paint = 255;
} else if (boom_activated && paint >= 0) {
drawFrame();
paint -= 0.7;
} else {
drawFrame();
}`
In my drawScene() I have this line:
scene_handler.postDelayed(DrawSceneThread, 25);
What you have to do is to animate the opacity values over time. You need to use a handler to update the alpha values and then draw the bitmap in your onDraw function. Have a look at this tutorial to get a better idea about updating the UI through handlers: http://developer.android.com/resources/articles/timed-ui-updates.html
Refer to this topic
How to change a bitmap's opacity?
Also, I would recommend to take your Paint instance and paint variable out of your drawScene and declare it in a global scope so you can reuse it. It would hurt performance when recreating it over and over.