Libgdx + rotate sprite point to the touch position - java

I'm having problem trying to point my "arrow_sprite" to the touch position.
The result I want is that the arrow(the sprite that I want to rotate)will point to the touch position.
How can I acheive this?

You need to calculate the vector between the touch position and the sprite position. To do so you have to unproject the touch position received through your InputProcessor.
public class MyInputProcessor implements InputProcessor {
...
#Override
public boolean touchDown (int x, int y, int pointer, int button) {
Vector3 touchDown = new Vector3(x, y, 0);
camera.unproject(touchDown);
Vector3 spritePosition = new Vector3(yourSpriteX, yourSpriteY, 0);
spritePosition.sub(touchDown);
return false;
}
...
}
Now we have a vector pointing from your sprite to the touch position. From there you just need to calculate the rotation angle. One way would be to use Vector2.angle(), as such creating a Vector2 from the spritePosition Vector3.

If you want to draw in 2D, then you have to set your SpriteBatch to Camera.combined,
something like this : yourBatch.setProjectionMatrix(yourCamera.combined);
Then you must unproject the camera like "batch" said.
After, you must choose if you want to use a vector or 2d coordinate. Basically identycal ending for angle calculation :
First define a float degrees then make it like so in the touchDown method :
degrees = (float) ((Math.atan2 (touchPoint.x - arrowPosition.x, -(touchPoint.y - arrowPosition.y))*180.0d/Math.PI)+90.0f);
assuming you use a Vector3 or 2 for both input and arrow.
then when rendering the Arrow sprite :
Batch.draw(Arrow, x, y, originX, originY, width, height, scaleX, scaleY, degrees);
Hope this will be helpfull.

Just like Psilopat said, we define the degree by :
degrees = (float) ((Math.atan2 (touchPoint.x - arrowPosition.x, -(touchPoint.y - arrowPosition.y))*180.0d/Math.PI)+90.0f);
but if the rotation seems wrong, change the "+90.0f" at the end of line to something else. My arrow is pointing up, so I change it to "-180.0f"

Related

libgdx rotate 3d object following mouse

i try to rotate a 3D instance when I move the mouse. i use Orthographic Camera, and i have a tiled isomap in background.
[EDIT] I use this code :
public boolean mouseMoved (int x, int y) {
Vector3 direction = new Vector3();
Vector3 worldCoordinate = cam.unproject(new Vector3(x, y, 0));
direction = (worldCoordinate).sub(position).nor();
direction.set(-direction.x, -direction.y, -direction.z);
Matrix4 instanceRotation = instance.transform.cpy().mul(instance.transform);
instanceRotation.setToLookAt(direction, new Vector3(0,-1,0));
instanceRotation.rotate(0, 0, 1, 180);
quat = new Quaternion();
instanceRotation.getRotation(quat);
instance.transform.set(position, quat);
return false;
}
Now, the instance follows the cursor, but in all axes. I just want to turn on the Y axis. I can change quat.x = 0 and quat.z = 0 to lock the rotation. After that, the rotation only works on the Y axis. But, the model should turn over if my cursor is at the top of the screen, but it remains facing, no matter where my cursor is.
I don't know how to convert the coordinates to tell my rotation that it needs to turn over. And to modify the quat in this way is not very elegant
Edit : Some image for illustrate what i want
Here, with cursor in the bottom of the screen, the model turn to look in good direction :
Here, the model dont turn over, like the cursor is in bottom of the screen :

libgdx - correcting for multiple coordinate origins?

I have a collision Rectangle (the libgdx one, not awt) set to a ball's coordinates. What I want to do is check if I've tapped on it. Two problems:
a.) I don't know where the origin of the rectangle's coordinates is.
b.) I can't find a way of correct way of correcting for the tap location.
What can I do?
Edit per request:
public void create() {
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
...
camera.unproject(tmpPos);
}
public void render() {
if (Gdx.input.isTouched()) {
float x = Gdx.input.getX();
float y = Gdx.input.getY();
tmpPos.set(x, y, 0);
camera.unproject(tmpPos);
// now the world coordinates are tmpPos.x and tmpPos.y
if (target.contains(tmpPos.x, tmpPos.y)) {
System.out.println("Touched. ");
score++;
}
System.out.println("Score: " + score + "..." + "X: " + (int) tmpPos.x + "...Y: " + (int) tmpPos.y);
...
}
I assume that you have a orthographic camera. (you really can't make a game without it)
You don't need to know its origin to check if is touched, but if you want to, the origin is
float originX = rectangle.x + rectangle.width / 2f;
float originY = rectangle.y + rectangle.height / 2f;
Anyways, you will need to unproject your touch coordinates, this means that you need to translate from the screen position to the camera position (world position).
For this you need a Vector3, is prefered to declare it somewhere outside of the method you are using, because initializing a object in every frame is not recommended.
Vector3 tmpPos=new Vector3();
And now check if your rectangle is touched, anywhere you want.
You have 2 ways to do this.
Do this in the render / update method, checking the position of the finger / cursor.
public void render(float delta) {
if (Gdx.input.isTouched() { // use .isJustTouched to check if the screen is touched down in this frame
// so you will only check if the rectangle is touched just when you touch your screen.
float x = Gdx.input.getX();
float y = Gdx.input.getY();
tmpPos.set(x, y, 0);
camera.unproject(tmpPos);
// now the world coordinates are tmpPos.x and tmpPos.y
if (rectangle.contains(tmpPos.x, tmpPos.y)) {
// your rectangle is touched
System.out.println("YAAAY I'm TOUCHED");
}
}
}
Options 2, use a input listener, so you only check when a touch event is triggered.
In the show / create method of your screen / game add your input listener
public void show() {
// .....
Gdx.input.setInputProcessor(new InputProcessor() {
// and in the method that you want check if the rectangle is touched
#override
public void touchDown(int screenX, int screenY, int pointer, int button) {
tmpPos.set(screenX, screenY, 0);
camera.unproject(tmpPos);
// now the world coordinates are tmpPos.x and tmpPos.y
if (rectangle.contains(tmpPos.x, tmpPos.y)) {
// your rectangle is touched
System.out.println("YAAAY I'm TOUCHED");
}
}
// and the rest of the methods
// ....
//
});
}
I would use the second way.
let me know if it worked for you.
My eventual solution was this:
Set the vector to the touch coordinates, however, with this correction: (Gdx.input.getY() * -1) + cy where cy is the height of the screen. I then unproject that vector, and draw it. Instead of the inverse y location I got without the correction, the circle follows directly under my finger and communicates with other objects in the world perfectly.

Achieve parallax effect in libGDX game

I'm working in a game with some friends in which we have a large horizontal world and a OrthographicCamera that shows only 1/3 of it. This camera it's moved when the horizontal position of the player change so the camera only move to the left and to the right.
Some of the objects showed in the game are near the player point-of-view but others are far away (for example, islands). With this in consideration, we cannot set fixed positions for elements and move only the camera. We need to achieve a parallax effect taking in consideration the distance of the elements.
Here is a simple image to explain it better:
The viewport to the left shows 3 objects of the game. The green one is near the player, the red ellipse is far and the yellow one is in the middle. In the viewport to the right the camera has been moved to the right so all the objects disappear to the left. The thing is that the relative movement of the green rectangle is greater than the movement of the yellow. In the same way, movement of yellow object is greater than red object movement.
I created all my assets scaled taking in consideration how far they are but now, how can I simulate this perspective using libGDX? Is there any class to do it? If I have to set elements position in each iteration, how could I calculate the right position?
Note that the example below is not tested as I am just recalling how I did it. The idea is simple - create layers with an extra layer for each with initial positions and velocity and move them. If a layer goes off the edge, put another one (that is why we create an extra layer) at the opposite edge.
Say you have a parallax object that takes initial positions, size, and velocity-
public class Parallax extends DynamicGameObject {
public float width, height; // Use setter/getter if you prefer
public Parallax(float x, float y, float width, float height, float velocityX, float velocityY) {
super(x, y, width, height);
velocity.set(velocityX, velocityY);
this.width = width;
this.height = height;
}
public void update(float deltaTime) {
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
}
public void setPosition(float x, float y) {
position.set(x, y);
}
}
DynamicGameObject is taken from SuperJumper demo-
public class DynamicGameObject extends GameObject {
public final Vector2 velocity;
public final Vector2 accel;
public DynamicGameObject(float x, float y, float width, float height) {
super(x, y, width, height);
velocity = new Vector2();
accel = new Vector2();
}
}
GameObject as well-
public class GameObject {
public final Vector2 position;
public final Rectangle bounds;
public GameObject(float x, float y, float width, float height) {
this.position = new Vector2(x,y);
this.bounds = new Rectangle(x - width/2f, y - height/2f, width, height);
}
}
Say we have two layers - one in front and the other goes at back. We have one texture for each. Each texture fills the entire screen. We create two instances for each layer so that when one texture starts going off the screen, the other shows up at the edge to fill the gap. If you have smaller textures, you need to determine first how many textures you need to fill the screen and then create layers with one extra to fill the gap in between.
We can create an array of parallax layers during world creation-
Array<Parallax> parallaxList = new Array<Parallax>(4);
We can create the layers like this-
// Back
/* First parallax for back layer is at 0 x-axis. If you want to move the texture from right to left, the value of BACK_VELOCITY_X should be negative. You can experiment with velocity value for desire pace of movement. We do not want our layer to move on y-axis. Hence, it is set to 0. */
parallaxList.add(new Parallax(0, BACK_TEXTURE_HEIGHT, BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, BACK_VELOCITY_X, 0));
/* This one is also for back layer but it is positioned at the right edge of the layer above*/
parallaxList.add(new Parallax(BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, SOME_VELOCITY_X, 0));
// Front
parallaxList.add(new Parallax(0, 0, FRONT_TEXTURE_WIDTH, FRONT_TEXTURE_HEIGHT, FRONT_VELOCITY_X, 0));
parallaxList.add(new Parallax(FRONT_TEXTURE_WIDTH, 0, FRONT_TEXTURE_WIDTH, FRONT_TEXTURE_HEIGHT, FRONT_VELOCITY_X, 0));
We update the layers on an update call in each frame-
// In our example, TOTAL_LAYERS is 4
for (int i = 0; i < TOTAL_LAYERS; i++) {
int tmpInt;
Parallax parallax = parallaxList.get(i);
parallax.update(deltaTime);
// If one layer is off the edge, put it at the right of the next one
// In this example, layers are moving from right to left
if (parallax.position.x <= -parallax.width) {
// We know that parallaxList's indexes 0 and 1 hold the back layers
// and indexes 2 and 3 have the front layers. You can add additional
// parameters in Parallax class to indicate a group so that you do not
// have to determine the group in dirty way like this
if(i == 0){
tmpInt = 1;
} else if(i == 1) {
tmpInt = 0;
} else if(i == 2) {
tmpInt = 3;
} else {
tmpInt = 2;
}
parallax.setPosition(parallaxList.get(tmpInt).position.x + parallax.width, parallax.position.y);
}
}
You can use an OrthographicCamera and a SpriteBatch to draw the parallax layers. You can actually use the game camera you have but I think using a separate camera is much cleaner. Anyways, parallax textures are usually big enough to be batched in a separate call so using the game camera most probably will not save you a draw call.

Drag And Drop LibGDX

I want to make a game where you can build stuff by dragging and dropping objects into place. I think LibGDX only supports DragNDrop on Actors, but I need physics on bricks in order to make them fall down if the construction is not stable.
So far, my approach to drag and drop is:
for(Brick b : map.getList()){
final Image im = new Image(b.ar);
stage.addActor(im);
im.setPosition(b.posX, b.posY);
im.setOrigin(b.posX, b.posY);
im.addListener((new DragListener() {
public void touchDragged (InputEvent event, float x, float y, int pointer) {
im.setOrigin(x, y);
im.setPosition(x, y);
//System.out.println("touchdragged ---> X=" + x + " , Y=" + y);
}
}));
}
where the map.getLists contains all bricks to be painted. b.ar is the texture to be painted.
With this aproach [this] is what happens. I don't know what may be causing it.
#Override
public void render(float delta) {
spritebatch.begin();
map.getWorld().step(1/60f, 6, 2);
renderer.render(map.getWorld(), camera.combined);
if(Gdx.input.justTouched()){
Vector3 touchPoint = new Vector3(Gdx.input.getX(), Gdx.input.getY(),0);
camera.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
System.out.println(touchPoint);
}
stage.draw();
spritebatch.end();
}
Of course i'd like to make the body fell (with the box 2d engine from libgdx) if you drop the object and it has nothing under it.
Thanks in advance
You're setting the origin in your listener callback to a screen coordinate. That is not going to work.
The origin is used to define the "center" of your object, so when you reposition it, Libgdx knows which part of the actor to put where. Generally the origin is either the bottom left corner of the object (I think this is the default) or its the center of the object.
I guess you may want to reset the origin so if someone taps on the left edge of a brick and then you reposition the object you'll reposition that point on the brick (and not reposition the bottom left corner of the brick). To do that you'll need to convert the screen coordinates into coordinates in the actor's space.
That's all somewhat icky though. I think you'd be better off just doing relative repositioning. Instead of trying to position the brick absolutely with setPosition just reposition it relatively:
im.setPosition(im.getX() + dx, im.getY() + dy);
Then it doesn't matter where the "origin" is.
You'll have to compute dx and dy in your listener based on the previous touch point.
It appears that the drag listener gives coordinates relative to the origin of the actor that is raising the event. That is a bit strange when you are moving that actor in response to the drag events, because the origin keeps changing. Essentially, I found that if I just move the actor by the x and y values of the event, it will follow the mouse or finger.
One improvement is to record the position that the drag started at and use it as an offset, so the pointer stays the same distance from the actor's origin.
Another option might be to add the listener to the stage instead of the button. I expect the coordinates would then be relative to the stage's origin, which is not changing. I haven't tried that technique.
Here's the code I used to drag a button horizontally:
DragListener dragListener = new DragListener() {
private float startDragX;
#Override
public void dragStart(
InputEvent event,
float x,
float y,
int pointer) {
startDragX = x;
}
#Override
public void drag(InputEvent event, float x, float y, int pointer) {
insertButton.translate(x - startDragX, 0);
}
};
dragListener.setTapSquareSize(2);
insertButton.addListener(dragListener);
If you want to drag something in two dimensions, just copy the x code for the y position.

Rotate Image Clockwise using LibGDX

How can we rotate a Image Clockwise using LibGDX? what i am looking is when a image is loaded,suppose a star, i need to rotate it from beginning of screen to end of the screen horizontally, with star rotating,how can i do that in libgdx?
When you draw the Texture with your SpriteBatch, you can use one of the draw functions that includes rotation. This javadoc has all the draw functions: SpriteBatch
You can keep a variable for position and rotation, and increase the rotation and x component of the position each time you render to make it rotate while moving horizontally.
Libgdx gives you more then one way to do that:
You can use Scene2D and add an Image to your Stage. Image is a subclass of Actor, so you can add Actions to it:
Image myImage = new Image(myTexture);
myImage.addAction(Actions.parallel(Actions.moveTo(endX, endY, duration), Actions.rotateBy(degrees, duration)));
myImage.setPosition(startX, startY);
myImage.setOrigin(sizeX/2, sizeY/2);
stage.add(myImage);
In render you can then call stage.act(), which updates the position, rotation, scale... of all your Actors and then call stage.draw() which will call draw() for all your Actors.
Image allready handles the draw() so you don't need to care about that anymore.
You can also do it without scene2d, by updating everything yourself:
You can store a int rotationSpeed in degrees/sec
You can store a int moveSpeed in units/sec (maybe pixel but i would suggest to use camera or viewport and use your own unit, which is equal on all devices)
Store the float angle, which is the current rotation of your Texture
and store a Vector2 position, which contains the x and y position of your Texture.
If you want to move in x and y direction you can also store a Vector2 direction, which is a normalized Vector, giving the percent of movement in x and y direction, but thats a different story.
Then in your render(float delta) you update everything:
angle+=delta*rotationSpeed;
angl%=360; // Limits the angle to be <= 360
while (angle < 0) // Unfortunally the "modulo" in java gives negative result for negativ values.
angle+=360;
position.x+=direction.x*moveSpeed*delta;
position.y+=direction.y*movSpeed*delta;
spriteBatch.draw(yourTextureRegion, position.x, position.y, sizeX/2, sizeY/2, sizeX, sizeY, scaleX, scaleY, angle);
For clockwise rotation simply use a negative rotationSpeed or replace the angle+= with angle-=.
Hope it helps.
Following is the implementation to rotate any sprite
batch.draw(sprite,(Gdx.graphics.getWidth() - sprite.getRegionWidth()) / 2.0f,(Gdx.graphics.getHeight() - sprite.getRegionHeight()) / 2.0f,sprite.getRegionWidth()/2.0f,sprite.getRegionHeight()/2.0f, sprite.getRegionWidth(), sprite.getRegionHeight(), 1f, 1f,count, false);
if(count < 0.0f)
count = 360.0f;
else
count --;
Initially set counter to
private float count =360.0f;
You can also use the Scene2D actions. I have an example here with asteroid-type thing falling down the screen and rotating.
http://www.netthreads.co.uk/2012/02/09/libgdx-scene2d-demo-with-scene-transitions/
To rotate anticlockwise and horizontally..
create a textureRegion
then
Sprite sprite = new Sprite(textureRegion, 0, 0, 128, 128);
sprite.setPosition(++mX, 0);
angle++;
sprite.setRotation(angle);
sprite.draw(batcher);
You can do it too like this:
on your create method
sprite.setOrigin(sprite.getWitdh() /2f, sprite.getHeight() /2f);
sprite.setPosition( 0, 200 ); //200 it's a example
on your render(float delta)
sprite.setX( sprite.getX() + delta ).setRotation( sprite.getRotation() + delta );
Here is a simple to rotate an actor in libgdx. First you need to set the origin:
img.setOrigin(getWidth/2,getHeight/2);
And then you can rotate clockwise and anticlockwise according to your need:
img.rotate(2f); or img.rotate(-2f);
So the following sample worked for me (infinite rotation)
Method 1: (recommended)
loadingActor.addAction(Actions.repeat(RepeatAction.FOREVER, Actions.rotateBy(360, 1)));
Method 2:
Image loadingActor = new Image(AssetsController.getInstance().getLoading());
loadingActor.setOrigin(Align.center);
final SequenceAction infiniteRotate = Actions.sequence();
infiniteRotate.addAction(Actions.rotateTo(0 , 0f) );
infiniteRotate.addAction(Actions.rotateTo(360 , 1f) );
loadingActor.addAction(Actions.forever(infiniteRotate));

Categories

Resources