Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

\"JavaFX\" programming (******Not Javascript******) Using the code from BallPane

ID: 3820170 • Letter: #

Question

"JavaFX" programming (******Not Javascript******)

Using the code from BallPane.java and BounceBallControl.java

Create a "Pong for One" game -

a rectangular paddle moves back and forth via mouse drag along the bottom of the pane;

the bottom of the paddle should be about 1/2 the diameter of the ball off the bottom.

If the ball connects with the paddle, then it bounces at a 90 degree angle back into the pane space.

If the ball misses the paddle, then the score is decremented by 1.

The game ends when 20 points are lost.

Nice things:

A label that displays the score (you can start at 20 and go to zero if you want...)

For every 10 paddle connections in a row, the ball moves faster

For every 10 paddle connections in a row, the ball changes color

For every (2) paddle misses in a row, the paddle grows in length

There is MATH involved in figuring out the connection between the paddle and the ball.

You probably want to pay a lot of attention to how moveBall() works.

-----------------------------------------------------------------------------------------------------------------------

BallPane.java

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.DoubleProperty;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Duration;

public class BallPane extends Pane {

public final double radius = 20;

private double x = radius, y = radius;

private double dx = 1, dy = 1;

private Circle circle = new Circle(x, y, radius);

private Timeline animation;

public BallPane() {

circle.setFill(Color.GREEN); // Set ball color

getChildren().add(circle); // Place a ball into this pane

animation = new Timeline(

new KeyFrame(Duration.millis(50), e -> moveBall()));

animation.setCycleCount(Timeline.INDEFINITE);

animation.play(); // Start animation

}
public void play(){

animation.play();

}

public void pause() {

animation.pause();

}

public void increaseSpeed() {

animation.setRate(animation.getRate() + 0.1);

}

public void decreaseSpeed() {

animation.setRate(

animation.getRate() > 0 ? animation.getRate() - 0.1 : 0);

}

public DoubleProperty rateProperty() {

return animation.rateProperty();

}

protected void moveBall() {

if (x < radius || x > getWidth() - radius) {

dx *= -1;}

if (y < radius || y > getHeight() - radius) {

dy *= -1; }

x += dx;

y += dy;

circle.setCenterX(x);

circle.setCenterY(y);

} }

--------------------------------------------------------------------------------------------------------

BounceBallControl.java

import javafx.application.Application;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;


public class BounceBallControl extends Application {

@Override
public void start(Stage primaryStage) {

BallPane ballPane = new BallPane(); // Create a ball pane

ballPane.setOnMousePressed(e -> ballPane.pause());

ballPane.setOnMouseReleased(e -> ballPane.play());

ballPane.setOnKeyPressed(e -> {

if (e.getCode() == KeyCode.UP) {

ballPane.increaseSpeed();

}

else if (e.getCode() == KeyCode.DOWN) {

ballPane.decreaseSpeed();

}

});

Scene scene = new Scene(ballPane, 250, 150);

primaryStage.setTitle("BounceBallControl"); // Set the stage title

primaryStage.setScene(scene); // Place the scene in the stage

primaryStage.show(); // Display the stage

ballPane.requestFocus();

}

}

Explanation / Answer

window.requestAnimFrame = (function(){
   return window.requestAnimationFrame ||
       window.webkitRequestAnimationFrame ||
       window.mozRequestAnimationFrame ||
       window.oRequestAnimationFrame ||
       window.msRequestAnimationFrame ||
       function( callback ){
           return window.setTimeout(callback, 1000 / 60);
       };
})();

window.cancelRequestAnimFrame = ( function() {
   return window.cancelAnimationFrame ||
       window.webkitCancelRequestAnimationFrame ||
       window.mozCancelRequestAnimationFrame ||
       window.oCancelRequestAnimationFrame ||
       window.msCancelRequestAnimationFrame ||
       clearTimeout
} )();


// Initialize canvas and required variables
var canvas = document.getElementById("canvas"),
       ctx = canvas.getContext("2d"), // Create canvas context
       W = window.innerWidth, // Window's width
       H = window.innerHeight, // Window's height
       particles = [], // Array containing particles
       ball = {}, // Ball object
       paddles = [2], // Array containing two paddles
       mouse = {}, // Mouse object to store it's current position
       points = 0, // Varialbe to store points
       fps = 60, // Max FPS (frames per second)
       particlesCount = 20, // Number of sparks when ball strikes the paddle
       flag = 0, // Flag variable which is changed on collision
       particlePos = {}, // Object to contain the position of collision
       multipler = 1, // Varialbe to control the direction of sparks
       startBtn = {}, // Start button object
       restartBtn = {}, // Restart button object
       over = 0, // flag varialbe, cahnged when the game is over
       init, // variable to initialize animation
       paddleHit;

// Add mousemove and mousedown events to the canvas
canvas.addEventListener("mousemove", trackPosition, true);
canvas.addEventListener("mousedown", btnClick, true);

// Initialise the collision sound
collision = document.getElementById("collide");

// Set the canvas's height and width to full screen
canvas.width = W;
canvas.height = H;

// Function to paint canvas
function paintCanvas() {
   ctx.fillStyle = "black";
   ctx.fillRect(0, 0, W, H);
}

// Function for creating paddles
function Paddle(pos) {
   // Height and width
   this.h = 5;
   this.w = 150;
  
   // Paddle's position
   this.x = W/2 - this.w/2;
   this.y = (pos == "top") ? 0 : H - this.h;
  
}

// Push two new paddles into the paddles[] array
paddles.push(new Paddle("bottom"));
paddles.push(new Paddle("top"));

// Ball object
ball = {
   x: 50,
   y: 50,
   r: 5,
   c: "green",
   vx: 4,
   vy: 8,
  
   // Function for drawing ball on canvas
   draw: function() {
       ctx.beginPath();
       ctx.fillStyle = this.c;
       ctx.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
       ctx.fill();
   }
};


// Start Button object
startBtn = {
   w: 100,
   h: 50,
   x: W/2 - 50,
   y: H/2 - 25,
  
   draw: function() {
       ctx.strokeStyle = "blue";
       ctx.lineWidth = "2";
       ctx.strokeRect(this.x, this.y, this.w, this.h);
      
       ctx.font = "18px Arial, sans-serif";
       ctx.textAlign = "center";
       ctx.textBaseline = "middle";
       ctx.fillStlye = "Green";
       ctx.fillText("Start", W/2, H/2 );
   }
};

// Restart Button object
restartBtn = {
   w: 100,
   h: 50,
   x: W/2 - 50,
   y: H/2 - 50,
  
   draw: function() {
       ctx.strokeStyle = "green";
       ctx.lineWidth = "2";
       ctx.strokeRect(this.x, this.y, this.w, this.h);
      
       ctx.font = "18px Arial, sans-serif";
       ctx.textAlign = "center";
       ctx.textBaseline = "middle";
       ctx.fillStlye = "white";
       ctx.fillText("Restart", W/2, H/2 - 25 );
   }
};

// Function for creating particles object
function createParticles(x, y, m) {
   this.x = x || 0;
   this.y = y || 0;
  
   this.radius = 1.2;
  
   this.vx = -1.5 + Math.random()*3;
   this.vy = m * Math.random()*1.5;
}

// Draw everything on canvas
function draw() {
   paintCanvas();
   for(var i = 0; i < paddles.length; i++) {
       p = paddles[i];
      
       ctx.fillStyle = "green";
       ctx.fillRect(p.x, p.y, p.w, p.h);
   }
  
   ball.draw();
   update();
}

// Function to increase speed after every 5 points
function increaseSpd() {
   if(points % 4 == 0) {
       if(Math.abs(ball.vx) < 15) {
           ball.vx += (ball.vx < 0) ? -1 : 1;
           ball.vy += (ball.vy < 0) ? -2 : 2;
       }
   }
}

// Track the position of mouse cursor
function trackPosition(e) {
   mouse.x = e.pageX;
   mouse.y = e.pageY;
}

// Function to update positions, score and everything.
// Basically, the main game logic is defined here
function update() {
  
   // Update scores
   updateScore();
  
   // Move the paddles on mouse move
   if(mouse.x && mouse.y) {
       for(var i = 1; i < paddles.length; i++) {
           p = paddles[i];
           p.x = mouse.x - p.w/2;
       }      
   }
  
   // Move the ball
   ball.x += ball.vx;
   ball.y += ball.vy;
  
   // Collision with paddles
   p1 = paddles[1];
   p2 = paddles[2];
  
   // If the ball strikes with paddles,
   // invert the y-velocity vector of ball,
   // increment the points, play the collision sound,
   // save collision's position so that sparks can be
   // emitted from that position, set the flag variable,
   // and change the multiplier
   if(collides(ball, p1)) {
       collideAction(ball, p1);
   }
  
  
   else if(collides(ball, p2)) {
       collideAction(ball, p2);
   }
  
   else {
       // Collide with walls, If the ball hits the top/bottom,
       // walls, run gameOver() function
       if(ball.y + ball.r > H) {
           ball.y = H - ball.r;
           gameOver();
       }
      
       else if(ball.y < 0) {
           ball.y = ball.r;
           gameOver();
       }
      
       // If ball strikes the vertical walls, invert the
       // x-velocity vector of ball
       if(ball.x + ball.r > W) {
           ball.vx = -ball.vx;
           ball.x = W - ball.r;
       }
      
       else if(ball.x -ball.r < 0) {
           ball.vx = -ball.vx;
           ball.x = ball.r;
       }
   }
  
  
  
   // If flag is set, push the particles
   if(flag == 1) {
       for(var k = 0; k < particlesCount; k++) {
           particles.push(new createParticles(particlePos.x, particlePos.y, multiplier));
       }
   }  
  
   // Emit particles/sparks
   emitParticles();
  
   // reset flag
   flag = 0;
}

//Function to check collision between ball and one of
//the paddles
function collides(b, p) {
   if(b.x + ball.r >= p.x && b.x - ball.r <=p.x + p.w) {
       if(b.y >= (p.y - p.h) && p.y > 0){
           paddleHit = 1;
           return true;
       }
      
       else if(b.y <= p.h && p.y == 0) {
           paddleHit = 2;
           return true;
       }
      
       else return false;
   }
}

//Do this when collides == true
function collideAction(ball, p) {
   ball.vy = -ball.vy;
  
   if(paddleHit == 1) {
       ball.y = p.y - p.h;
       particlePos.y = ball.y + ball.r;
       multiplier = -1;  
   }
  
   else if(paddleHit == 2) {
       ball.y = p.h + ball.r;
       particlePos.y = ball.y - ball.r;
       multiplier = 1;  
   }
  
   points++;
   increaseSpd();
  
   if(collision) {
       if(points > 0)
           collision.pause();
      
       collision.currentTime = 0;
       collision.play();
   }
  
   particlePos.x = ball.x;
   flag = 1;
}

// Function for emitting particles
function emitParticles() {
   for(var j = 0; j < particles.length; j++) {
       par = particles[j];
      
       ctx.beginPath();
       ctx.fillStyle = "white";
       if (par.radius > 0) {
           ctx.arc(par.x, par.y, par.radius, 0, Math.PI*2, false);
       }
       ctx.fill();     
      
       par.x += par.vx;
       par.y += par.vy;
      
       // Reduce radius so that the particles die after a few seconds
       par.radius = Math.max(par.radius - 0.05, 0.0);
      
   }
}

// Function for updating score
function updateScore() {
   ctx.fillStlye = "white";
   ctx.font = "16px Arial, sans-serif";
   ctx.textAlign = "left";
   ctx.textBaseline = "top";
   ctx.fillText("Score: " + points, 20, 20 );
}

// Function to run when the game overs
function gameOver() {
   ctx.fillStlye = "white";
   ctx.font = "20px Arial, sans-serif";
   ctx.textAlign = "center";
   ctx.textBaseline = "middle";
   ctx.fillText("Game Over - You scored "+points+" points!", W/2, H/2 + 25 );
  
   // Stop the Animation
   cancelRequestAnimFrame(init);
  
   // Set the over flag
   over = 1;
  
   // Show the restart button
   restartBtn.draw();
}

// Function for running the whole animation
function animloop() {
   init = requestAnimFrame(animloop);
   draw();
}

// Function to execute at startup
function startScreen() {
   draw();
   startBtn.draw();
}

// On button click (Restart and start)
function btnClick(e) {
  
   // Variables for storing mouse position on click
   var mx = e.pageX,
           my = e.pageY;
  
   // Click start button
   if(mx >= startBtn.x && mx <= startBtn.x + startBtn.w) {
       animloop();
      
       // Delete the start button after clicking it
       startBtn = {};
   }
  
   // If the game is over, and the restart button is clicked
   if(over == 1) {
       if(mx >= restartBtn.x && mx <= restartBtn.x + restartBtn.w) {
           ball.x = 20;
           ball.y = 20;
           points = 0;
           ball.vx = 4;
           ball.vy = 8;
           animloop();
          
           over = 0;
       }
   }
}

// Show the start screen
startScreen();