JavaFX游戏动画如何根据角度在X轴和Y轴上移动ImageView
JavaFX Game Animation How to move ImageView in X-axis and Y-axis according to angle
我想让子弹直奔目标。我知道如何根据目标位置改变玩家的方向,我也知道我需要根据角度决定 X 轴和 Y 轴但是..不知道怎么做?任何人都知道我该怎么做。此外,目标将在 x 轴上向下移动,我希望目标船朝向玩家。同样的问题。我的数学不太好我不知道我需要采取什么样的三角方法。
只有 2 个 class 个文件,您可以 运行 自己编写代码
Main.java
package bullitsrunning;
import java.util.ArrayList;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
public class Main extends Application {
private final int HEIGHT = 600, WIDTH = 600;
public static Pane root = new Pane();;
ArrayList<ImageObject> rocket_list = new ArrayList<>();
ArrayList<ImageObject> enemy_rocket_list = new ArrayList<>();
boolean up = false,down = false,left = false,right = false, rotateLeft = false, rotateRight= false;
ImageObject player = new ImageObject(300, 450, 100, 100, "alienship2.png");
ImageObject enemy = new ImageObject(100, 10, 50, 50, "animemonster.png");
@Override
public void start(Stage stage) {
try {
Timeline tl = new Timeline(new KeyFrame(Duration.millis(5), e-> {
playerUpdate();
enemyUpdate();
for(ImageObject rock : new ArrayList<ImageObject>(rocket_list)) {
rock.setLayoutY(rock.getLayoutY() - 2);
if(rock.getLayoutY() < 0) {
if(rock.getBound().intersects(enemy.getBound()))
{
//enemy.delete();
}
System.out.println(rocket_list.size());
rock.delete();
rocket_list.remove(rock);
}
}
}));
tl.setCycleCount(Animation.INDEFINITE);
tl.play();
Scene scene = new Scene(root,600,600);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent e)
{
switch (e.getCode()) {
case W:
up = true;
break;
case S:
down = true;
break;
case A:
left = true;
break;
case D:
right = true;
break;
case LEFT:
System.out.println("Rotate Left");
rotateLeft = true;
break;
case RIGHT:
System.out.println("Rotate Right");
rotateRight = true;
break;
case SPACE:
ImageObject io = new ImageObject(player.getX() + 38, player.getY(), 25, 25, "blackbullet.png");
rocket_list.add(io);
break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent e)
{
switch (e.getCode()) {
case W:
up = false;
break;
case S:
down = false;
break;
case A:
left = false;
break;
case D:
right = false;
break;
case LEFT:
System.out.println("Rotate Left");
rotateLeft = false;
break;
case RIGHT:
System.out.println("Rotate Right");
rotateRight = false;
break;
}
}
});
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
private void enemyUpdate() {
for(ImageObject rock : new ArrayList<ImageObject>(enemy_rocket_list)) {
rock.setLayoutY(rock.getLayoutY() + 2);
if(rock.getLayoutY() > HEIGHT) {
System.out.println(rocket_list.size());
rock.delete();
rocket_list.remove(rock);
}
}
}
private void playerUpdate() {
Point2D ene = new Point2D(enemy.getLayoutX(), enemy.getLayoutY());
Point2D play = new Point2D(player.getLayoutX(), player.getLayoutY());
Point2D p3 = play.subtract(ene);
Point2D p4 = new Point2D(1, 0);
System.out.println( "Point2D: " + p4.angle(p3));
player.setRotate(p4.angle(p3) - 90);
System.out.println(Math.sin(p4.angle(p3)));
//So Player Can't move outside of the border
if(player.getX() < 0 ) {
player.setLayoutX(0);
} else if(player.getX() > WIDTH- player.getWidth())
{
player.setLayoutX(WIDTH - player.getWidth());
}else if(player.getY() < 0 )
{
player.setLayoutY(0);
}else if(player.getY() > HEIGHT - player.getHeight())
{
player.setLayoutY(HEIGHT - player.getHeight());
}else
{
//Player movement UP, DOWN, LEFT, RIGHT
if(up)
{
player.setLayoutY(player.getLayoutY() - 1);
}
if(down)
{
player.setLayoutY(player.getLayoutY() + 1);
}
if(left)
{
player.setLayoutX(player.getLayoutX() - 1);
}
if(right)
{
player.setLayoutX(player.getLayoutX() + 1);
}
if(rotateLeft)
{
player.setRotate(120 - 90);
}
if(rotateLeft)
{
player.setRotate(60 - 90);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
ImageObject.java
package bullitsrunning;
import javafx.geometry.Bounds;
import javafx.scene.image.ImageView;
public class ImageObject {
private String folder_location ="File:Images/";
private ImageView image_view;
private boolean alive = true;
public ImageObject(double x,double y,double w,double h,String image)
{
image_view = new ImageView(folder_location+image);
image_view.setCache(true); //help in performance
image_view.setFitHeight(h );
image_view.setFitWidth(w);
image_view.setLayoutX(x);
image_view.setLayoutY(y);
image_view.setSmooth(true);
Main.root.getChildren().add(image_view);
}
public double getX(){
return image_view.getLayoutX();
}
public double getY() {
return image_view.getLayoutY();
}
public void setRotate(double rot) {
image_view.setRotate(rot);
}
public double getHeight()
{
return image_view.getFitHeight();
}
public double getWidth()
{
return image_view.getFitWidth();
}
public void setHeight(double h)
{
image_view.setFitHeight(h);
}
public void setWidth(double w)
{
image_view.setFitWidth(w);
}
public void setSize(double h,double w)
{
image_view.setFitHeight(h);
image_view.setFitWidth(w);
}
//Axis
public double getLayoutX()
{
return image_view.getLayoutX();
}
public double getLayoutY()
{
return image_view.getLayoutY();
}
public void setLayoutX(double x)
{
image_view.setLayoutX(x);
}
public void setLayoutY(double y)
{
image_view.setLayoutY(y);
}
public void setPos(double x,double y)
{ image_view.setLayoutX(x);
image_view.setLayoutY(y);
}
public Bounds getBound()
{
return image_view.getBoundsInParent();
}
public ImageView getView()
{
return image_view;
}
public void delete()
{
Main.root.getChildren().remove(image_view);
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
}
我不了解 JavaFX,也不会深入了解您的实施细节。但核心思想如下:
您需要创建一个从源位置(当前玩家位置)到目的地(我猜是敌人)的 direction
向量:
direction = new Vector()
direction.x = des.x-src.x;
direction.y = des.y-src.y;
现在你应该正常化像这样的向量:
double direction_magnitude = Math.sqrt(direction.x*direction.x + direction.y*direction.y)
direction.x = direction.x/direction_magnitude;
direction.y = direction.y/direction_magnitude;
现在只需 根据 direction
向量逐渐更新播放器位置,例如:
void update(float deltaTime) {
// recalculate `direction` if your destination is moving
player.x = player.x + (direction.x * deltaTime);
player.y = player.y + (direction.y * deltaTime);
player.rotation = Math.atan2(direction.y, direction.x)
}
最后一行 旋转 面向目的地的玩家(了解有关此行的更多信息 here)。
只需使用节点的变换来确定镜头的方向:
给定图像坐标 shotLocalX
、shotLocalY
中的拍摄方向,只需执行
Point2D shotDirection = player.getLocalToParentTransform().deltaTransform(shotLocalX, shotLocalY);
shotDirection
的x
和y
属性包含root
.
坐标系中的射击方向
至于计算移动方向,让敌人直接向玩家移动:利用位置的差异,缩放到合适的长度
dx = targetX - startX
dy = targetY - startY
magnitude = Math.sqrt(dx * dx + dy *dy);
directionX = dx / magnitude;
directionY = dy / magnitude;
directionX
和 directionY
是从位置 (startX, startY)
和 (targetX, targetY)
.
的归一化(长度 1)移动方向
一个最好的方法
Timeline frame = new Timeline(new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
for (Bullet bul : new ArrayList<Bullet>(bullet_list))
{
Point2D ene = new Point2D(bot_list.get(selected_bot_id).getX(),bot_list.get(selected_bot_id).getY());
Point2D play = new Point2D(Player.getCenterX(), Player.getCenterY());
Point2D p3 = play.subtract(ene);
Point2D p4 = new Point2D(1, 0);
System.out.println("Bullet run");
bul.setRotate(p4.angle(p3) - 90);
//*100 is multipl of speed u need
bul.setTranslateX(bul.getTranslateX() - (Math.cos(Math.toRadians(p4.angle(p3))) *100 ));
bul.setTranslateY(bul.getTranslateY() - (Math.sin(Math.toRadians(p4.angle(p3))) *100 ));
if(bul.getTranslateX() < 0 ||bul.getTranslateX() > Constant.WIDTH ||bul.getTranslateY() < 0) {
System.out.println("Delecte");
bul.delete();
}
}
}
}));
frame.setCycleCount(Animation.INDEFINITE);
frame.play();
我想让子弹直奔目标。我知道如何根据目标位置改变玩家的方向,我也知道我需要根据角度决定 X 轴和 Y 轴但是..不知道怎么做?任何人都知道我该怎么做。此外,目标将在 x 轴上向下移动,我希望目标船朝向玩家。同样的问题。我的数学不太好我不知道我需要采取什么样的三角方法。
只有 2 个 class 个文件,您可以 运行 自己编写代码
Main.java
package bullitsrunning;
import java.util.ArrayList;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
public class Main extends Application {
private final int HEIGHT = 600, WIDTH = 600;
public static Pane root = new Pane();;
ArrayList<ImageObject> rocket_list = new ArrayList<>();
ArrayList<ImageObject> enemy_rocket_list = new ArrayList<>();
boolean up = false,down = false,left = false,right = false, rotateLeft = false, rotateRight= false;
ImageObject player = new ImageObject(300, 450, 100, 100, "alienship2.png");
ImageObject enemy = new ImageObject(100, 10, 50, 50, "animemonster.png");
@Override
public void start(Stage stage) {
try {
Timeline tl = new Timeline(new KeyFrame(Duration.millis(5), e-> {
playerUpdate();
enemyUpdate();
for(ImageObject rock : new ArrayList<ImageObject>(rocket_list)) {
rock.setLayoutY(rock.getLayoutY() - 2);
if(rock.getLayoutY() < 0) {
if(rock.getBound().intersects(enemy.getBound()))
{
//enemy.delete();
}
System.out.println(rocket_list.size());
rock.delete();
rocket_list.remove(rock);
}
}
}));
tl.setCycleCount(Animation.INDEFINITE);
tl.play();
Scene scene = new Scene(root,600,600);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent e)
{
switch (e.getCode()) {
case W:
up = true;
break;
case S:
down = true;
break;
case A:
left = true;
break;
case D:
right = true;
break;
case LEFT:
System.out.println("Rotate Left");
rotateLeft = true;
break;
case RIGHT:
System.out.println("Rotate Right");
rotateRight = true;
break;
case SPACE:
ImageObject io = new ImageObject(player.getX() + 38, player.getY(), 25, 25, "blackbullet.png");
rocket_list.add(io);
break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent e)
{
switch (e.getCode()) {
case W:
up = false;
break;
case S:
down = false;
break;
case A:
left = false;
break;
case D:
right = false;
break;
case LEFT:
System.out.println("Rotate Left");
rotateLeft = false;
break;
case RIGHT:
System.out.println("Rotate Right");
rotateRight = false;
break;
}
}
});
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
private void enemyUpdate() {
for(ImageObject rock : new ArrayList<ImageObject>(enemy_rocket_list)) {
rock.setLayoutY(rock.getLayoutY() + 2);
if(rock.getLayoutY() > HEIGHT) {
System.out.println(rocket_list.size());
rock.delete();
rocket_list.remove(rock);
}
}
}
private void playerUpdate() {
Point2D ene = new Point2D(enemy.getLayoutX(), enemy.getLayoutY());
Point2D play = new Point2D(player.getLayoutX(), player.getLayoutY());
Point2D p3 = play.subtract(ene);
Point2D p4 = new Point2D(1, 0);
System.out.println( "Point2D: " + p4.angle(p3));
player.setRotate(p4.angle(p3) - 90);
System.out.println(Math.sin(p4.angle(p3)));
//So Player Can't move outside of the border
if(player.getX() < 0 ) {
player.setLayoutX(0);
} else if(player.getX() > WIDTH- player.getWidth())
{
player.setLayoutX(WIDTH - player.getWidth());
}else if(player.getY() < 0 )
{
player.setLayoutY(0);
}else if(player.getY() > HEIGHT - player.getHeight())
{
player.setLayoutY(HEIGHT - player.getHeight());
}else
{
//Player movement UP, DOWN, LEFT, RIGHT
if(up)
{
player.setLayoutY(player.getLayoutY() - 1);
}
if(down)
{
player.setLayoutY(player.getLayoutY() + 1);
}
if(left)
{
player.setLayoutX(player.getLayoutX() - 1);
}
if(right)
{
player.setLayoutX(player.getLayoutX() + 1);
}
if(rotateLeft)
{
player.setRotate(120 - 90);
}
if(rotateLeft)
{
player.setRotate(60 - 90);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
ImageObject.java
package bullitsrunning;
import javafx.geometry.Bounds;
import javafx.scene.image.ImageView;
public class ImageObject {
private String folder_location ="File:Images/";
private ImageView image_view;
private boolean alive = true;
public ImageObject(double x,double y,double w,double h,String image)
{
image_view = new ImageView(folder_location+image);
image_view.setCache(true); //help in performance
image_view.setFitHeight(h );
image_view.setFitWidth(w);
image_view.setLayoutX(x);
image_view.setLayoutY(y);
image_view.setSmooth(true);
Main.root.getChildren().add(image_view);
}
public double getX(){
return image_view.getLayoutX();
}
public double getY() {
return image_view.getLayoutY();
}
public void setRotate(double rot) {
image_view.setRotate(rot);
}
public double getHeight()
{
return image_view.getFitHeight();
}
public double getWidth()
{
return image_view.getFitWidth();
}
public void setHeight(double h)
{
image_view.setFitHeight(h);
}
public void setWidth(double w)
{
image_view.setFitWidth(w);
}
public void setSize(double h,double w)
{
image_view.setFitHeight(h);
image_view.setFitWidth(w);
}
//Axis
public double getLayoutX()
{
return image_view.getLayoutX();
}
public double getLayoutY()
{
return image_view.getLayoutY();
}
public void setLayoutX(double x)
{
image_view.setLayoutX(x);
}
public void setLayoutY(double y)
{
image_view.setLayoutY(y);
}
public void setPos(double x,double y)
{ image_view.setLayoutX(x);
image_view.setLayoutY(y);
}
public Bounds getBound()
{
return image_view.getBoundsInParent();
}
public ImageView getView()
{
return image_view;
}
public void delete()
{
Main.root.getChildren().remove(image_view);
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
}
我不了解 JavaFX,也不会深入了解您的实施细节。但核心思想如下:
您需要创建一个从源位置(当前玩家位置)到目的地(我猜是敌人)的 direction
向量:
direction = new Vector()
direction.x = des.x-src.x;
direction.y = des.y-src.y;
现在你应该正常化像这样的向量:
double direction_magnitude = Math.sqrt(direction.x*direction.x + direction.y*direction.y)
direction.x = direction.x/direction_magnitude;
direction.y = direction.y/direction_magnitude;
现在只需 根据 direction
向量逐渐更新播放器位置,例如:
void update(float deltaTime) {
// recalculate `direction` if your destination is moving
player.x = player.x + (direction.x * deltaTime);
player.y = player.y + (direction.y * deltaTime);
player.rotation = Math.atan2(direction.y, direction.x)
}
最后一行 旋转 面向目的地的玩家(了解有关此行的更多信息 here)。
只需使用节点的变换来确定镜头的方向:
给定图像坐标 shotLocalX
、shotLocalY
中的拍摄方向,只需执行
Point2D shotDirection = player.getLocalToParentTransform().deltaTransform(shotLocalX, shotLocalY);
shotDirection
的x
和y
属性包含root
.
至于计算移动方向,让敌人直接向玩家移动:利用位置的差异,缩放到合适的长度
dx = targetX - startX
dy = targetY - startY
magnitude = Math.sqrt(dx * dx + dy *dy);
directionX = dx / magnitude;
directionY = dy / magnitude;
directionX
和 directionY
是从位置 (startX, startY)
和 (targetX, targetY)
.
一个最好的方法
Timeline frame = new Timeline(new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
for (Bullet bul : new ArrayList<Bullet>(bullet_list))
{
Point2D ene = new Point2D(bot_list.get(selected_bot_id).getX(),bot_list.get(selected_bot_id).getY());
Point2D play = new Point2D(Player.getCenterX(), Player.getCenterY());
Point2D p3 = play.subtract(ene);
Point2D p4 = new Point2D(1, 0);
System.out.println("Bullet run");
bul.setRotate(p4.angle(p3) - 90);
//*100 is multipl of speed u need
bul.setTranslateX(bul.getTranslateX() - (Math.cos(Math.toRadians(p4.angle(p3))) *100 ));
bul.setTranslateY(bul.getTranslateY() - (Math.sin(Math.toRadians(p4.angle(p3))) *100 ));
if(bul.getTranslateX() < 0 ||bul.getTranslateX() > Constant.WIDTH ||bul.getTranslateY() < 0) {
System.out.println("Delecte");
bul.delete();
}
}
}
}));
frame.setCycleCount(Animation.INDEFINITE);
frame.play();