How would I make a Box2D body rotate such that it faces the a point given when the user clicks their mouse?
I am trying to implement a mechanic you can visualize as a top-down flashlight.
Problems:
To do this, in the show() method, I have attached a ConeLight to a Box2D body using the following method:
PolygonShape shape = new PolygonShape();
shape.setAsBox(5 / PPM, 5 / PPM);
BodyDef bdef = new BodyDef();
bdef.position.set(160 / PPM, 200 / PPM);
bdef.type = BodyType.DynamicBody;
body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
fdef.shape = shape;
body.createFixture(fdef);
rayHandler = new RayHandler(world);
cone = new ConeLight
(rayHandler, 40, Color.WHITE, 30, 160 / PPM, 200 / PPM, -90, 40);
Then, again in the show() method, I set up the camera:
b2dcam = new OrthographicCamera();
b2dcam.setToOrtho(false, Gdx.graphics.getWidth() / PPM, Gdx.graphics.getHeight() / PPM);
I am rendering it like this in the render() method:
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1f/60f, 6, 2);
b2dr.render(world, b2dcam.combined);
rayHandler.setCombinedMatrix(b2dcam.combined);
rayHandler.updateAndRender();
I am handling the input in this fashion:
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if(button == Buttons.LEFT){
body.setTransform(body.getPosition(), (float) (Math.atan2( (body.getPosition().y - screenY),
(screenX - body.getPosition().x) ) ));
}
return false;
}
The light rotates on mouse click, which means the listener is working, but it does not rotate to the correct point. I assume it has something to do with my math being incorrect, and the scaling done from meters to pixels being wrong.
Can someone help me on both of these issues? The intended behavior is illustrated below:
When the mouse is clicked, the body, and by association the ConeLight, should move to face the direction of the mouse click.
My full code can be viewed here: https://gist.githubusercontent.com/Elsealabs/1afaa812aafb56ecd3c2/raw/5d0959df795516c89fb7e6ab81aecc01dc8cd441/gistfile1.txt
I never got an answer to this, but I figured it out with some help from some friends.
To handle this problem, I created a class that does a lot of the math automatically.
public class Rot2D {
public static Rot2D fromDegrees(double angle) {
return fromRadians(Math.toRadians(angle));
}
public static Rot2D fromRadians(double angle) {
return new Rot2D(Math.cos(angle), Math.sin(angle));
}
public static Rot2D fromVector(double dx, double dy) {
float length = (float) Math.sqrt(dx * dx + dy * dy);
return new Rot2D(dx / length, dy / length);
}
public double cos, sin;
private Rot2D(double cos, double sin) {
this.cos = cos;
this.sin = sin;
}
public Rot2D load(Rot2D that) {
this.cos = that.cos;
this.sin = that.sin;
return this;
}
public Rot2D copy() {
return new Rot2D(cos, sin);
}
public Rot2D rotate(Rot2D that) {
double cos = (this.cos * that.cos) - (this.sin * that.sin);
double sin = (this.cos * that.sin) + (this.sin * that.cos);
this.cos = cos;
this.sin = sin;
return this;
}
public static double cross(Rot2D a, Rot2D b) {
return (a.cos * b.sin) - (a.sin * b.cos);
}
}
And in my game code I used the following code to implement the movement:
if (Gdx.input.isTouched())
{
Vector3 tmp = camera.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
touch_target = new Vector2(tmp.x, tmp.y);
}
touch_angleWant = Rot2D.fromVector(
touch_target.x - entity_player.getBody().getPosition().x,
touch_target.y - entity_player.getBody().getPosition().y
);
double cross1 = Rot2D.cross(touch_angleCur, touch_angleWant);
if (cross1 > 0.0)
touch_angleCur.rotate(Rot2D.fromDegrees(5.0));
else
touch_angleCur.rotate(Rot2D.fromDegrees(-5.0));
double cross2 = Rot2D.cross(touch_angleCur, touch_angleWant);
if (Math.signum(cross1) != Math.signum(cross2))
touch_angleCur.load(touch_angleWant);
entity_player.getBody().setTransform(entity_player.getBody().getPosition(), (float) (touch_angleCur.getAngle()));
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加