Libgdx: Move Body away from touch event - java

I want an object to move away from the position of a touch event.
So far I have the following:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPosition = new Vector3();
camera.unproject(touchPosition.set(screenX, screenY, 0));
Vector2 directionBody = body.getPosition();
Vector2 directionTouch = new Vector2(touchPosition.x, touchPosition.y);
Vector2 direction = directionBody.sub(directionTouch);
direction.nor();
float speed = 3;
body.setLinearVelocity(direction.scl(speed));
return true;
}
Using this code if I press at the right side of the screen the body moves to the left. If press at the left side of the screen the body will go to the right side. Could someone help me out please?

Your code is a bit fuzzy to me, maybe because you are using classes I don't but generally it's simple:
First you unproject touch coordinates to screen coordinate system, where your body object is, like you did.
Second calculate horizontal and vertical distance between touch place and your body object. Let's say you get dx and dy.
If you want constant speed you just have to check are those dx and dy positive or negative and depending on that you set positive or negative speed, i.e.:
if (dx >0) vx = SPEED_CONSTANT;
else vx = -SPEED_CONSTANT;
Same goes for vertical speed.
If you want your body to accelerate you should use those dx and dy multiplied with some constant. That is, the bigger dx is the higher vertical speed should be. Same goes for vertical speed:
vx = dx * SPEED_CONSTANT;
vy = dy * SPEED_SONSTANT;
If you want your body to decelerate then you should devide some constant value with those dx and dy, to have opposite effect:
vx = SPEED_CONSTANT / dx;
vy = SPEED_CONSTANT / dy;
Something like that. You can set value of that SPEED_CONSTANT by trying some values - tune it up.
I hope this will help.

So I finally did it.
Code snippet:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPosition3D = new Vector3();
//Change touch coordinates to world coordinates
camera.unproject(touchPosition3D.set(screenX, screenY, 0));
//Add unit factor to the vector
touchPosition3D.x = Utility.convertToMeter(touchPosition3D.x);
touchPosition3D.y = Utility.convertToMeter(touchPosition3D.y);
Vector3 bodyPosition = new Vector3(body.getPosition().x, body.getPosition().y, 0 );
Vector3 finalVector = new Vector3(bodyPosition.x, bodyPosition.y, 0).sub(touchPosition3D);
Vector2 direction = new Vector2(finalVector.x, finalVector.y);
float speed = 3;
body.setLinearVelocity(direction.scl(speed));
return true;
}
Basically I had to unproject the touchDown coordinates and convert them to the units I'm using in my application.
Then I do a simple Vector operation, subtracting the calcualted touch vector drom the vector of my body.
Finally apply some linear velocity.

Related

Android/Libgdx How to fix this issue?

Currently iam programming on a game where you move a spaceship and try to avoid asteroids. The spaceship should move when the user touches it and so follow the finger movement of the user.
The spaceship is a sprite that moves arround with:
if (Gdx.input.isTouched()) {
x = Gdx.input.getX() - width / 2;
y = -Gdx.input.getY() + height / 2;
}
The problem that i'm having right now is that the user can teleport the spaceship by touching the screen. How can i fix this? Is it possible to set a touch region?
Calculate a unit vector direction from the ship to the touch point and multiply that by a speed. You need to convert touch coordinates to world coordinates by unprojecting with the camera.
private static final float SHIP_MAX_SPEED = 50f; //units per second
private final Vector2 tmpVec2 = new Vector2();
private final Vector3 tmpVec3 = new Vector3();
//...
if (Gdx.input.isTouched()) {
camera.unproject(tmpVec3.set(Gdx.input.getX(), Gdx.input.getY(), 0)); //touch point to world coordinate system.
tmpVec2.set(tmpVec3.x, tmpVec3.y).sub(x, y); //vector from ship to touch point
float maxDistance = SHIP_MAX_SPEED * Gdx.graphics.getDeltaTime(); //max distance ship can move this frame
if (tmpVec2.len() <= maxDistance) {
x = tmpVec3.x;
y = tmpVec3.y;
} else {
tmpVec2.nor().scl(maxDistance); //reduce vector to max distance length
x += tmpVec2.x;
y += tmpVec2.y;
}
}

Moving entity to location with pixels - libgdx - vector math

So I am making my bullets go to a point and travel further. Only its acting really really weird. Its like its thinking that the 0,0 location is at the top left instead of the bottom left.
This is the code:
float speed = 100;
Vector2 direction;
Vector2 thisPos = new Vector2(getX(), getY());
Vector2 mousePos;
public Bullet(){
super();
setSprite(sprite);
setX(0); setY(0);
float dx = Gdx.input.getX() - getX();
float dy = Gdx.input.getY() - getY();
mousePos = new Vector2(Gdx.input.getX(), Gdx.input.getY());
direction = new Vector2(dx, dy);
//sprite.setRotation(direction.angle(thisPos));
direction.nor();
}
public void update(){
Vector2 dirAd = new Vector2(direction);
thisPos.x += dirAd.x * speed * Gdx.graphics.getDeltaTime();
thisPos.y += dirAd.y * speed * Gdx.graphics.getDeltaTime();
setPosition(thisPos.x, thisPos.y);
super.update();
}
I hope someone can help me what I did wrong with this.
Gdx.input.getX() and getY() by definition do treat the top left as 0,0. From the getX() method:
"The screen origin is the top left corner."
You may need to look into the camera's unproject method, which takes the screen input coordinates and translates them to "world" space.

Move in the same angle from point to point?

I need to be able to move my player x and y pixels in the same direction as a point to a point. It's hard to explain, but this is what I am trying to do:
Angles 1 and 2 have to be the same. Point 1 stays the same at (100, 100), however point 2 constantly changes and so must the angles. I have tried this:
moveRectangle.setX(touchEvent.getX());
moveRectangle.setY(touchEvent.getY());
float theta = (float) Math.toDegrees(Math.atan2(touchEvent.getY() - 100,touchEvent.getY() - 100));
float velX = (float) (getSpeed() * Math.cos(theta));
float velY = (float) (getSpeed() * Math.sin(theta));
player.move(velX, velY);
The above code is constantly run when the user puts his finger on moveRectangle (Point 2) and moves it. But the above code does not work. The player just moves in one of two directions. player.move just adds velX and velY velocity. So how can I get the two angles and move the player in the right direction? Thanks.
Would it be easier to approach this problem using a cartesian approach (vectors) versus polar approach (angle and magnitude)? So, if the player is at point p0 and the "finger" is at point p1, then the direction the player should be moving v is given by the vector p1-p0. You can then scale the resulting vector v by the player's speed, and add the player's speed to his position. You can do this easily on a frame-by-frame basis.
Do you need just to know velocity on X and Y axis? You can do it without using trigonometry (just use Pythagorean theorem).
final float deltaX = touchEvent.getX() - player.x; // player.x is point1.x
final float deltaY = touchEvent.getY() - player.y; // player.y is point1.y
final float length = Maths.sqrt((deltaX)^2 + (deltaY)^2);
final float itterations = length / getSpeed();
final float velX = deltaX / itterations;
final float velY = deltaY / itterations;
player.move(velX, velY);
Or you need a code of player moving in cycle?
Remove Math.toDegrees().
From the Math.sin() / cos() Javadoc:
Parameters:
a - an angle, in radians.
Returns:
the sine of the argument.

Android - problem with Math.atan2

So in my android game I'm making with andengine, I have it set up so as I touch and drag the player sprite, it continously rotates so that the character is always facing the direction it is traveling.
public class Player extends AnimatedSprite {
private float lastX = Game.centerX;
private float lastY = Game.centerY;
private static int angle = 0;
// ...
#Override
public boolean onAreaTouched(final TouchEvent sceneTouchEvent, final float touchAreaLocalX, final float touchAreaLocalY) {
Body body = OrbCatch.physicsWorld.getPhysicsConnectorManager().findBodyByShape(this);
if (sceneTouchEvent.getAction() == TouchEvent.ACTION_MOVE) {
float currentX = sceneTouchEvent.getX();
float currentY = sceneTouchEvent.getY();
angle = (int) (Math.atan2(currentY - lastY, currentX - lastX) * 180 / Math.PI);
lastX = currentX;
lastY = currentY;
}
body.setTransform(new Vector2(sceneTouchEvent.getX(),sceneTouchEvent.getY() )
.mul(1/PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT),angle);
return true;
}
}
The key line is this:
angle = (int) (Math.atan2(currentY - lastY, currentX - lastX) * 180 / Math.PI)
It takes the last known coordinates and the current coordinates, calculates the angle between them, and converts it from radians to degrees. Well, this was all working fine yesterday, but despite changing none of this code today it's behaving strangely. The sprite's orientation changes erratically, with no apparent pattern. If I move it in a straight path, it continuously alternates between 2 or 3 distinctly different angles(usually one of them is the correct one).
edit: solved, see below
The problem was that Body.setTransform angle parameter takes values in radians, not degrees. Andengine is so poorly documented...
math.todegree(math.atan(....))....
You should use toDegree().

Collision system for an object?

I am making a small game, 2D, and I have a player.
EDIT:
This is what I have right now:
int oldX = player.x;
int oldY = player.y;
int newX = oldX - player.getSpeedX();
int newY = oldY - player.getSpeedY();
if(player.getBounds().intersects(brush1.getBounds())){
player.x = newX;
player.y = newY;
}else{
player.x = oldX;
player.y = oldY;
}
But, it is acting really weird, it changes speed when I go in from one side, etc.
For a formula and code that checks the intersection of a line segment and a circle, have a look at this SO answer.
The rest of the code should be quite clear, before you make a move, check if a collision occurs, if it would, don't move.
Depending on the behaviour you prefer, you could also move as close to the wall as possible and then move parallel to it to let the circle "slide" along the wall. This can be done by projecting the movement vector on a line with the same direction as the wall.
EDIT: Some comments on how to use the code from the answer to check for collisions:
The code uses a Dot function that computes the dot product of two vectors. You can either create a Vector class (a good exercise and it is useful for such projects) or compute just the dot product directly using the formulas here.
A vector class will make some of the code easier to read, but you can also operate on floats directly. For example, let's have a look at the computation of d (Direction vector of ray) and f (Vector from center sphere to ray start) as described at the start of the answer. With a vector class, this will be as easy as the formulas used there:
// L, E, C, d and f are of some vector type
d = L - E;
f = E - C;
Without a vector class, you'll have seperate x/y coordinates for all of the variables, bloating the code a bit but doing just the same:
// Twice as much variables, but all of them are usual floats.
dx = Lx - Ex;
dy = Ly - Ey;
fx = Ex - Cx;
fy = Ey - Cy;
I think your code snippet has a few bugs. Suggested fixes:
int oldX = player.x;
int oldY = player.y;
// *add* speed to old pos to get new pos
int newX = oldX + player.getSpeedX();
int newY = oldY + player.getSpeedY();
if(player.getBounds().intersects(brush1.getBounds())){
// Collision! Keep old position.
// Reverse speed (just a suggestion).
player.setSpeedX(-player.getSpeedX());
player.setSpeedY(-player.getSpeedY());
}else{
// No collision. Set position to *new* pos, not old pos.
player.x = newX;
player.y = newY;
}

Categories