简体   繁体   中英

JavaFX localToScene causes results to be twice as big - Why?

Hello fellow programmers,

I am currently writing a small graphical application for my studies that should showcase an AI in a small 2D game. I am kind of stuck though right now. I have made a class hierarchy with Entity at the top to represent basically any entity, like the player, enemies and obstacles, it has a Node attribute that shall represent the Entity graphically. Entity also has two protected SimpleIntegerProperty objects x and y, to which I bind the layout-properties of the Node attribute, so that whenever I change the values of x and y, the graphical representation moves as well.

So far, I could do anything that doesn't rely on Entity-object coordinates well. Collision works etc. However, when I tried to implement a system that spawns bullets (little Circle objects) at the place the player character is (the values of both x and y properties), there was a strange offset of double the distance the player has to the upper left corner (to the bottom right). I experimented a little and saw that when I checked the coordinates through the localToScene method, with either the values of both properties or directly the layoutX and layoutY methods of the Node, it would give me coordinates TWICE AS BIG as the actual coordinates. My pane is 600x600 px big and when I place my player (another object that extends to Entity) at 300,300, everything looks fine, but the localToScene method apparently tells me that it is at double of that, so 600,600. When I go with my player to the bottom right corner and print the coordinates via localToScene, it tells me that it is at 1200,1200.

public void addProjectile(Projectile p)
{
    Projectile p2 = new PlayerProjectile(100, 100, 0.5);
    projectiles.add(p2);
    System.out.println(p2.getSkin().localToScene(p2.getX(), p2.getY()));
    System.out.println(p2.getSkin().getLayoutX() + " " + p2.getSkin().getLayoutY());
    this.getChildren().add(p2.getSkin());
    System.out.println(p2.getSkin().getLayoutX() + " " + p2.getSkin().getLayoutY());

// p.setPosition(p.getSkin().localToScreen(p.getX(), p.getY()));

}

This method creates a Projectile at 100,100 (layoutX and Y confirms that as well). Then, I add that Projectile p2 to an ArrayList (not of importance). The first print there gives me two coordinates, 200 and 200. The second print gives me 100 and 100. The third print gives me 100 and 100 as well (adding to this, which is a Pane, doesn't change anything apparently and is not the cause).

Does anyone have a clue why it just doubles everything? Here is every related class.

PlayerProjectile class:

public class PlayerProjectile extends Projectile
{

public static final int FIRE_RATE = 5; // Higher is slower

public PlayerProjectile(int x, int y, double dir)
{

    super(x, y, dir);
    range = 150;
    speed = 4;
    damage = 20;

    nx = (int) (speed * Math.cos(angle));
    ny = (int) (speed * Math.sin(angle));

}

@Override
public void update()
{

    move();

}

@Override
protected void move()
{
    x.setValue(x.getValue() + nx);
    y.setValue(y.getValue() + ny);

    // if (distance() > range)
    // {
    // remove();
    // }
}
}

Projectile class:

public abstract class Projectile extends Entity
{
final protected int xOrigin, yOrigin;

protected double angle;

protected int nx, ny;

protected double distance;

protected double speed, range, damage;

public Projectile(int x, int y, double dir)
{
    super(x, y);
    skin = new Circle(x, y, 3);
    ((Circle) skin).setFill(new Color(0, 1, 0, 1));
    xOrigin = x;
    yOrigin = y;
    angle = dir;
    // this.getVisual().translateXProperty().bind(this.x);
    // this.getVisual().translateYProperty().bind(this.y);
    this.getSkin().layoutXProperty().bind(this.x);
    this.getSkin().layoutYProperty().bind(this.y);
    // this.getVisual().getChildren().add(skin);
}

protected void move()
{

}

public int getX()
{
    return x.getValue().intValue();
}

public int getY()
{
    return y.getValue().intValue();
}

public int getOriginX()
{
    return xOrigin;
}

public int getOriginY()
{
    return yOrigin;
}
}

Entity class:

public class Entity
{
private boolean removed = false;

protected Level level;

protected Node skin;

// PROPERTIES FÜR X UND Y KOORDINATEN DES SKINS DES SPIELERS
protected SimpleIntegerProperty x, y;

// VISUELLE REPRÄSENTATION DER ENTITY
// protected Pane visual = new Pane();

public Entity()
{

}

public Entity(int x, int y)
{
    this.x = new SimpleIntegerProperty(x);
    this.y = new SimpleIntegerProperty(y);

}

public void update()
{

}

public void remove()
{
    // Remove from level
    removed = true;
}

public void setX(int x)
{
    this.x.setValue(x);
}

public void setY(int y)
{
    this.y.setValue(y);
}

public void setPosition(Point2D p)
{
    this.setX((int) p.getX());
    this.setY((int) p.getY());
}

public boolean isRemoved()
{
    return removed;
}

public void init(Level level)
{
    this.level = level;
}

// public Pane getVisual()
// {
// return visual;
// }

public Node getSkin()
{
    return skin;
}

}

localToScene transforms from local coordinates to the scene coordinates. Local coordinates are relative to the origin of the node the method is called for. The transform already includes layoutX and layoutY of this node. Therefore given P = (layoutX, layoutY) the result you get is

Inverse(sceneToLocal) * P = Inverse(Inverse(nodeTransform)) * P
                          = Inverse(Inverse(Translation(P))) * P
                          = Translation(P) * P
                          = 2 * P

Transform the origin in the local coordinate system instead to get the real position:

p.setPosition(p.getSkin().localToScreen(0, 0));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM