Drawing a moving ball with Canvas using JavaFX - java

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);

Related

Collision detection in game of pong corner cases causing issues

I have made a game of pong and everything about it is working so far. I did the collisions against the paddles to the ball and it can correctly bounce them away unless it hits the corners.
This is a video of what happens when the ball hits the corner of one of the paddles.
https://drive.google.com/file/d/1nyRzsp5tn5Qvst7kVjtlr_rDNH98avbA/view?usp=sharing
Essentially what you can see happen in the video is the ball hits the the paddle on the left at the corner and it doesn't bounce back it just traverses the paddle downwards and then keeps going and they get a point. Here is my code for the collision testing
public void collision() {
this.width = (float) getBounds().width;
this.height = (float) getBounds().height;
for (int i = 0; i < handler.objects.size(); i++) {
if (handler.objects.get(i).getId() == ID.ball) {
GameObject current = handler.objects.get(i);
if (getBounds().intersects(current.getBounds())) {
current.setVx(current.getVx() * -1);
}
}
}
}
getBounds is an overridden method that just returns a rectangle for both the ball(which is a circle) and the paddle
I am happy to provide more of my code if necessary.
Any help on this would be great, thanks!
You are swapping the velocity direction each time you are hitting the paddle, even when you are still touching the paddle in the next frame. The solution is to swap the velocity direction only when the ball is heading towards the paddle, not when (already) going away. The pseudo code can look like this:
if (GeometryUtil.isDirectionGoingDown(direction)) {
if (GeometryUtil.isBallHittingHorizontalLine(
newPosition,
Ball.RADIUS,
paddleTopLeft,
paddleTopRight)) {
direction = calculateNewDirectionAfterHittingPaddle(
direction,
paddlePosition,
newPosition);
ball.setDirection(direction);
}
}
Here the GeometryUtil.isDirectionGoingDown() method is checking if the ball is actually going down. That way the new direction is only set when this condition returned true. When the direction has been swapped in one frame, the next frame will not swap the direction again because GeometryUtil.isDirectionGoingDown() will return false then.

How to split a bullet to many bullets after shooting

im a programming beginner and i have do to for a game we are coding a shotgun shot but have a problem and dont know how to do it
i want to add a bullet in the game that when you shoot it, it spits itself into a few and small bullets in small different directions, so basically a shotgun shot.
i already have a normal bullet with his position,vector and velocity , and you can shoot it already. but my problem is or the thing i dont understand is how i can split that one bullet after i shoot it in many bullets and how every of it gets it own position and moving vector
Bullet class{
Vector2 moveVector;
float speed =15;
public void setMoveVector(float x, float y) {
moveVector = new Vector2(x,y);}
// in that area here its for the bullet how it moving/acting including if the path is free or blocked by walls or something
if(map.pathFree(getX(), getY(), getX()+ moveVector.x * speed, getY() + moveVector.y * speed, this)) {
setPosition(getX() + moveVector.x * speed, getY() + moveVector.y * speed);
//somewhere here sould come the code splitting the bullet
//removing the bullet after a distance
DistanceIndex += speed;
if(DistanceIndex >= 1000) {
remove();
}
}
else
HitWall();
if(outsideMap()) this.remove();
}
....
}
Obj Class
//class/object/gamefigure using/creating the bullet
.....
public void shootingMethod(){
......
double direction_x = Math.cos(Math.toRadians(rotation));
double direction_y = Math.sin(Math.toRadians(rotation));
Bullet bullet = new Bullet();
....
bullet.setMoveVector((float)direction_x, (float)directoin_y);
}
Picture of my problem i mean
Just make a bunch of smaller bullets start off at the same position and travel in slightly different directions. You could rotate the velocity vectors slightly for each bullet to achieve this. If they aren't already, you can make the bullets sensors so overlapping is not a problem

How to clear the Canvas (after drawing increasing circles) in a TextureView

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;
}

JAVA Background Animation (LinearGradientPaint)

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?

Yellow circle around cursor in Java

I'm trying to figure out how to make a yellow circle around the cursor in Java. The thing is that we've got a screen-recorder that (obviously) records the screen. Using the keywords "Yellow circle around cursor in Java" on Google only takes me to how to add a yellow circle around the cursor on a MAC, on WM and other applications, but not how to do it in Java on a users computer when the application starts.
How can I do it without using existing images? Drawing a simple yellow circle with some opacity would be the easiest thing to do, making it follow the mouse on the screen. And also, if it is possible to make it disappear and reappear when the user clicks a mouse-button, that'd be awesome.
It is possible to do this by attaching a MouseMotionListener to your component, but it will take a little work to get it working exactly how you want it.
I would start from something like this:
private static final double RADIUS = 15.0;
private static final double DIAMETER = 2.0 * RADIUS;
private static final Color XOR_COLOR = Color.yellow;
private static Shape m_circle = null;
#Override
public void mouseMoved(MouseEvent e)
{
Graphics2D g2 = (Graphics2D) getGraphics();
Point p = e.getPoint();
Shape circle = new Ellipse2D.Double(p.getX() - RADIUS, p.getY() - RADIUS, DIAMETER, DIAMETER);
clearCircle(g2);
g2.setXORMode(XOR_COLOR);
g2.draw(circle);
g2.setPaintMode();
m_circle = circle;
}
private void clearCircle(Graphics2D g2)
{
if (m_circle != null)
{
g2.setXORMode(XOR_COLOR);
g2.draw(m_circle);
g2.setPaintMode();
m_circle = null;
}
}
It will also be necessary to make sure that the old circle is cleared on the mouseExited event which you can listen for by adding a MouseListener. This also has the mousePressed/mouseReleased/mouseClicked events that you need for making it disappear/reappear on a user's mouse click.
Using XOR is convenient because it is very easy to restore the screen by repainting the same shape with the same color and style but it isn't quite what you asked for. It is possible to repair the screen by capturing an image of the area that you are about to draw the circle into. The circle can be removed from the screen by repainting the damaged area before painting a circle in a new position.
It's not possible to add a circle around the existing mouse pointer. You can only set the mouse pointer to a complete image.

Categories