Box2d Body to follow mouse movement - libgdx

I am trying a box2d body to rotate following the mouse. Here's an image to clarify what I mean.
The red and blue circles are current point of the mouse and the body (of corresponding color) moving/rotating to follow it. Basically the rectangle should rotate with its one end pointed towards where the mouse pointer is.
Here's my code so far,
World world;
Body body, bullet;
Box2DDebugRenderer debugRenderer;
OrthographicCamera camera;
#Override
public void create() {
world = new World(new Vector2(0, 0f), true);
debugRenderer = new Box2DDebugRenderer();
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(10, 10);
body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(2, 5);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1f;
Fixture fixture = body.createFixture(fixtureDef);
shape.dispose();
Gdx.input.setInputProcessor(this);
camera = new OrthographicCamera(200, 100 * (h / w));
camera.position.set(camera.viewportWidth / 2f, camera.viewportHeight / 2f, 0);
camera.update();
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(Gdx.graphics.getDeltaTime(), 6, 2);
camera.update();
debugRenderer.render(world, camera.combined);
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
int mouseX = screenX;
int mouseY = Gdx.graphics.getHeight() - screenY;
float rotateAngle = MathUtils.radiansToDegrees * MathUtils.atan2((float) mouseY - (float) body.getPosition().y, (float) mouseX - (float) body.getPosition().x);
body.setTransform(body.getPosition(), rotateAngle / 57.2957795f);
return true;
}
And here's a gif of how it appears now.
as you can see the body gets skewed and also doesn't rotate properly. What am I missing?

The skew looks like a problem with aspect correction, try,
camera = OrthographicCamera(200, 100 * (w / h));
or even,
camera = OrthographicCamera(200, 100);
To get the end of the box to follow the mouse as in the picture just redefine the box,
shape.setAsBox(5, 2, Vector2(offset, 0), 0);

Related

libgdx: How do i get the result of an orthographic camera through another orthographic camera?

I would like to have a TV screen on my stage. I have a master scene containing the TV screen and some other things (some sprites) and the scene corresponding to what I want to render in the TV.
So I would like to render the TV scene through an OrthographicCamera and then put the result in something like a sprite which can then be rendered through the master orthographic camera, how to do that?
I know that one can use multiple camera in multiple viewports but these are directly rendered on the pixels of my computer screen.
Any advice would be much appreciated
This can be achieved by rendering the scene from the perspective of a screen camera to a FrameBuffer and then taking the TextureRegion from the FrameBuffer and rendering that to screen and then render the scene again.
For example:
In the above example the cyan rect shows what the in-scene camera sees, and this is rendered to the grey box, it is possible to move both the scene camera and the main camera independentely.
By creating and grabbing the TextureRegion from a FrameBuffer
screenFrameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),true);
screenTexture = new TextureRegion(screenFrameBuffer.getColorBufferTexture());
screenTexture.flip(false, true);
all render calls can be made to affect only the screenFrameBuffer by calling screenFrameBuffer.begin(), after screenFrameBuffer.end() is called the next draw call will again affect the actual screen/window.
So in in the render method you can first draw your scene to the FrameBuffer
screenFrameBuffer.begin();
renderScene(screenCamera, Color.DARK_GRAY);
screenFrameBuffer.end();
And then draw it again, followed by the "screen" as a sprite:
renderScene(sceneCamera, Color.BLACK);
batch.setProjectionMatrix(sceneCamera.combined);
batch.begin();
batch.draw(screenTexture, -sceneCamera.viewportWidth / 2.0f,-sceneCamera.viewportHeight / 2.0f,0,0,screenCamera.viewportWidth,screenCamera.viewportHeight,1.0f, 1.0f, 0.0f);
batch.end();
Complete source code for the gif above is:
package com.bornander.sandbox;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.RandomXS128;
import com.badlogic.gdx.math.Vector2;
public class MyGdxGame implements ApplicationListener {
public static class Ball {
public Vector2 position = new Vector2();
public Vector2 velocity = new Vector2();
public float size = 1.0f;
public Color color = new Color();
public void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(color);
shapeRenderer.circle(position.x, position.y, size, 16);
}
public void update() {
position.x += velocity.x * Gdx.graphics.getDeltaTime();
position.y += velocity.y * Gdx.graphics.getDeltaTime();
}
}
static RandomXS128 rnd = new RandomXS128();
OrthographicCamera sceneCamera;
OrthographicCamera screenCamera;
ShapeRenderer shapeRenderer;
SpriteBatch batch;
FrameBuffer screenFrameBuffer;
TextureRegion screenTexture;
Ball[] balls;
private static float rnd(float min, float max) {
return min + rnd.nextFloat() * (max - min);
}
#Override
public void create() {
float aspectRatio = (float) Gdx.graphics.getWidth() / (float)Gdx.graphics.getHeight();
sceneCamera = new OrthographicCamera(100.0f, 100.0f / aspectRatio);
screenCamera = new OrthographicCamera(32.0f, 32.0f / aspectRatio);
batch = new SpriteBatch();
screenFrameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),true);
screenTexture = new TextureRegion(screenFrameBuffer.getColorBufferTexture());
screenTexture.flip(false, true);
shapeRenderer = new ShapeRenderer();
balls = new Ball[128];
for(int i = 0; i < balls.length; ++i) {
balls[i] = new Ball();
balls[i].position.set(0, 0);
balls[i].velocity.set(rnd(-4, 4), rnd(-4, 4));
balls[i].size = rnd(1, 1);
balls[i].color.set(rnd(0.5f, 1.0f), rnd(0.5f, 1.0f), rnd(0.5f, 1.0f), 1.0f);
}
}
private void renderScene(Camera camera, Color background) {
camera.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(background.r, background.g, background.b, background.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
for(int i = 0; i < balls.length; ++i) {
balls[i].render(shapeRenderer);
}
shapeRenderer.end();
}
#Override
public void render() {
float cs = 8.0f;
for(int i = 0; i < balls.length; ++i)
balls[i].update();
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
sceneCamera.position.x -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
sceneCamera.position.x += cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.UP))
sceneCamera.position.y -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
sceneCamera.position.y += cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.A))
screenCamera.position.x -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.D))
screenCamera.position.x += cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.W))
screenCamera.position.y -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.S))
screenCamera.position.y += cs * Gdx.graphics.getDeltaTime();
// Render to framebuffer, clear the background to DARK_GRAY
screenFrameBuffer.begin();
renderScene(screenCamera, Color.DARK_GRAY);
screenFrameBuffer.end();
// Render to window/screen, clear backgroun to BLACK
renderScene(sceneCamera, Color.BLACK);
// Draw the framebuffer's texture as a sprite using a normal SpriteBatch
batch.setProjectionMatrix(sceneCamera.combined);
batch.begin();
batch.draw(screenTexture, -sceneCamera.viewportWidth / 2.0f,-sceneCamera.viewportHeight / 2.0f,0,0,screenCamera.viewportWidth,screenCamera.viewportHeight,1.0f, 1.0f, 0.0f);
batch.end();
// This just draws the outline of what the screen camera looks at
shapeRenderer.setProjectionMatrix(sceneCamera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(Color.CYAN);
shapeRenderer.rect(
screenCamera.position.x - screenCamera.viewportWidth / 2.0f,
screenCamera.position.y - screenCamera.viewportHeight / 2.0f,
screenCamera.viewportWidth,
screenCamera.viewportHeight
);
shapeRenderer.end();
}
#Override
public void dispose() {
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}

Bullet trajectory using LIBGDX

Im having problems with the bullet trajectory,the bullet is not accurately fire at the mouse cursor on screen when i do clicks.
Here my code:
#Override
public boolean mouseMoved(int screenX, int screenY) {
touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
gamecam.unproject(touchPos);
return false;
}
public void shoot() {
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(x,y);
body = world.createBody(bodyDef);
polygonShape = new PolygonShape();
polygonShape.setAsBox(0.2f / 2.0f, 0.01f /2.0f);
fixtureDef2 = new FixtureDef();
fixtureDef2.shape = polygonShape;
float calc= (float) (Math.atan2(touchPos.y-(body.getPosition().y),touchPos.x-body.getPosition().x));
body.setTransform(body.getWorldCenter(),calc);
body.applyLinearImpulse((touchPos.x-body.getPosition().x)*3, (touchPos.y-body.getPosition().y)*3, 0, 0, true);
}
You're removing the bodies position from the impulse vector which is causing your body to be misaligned with your target.
body2.applyLinearImpulse(touchPos.x, touchPos.y, 0, 0, true);

Dragging a texture (without jump)

How can I drag a texture (image) without making it jump and centering itself on the mouse cursor (what I have below in my code)?
When I click on the texture, nothing should happen, and when I drag, the mouse cursor should stay in place (relative to the edges of the texture).
Example: https://s31.postimg.org/ojapwbj6j/Untitled_1.jpg
SpriteBatch batch;
Texture texture;
OrthographicCamera camera;
Vector3 spritePosition = new Vector3();
float offsetX, offsetY;
Vector3 input;
#Override
public void create () {
batch = new SpriteBatch();
texture = new Texture("badlogic.jpg");
camera = new OrthographicCamera();
camera.setToOrtho(false);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(texture, spritePosition.x, spritePosition.y);
batch.end();
if (Gdx.input.justTouched()){
int x1 = Gdx.input.getX();
int y1 = Gdx.input.getY();
input = new Vector3(x1, y1, 0);
camera.unproject(input);
offsetX = x1 - spritePosition.x;
offsetY = y1 - spritePosition.y;
}
if (Gdx.input.isTouched()) {
spritePosition.set(Gdx.input.getX() - offsetX, Gdx.input.getY() - offsetY, 0);
}
}
What you need to do is work out the offset of the mouse position relative to your image, and subtract that, rather than half the width / height as you're doing at the moment.
Here's some very rough pseudocode to show what I mean - You'll need to rewrite as Java...
if Gdx.input.justTouched {
get mouse position from Gdx.input
camera.unproject it into cameraX and cameraY
offsetX = cameraX - imageX
offsetY = cameraY - imageY
}
if Gdx.input.isTouched {
spritePisition.set(Gdx.input.getX() - offsetX, Gdx.input.getY - offsetY)
}
Why are you using camera.unproject?
Try this:
Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture, spritePosition.x, spritePosition.y);
batch.end();
if (Gdx.input.isTouched()) {
spritePosition.set(Gdx.input.getX() - texture.getWidth() / 2, Gdx.input.getY() + texture.getHeight() / 2, 0);
}
}

libgdx box2d friction joint not working

I am trying to make a simple example using the friction joints of box2d. I have created a circle that can be controlled with the mouse or arrow keys. There is also a box which is meant to be pushed with the circle. The problem is that when I push the box it keeps moving forever. I have added an auxiliary static box so I can join both boxes with a friction joint to simulate top-down friction. But it doesn't work. Here is the code.
public class MyGdxGame extends ApplicationAdapter {
Camera camera;
int windowWidth, windowHeight;
World physicsWorld;
Box2DDebugRenderer debugRenderer;
Body frictionerBox;
Body boxBody;
Body circleBody;
#Override
public void create () {
camera = new OrthographicCamera(2, 2);
Box2D.init();
physicsWorld = new World(new Vector2(0, 0), true);
debugRenderer = new Box2DDebugRenderer();
// frictioner box
BodyDef bDef = new BodyDef();
bDef.type = BodyDef.BodyType.StaticBody;
bDef.position.set(0, 0);
frictionerBox = physicsWorld.createBody(bDef);
PolygonShape fShape = new PolygonShape();
fShape.setAsBox(10, 10);
FixtureDef fixDef = new FixtureDef();
fixDef.shape = fShape;
fixDef.density = 1.f;
fixDef.friction = 1.f;
//Fixture fix =
frictionerBox.createFixture(fixDef);
// box
bDef = new BodyDef();
bDef.type = BodyDef.BodyType.DynamicBody;
bDef.position.set(0, 50);
boxBody = physicsWorld.createBody(bDef);
PolygonShape bShape = new PolygonShape();
bShape.setAsBox(25, 25);
fixDef = new FixtureDef();
fixDef.shape = bShape;
fixDef.density = 1.f;
fixDef.friction = 1.f;
boxBody.createFixture(fixDef);
// circle
BodyDef cDef = new BodyDef();
cDef.type = BodyDef.BodyType.DynamicBody;
cDef.position.set(20, 20);
circleBody = physicsWorld.createBody(cDef);
CircleShape cShape = new CircleShape();
cShape.setRadius(12);
fixDef = new FixtureDef();
fixDef.shape = cShape;
fixDef.density = 1.f;
circleBody.createFixture(fixDef);
FrictionJointDef frictionJointDef = new FrictionJointDef();
frictionJointDef.maxForce = 10;
frictionJointDef.maxTorque = 10;
frictionJointDef.initialize(frictionerBox, boxBody, new Vector2(0, 0));
physicsWorld.createJoint(frictionJointDef);
bShape.dispose();
cShape.dispose();
fShape.dispose();
}
#Override
public void render () {
handleInput();
physicsWorld.step(Gdx.graphics.getDeltaTime(), 6, 2);
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
debugRenderer.render(physicsWorld, camera.combined);
}
#Override
public void resize(int width, int height)
{
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update();
windowWidth = width;
windowHeight = height;
System.out.println("resized");
}
private void handleInput()
{
final float ARROW_SPEED = 60.0f;
final float MAX_SPEED = 200.f;
final float MIN_SPEED = 20.f;
float vx, vy;
if(Gdx.input.isTouched() || Gdx.input.isButtonPressed(Input.Buttons.LEFT))
{
int tx = (Gdx.input.getX() - windowWidth/2);
int ty = -Gdx.input.getY() + windowHeight/2;
float cx = camera.position.x;
float cy = camera.position.y;
float px = circleBody.getPosition().x;
float py = circleBody.getPosition().y;
px = px - cx;
py = py - cy;
vx = tx - px;
vy = ty - py;
float speed = (float) Math.sqrt(vx*vx + vy*vy);
if( speed > MAX_SPEED )
{
vx = (vx/speed) * MAX_SPEED;
vy = (vy/speed) * MAX_SPEED;
}
if( speed > 0 && speed < MIN_SPEED )
{
vx = (vx/speed) * MIN_SPEED;
vy = (vy/speed) * MIN_SPEED;
}
}
else
{
vx = vy = 0;
if(Gdx.input.isKeyPressed(Input.Keys.W))
{
vy += 1;
}
if(Gdx.input.isKeyPressed(Input.Keys.S))
{
vy -= 1;
}
if(Gdx.input.isKeyPressed(Input.Keys.A))
{
vx -= 1;
}
if(Gdx.input.isKeyPressed(Input.Keys.D))
{
vx += 1;
}
float speed = (float) Math.sqrt(vx*vx + vy*vy);
if(speed > 0.f)
{
vx = (vx/speed) * ARROW_SPEED;
vy = (vy/speed) * ARROW_SPEED;
}
}
circleBody.setLinearVelocity(vx, vy);
}
}
What am I doing wrong?
I figured it out. It seems that for the friction to be noticeable you have to set very high values to maxForce and maxTorque.
frictionJointDef.maxForce = 1000000;
frictionJointDef.maxTorque = 10000000;

libgdx - group transformation

I'm new in LibGDX.
I created group with actors in show method and add listener (where i calculate rotation matrix) and want to rotate all actors from group with batch.setTransformMatrix(matrixResult); but nothing happens. How can I force to rotate all actors of group?
#Override
public void show() {
camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(0f, 0f, - 120);
camera.lookAt(0,0,0);
camera.near = 0.1f;
camera.far = 300f;
camera.update();
stage = new Stage();
shader = new ShaderProgram(vertexShader, fragmentShader);
myBatch = new SpriteBatch();
shapeRenderer = new ShapeRenderer();
sphere = BuildSphere(5, 100);
group = new Group(){
#Override
public void draw(Batch batch, float parentAlpha) {
batch.setTransformMatrix(matrixResult);
super.draw(batch, parentAlpha);
}
};
group.setTouchable(Touchable.enabled);
group.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
Gdx.app.log("MOUSE_X_BEG", Float.toString(x));
Gdx.app.log("MOUSE_Y_BEG", Float.toString(y));
begX = x;
begY = y;
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y,
int pointer) {
endX = x;
endY = y;
//isRotate = true;
float translationX = endX-begX;
float translationY = begY-endY;
float length = (float)Math.sqrt(Math.pow(translationX,2) + Math.pow(translationY,2));
Vector3 axis = new Vector3(0, 0, 0);
if(length>0){
if(begX-endX == 0){
axis.x = 1;
}else{
float angle = (float) (Math.atan(translationY/translationX) + Math.PI/2.0*(translationX <0 ? -1 : 1));
axis.z = 1;
axis.x = (float) Math.cos(angle);
axis.y = (float) Math.sin(angle);
}
}
quaternion = new Quaternion(axis, 0.02f*length);
Matrix4 rotation = new Matrix4(quaternion);
matrixResult = rotation.mul(matrixRotationOld);
matrixRotationOld = matrixResult;
}
});
//group.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
for (CenterCoordinate cenCoordinate : sphere.getPolygonCenterCoordinates()) {
Vector3 vector = cenCoordinate.getCartesianCenter();
Polygon polygon = new Polygon(1, cenCoordinate.getType().getCode(), cenCoordinate.getRadius(), cenCoordinate.getPsi(),
cenCoordinate.getKsi(), vector, cenCoordinate.getRotation());
group.addActor(polygon);
}
stage.addActor(group);
Gdx.input.setInputProcessor(stage);
}
Polygon extends Actor draw method :
#Override
public void draw(Batch batch, float parentAlpha) {
translation.setToTranslation(vertex.x, vertex.y, vertex.z);
matrix.mul(translation);
shader.begin();
shader.setUniformMatrix("u_worldView", matrix);
mesh.render(shader, GL20.GL_LINE_LOOP, 1, mesh.getNumVertices()-1);
shader.end();
matrix.idt();
}
Rotating the batch will not rotate the group. If you want to rotate everything i would suggest to rotate the camera of the Stage and set the Stages SpriteBatchs ProjectionMatrix to cam.combined. But to rotate only the Group use the rotateBy(degrees) or setRotation(degrees) method.
Rotating the SpriteBatch or the camera is actually only a change of the view, but rotating the Actor (in your case the Group) changes the logic of them.
In the draw() method you then will need to take care about this rotation and then you will have the result you want.