I am trying to make a 2D top-down game where player controls a spaceship. The spaceship (a rocket) is just a sprite following the mouse cursor with a fixed speed and is always pointing toward the cursor location. I calculate rotation using atan2(yDistance, xDistance)
. I've already implemented movement to cursor and rotation toward cursor;
float XDistance = Xplayer - Gdx.input.getX();
float YDistance = Yplayer - (Gdx.graphics.getHeight() - Gdx.input.getY());
rotation = (float) Math.atan2(YDistance, XDistance);
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
if (XDistance >= playerSpeed | YDistance >= playerSpeed | XDistance <= -playerSpeed | YDistance <= -playerSpeed) {
Xplayer -= (float) (playerSpeed * Math.cos(rotation) * deltaTime);
Yplayer -= (float) (playerSpeed * Math.sin(rotation) * deltaTime);
}
MathUtils.clamp(Xplayer, 0, Gdx.graphics.getWidth());
MathUtils.clamp(Yplayer, 0, Gdx.graphics.getHeight());
sprite.setPosition(Xplayer - sprite.getOriginX(), Yplayer - sprite.getOriginY());
sprite.setRotation((float) Math.toDegrees(rotation));
This algorithm makes U-turn (and every rotation in general) instant. I want to achieve a smoother rotation. Instead of instant rotation, I'd like to implement either a curve or simply a bit slower, non instant rotation (while still moving towards cursor current location).
Also, instead of fixed velocity, I am trying to implement acceleration and deceleration, but to no success (for now).
I've already googled lots of various algorithms, but never found the right one.
Update:
public class PlayerEntity {
private float movementSpeedMax;
private float rotationSpeedMax;
private float decay;
private float destinationX;
private float destinationY;
// player
private float playerX;
private float playerY;
private float rotation;
// global
private float _dx;
private float _dy;
private float _vx;
private float _vy;
private float actualRotation = 0;
public PlayerEntity(){
movementSpeedMax = 1000;
rotationSpeedMax = 15;
decay = .95f;
destinationY = 500;
destinationX = 500;
playerX = 0;
playerY = 0;
rotation = 0;
_dx = 0;
_dy = 0;
_vx = 0;
_vy = 0;
actualRotation = 0;
}
public int getX() {
return (int) playerX;
}
public int getY() {
return (int) playerY;
}
public float getAngle() {
return rotation;
}
public void updateRotation() {
// calculate rotation
_dx = playerX - destinationX;
_dy = playerY - destinationY;
// which way to rotate
float rotateTo = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (rotateTo > rotation + 180) {
rotateTo -= 360;
}
if (rotateTo < rotation - 180) {
rotateTo += 360;
}
// ease rotation
actualRotation = (rotateTo - rotation)/ rotationSpeedMax;
// update rotation
if (actualRotation < 180);
rotation += actualRotation;
}
/**
* Calculate Position
*/
public void updatePosition() {
// check if mouse is down
if (Gdx.input.isButtonPressed(Input.Keys.LEFT)) {
// update destination
destinationX = Gdx.input.getX();
destinationY = Gdx.graphics.getHeight() - Gdx.input.getY();
// update velocity
_vx += (destinationX - playerX) / movementSpeedMax;
_vy += (destinationY - playerY) / movementSpeedMax;
}
// apply decay (drag)
_vx *= decay;
_vy *= decay;
// if close to target, slow down turn speed
if (getLength(_dx, _dy) < 50) {
actualRotation *= .25f;
}
if (getDistanceCorrect(destinationX, playerX, destinationY, playerY) < 5) {
_vx = 0;
_vy = 0;
}
// update position
playerX += _vx;
playerY += _vy;
}
private float getLength(float delta_x, float delta_y) {
return (float) Math.sqrt((delta_x * delta_x) + (delta_y * delta_y));
}
private float getDistanceCorrect(float x1, float y1, float x2, float y2) {
return (float) Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
}
private float getRadians(float delta_x, float delta_y) {
float r = (float) Math.atan2(delta_y, delta_x);
if (delta_y < 0) {
r += (2 * Math.PI);
}
return r;
}
private float getDegrees(float radians) {
return (float) Math.floor(radians / (Math.PI / 180));
}
}
I've created this class (based on someone's solution on actionscript). However, this implementation has very annoying bug. If the character rotates clockwise, he will instantly rotate counter-clockwise by ~360. I need help in solving this problem.
This instant rotation happens after one full rotation (rotation direction doesn't matter).
No comments:
Post a Comment