I am trying to code a very simple Pong-game, I think that is the name of this old game where a ball bounces between the player and a bunch of bricks with the ball going up and down. The player can move horizontally at the bottom.
So basically just some moving rectangles, eventually they are supposed to collide and so on.
However, I can allow the player to move the Rectangle with the buttons, but I can't manage to make objects move with the help of the AnimationTimer. (javafx.animation.AnimationTimer)
I already searched a lot but only found examples with mistakes that I managed to avoid.
(eg. like this AnimationTimer & JavaFX: Rectangle won't move horizontally using the setTranslateX() method. How to move Rectangle?).
I tried debugging it to see where the unexpected happens, but I couldn't find it. here is my code:
package bounceBall;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.control.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class BounceBallApp extends Application {
private Pane root = new Pane();
private Sprite player = new Sprite(400, 500, 40, 4, "player", Color.BLUE);
private boolean play;
private Parent createContent() {
this.play = false;
root.setPrefSize(800, 600);
root.getChildren().add(player);
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
update();
}
};
timer.start();
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 40; x++) {
Sprite s = new Sprite(20*x, y*8, 18, 5, "brick", Color.AQUA);
root.getChildren().add(s);
}
}
return root;
}
private List<Sprite> getSprites(){
List<Sprite> list = new ArrayList<Sprite>();
for (Node n : root.getChildren()) {
if (n instanceof Sprite) {
Sprite s = (Sprite)n;
list.add(s);
}
}
return list;
}
private void update() {
getSprites().forEach(b -> {
if (b.type.equals("bullet")) {
b.moveRight(b.getXspeed());
b.moveDown(b.getYspeed());
}
});
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createContent());
scene.setOnKeyPressed(e -> {
//as soon as any key gets hit the game starts with the shoot method
if (play == false) {
shoot(player);
play = true;
}
switch (e.getCode()) {
case A:{
player.moveLeft(10);
break;
}
case D:{
player.moveRight(10);
break;
}
default:
break;
}
});
primaryStage.setScene(scene);
primaryStage.setTitle("Bounce Ball");
primaryStage.show();
}
/*this method should be called once at the beginning to initiate the ball
the ball appears but it doesn't move, instead remains still
if I try to make the player move with AnimationTimer it doesn't work either, it works just by pressing keys*/
private void shoot(Sprite who) {
Sprite s = new Sprite((int)who.getTranslateX(), (int)who.getTranslateY()-2, 4, 4, "bullet", Color.BLACK);
s.setYspeed(-10);
root.getChildren().add(s);
System.out.println(root.getChildren().size());
}
private static class Sprite extends Rectangle {
final String type;
private int Xspeed, Yspeed;
public Sprite(int x, int y, int w, int h, String type, Color color) {
super(w, h, color);
this.type = type;
setTranslateX(x);
setTranslateY(y);
Xspeed = 0;
Yspeed = 0;
}
public void moveLeft(int d) {
setTranslateX(getTranslateX() - d);
}
public void moveRight(int d) {
setTranslateX(getTranslateX() + d);
}
public void moveUp(int d) {
setTranslateX(getTranslateY() - d);
}
public void moveDown(int d) {
setTranslateX(getTranslateY() + d);
}
public int getXspeed() {
return Xspeed;
}
public int getYspeed() {
return Yspeed;
}
public void setXspeed(int xspeed) {
Xspeed = xspeed;
}
public void setYspeed(int yspeed) {
Yspeed = yspeed;
}
}
public static void main(String[] args) {
launch(args);
}
}
I expect the ball to go straight up at the beginning but it appears at the wrong position (ca. 50px right from where I expect).
Most importantly it doesn't move.
Thanks a lot in advance.
Related
I'm trying to make a racing game with the top down view on a static player in the middle of the screen, so instead of moving the player through the map, the map would move around the player. Since it's a racing game, I wanted it to also be somewhat similar to a car, but I've been having trouble with rotating the map around the player and having that work with translations.
I've tried keeping track of the center by adding or subtracting from it, which is what I did for the translations, but it doesn't work with the rotate method. The rotate function wouldn't rotate about the player and instead would rotate the player around some other point, and the translations would snap to a different location from the rotations. I'm sure my approach is flawed, and I have read about layers and such, but I'm not sure what I can do with them or how to use them. Also, any recommendations as to how to use java graphics in general would be greatly appreciated!
This is what I have in my main:
import javax.swing.JFrame;
import java.awt.BorderLayout;
public class game
{
public static void main(String []args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 1000;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Map b = new Map();
frame.add(b,BorderLayout.CENTER);
frame.setVisible(true);
b.startAnimation();
}
}
And this is the class that handles all the graphics
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Map extends JComponent implements Runnable, KeyListener
{
private int speed = 5;
private int xcenter = 500; // starts on player
private int ycenter = 300;
private double angle = 0.0;
private int[] xcords = {xcenter+10, xcenter, xcenter+20};
private int[] ycords = {ycenter-10, ycenter+20, ycenter+20};
private boolean moveNorth = false;
private boolean moveEast = false;
private boolean moveSouth = false;
private boolean moveWest = false;
public Map()
{
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void startAnimation()
{
Thread t = new Thread(this);
t.start();
}
public void paintComponent(Graphics g)
{
g.fillPolygon(xcords, ycords, 3);
// move screen
if(moveNorth)
{
ycenter += speed;
g.translate(xcenter, ycenter);
}
else if(moveEast)
{
angle += ((1 * Math.PI/180) % (2 * Math.PI));
((Graphics2D) g).rotate(angle, 0, 0);
}
else if(moveSouth)
{
System.out.println(xcenter + ", " + ycenter);
ycenter -= speed;
((Graphics2D) g).rotate(angle, 0, 0);
g.translate(xcenter, ycenter);
}
else if(moveWest)
{
angle -= Math.toRadians(1) % (2 * Math.PI);
((Graphics2D) g).rotate(angle, 0, 0);
}
for(int i = -10; i < 21; i++)
{
g.drawLine(i * 50, -1000, i * 50, 1000);
g.drawLine(-1000, i * 50, 1000, i * 50);
}
g.drawOval(0, 0, 35, 35);
}
public void run()
{
while (true)
{
try
{
if(moveNorth || moveEast || moveSouth || moveWest)
{
repaint();
}
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void keyPressed(KeyEvent e)
{
if(e.getExtendedKeyCode() == 68) // d
{
moveEast = true;
}
else if(e.getExtendedKeyCode() == 87) // w
{
moveNorth = true;
}
else if(e.getExtendedKeyCode() == 65) // a
{
moveWest = true;
}
else if(e.getExtendedKeyCode() == 83) // s
{
moveSouth = true;
}
}
public void keyReleased(KeyEvent e)
{
moveNorth = false;
moveEast = false;
moveSouth = false;
moveWest = false;
}
public void keyTyped(KeyEvent e)
{
}
}
You have to keep in mind that transformations are compounding, so if you rotate the Graphics context by 45 degrees, everything painted after it will be rotated 45 degrees (around the point of rotation), if you rotate it again by 45 degrees, everything painted after it will be rotated a total of 90 degrees.
If you want to paint additional content after a transformation, then you either need to undo the transformation, or, preferably, take a snapshot of the Graphics context and dispose of it (the snapshot) when you're done.
You also need to beware of the point of rotation, Graphics2D#rotate(double) will rotate the Graphics around the point of origin (ie 0x0), which may not be desirable. You can change this by either changing the origin point (ie translate) or using Graphics2D#rotate(double, double, double), which allows you to define the point of rotation.
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
enum Direction {
LEFT, RIGHT;
}
protected enum InputAction {
PRESSED_LEFT, PRESSED_RIGHT, RELEASED_LEFT, RELEASED_RIGHT
}
private BufferedImage car;
private BufferedImage road;
private Set<Direction> directions = new TreeSet<>();
private double directionOfRotation = 0;
public TestPane() throws IOException {
car = ImageIO.read(getClass().getResource("/images/Car.png"));
road = ImageIO.read(getClass().getResource("/images/Road.png"));
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), InputAction.PRESSED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), InputAction.RELEASED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), InputAction.PRESSED_RIGHT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), InputAction.RELEASED_RIGHT);
am.put(InputAction.PRESSED_LEFT, new DirectionAction(Direction.LEFT, true));
am.put(InputAction.RELEASED_LEFT, new DirectionAction(Direction.LEFT, false));
am.put(InputAction.PRESSED_RIGHT, new DirectionAction(Direction.RIGHT, true));
am.put(InputAction.RELEASED_RIGHT, new DirectionAction(Direction.RIGHT, false));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (directions.contains(Direction.RIGHT)) {
directionOfRotation += 1;
} else if (directions.contains(Direction.LEFT)) {
directionOfRotation -= 1;
}
// No doughnuts for you :P
if (directionOfRotation > 180) {
directionOfRotation = 180;
} else if (directionOfRotation < -180) {
directionOfRotation = -180;
}
repaint();
}
});
timer.start();
}
protected void setDirectionActive(Direction direction, boolean active) {
if (active) {
directions.add(direction);
} else {
directions.remove(direction);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(213, 216);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawRoadSurface(g2d);
drawCar(g2d);
g2d.dispose();
}
protected void drawCar(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
int x = (getWidth() - car.getWidth()) / 2;
int y = (getHeight() - car.getHeight()) / 2;
g2d.drawImage(car, x, y, this);
g2d.dispose();
}
protected void drawRoadSurface(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
// This sets the point of rotation at the center of the window
int midX = getWidth() / 2;
int midY = getHeight() / 2;
g2d.rotate(Math.toRadians(directionOfRotation), midX, midY);
// We then need to offset the top/left corner so that what
// we want draw appears to be in the center of the window,
// and thus will be rotated around it's center
int x = midX - (road.getWidth() / 2);
int y = midY - (road.getHeight() / 2);
g2d.drawImage(road, x, y, this);
g2d.dispose();
}
protected class DirectionAction extends AbstractAction {
private Direction direction;
private boolean active;
public DirectionAction(Direction direction, boolean active) {
this.direction = direction;
this.active = active;
}
#Override
public void actionPerformed(ActionEvent e) {
setDirectionActive(direction, active);
}
}
}
}
i am making a game with cactus pictures but when i do my code if its trying to switch between pictures it will stops and will freeze on that point the else if it does not work i also use bufferedimage for the pictures
my code:
package objectgame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import util.Resource;
public class EnemiesManager {
private List<Enemy> enemies;
private Random random;
private BufferedImage imagecactus1, imagecactus2, imagecactus3 ;
public EnemiesManager() {
enemies = new ArrayList<Enemy>();
imagecactus1 = Resource.getResourceImage("data/cactus1.png");
imagecactus2 = Resource.getResourceImage("data/cactus2.png");
imagecactus3 = Resource.getResourceImage("data/cactus3.png");
random = new Random();
enemies.add(getRandomCactus());
random = new Random();
}
public void update() {
for(Enemy e: enemies) {
e.update();
}
Enemy firstEnemy = enemies.get(0);
if(firstEnemy.isOutOfScreen()) {
enemies.remove(firstEnemy);
enemies.add(getRandomCactus());
}
}
public void draw(Graphics g) {
for(Enemy e: enemies) {
e.draw(g);
}
}
private Cactus getRandomCactus() {
Cactus cactus;
cactus = new Cactus();
cactus.setX(600);
if(random.nextBoolean()) {
cactus.setImage(imagecactus1);
}
else{
cactus.setImage(imagecactus2);
}
return cactus;
}
}
new class
package objectgame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import util.Resource;
public class Cactus extends Enemy{
private BufferedImage image;
private int posX, posY;
private Rectangle rect;
public Cactus() {
image = Resource.getResourceImage("data/cactus1.png");
posX = 200;
posY = 83;
rect = new Rectangle();
}
public void update() {
posX -= 3;
rect.x = posX;
rect.y = posY;
rect.width = image.getWidth();
rect.height = image.getHeight();
}
#Override
public Rectangle getBound() {
return rect;
}
#Override
public void draw(Graphics g) {
g.drawImage(image, posX, posY, null);
}
public void setX(int x) {
posX = x;
}
public void setY(int y) {
posY = y;
}
public void setImage(BufferedImage images) {
this.image = images;
}
#Override
public boolean isOutOfScreen() {
return (posX + image.getWidth() < 0);
}
}
what is the problem this is the code from the anamation manager and the details from the picture. I have tried many tutorials but none where working correct always slightly off the purpose for the random bool. I use eclipse so I don't get any errors specific to the location where the error happens. I also did use debugger but non are working. So I really need your guys help.
A clean approach is as follows:
private Cactus getRandomCactus() {
Cactus cactus = new Cactus();
cactus.setX(600);
BufferedImage [] images = {imagecactus1, imagecactus2, imagecactus3};
cactus.setImage(images[random.nextInt(3)]);
return cactus;
}
Note: random.nextInt(3) returns an int from 0 to 2 i.e. either 0 or 1 or 2.
There are a couple reasons you could be running into issues, the main one being the fact that you're called Random.nextBoolean() multiple times. When you do that, it gives you a new value each time. You'd want to set a variable equal to Random.nextBoolean().
Also, since you appear to be choosing between three different images, rather than two. For this, I recommend you use Random.nextInt instead:
private Cactus getRandomCactus() {
Cactus cactus;
cactus = new Cactus();
int randomInt = random.nextInt(0, 3); // this only called random.nextInt once, and gives me a random number between 0 and 2
cactus.setX(600);
if(randomInt == 0) {
cactus.setImage(imagecactus1);
}
else if (randomInt == 1) {
cactus.setImage(imagecactus2);
}
else {
cactus.setImage(imagecactus3);
}
return cactus;
}
the problem what that there where 2 files called cactus3.png and also there was one space to much. thanks for thinking with me .
I am attempting to embed a game into my website that I programmed in java. I have no idea how to take my code from eclipse(which is what my JDE is) and put it into my website. I am using a weebly.com website. I do have several unfinished classes, I want to upload my incomplete games as well as complete just to show progress. so I ask you, how do I get this code from eclipse, to my website. Thanks for the help and the following is my code.
This is my Main class:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
public class Main extends Applet implements Runnable {
private static final long serialVersionUID = 1L;
Thread th = new Thread(this);
boolean running = true;
public int Jweidth = 400, Jheight = 400;
Image dbImage;
Graphics dbGraphics;
Bullet b;
Player p;
Enemy e, e2, e3, e4, e5, e6, e7, e8;
HealthBar hb;
NameSign ns;
Restart r;
private boolean BFire;
public void init() {
//set window size
setSize(Jweidth, Jheight);
//calls player class
p = new Player(this);
//calls healthBar
hb = new HealthBar(this, p);
//calls enemy class
e = new Enemy(this);
e2 = new Enemy(42, 0, this);
e3 = new Enemy(84, 0, this);
e4 = new Enemy(126, 0, this);
e5 = new Enemy(0, 42, this);
e6 = new Enemy(42, 42, this);
e7 = new Enemy(84, 42, this);
e8 = new Enemy(126, 42, this);
//calls bullet class
b = new Bullet(this);
//calls nameSign class
ns = new NameSign(this);
//calls Restart class
r = new Restart(this);
}
public void start() {
//starts a new thread
th.start();
}
public void stop() {
running = false;
}
public void destroy() {
running = false;
}
public void run() {
while (running) {
setBFire(b.getFire());
//calls update method from player class
p.update(this);
//calls update method from enemy class
e.update(this, p);
e2.update(this, p);
e3.update(this, p);
e4.update(this, p);
e5.update(this, p);
e6.update(this, p);
e7.update(this, p);
e8.update(this, p);
//calls update method from fire class if BFire is true
if (setBFire(true)) {
b.update(this, p);
}
//calls update method from HealthBar class
hb.update(this, p);
//calls update method from NameSign class
ns.update(this);
//calls update method from Restart class
r.update(this, p);
repaint();
//sets Thread to repeat every 17 milliseconds
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//doublebuffer
public void update(Graphics g) {
dbImage = createImage(Jweidth, Jheight);
dbGraphics = dbImage.getGraphics();
paint(dbGraphics);
g.drawImage(dbImage, 0, 0, this);
}
//paint class
public void paint(Graphics g) {
//calls paint method from player class
p.paint(g, this);
//calls paint method from enemy class
e.paint(g, this);
e2.paint(g, this);
e3.paint(g, this);
e4.paint(g, this);
e5.paint(g, this);
e6.paint(g, this);
e7.paint(g, this);
e8.paint(g, this);
//calls paint method from bullet class
b.paint(g, this);
//calls paint method from healthBar class
hb.paint(g, this);
//calls paint method from nameSign class
ns.paint(g, this);
//calls paint method from Restart class
r.paint(g);
}
public int getJweidth() {
return Jweidth;
}
public int getJheight() {
return Jheight;
}
//ignore all boolean Bfire methods
public boolean isBFire() {
return BFire;
}
public boolean setBFire(boolean bFire) {
BFire = bFire;
return bFire;
}
}
This is my Enemy class:
import java.awt.*;
import java.net.URL;
public class Enemy {
//Enemy ints
private int x = 0, y = 0, speed = 2;
private URL url;
private Image Enemy;
//adds image
public Enemy(Main m){
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
}
public Enemy(int i, int j, Main m) {
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
x = i;
y = j;
}
//same as run method but just for the enemy
public void update(Main m, Player p){
x += speed;
if(x <= 0){
speed = 2;
y += 32;
}
else if(x > m.getJweidth() - 32){
speed = -2;
y += 32;
}
//calls collision method
collision(p);
}
//enemy player hitbox
private void collision(Player p) {
int Px = p.getX();
int Py = p.getY();
int Pr = p.getRadious();
if(Px - Pr <= x && Px + Pr >= x && Py - Pr <= y && Py + Pr >= y){
p.hit();
}
}
//Graphics for enemy
public void paint(Graphics g, Main m){
g.drawImage(Enemy, x, y, m);
}
}
This is my Bullet class (this game is a work in progress and this class isn't working, but that is just unfinished work that I will do soon)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
public class Enemy {
//Enemy ints
private int x = 0, y = 0, speed = 2;
private URL url;
private Image Enemy;
//adds image
public Enemy(Main m) {
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
}
public Enemy(int i, int j, Main m) {
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
x = i;
y = j;
}
//same as run method but just for the enemy
public void update(Main m, Player p) {
x += speed;
if (x <= 0) {
speed = 2;
y += 32;
} else if (x > m.getJweidth() - 32) {
speed = -2;
y += 32;
}
//calls collision method
collision(p);
}
//enemy player hitbox
private void collision(Player p) {
int Px = p.getX();
int Py = p.getY();
int Pr = p.getRadious();
if (Px - Pr <= x && Px + Pr >= x && Py - Pr <= y && Py + Pr >= y) {
p.hit();
}
}
//Graphics for enemy
public void paint(Graphics g, Main m) {
g.drawImage(Enemy, x, y, m);
}
}
This is my Restart class(once again unfinished but on the way)
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Restart implements KeyListener {
private int x, y;
private int pHealth;
private String string = "Would you like to play again?";
private boolean restart = false;
public Restart(Main m) {
x = 600;
y = 600;
}
public void update(Main m, Player p) {
//checks if players health = 0 and if restart is true
pHealth = p.getpHealth();
if (setRestart(true && pHealth <= 0)) {
System.out.println("Restart");
x = m.Jweidth / 2 - 75;
y = m.Jheight / 2;
}
//reset ints for player
//TODO
//reset ints for enemy
//TODO
//reset ints for bullet
//TODO
//reset ints for healthbar
//TODO
}
public void paint(Graphics g) {
g.drawString(string, x, y);
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_F1: {
setRestart(true);
break;
}
}
}
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_F1: {
setRestart(false);
break;
}
}
}
public void keyTyped(KeyEvent arg0) {
}
//ignore all boolean methods
public boolean isRestart() {
return restart;
}
public boolean setRestart(boolean restart) {
this.restart = restart;
return restart;
}
}
You will have to use Applets to embed your Java program in a browser, or Java Web Start if you just want to start it from the web in a new window.
Some security issues may apply depending on the Java version you are using.
Here are some examples on how to do it:
https://docs.oracle.com/javase/tutorial/deployment/applet/
http://www.javatpoint.com/java-applet
And here for the Java Web Start:
https://docs.oracle.com/javase/tutorial/deployment/webstart/
You're gonna need to make a .jar file and a compiled .class file, no .java file. To implement Java code in HTML, you can use the deprecated <applet> tag, or the new <object> tag.
<object codetype="application/java" classid="java:yourclass.class" archive="yourjar.jar" width="1000" height="1000"></object>
codetype="application/java" - The type of code, use application/java.
classid="?" - Java class to run, eg. java:MyApplet.class
archive="url" - Address or filename of the Java archive file (.jar) containing the class files.
width="?" - The width of the window, in pixels.
height="?" - The height of the window, in pixels.
Just telling you, I'm not sure that it'll work.
I'm working on a project where i need
to make circles and relate between them with cubicCurve
as shown in this image:
And i need to pass mouseclick events through the part of the cubicCurve colored with "ALICEBLUE", but still being able to pass mouseclick events to the Line colored with "BLACK".
cubicCurve Code:
public class transLine extends CubicCurve {
private Polygon polygon;
private Circle to;
private Circle from;
private double arrowHeadTransLength;
public Circle getTo() {
return to;
}
public void setTo(Circle to) {
this.to = to;
}
public Circle getFrom() {
return from;
}
public void setFrom(Circle from) {
this.from = from;
}
public transLine() {
setStroke(Color.BLACK);
setFill(Color.ALICEBLUE);
// doesn't work because i can't pass click event to the black line
setMouseTransparent(true);
// just arrow head part
polygon = new Polygon();
fixPolygon();
}
public void fixPolygon(){
Point2D A = new Point2D(getEndX(),getEndY());
Point2D Ap = new Point2D(getControlX2(),getControlY2());
Point2D Ms = getMSecond(A,Ap,arrowHeadTransLength);
Point2D P1 = getRotatePoint(Ms, A, Math.PI/7);
Point2D P2 = getRotatePoint(Ms, A, -Math.PI/7);
getPolygon().getPoints().setAll(new Double[]
{A.getX(),A.getY(),P1.getX(),P1.getY(),P2.getX(),P2.getY()});
}
public Point2D getMSecond(Point2D A, Point2D B, double r){
if( A.getX()==B.getX() && A.getY()==B.getY() ){
return B;
}
double a = (A.getY()-B.getY())/(A.getX()-B.getX());
double b = A.getY()-a*A.getX();
double xs = -r*(A.getX()-B.getX())/A.distance(B)+A.getX();
double ys = a*xs+b;
return new Point2D(xs,ys);
}
public Point2D getRotatePoint(Point2D P, Point2D O, double theta){
double rx = Math.cos(theta)*(P.getX()-O.getX()) - Math.sin(theta)*
(P.getY()-O.getY()) + O.getX();
double ry = Math.sin(theta)*(P.getX()-O.getX()) + Math.cos(theta)*
(P.getY()-O.getY()) + O.getY();
return new Point2D(rx,ry);
}
}
I can't see a particularly easy way to do this. I think that in order to have different mouse behaviors for the fill and the curve, you need those to be different nodes. So the idea is to create the curve and the fill as separate pieces, place them in a Group, and then use the Group in the display. Then make the piece representing the fill mouse-transparent.
Actually implementing that is a bit tricky; particularly getting a cubic curve that doesn't respond to mouse clicks in its "interior". The only way I could find to do this was to use a Path comprising of a MoveTo, a CubicCurveTo, and then another CubicCurveTo that retraced the reverse path (this ensures the interior is essentially empty). Then, as suggested, place that in a group along with a regular CubicCurve representing the filled portion.
SSCCE:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
public class ConnectingCubicCurve extends Application {
#Override
public void start(Stage primaryStage) {
Circle start = createDraggingCircle(100, 100, 10, Color.CORAL);
Circle end = createDraggingCircle(300, 300, 10, Color.CORAL);
Connection connection = new Connection();
connection.setFromCircle(start);
connection.setToCircle(end);
Pane pane = new Pane(connection.asNode(), start, end);
pane.setOnMouseClicked(e -> System.out.println("Click on pane"));
connection.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("Click on connection"));
start.setOnMouseClicked(e -> System.out.println("Click on start"));
end.setOnMouseClicked(e -> System.out.println("Click on end"));
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private Circle createDraggingCircle(double centerX, double centerY, double radius, Paint fill) {
Circle circle = new Circle(centerX, centerY, radius, fill);
ObjectProperty<Point2D> mouseLoc = new SimpleObjectProperty<>();
circle.setOnDragDetected(e ->
mouseLoc.set(new Point2D(e.getSceneX(), e.getSceneY())));
circle.setOnMouseReleased(e -> mouseLoc.set(null));
circle.setOnMouseDragged(e -> {
if (mouseLoc.get() == null) return ;
double x = e.getSceneX() ;
double y = e.getSceneY() ;
double deltaX = x - mouseLoc.get().getX() ;
double deltaY = y - mouseLoc.get().getY() ;
circle.setCenterX(circle.getCenterX() + deltaX);
circle.setCenterY(circle.getCenterY() + deltaY);
mouseLoc.set(new Point2D(x, y));
});
return circle ;
}
public static class Connection {
private Path connectingLine ;
private CubicCurve fill ;
private Group group ;
private ObjectProperty<Circle> fromCircle = new SimpleObjectProperty<>();
private ObjectProperty<Circle> toCircle = new SimpleObjectProperty<>();
public Connection() {
connectingLine = new Path();
MoveTo start = new MoveTo();
CubicCurveTo curve = new CubicCurveTo();
CubicCurveTo reverseCurve = new CubicCurveTo();
reverseCurve.xProperty().bind(start.xProperty());
reverseCurve.yProperty().bind(start.yProperty());
reverseCurve.controlX1Property().bind(curve.controlX2Property());
reverseCurve.controlX2Property().bind(curve.controlX1Property());
reverseCurve.controlY1Property().bind(curve.controlY2Property());
reverseCurve.controlY2Property().bind(curve.controlY1Property());
connectingLine.getElements().addAll(start, curve, reverseCurve);
fill = new CubicCurve();
fill.setMouseTransparent(true);
group = new Group();
group.getChildren().addAll(fill, connectingLine);
connectingLine.setStroke(Color.BLACK);
connectingLine.setStrokeWidth(3);
fill.setStrokeWidth(0);
fill.setStroke(Color.TRANSPARENT);
fill.setFill(Color.ALICEBLUE);
fill.startXProperty().bind(start.xProperty());
fill.startYProperty().bind(start.yProperty());
fill.controlX1Property().bind(curve.controlX1Property());
fill.controlX2Property().bind(curve.controlX2Property());
fill.controlY1Property().bind(curve.controlY1Property());
fill.controlY2Property().bind(curve.controlY2Property());
fill.endXProperty().bind(curve.xProperty());
fill.endYProperty().bind(curve.yProperty());
fromCircle.addListener((obs, oldCircle, newCircle) -> {
if (oldCircle != null) {
start.xProperty().unbind();
start.yProperty().unbind();
}
if (newCircle != null) {
start.xProperty().bind(newCircle.centerXProperty());
start.yProperty().bind(newCircle.centerYProperty());
}
});
toCircle.addListener((obs, oldCircle, newCircle) -> {
if (oldCircle != null) {
curve.xProperty().unbind();
curve.yProperty().unbind();
}
if (newCircle != null) {
curve.xProperty().bind(newCircle.centerXProperty());
curve.yProperty().bind(newCircle.centerYProperty());
}
});
ChangeListener<Number> endpointListener = (obs, oldValue, newValue) -> {
Point2D startPoint = new Point2D(start.getX(), start.getY());
Point2D end = new Point2D(curve.getX(), curve.getY());
Point2D vector = end.subtract(startPoint);
Point2D perpVector = new Point2D(-vector.getY(), vector.getX());
Point2D control1 = startPoint.add(perpVector);
Point2D control2 = end.add(perpVector);
curve.setControlX1(control1.getX());
curve.setControlX2(control2.getX());
curve.setControlY1(control1.getY());
curve.setControlY2(control2.getY());
};
start.xProperty().addListener(endpointListener);
start.yProperty().addListener(endpointListener);
curve.xProperty().addListener(endpointListener);
curve.yProperty().addListener(endpointListener);
}
public <E extends Event> void addEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) {
connectingLine.addEventHandler(eventType, eventHandler);
}
public <E extends Event> void removeEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) {
connectingLine.removeEventHandler(eventType, eventHandler);
}
public Node asNode() {
return group ;
}
public final ObjectProperty<Circle> fromCircleProperty() {
return this.fromCircle;
}
public final javafx.scene.shape.Circle getFromCircle() {
return this.fromCircleProperty().get();
}
public final void setFromCircle(final javafx.scene.shape.Circle fromCircle) {
this.fromCircleProperty().set(fromCircle);
}
public final ObjectProperty<Circle> toCircleProperty() {
return this.toCircle;
}
public final javafx.scene.shape.Circle getToCircle() {
return this.toCircleProperty().get();
}
public final void setToCircle(final javafx.scene.shape.Circle toCircle) {
this.toCircleProperty().set(toCircle);
}
}
public static void main(String[] args) {
launch(args);
}
}
Would like to first state that I am a computer science student and my University is strict on direct code copying so if you could please refrain from answers such as "it should look like this" it would be greatly appreciated. So basically my assignment is to create a JavaFX program that contains multiple green balls, and one red ball. All the balls must wrap around the pane (in an asteroids type of way) and if a red ball happens to collide with the green ball, the green ball is removed. I have multiple issues, but the key one I need to focus on is how to get all the balls from my ArrayList along with my one red ball to show up in the pane and move independently. They are all there in the pane (and bounce currently) but its like they are all bound together. I have given each ball random xy values and they should also all have random dx/dy values(their velocity). And I believe that is where my problem lies, each ball does not have their own dx/dy, thus I created a class that extends Circle to try and solve that problem but my getters and setters do not seem to be accessible. I also know the root of the problem lies in the moveBall() method as it is the method that needs to adjust values, but I cannot figure out the algorithm, and since my professor's office hours are over, I have came here in hopes of someone pointing me in the right direction. Here are the classses(I would also like to state, this is not fully my code; it's modified code from a Case Study exercise from "Intro To Java Programming 10th ed. by Y. Daniel Liang):
EDIT: Corrected a small error. Main problem is getting all the balls to now move independently via the moveBall() method.
EDIT 2: Assignment is OVER. Answers are are no longer restricted. Also added other methods that are not doing what I want addBallToPane() and checkForCollision() If anyone can tell me how I could repair these that would be great. Still want to solve this on my own, but with help :)
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;
import java.util.ArrayList;
public class BallPane extends Pane {
MovementGenerator mG = new MovementGenerator();
public final double radius = 20;
private double x = mG.position(), y = mG.position();
private double dx = mG.velocity(), dy = mG.velocity();
private Circle predator = new MovableCircle(x, y, radius, Color.RED);
private Timeline animation;
ArrayList<MovableCircle> circles = new ArrayList<>();
public BallPane() {
for (int i = 0; i < 10; i++) {
circles.add(i, new MovableCircle(x, y, radius, Color.GREEN));
circles.get(i).setDx(dx);
circles.get(i).setDy(dy);
}
getChildren().addAll(circles);
predator.setFill(Color.RED);
getChildren().add(predator);
// Create an animation for moving the ball
animation = new Timeline(
new KeyFrame(Duration.millis(5), 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 void addBallToPane() {
incrementalEnding++;
circles.add(new MovableCircle(radius, Color.GREEN));
getChildren().add(circles.get(incrementalEnding));
}
public void checkForCollison() {
for (int i = 0; i < getChildren().size(); i++) {
if ((predator.intersects(circles.get(i).getBoundsInLocal()))) {
getChildren().remove(circles.get(i));
}
}
protected void moveBall() {
// Check boundaries
if (x < radius || x > getWidth() - radius) {
dx *= -1; // Change ball move direction
}
if (y < radius || y > getHeight() - radius) {
dy *= -1; // Change ball move direction
}
// Adjust ball position
for (int i = 0; i < circles.size(); i++) {
x += dx;
y += dy;
circles.get(i).setCenterX(x);
circles.get(i).setCenterY(y);
}
predator.setCenterX(x);
predator.setCenterY(y);
}
}
Side note: I wanna set the dx/dy as the objects are created in the ArrayList, but as I stated my accessors and mutators are not accessible.
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
public class BounceBallControl extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
BallPane ballPane = new BallPane(); // Create a ball pane
// Pause and resume animation
// ballPane.setOnMousePressed(e -> ballPane.pause());
// ballPane.setOnMouseReleased(e -> ballPane.play());
// Increase and decrease animation
ballPane.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.UP) {
ballPane.increaseSpeed();
}
else if (e.getCode() == KeyCode.DOWN) {
ballPane.decreaseSpeed();
}
});
// Create a scene and place it in the stage
Scene scene = new Scene(ballPane, 500, 500);
primaryStage.setTitle("BounceBallControl"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
// Must request focus after the primary stage is displayed
ballPane.requestFocus();
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class MovableCircle extends Circle{
MovementGenerator mG = new MovementGenerator();
private double dx, dy;
MovableCircle(double x, double y, double radius, Color color){
super(x, y, radius);
setFill(color);
}
public double getDx() {
return dx;
}
public void setDx(double newDx) {
if (newDx < -10 || newDx > 10) {
newDx = mG.velocity();
} else {
dx = newDx;
}
}
public double getDy() {
return dy;
}
public void setDy(double newDy) {
if (newDy < -10 || newDy > 10) {
newDy = mG.velocity();
} else {
dy = newDy;
}
}
}
This next class doesn't do much besides generate random values, probably didn't need to make a whole new class for its function but eh. And it is just here for reference just in case:
import java.util.Random;
public class MovementGenerator {
private static int movement;
private static int spawnPoint;
Random rand = new Random();
MovementGenerator(){
movement = 0;
spawnPoint = 0;
}
public static int getMovement() {
return movement;
}
public static void setMovement(int movement) {
MovementGenerator.movement = movement;
}
public static int getSpawnPoint() {
return spawnPoint;
}
public static void setSpawnPoint(int spawnPoint) {
MovementGenerator.spawnPoint = spawnPoint;
}
public int velocity(){
movement = rand.nextInt(1);
if (movement == 1) {
movement = rand.nextInt(10);
}
else if (movement == 0) {
movement = (rand.nextInt(10)*-1);
}
return movement;
}
public int position(){
return spawnPoint = rand.nextInt(500);
}
}
This is a partial answer to give you the chance to start dealing with your project...
Following James_D suggestion, not only you need a moveBall method in MovableCircle, but also you need to get rid of x,y,dx,dy on BallPane, and transfer the control to each ball.
This is what I think should be done for starters:
MovableCircle
public class MovableCircle extends Circle {
private final MovementGenerator mG = new MovementGenerator();
private double x = mG.position(), y = mG.position();
private double dx = mG.velocity(), dy = mG.velocity();
private final double radius;
MovableCircle(double radius, Color color){
this.setCenterX(x);
this.setCenterY(y);
this.radius=radius;
this.setRadius(radius);
this.setFill(color);
setDx(dx);
setDy(dy);
}
public double getDx() { return dx; }
public final void setDx(double newDx) {
while (newDx < -10 || newDx > 10) {
newDx = mG.velocity();
}
dx = newDx;
}
public double getDy() { return dy; }
public final void setDy(double newDy) {
while(newDy < -10 || newDy > 10) {
newDy = mG.velocity();
}
dy = newDy;
}
public void moveBall() {
// Check boundaries
if (x < radius || x > BounceBallControl.WIDTH - radius) {
dx *= -1; // Change ball move direction
}
if (y < radius || y > BounceBallControl.HEIGHT - radius) {
dy *= -1; // Change ball move direction
}
// Adjust ball position
x += dx;
y += dy;
setCenterX(x);
setCenterY(y);
}
}
BallPane
public class BallPane extends Pane {
public final double radius = 20;
private final MovableCircle predator = new MovableCircle(radius, Color.RED);
private final Timeline animation;
private final List<MovableCircle> circles;
public BallPane() {
circles=IntStream.range(0,10).mapToObj(i->new MovableCircle(radius, Color.GREEN))
.collect(Collectors.toList());
getChildren().addAll(circles);
predator.setFill(Color.RED);
getChildren().add(predator);
setWidth(BounceBallControl.WIDTH);
setHeight(BounceBallControl.HEIGHT);
// Create an animation for moving the ball
animation = new Timeline(new KeyFrame(Duration.millis(20), e -> moveBall()));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play(); // Start animation
}
public final void moveBall() {
circles.forEach(MovableCircle::moveBall);
predator.moveBall();
}
...
}
where
public class BounceBallControl extends Application {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
...
}
Run and you'll find something like this:
Now it's time to figure out the way to remove green balls...