views:

78

answers:

2

Background: I have a bird view's JavaScript game where the player controls a space ship by touching a circle -- e.g. touch to the left of the circle center, and the ship will move left, touch the top right and it will move to the top right and so on... the further away from the circle center of pseudo joystick, the more speed in that direction. However, I'm not directly adjusting the ship's speed, but rather set a targetSpeed.x and targetSpeed.y value, and the ship will then adjust its speed using something like:

if (this.speed.x < this.targetSpeed.x) {
    this.speed.x += this.speedStep;
}
else if (this.speed.x > this.targetSpeed.x) {
    this.speed.x -= this.speedStep;
}

... and the same for the y speed, and speedStep is a small value to make it smoother and not too abrupt (a ship shouldn't go from a fast leftwards direction to an immediate fast rightwards direction).

My question: Using above code, I believe however that the speed will be adjusted quicker in diagonal directions, and slower along the horizontal/ vertical lines. How do I correct this to have an equal target speed following?

Thanks so much for any help!

+5  A: 
var xdiff = targetSpeed.x - speed.x;
var ydiff = targetSpeed.y - speed.y;
var angle = Math.atan2(ydiff, xdiff);
speed.x += speedStep * Math.cos(angle);
speed.y += speedStep * Math.sin(angle);
Chris Jester-Young
+1 beat me to it. atan2 will get the angle between 2 points. cos and sin get your x and y offsets. I would have just used speed step instead of calculating norm on the last 2 lines though.
DrDipshit
@DrDipshit: Indeed, I fixed my answer to do just that. :-)
Chris Jester-Young
Works like a charm, I love Stackoverflow! Thanks Chris!
Philipp Lenssen
+1  A: 

Assuming you already checked that the touch is inside the circle, and that the edge of the circle represents max speed, and that the center of the circle is circleTouch == [0, 0]

In some C++-like pseudo code:

Scalar circleRadius = ...;
Scalar maxSpeed = ...;
Scalar acceleration = ...;

Vector calculateTargetSpeed( Vector circleTouch ) {
    Vector targetSpeed = maxSpeed * circleTouch / circleRadius;

    return targetSpeed;
}

Vector calculateNewSpeed( Vector currentSpeed, Vector targetSpeed ) {
    Vector speedDiff = targetSpeed - currentSpeed;

    Vector newSpeed = currentSpeed + acceleration * normalized(speedDiff);

    return newSpeed;
}

// Divide v by its length to get normalized vector (length 1) with same x/y ratio
Vector normalized( Vector v ) {
    return v / length(v);
}

// Pythagoras for the length of v
Scalar length( Vector v ) {
    Scalar length = sqrt(v.x * v.x + v.y * v.y); // or preferably hypot(v.x, v.y)

    return length;
}

This is just off the top of my head, and i haven't tested it. The other answer is fine, i just wanted to give an answer without trigonometry functions. :)

Christoffer Hammarström
Great to have this as alternative, thanks Christoffer! Do you suspect this code may be a faster alternative because it avoids certain math functions?
Philipp Lenssen
@Philipp: Sorry, i have no idea, you'd have to benchmark for yourself. Also, i hope the vector math was understandable enough? :)
Christoffer Hammarström