Inside my game, I have a spinner, just like the ones in Mario.
When the game doesn't lag, the spinner functions perfectly and rotates in a full 360 degrees circle at constant speed.
However, when it lags (which happens a lot for Android version), gaps start appearing between the different projectiles and it doesn't even rotate in a circle anymore, it just rotates in a distorted elliptical pattern.
Here is my Java code for the Spinner
helper += speedVariable * 1f;
speedY = (float) (speedVariable *helper2 * Math.cos(Math.toRadians(helper)));
speedX = (float) (speedVariable * -1 * helper2 * Math.sin(Math.toRadians(helper)));
setX(getX() + (speedX * delta) + ((Background.bg.getSpeedX() * 5) * delta));
setY(getY() + (speedY * delta));
float helper is the field that is inside the cosine and sine functions that make the spinner spin
speedVariable controls the speed of revolution
helper2 sets the radius of which it rotates
Am I doing anything wrong? Thanks!
Don't set the new position relative to the previous one. You want to stay on a circle around a central point, so it's a lot easier to reliably calculate the position from that point:
setX(getCenterX() + xFromCenter + (Background.bg.getSpeedX() * 5));
setY(getCenterY() + yFromCenter);
(I'm not sure what the Background part is about, I just assumed it should be kept.)
xFromCenter
and yFromCenter
are the cosine and sine of the rotation. In your original code, you had the rotation in helper
, so let's keep it like that. But you should apply delta
to its increment, since you want to rotate the same amount of degrees in the same amount of seconds.
helper += speedVariable * delta;
Think of it like this: The delta should directly influence how much it rotates, not how much it moves on the x and y axis (as those values don't change linearly with time).
Then you can just get xFromCenter
as you got speedX
, except there's no need for speed there now, and do the same for Y. Though I'd set the X by cos and Y by sin, not the other way around - that's the typical usage, with angles measured from 0 at the right side. (The difference is just a 90 degrees rotation.)
Also, a small matter: you could use the MathUtils.sinDeg()
and cosDeg()
functions when calculating, so you don't need to convert to radians and cast the result back to float. It's a bit more readable.
The entire code:
helper += speedVariable * delta;
xFromCenter = helper2 * MathUtils.cosDeg(helper));
yFromCenter = -1 * helper2 * MathUtils.sinDeg(helper));
setX(getCenterX() + xFromCenter + (Background.bg.getSpeedX() * 5));
setY(getCenterY() + yFromCenter);
You might need to play around with the constants (helper2, speedVariable, -1 multiplication) and possibly undo the swapping of X and Y to get exactly what you want, but this should keep the objects on a circle under all conditions.