From 826376a127088e61991ba6676ccf4ec502ff536f Mon Sep 17 00:00:00 2001 From: PizzaLovers007 Date: Mon, 9 Feb 2015 17:11:49 -0600 Subject: [PATCH 1/5] Initial Implementation of a "weighted" spinner Added angular velocity and angular drag --- src/itdelatrisu/opsu/objects/Spinner.java | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 4f61e5b8..54c2e288 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -37,6 +37,10 @@ import org.newdawn.slick.Image; * Data type representing a spinner object. */ public class Spinner implements HitObject { + + /** The rate at which the spinner slows down in radians/second^2. */ + private static final float angularDrag = 500f; + /** Container dimensions. */ private static int width, height; @@ -54,6 +58,9 @@ public class Spinner implements HitObject { /** The total number of rotations needed to clear the spinner. */ private float rotationsNeeded; + + /** The current angular velocity of the spinner in radians/second. */ + private float angularVelocity; /** * Initializes the Spinner data type with images and dimensions. @@ -186,8 +193,10 @@ public class Spinner implements HitObject { if (lastAngle >= 0f) { // skip initial clicks float angleDiff = Math.abs(lastAngle - angle); if (angleDiff < Math.PI / 2) { // skip huge angle changes... + angularVelocity = Math.max(angularVelocity - angularDrag * delta / 1000, + angleDiff / (Math.PI * 2) / ((float)delta / 1000)); data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); - rotate(angleDiff); + rotate(angularVelocity * delta / 1000); } } @@ -196,11 +205,11 @@ public class Spinner implements HitObject { } /** - * 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) { + float newRotations = rotations + (angle / (float) (2 * Math.PI)); // added one whole rotation... if (Math.floor(newRotations) > rotations) { @@ -215,4 +224,4 @@ public class Spinner implements HitObject { rotations = newRotations; } -} \ No newline at end of file +} From 7ec6e81e8fec2560d51aea06baaa50af6da2e6b6 Mon Sep 17 00:00:00 2001 From: Terrence Date: Mon, 9 Feb 2015 17:57:20 -0600 Subject: [PATCH 2/5] Further implementation of "weighted" spinner Current Issues: - Need to handle change in direction better - Spinning speed seems to be inaccurate --- src/itdelatrisu/opsu/objects/Spinner.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 54c2e288..1be3d237 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -38,8 +38,8 @@ import org.newdawn.slick.Image; */ public class Spinner implements HitObject { - /** The rate at which the spinner slows down in radians/second^2. */ - private static final float angularDrag = 500f; + /** The rate at which the spinner slows down in rotations/second^2. */ + private static final float angularDrag = 20f; /** Container dimensions. */ private static int width, height; @@ -59,7 +59,7 @@ public class Spinner implements HitObject { /** The total number of rotations needed to clear the spinner. */ private float rotationsNeeded; - /** The current angular velocity of the spinner in radians/second. */ + /** The current angular velocity of the spinner in rotations/second. */ private float angularVelocity; /** @@ -126,6 +126,10 @@ public class Spinner implements HitObject { if (extraRotations > 0) data.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1.0f); } + + // rotations per minute + g.setColor(new Color(0,0,0)); + g.drawString(String.format("RPM: %d", Math.round(angularVelocity * 60)), 100, 100); } /** @@ -179,9 +183,11 @@ public class Spinner implements HitObject { return false; } - // not spinning: nothing to do + // not spinning: spinner slows down if (!Utils.isGameKeyPressed()) { lastAngle = -1f; + angularVelocity = Math.max(0, angularVelocity - angularDrag * delta / 1000); + rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); return false; } @@ -193,10 +199,10 @@ public class Spinner implements HitObject { if (lastAngle >= 0f) { // skip initial clicks float angleDiff = Math.abs(lastAngle - angle); if (angleDiff < Math.PI / 2) { // skip huge angle changes... - angularVelocity = Math.max(angularVelocity - angularDrag * delta / 1000, + angularVelocity = (float)Math.max(angularVelocity - angularDrag * delta / 1000, angleDiff / (Math.PI * 2) / ((float)delta / 1000)); data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); - rotate(angularVelocity * delta / 1000); + rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); } } From 582af96e12a396944229d00007eef2ba6ee22299 Mon Sep 17 00:00:00 2001 From: Terrence Date: Mon, 9 Feb 2015 17:57:49 -0600 Subject: [PATCH 3/5] Revert "Further implementation of "weighted" spinner" This reverts commit 7ec6e81e8fec2560d51aea06baaa50af6da2e6b6. --- src/itdelatrisu/opsu/objects/Spinner.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 1be3d237..54c2e288 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -38,8 +38,8 @@ import org.newdawn.slick.Image; */ public class Spinner implements HitObject { - /** The rate at which the spinner slows down in rotations/second^2. */ - private static final float angularDrag = 20f; + /** The rate at which the spinner slows down in radians/second^2. */ + private static final float angularDrag = 500f; /** Container dimensions. */ private static int width, height; @@ -59,7 +59,7 @@ public class Spinner implements HitObject { /** The total number of rotations needed to clear the spinner. */ private float rotationsNeeded; - /** The current angular velocity of the spinner in rotations/second. */ + /** The current angular velocity of the spinner in radians/second. */ private float angularVelocity; /** @@ -126,10 +126,6 @@ public class Spinner implements HitObject { if (extraRotations > 0) data.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1.0f); } - - // rotations per minute - g.setColor(new Color(0,0,0)); - g.drawString(String.format("RPM: %d", Math.round(angularVelocity * 60)), 100, 100); } /** @@ -183,11 +179,9 @@ public class Spinner implements HitObject { return false; } - // not spinning: spinner slows down + // not spinning: nothing to do if (!Utils.isGameKeyPressed()) { lastAngle = -1f; - angularVelocity = Math.max(0, angularVelocity - angularDrag * delta / 1000); - rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); return false; } @@ -199,10 +193,10 @@ public class Spinner implements HitObject { if (lastAngle >= 0f) { // skip initial clicks float angleDiff = Math.abs(lastAngle - angle); if (angleDiff < Math.PI / 2) { // skip huge angle changes... - angularVelocity = (float)Math.max(angularVelocity - angularDrag * delta / 1000, + angularVelocity = Math.max(angularVelocity - angularDrag * delta / 1000, angleDiff / (Math.PI * 2) / ((float)delta / 1000)); data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); - rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); + rotate(angularVelocity * delta / 1000); } } From 6c7aac53f41e62180109a7e769dccfef2fd10328 Mon Sep 17 00:00:00 2001 From: Terrence Date: Mon, 9 Feb 2015 17:58:04 -0600 Subject: [PATCH 4/5] Revert "Revert "Further implementation of "weighted" spinner"" This reverts commit 582af96e12a396944229d00007eef2ba6ee22299. --- src/itdelatrisu/opsu/objects/Spinner.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 54c2e288..1be3d237 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -38,8 +38,8 @@ import org.newdawn.slick.Image; */ public class Spinner implements HitObject { - /** The rate at which the spinner slows down in radians/second^2. */ - private static final float angularDrag = 500f; + /** The rate at which the spinner slows down in rotations/second^2. */ + private static final float angularDrag = 20f; /** Container dimensions. */ private static int width, height; @@ -59,7 +59,7 @@ public class Spinner implements HitObject { /** The total number of rotations needed to clear the spinner. */ private float rotationsNeeded; - /** The current angular velocity of the spinner in radians/second. */ + /** The current angular velocity of the spinner in rotations/second. */ private float angularVelocity; /** @@ -126,6 +126,10 @@ public class Spinner implements HitObject { if (extraRotations > 0) data.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1.0f); } + + // rotations per minute + g.setColor(new Color(0,0,0)); + g.drawString(String.format("RPM: %d", Math.round(angularVelocity * 60)), 100, 100); } /** @@ -179,9 +183,11 @@ public class Spinner implements HitObject { return false; } - // not spinning: nothing to do + // not spinning: spinner slows down if (!Utils.isGameKeyPressed()) { lastAngle = -1f; + angularVelocity = Math.max(0, angularVelocity - angularDrag * delta / 1000); + rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); return false; } @@ -193,10 +199,10 @@ public class Spinner implements HitObject { if (lastAngle >= 0f) { // skip initial clicks float angleDiff = Math.abs(lastAngle - angle); if (angleDiff < Math.PI / 2) { // skip huge angle changes... - angularVelocity = Math.max(angularVelocity - angularDrag * delta / 1000, + angularVelocity = (float)Math.max(angularVelocity - angularDrag * delta / 1000, angleDiff / (Math.PI * 2) / ((float)delta / 1000)); data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); - rotate(angularVelocity * delta / 1000); + rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); } } From 548e38972453f37c19f7c3667d63890d43af9de4 Mon Sep 17 00:00:00 2001 From: PizzaLovers007 Date: Fri, 13 Feb 2015 17:12:04 -0600 Subject: [PATCH 5/5] Completely reworked how the spinner spins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a “weight” to the spinner to make the RPM more like osu! May need to tweak constants to make the spinner feel more natural. --- src/itdelatrisu/opsu/objects/Spinner.java | 91 ++++++++++++++++++----- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 1be3d237..d55209fa 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -39,7 +39,10 @@ import org.newdawn.slick.Image; public class Spinner implements HitObject { /** The rate at which the spinner slows down in rotations/second^2. */ - private static final float angularDrag = 20f; + private static final float ANGULAR_DRAG = 12f; + + /** The maximum rate at which the spinner can speed up in rotations/second^2. */ + private static final float MAX_ANGULAR_INCREASE = 26f; /** Container dimensions. */ private static int width, height; @@ -51,7 +54,7 @@ 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; @@ -61,6 +64,13 @@ public class Spinner implements HitObject { /** The current angular velocity of the spinner in rotations/second. */ private float angularVelocity; + + private float cv; + private float mv; + private int limitUpdate = 0; + + /** True if the mouse cursor is pressed. */ + private boolean isSpinning; /** * Initializes the Spinner data type with images and dimensions. @@ -128,8 +138,14 @@ public class Spinner implements HitObject { } // rotations per minute - g.setColor(new Color(0,0,0)); - g.drawString(String.format("RPM: %d", Math.round(angularVelocity * 60)), 100, 100); + g.setColor(new Color(255,255,255)); + g.drawString(String.format("RPM: %d", Math.abs(Math.round(angularVelocity * 60))), 100, 100); + + // debug stuff + g.drawString("key down: " + Utils.isGameKeyPressed(), 200, 100); + g.drawString("momentum velocity: " + mv, 100, 200); + g.drawString("cursor velocity: " + cv, 100, 300); + g.drawString("angular velocity: " + angularVelocity, 100, 400); } /** @@ -183,29 +199,63 @@ public class Spinner implements HitObject { return false; } - // not spinning: spinner slows down - if (!Utils.isGameKeyPressed()) { - lastAngle = -1f; - angularVelocity = Math.max(0, angularVelocity - angularDrag * delta / 1000); - rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); + // 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; } + + 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 = (float)(angleDiff / (Math.PI*2) / delta * 1000); + // spin from the momentum of the spinner + float momentumVelocity = (angularVelocity > 0) ? + Math.max(0, angularVelocity - ANGULAR_DRAG * delta / 1000) : + Math.min(0, angularVelocity + ANGULAR_DRAG * delta / 1000); - // 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; + //debug stuff + cv = cursorVelocity; + mv = momentumVelocity; - if (lastAngle >= 0f) { // skip initial clicks - float angleDiff = Math.abs(lastAngle - angle); - if (angleDiff < Math.PI / 2) { // skip huge angle changes... - angularVelocity = (float)Math.max(angularVelocity - angularDrag * delta / 1000, - angleDiff / (Math.PI * 2) / ((float)delta / 1000)); - data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); - rotate(angularVelocity * (float)Math.PI * 2 * delta / 1000); + //sets the new angular velocity of the spinner + if (momentumVelocity > 0 && cursorVelocity < 0 || + momentumVelocity < 0 && cursorVelocity > 0) { + angularVelocity = momentumVelocity + cursorVelocity; + } else if (Math.abs(cursorVelocity) > Math.abs(momentumVelocity)) { + // limit the increase in angular velocity + if (momentumVelocity > 0) { + angularVelocity = Math.min(cursorVelocity, + angularVelocity + MAX_ANGULAR_INCREASE * delta / 1000); + } else { + angularVelocity = Math.max(cursorVelocity, + angularVelocity - MAX_ANGULAR_INCREASE * delta / 1000); } + } else { + angularVelocity = momentumVelocity; } + data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER); + rotate(angularVelocity * (float)Math.PI*2 * delta / 1000); + lastAngle = angle; return false; } @@ -215,6 +265,7 @@ public class Spinner implements HitObject { * @param angle the angle to rotate (in radians) */ private void rotate(float angle) { + angle = Math.abs(angle); float newRotations = rotations + (angle / (float) (2 * Math.PI)); // added one whole rotation...