diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 3401aa38..1a97a57d 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -37,6 +37,7 @@ import org.newdawn.slick.Image; * Data type representing a spinner object. */ public class Spinner implements HitObject { + /** Container dimensions. */ private static int width, height; @@ -47,13 +48,25 @@ public class Spinner implements HitObject { private GameData data; /** The last rotation angle. */ - private float lastAngle = -1f; + private float lastAngle = 0f; /** The current number of rotations. */ private float rotations = 0f; /** The total number of rotations needed to clear the spinner. */ private float rotationsNeeded; + + /** The sum of all the velocities in storedVelocities. */ + private float sumVelocity = 0f; + + /** Array of the last 50 rotation velocities. */ + private float[] storedVelocities = new float[50]; + + /** True if the mouse cursor is pressed. */ + private boolean isSpinning; + + /** Current index of the stored velocities in rotations/second. */ + private int velocityIndex = 0; /** * Initializes the Spinner data type with images and dimensions. @@ -120,6 +133,9 @@ public class Spinner implements HitObject { if (extraRotations > 0) data.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1.0f); } + + int rpm = Math.abs(Math.round(sumVelocity/storedVelocities.length*60)); + //TODO: add rpm meter at bottom of spinner } /** @@ -173,35 +189,54 @@ public class Spinner implements HitObject { return false; } - // not spinning: nothing to do - if (!Utils.isGameKeyPressed()) { - lastAngle = -1f; + // game button is released + if (isSpinning && !Utils.isGameKeyPressed()) { + isSpinning = false; + } + + float angle = (float) Math.atan2(mouseY - (height / 2), mouseX - (width / 2)); + + // set initial angle to current mouse position to skip first click + if (!isSpinning && Utils.isGameKeyPressed()) { + lastAngle = angle; + isSpinning = true; return false; } - - // scale angle from [-pi, +pi] to [0, +pi] - float angle = (float) Math.atan2(mouseY - (height / 2), mouseX - (width / 2)); - if (angle < 0f) - angle += Math.PI; - - if (lastAngle >= 0f) { // skip initial clicks - float angleDiff = Math.abs(lastAngle - angle); - if (angleDiff < Math.PI / 2) { // skip huge angle changes... - data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); - rotate(angleDiff); - } + + float angleDiff = angle - lastAngle; + + // make angleDiff the smallest angle change possible + // (i.e. 1/4 rotation instead of 3/4 rotation) + if (angleDiff < -Math.PI) { + angleDiff = (float) (angleDiff + Math.PI*2); + } else if (angleDiff > Math.PI) { + angleDiff = (float) (angleDiff - Math.PI*2); } + + // spin caused by the cursor + float cursorVelocity = 0; + if (isSpinning) + cursorVelocity = Math.min((float)(angleDiff / (Math.PI*2) / delta * 1000), 8f); + + sumVelocity -= storedVelocities[velocityIndex]; + sumVelocity += cursorVelocity; + storedVelocities[velocityIndex++] = cursorVelocity; + velocityIndex %= storedVelocities.length; + data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); + rotate(sumVelocity / storedVelocities.length * (float)Math.PI*2 * delta / 1000); + lastAngle = angle; return false; } /** - * Rotates the spinner by a number of degrees. - * @param degrees the angle to rotate (in radians) + * Rotates the spinner by a number of radians. + * @param angle the angle to rotate (in radians) */ - private void rotate(float degrees) { - float newRotations = rotations + (degrees / (float) (2 * Math.PI)); + private void rotate(float angle) { + angle = Math.abs(angle); + float newRotations = rotations + (angle / (float) (2 * Math.PI)); // added one whole rotation... if (Math.floor(newRotations) > rotations) { @@ -216,4 +251,4 @@ public class Spinner implements HitObject { rotations = newRotations; } -} \ No newline at end of file +}