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.
Related
I'm drawing arrows using Java and I can draw them straight but now I need to have the arrows pointing in different directions.
In my current code, I draw a triangle and then a square.
Is there a way to group the two after they've been drawn and then rotate them at a random angle?
Right now I'm only able to rotate the triangle and square separately, causing some messy thing.
void setup() {
size(400, 400);
}
void draw() {
float r = random(24, 64);
background(255);
drawArrow(r);
//drawPlus(r);
saveFrame("dataArrow/plus####.png");
if (frameCount == 100) {
exit();
}
}
void drawArrow(float r){
float base = r * 2;
float xStart = random(1, width-base - 1);
float xEnd = xStart + base;
float k = 0.5 * base;
float y = random(k, width-k);
float middleBase = base/2 + xStart;
float rectSide = 0.5 * base;
float rectX1 = middleBase - rectSide/2;
float rectX2 = middleBase + rectSide/2;
fill(0);
triangle(xStart, y, xEnd, y, middleBase, y - k);
rect(rectX1, y, rectSide, rectSide);
}
not sure if this exactly what you mean but here is how to move things around
push and pop matrix allows you to organize things that should have the same translations
https://processing.org/reference/pushMatrix_.html
https://processing.org/reference/rotate_.html
https://processing.org/reference/translate_.html
basic example
pushMatrix();//start of new translation and rotation things
translate(xAmount,yAmount);//this moves the origin
rotate(angle);//this rotates around origin
//drawing around the point of rotation 0,0 here
//drawing...
popMatrix();//reset all translations and rotations to before
I currently have a sprite following a path...all is working well from a steering perspective, however I am trying to make it so the center of the sprite tracks along the path, rather than the corner (0,0) tracing along the path. Essentially, I would like the center of the fish to follow the line.
Below is an image of what I have implemented, and what I would like to achieve.
The core implementation of this mechanic lies within my update() method; as follows;
private void update(float deltaTime) {
float angle = (float) Math.atan2(path.get(waypoint).y - getY(), path.get(waypoint).x - getX());
velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);
velocity_normal = new Vector2(-velocity.y, velocity.x).nor();
setPosition(
getX() + (velocity.x * deltaTime),
getY() + (velocity.y * deltaTime)
);
setRotation(angle * MathUtils.radiansToDegrees);
if(isWayPointReached()){
setPosition(path.get(waypoint).x, path.get(waypoint).y);
if(waypoint + 1 >= path.size){
waypoint = 0;
} else {
waypoint++;
}
}
}
In particular the setPosition call. My initial thoughts were to calculate the normal vector to the velocity vector, normalize, and multiply the x and y components respectively by the fish height... to my mind this would offset the fish by its height (150px). The code attempted is as follows;
velocity_normal = new Vector2(-velocity.y, velocity.x).nor();
setPosition(
getX() + (velocity.x * deltaTime) + velocity_normal.x * getHeight() * deltaTime,
getY() + (velocity.y * deltaTime) + velocity_normal.y * getHeight() * deltaTime
);
The results in some odd behavior, the fish gets progressively further from the line, it seems the vector is getting compounded and added each frame.
I have also tried to update the normal vector once each way-point has been reached, however this does not work either.
I think the above logic is correct, however have I made a fundamental error in my vector maths?
Your assistance would be greatly appreciated.
EDIT:
Added to constructor:
setPosition(
path.get(waypoint).x - 0.5f * getWidth() ,
path.get(waypoint).y - 0.5f * getHeight()
);
Amended update() method;
private void update(float deltaTime) {
float angle = (float) Math.atan2(path.get(waypoint).y - getY(), path.get(waypoint).x - getX());
velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);
Vector2 velocity_normal = new Vector2();
velocity_normal.set(velocity).nor().scl( speed * deltaTime ); // multiply the speed to scale the unit vector up
translate( velocity_normal.x, velocity_normal.y );
setRotation(angle * MathUtils.radiansToDegrees);
if(isWayPointReached()){
setPosition(path.get(waypoint).x, path.get(waypoint).y);
if(waypoint + 1 >= path.size){
waypoint = 0;
} else {
waypoint++;
}
}
}
Note the omission of the setPosition call, and the replacement with;
Vector2 velocity_normal = new Vector2();
velocity_normal.set(velocity).nor().scl( speed * deltaTime );
translate( velocity_normal.x, velocity_normal.y );
How would I influence the pointA / pointB as mentioned below?
Thanks.
The Sprite position is from the left bottom corner and the origin (where the sprite rotates around) is already set to the center of the sprite. So only the local offset is wrong. You have to substract half the size from the position and then the sprite can move relatively from that offset.
Where you set the sprite:
setPosition(
path.get(waypoint).x - 0.5f * getWidth(),
path.get(waypoint).y - 0.5f * getHeight()
);
In the update method. Because you are adding the velocity every frame you can translate the sprite.
void update(float deltaTime){
// directional global vector
Vector2 velocity = tmp.set(path.get(waypoint)).sub(path.get(waypoint - 1)).nor().scl(speed * deltaTime);
// reference angle is relative to the right vector(1, 0)
float angle = velocity.angle();
setRotation(angle);
translate(velocity.x, velocity.y);
if (isWayPointReached()){
setPosition(
path.get(waypoint).x - 0.5f * getWidth(),
path.get(waypoint).y - 0.5f * getHeight()
);
if(waypoint + 1 >= path.size){
waypoint = 1;
} else {
waypoint++;
}
}
}
There is setCenter() method in Sprite class:
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Sprite.html#setCenter-float-float-
Try setting center like that instead of calculating it additionally.
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;
}
}
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.
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().