JavaFX "y" position on Canvas - java

I created a program that randomly draws circles,squares,rectangles. My problem is I'm getting the click position with event.getX() and event.getY();
Here is the problem:
Green point is the where I click the Canvas.
↑→ axis must be like this. But in my program it stands like this ↓→
Here is the details:
Getting mouse position with (extending Canvas):
super.setOnMouseClicked(event -> selectFigureContaining(event.getX(),event.getY()));
Initializing part :
#Override
public void start(Stage primaryStage) {
this.color = Color.BLACK;
toggleGroup = new ToggleGroup();
hBox = new HBox();
vBox = new VBox();
label = new Label();
vBox.setPadding(new Insets(5,15,0,15));
vBox.setSpacing(10);
hBox.setPadding(new Insets(5,0,0,0));
//Radio Buttons
red = new RadioButton("Red");
red.setSelected(true);
green = new RadioButton("Green");
blue = new RadioButton("Blue");
red.setToggleGroup(toggleGroup);
green.setToggleGroup(toggleGroup);
blue.setToggleGroup(toggleGroup);
//Buttons
buttonCircle = new Button("Circle");
buttonCircle.setMinSize(70,20);
buttonCircle.setOnMouseClicked(event -> circleButtonClicked());
buttonSquare = new Button("Square");
buttonSquare.setMinSize(70,20);
buttonSquare.setOnMouseClicked(event -> squareButtonClicked());
buttonRectangle = new Button("Rectangle");
buttonRectangle.setMinSize(70,20);
buttonRectangle.setOnMouseClicked(event -> rectangleButtonClicked());
cleanAll = new Button("Clean All");
cleanAll.setMinSize(70,20);
cleanAll.setOnMouseClicked(event -> cleanAllEvent());
figureCanvas = new FigureCanvas(10,400,500, this);
vBox.getChildren().addAll(red,green,blue,buttonCircle,buttonSquare,buttonRectangle,cleanAll,label);
hBox.getChildren().addAll(vBox,figureCanvas);
Scene scene = new Scene(hBox,500,500);
primaryStage.setScene(scene);
primaryStage.setTitle("Draw Figure");
primaryStage.show();
}
I'm really new to JavaFX. I couldn't understand why y axis getting smaller on left upper side. Thanks.

Normally, the coordinate system's origin is at the top left of the screen and positive y is downwards:
. ---> +x
|
v +y
You can transform your y position like this to get expected movement (origin at the bottom left, +y goes up):
y = canvas.getHeight() - y;

Related

How to move an existing Line shape in java using a mouse?

I would like to drag a selected line, but I'm unsure how to do it.
I tried the following but it doesn't work and the line doesn't move correctly. What calculations am I missing?
var deltaX = mouseEvent.x - (line.startX + line.endX)
var deltaY = mouseEvent.y - (line.startY + line.endY)
line.startX = line.startX + deltaX
line.startY = line.startY +deltaY
line.endX = line.endX + deltaX
line.endY = line.endY +deltaY
moving line with mouse
moving a line using mouse event
App.java
public class App extends Application {
private double startX;
private double startY;
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(0, 0, 0, 200);
line.setStrokeWidth(8);
Shape endHandler = new Circle(15, Color.BLUE);
endHandler.setStroke(Color.BLACK);
line.setOnMousePressed(e -> {
startX = line.getLayoutX() - e.getX();
startY = line.getLayoutY() - e.getY();
});
line.setOnMouseDragged(e -> {
line.setTranslateX(line.getTranslateX() + e.getX()+startX);
line.setTranslateY(line.getTranslateY() + e.getY()+startY);
});
Group group = new Group(line);
group.setTranslateX(250);
group.setTranslateY(250);
Scene scene = new Scene(new AnchorPane(group), 500, 500);
stage.setTitle("moving line");
stage.setScene(scene);
stage.show();
}
}
moving by binding start x y and end x y
In this aproach we are dragging circle shapes and the start and the end of line object will follow those shapes 'cause they are binded
This is a functional single javafx app you can try .
red circle is for start line position and blue is for end
public class App extends Application {
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(0, 0, 0, 200);
Shape endHandler = new Circle(15, Color.BLUE);
endHandler.setStroke(Color.BLACK);
Shape startHandler = new Circle(15, Color.RED);
startHandler.setStroke(Color.BLACK);
endHandler.translateXProperty().bindBidirectional(line.endXProperty());
endHandler.translateYProperty().bindBidirectional(line.endYProperty());
startHandler.translateXProperty().bindBidirectional(line.startXProperty());
startHandler.translateYProperty().bindBidirectional(line.startYProperty());
endHandler.setOnMouseDragged(e -> {
endHandler.setTranslateX(endHandler.getTranslateX() + e.getX());
endHandler.setTranslateY(endHandler.getTranslateY() + e.getY());
});
startHandler.setOnMouseDragged(e -> {
startHandler.setTranslateX(startHandler.getTranslateX() + e.getX());
startHandler.setTranslateY(startHandler.getTranslateY() + e.getY());
});
Group group = new Group(line, endHandler, startHandler);
group.setTranslateX(250);
group.setTranslateY(250);
Scene scene = new Scene(new AnchorPane(group), 500, 500);
stage.setTitle("moving line");
stage.setScene(scene);
stage.show();
}
}
This code cancels out the start / end position.
for
line.startX = line.startX + deltaX
=
line.startX = line.startX +(mouseEvent.x - (line.startX + line.endX))
=
line.startX = -line.endX+mouseEvent.x
So now you dont even have the start position
You should have
var deltaX=mouseEvent.x
var deltaY = mouseEvent.y
line.startX = line.startX + deltaX
line.startY = line.startY +deltaY
line.endX = line.endX + deltaX
line.endY = line.endX +deltaY
Make sure the mouse Positions update

Switch forms color when it is inside another one

I am trying to set a panel that contains several points and then draw a triangle or any others forms. And all points that are inside that form will switch their colors to red.
Seems like i am doing something wrong, is this the correct way to draw point inside the for loop ?
Make sure the Polygon is created before creating the circles. This allows you to use check for intersection of the shapes as described in this answer: https://stackoverflow.com/a/15014709/2991525
Choose the circle fill accordingly:
#Override
public void start(Stage stage) {
Group root = new Group();
Polygon triangle = new Polygon(300d, 100d, 600d, 150d, 500d, 300d);
root.getChildren().add(triangle);
Scene scene = new Scene(root, 900, 500);
for (double x = 65; x < scene.getWidth(); x += 65) {
for (double y = 65; y < scene.getHeight(); y += 65) {
Circle circle = new Circle(x, y, 10);
root.getChildren().add(circle);
Shape intersection = Shape.intersect(circle, triangle);
//Setting the color of the circle
circle.setFill(intersection.getBoundsInLocal().getWidth() == -1 ? Color.BLACK : Color.RED);
}
}
triangle.setFill(Color.TRANSPARENT);
triangle.setStroke(Color.RED);
triangle.toFront();
stage.setTitle("Scale transition example");
stage.setScene(scene);
stage.show();
}

How do I use Bindings.bindContent?

I have a polygon that I want to grow in size when the window is resized. I have a DoubleBinding that it the baseline for the size of all of my shapes in the scene. I use this DoubleBinding to create a ListBinding that calculates how big the polygon should be. I tried to use Bindings.bindContent(list1, list2) to bind the ListBinding to the polygon's points, but it doesn't seem to work.
Polygon triangle = new Polygon();
ListBinding<Double> trianglePoints = new ListBinding<Double>() {
{
super.bind(width, height);
}
#Override
protected ObservableList<Double> computeValue() {
ObservableList<Double> points = FXCollections.observableArrayList();
points.addAll(0.0, 0.0, width.get()/2, height.get()/4, 0.0, height.get()/2);
return points;
}
};
Bindings.bindContent(triangle.getPoints(), trianglePoints.get());
I found that if I add an InvalidationListener to the triangle points and manually change the the polygon points when it fires off, it works.
trianglePoints.addListener((InvalidationListener)(listener) -> triangle.getPoints().setAll(trianglePoints.get()));
What am I doing wrong?
You should change your binding in following way:
Bindings.bindContent(triangle.getPoints(), trianglePoints);
Your previous binding did not work because trianglePoints.get() is just result of computeValue() call i.e. creating ObservableList with some values calculated upon initial width and height. Thus further changes to width and height properties were not taken into account.
I recommend not using a ListBinding. You do not need to recreate the list over and over again, you just need to modify some of the points:
#Override
public void start(Stage primaryStage) {
Polygon triangle = new Polygon(
0, 0,
0, 0,
0, 0);
StackPane root = new StackPane();
root.getChildren().add(triangle);
root.heightProperty().addListener((observable, oldH, newH) -> {
double h = newH.doubleValue();
triangle.getPoints().set(3, h / 4);
triangle.getPoints().set(5, h / 2);
});
root.widthProperty().addListener((observable, oldW, newW) -> {
double w = newW.doubleValue();
triangle.getPoints().set(2, w / 2);
});
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
Furthermore it's also possible to do this using the scale properties (unless you're using a stroke or some exotic fill):
#Override
public void start(Stage primaryStage) {
Polygon triangle = new Polygon(
0, 0,
0.5, 0.25,
0, 0.5);
StackPane root = new StackPane();
root.getChildren().add(triangle);
triangle.scaleXProperty().bind(root.widthProperty());
triangle.scaleYProperty().bind(root.heightProperty());
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

JavaFx - Circle path animation and ScrollEvent

For a Circle Path Animation I copied the Code from this link
JavaFX 2 circle path for animation,
But I need this Code to do the following:
I would like to move the green rectangle with my MouseWheel, I'm not sure if and how this works with a ScrollEvent.
With a Button "Add Rectangle" I would like to add some rectangles to this Circle path
Any help would be greatly appreciated
I actually forgot to put an answer to this, so here it is:
public void start(Stage primaryStage) throws Exception {
// Choose a Object to move around the Path
Circle objectCircle = new Circle();
objectCircle.setRadius(10);
// Use a Shape for the Path or...
Circle pathCircle = new Circle(300, 200, 150);
pathCircle.setFill(null);
pathCircle.setStroke(Color.BLACK);
// ...use different approach (see createEllipsePath below) or...
Path path = createEllipsePath(400, 200, 150, 150, 0);
// ...use Class MoveTo & CubicCurveTo
//path.getElements().add (new MoveTo (0f, 50f));
//path.getElements().add(new CubicCurveTo(40f, 10f, 390f, 240f, 1904, 50f));
// Set up a Path Transition
PathTransition pathTransitionCircle = new PathTransition();
pathTransitionCircle.setDuration(Duration.seconds(10));
pathTransitionCircle.setNode(objectCircle);
pathTransitionCircle.setPath(pathCircle);
pathTransitionCircle.setCycleCount(Timeline.INDEFINITE);
pathTransitionCircle.setAutoReverse(false);
pathTransitionCircle.setInterpolator(Interpolator.LINEAR);
pathTransitionCircle.play();
BorderPane root = new BorderPane();
root.getChildren().addAll(pathCircle,objectCircle);
// Pause Transition
root.setOnMousePressed(eve -> pathTransitionCircle.pause());
// Set up the ScrollEvent
root.setOnScroll(event -> {
//SCROLL UP
double currentTime = pathTransitionCircle.getCurrentTime().toMillis();
double jumpRate = 100; // change rate for smaller/bigger jumps
pathTransitionCircle.jumpTo(Duration.millis(currentTime + jumpRate));
//SCROLL DOWN
double deltaY = event.getDeltaY();
if (deltaY < 0) {
if (currentTime == 0) {
currentTime = 10000; // end of circle is 10000millis: at second 0 we cannot jump to negative seconds, so we set it to 10000millis
pathTransitionCircle.jumpTo(Duration.millis(currentTime - jumpRate));
} else {
pathTransitionCircle.jumpTo(Duration.millis(currentTime - jumpRate));
}
}
});
primaryStage.setTitle("Path Transition ScrollEvent");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
//create an EllipsePath with ArcTo
private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate) {
ArcTo arcTo = new ArcTo();
arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree circle
arcTo.setY(centerY - radiusY);
arcTo.setSweepFlag(false);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(radiusX);
arcTo.setRadiusY(radiusY);
arcTo.setXAxisRotation(rotate);
Path pathCircle = new Path();
pathCircle.getElements().addAll(new MoveTo(centerX - radiusX, centerY - radiusY),arcTo);
pathCircle.getElements().add(new ClosePath());
// Styling
pathCircle.setStroke(Color.RED);
pathCircle.getStrokeDashArray().setAll(5d, 5d);
return pathCircle;
}
public static void main(String[] args) { launch(args); }
}

JavaFX - Interaction between circle and rectangle

I want to know how I can make an interaction when rectangle collapses with a circle . Like some kind of action that happens when circle and rectangle collapses. There is also a problem that circle can go out of frame, which I don't know how to limit it's movement. I'm not even sure if it's possible to do what I want this way.This is supposed to be a game where I need to dodge all rectangles and this is best I could do. Thanks it advance :)
public class Java2 extends Application {
public static final int KRUG_WIDTH = 10;
public static final int PANEL_WIDTH = 600;
public static final int PANEL_HEIGHT = 600;
private int mX = (PANEL_WIDTH - KRUG_WIDTH) / 2;
private int mY = (PANEL_HEIGHT - KRUG_WIDTH) / 2;
Random ran = new Random();
#Override
public void start(Stage primaryStage) {
Rectangle rekt = new Rectangle(20, 20);
Rectangle rekt1 = new Rectangle(20, 20);
Circle r1 = new Circle(mX,mY,KRUG_WIDTH);
Pane root = new Pane(); //PANE
r1.setFill(Color.WHITE);
r1.setStroke(Color.BLACK);
root.getChildren().add(r1);
root.getChildren().add(rekt);
root.getChildren().add(rekt1);
Scene scene = new Scene(root, PANEL_WIDTH, PANEL_HEIGHT);
PathTransition pathTransition = new PathTransition();
Path path = new Path();
//REKT-PATH
pathTransition.setDuration(javafx.util.Duration.millis(600));
pathTransition.setPath(path);
pathTransition.setNode(rekt);
pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pathTransition.setCycleCount(2);
pathTransition.setAutoReverse(true);
pathTransition.setOnFinished(e -> {
pathTransition.setPath(createPath());
pathTransition.play();
});
pathTransition.play();
PathTransition pathTransition1 = new PathTransition();
Path path1 = new Path();
//REKT1-PATH
pathTransition1.setDuration(javafx.util.Duration.millis(550));
pathTransition1.setPath(path1);
pathTransition1.setNode(rekt1);
pathTransition1.setOrientation(
PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pathTransition1.setCycleCount(Timeline.INDEFINITE);
pathTransition1.setAutoReverse(true);
pathTransition1.setOnFinished(e -> {
pathTransition1.setPath(createPath());
pathTransition1.play();
});
pathTransition1.play();
r1.setOnKeyPressed(e -> {
switch (e.getCode()) {
case DOWN: r1.setCenterY(r1.getCenterY()+ 10);
break;
case UP: r1.setCenterY(r1.getCenterY()- 10);
break;
case LEFT: r1.setCenterX(r1.getCenterX() - 10);
break;
case RIGHT: r1.setCenterX(r1.getCenterX() + 10);
break;
case SPACE:
break;
default:
}
});
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
r1.requestFocus();
}
private Path createPath() {
int loc2 = ran.nextInt(600 - 300 + 1) + 300;
int loc = ran.nextInt(600 - 20 + 1) + 20;
Path path = new Path();
path.getElements().add(new MoveTo(20, 20));
path.getElements().add(new LineTo(loc, loc2));
return path;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Your approach isn't one I would take. Usually you have a timer as a game loop in which all the magic is happening, i. e. move sprites, check collision, update sprites in the UI. In JavaFX this would be an AnimationTimer.
In your code you miss several important things, among them the keyboard or mouse input. Or how you check the collision. There is e. g. an intersects method for the nodes, but that checks only the rectangular bounds of a node. You however have a circle, which makes matters more complex. However, if performance isn't an issue for your game, you could use the Shape's intersect method to create a new shape out of Rectangle and Circle and depending on the result decide whether you have a collision or not.
Some time ago I created example code about how to move sprites on the screen and check if they collide with others.
Regarding bouncing off the scene bounds in that code you simply check the scene bounds and change the movement delta to a bouncing value, i. e. if the sprite moves from left to right (dx is positive) and is at the right side, you set the delta dx to a negative value so that it moves in the opposite direction.
You can also take a look at a simple Pong game which uses a slightly modified version of that engine.
Example for shape intersection with your code:
Shape shape = Shape.intersect(rekt, r1);
boolean intersects = shape.getBoundsInLocal().getWidth() != -1;
if( intersects) {
System.out.println( "Collision");
}
That alone raises the question where you'd put the check. Normally you'd have to perform it when anything moves, i. e. in both path transitions like this
pathTransition.currentTimeProperty().addListener( e -> {
...
});
and in the circle transition. That would be 2 checks too many.

Categories