Merge pull request #99 from fluddokt/ReplayTest
Replay importing, spinner fixes (fixes #67), replay seeking, in-place MD5 calculation, pitch change time sync (fixes #86).
This commit is contained in:
@@ -38,6 +38,9 @@ public class Circle implements GameObject {
|
||||
/** The amount of time, in milliseconds, to fade in the circle. */
|
||||
private static final int FADE_IN_TIME = 375;
|
||||
|
||||
/** The diameter of Circle Hitobjects */
|
||||
private static float diameter;
|
||||
|
||||
/** The associated HitObject. */
|
||||
private HitObject hitObject;
|
||||
|
||||
@@ -62,11 +65,12 @@ public class Circle implements GameObject {
|
||||
* @param circleSize the map's circleSize value
|
||||
*/
|
||||
public static void init(GameContainer container, float circleSize) {
|
||||
int diameter = (int) (104 - (circleSize * 8));
|
||||
diameter = (int) (diameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
||||
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameter, diameter));
|
||||
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameter, diameter));
|
||||
GameImage.APPROACHCIRCLE.setImage(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(diameter, diameter));
|
||||
diameter = (104 - (circleSize * 8));
|
||||
diameter = (diameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
||||
int diameterInt = (int)diameter;
|
||||
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt));
|
||||
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameterInt, diameterInt));
|
||||
GameImage.APPROACHCIRCLE.setImage(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,15 +123,16 @@ public class Circle implements GameObject {
|
||||
private int hitResult(int time) {
|
||||
int timeDiff = Math.abs(time);
|
||||
|
||||
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
int result = -1;
|
||||
if (timeDiff < hitResultOffset[GameData.HIT_300])
|
||||
if (timeDiff <= hitResultOffset[GameData.HIT_300])
|
||||
result = GameData.HIT_300;
|
||||
else if (timeDiff < hitResultOffset[GameData.HIT_100])
|
||||
else if (timeDiff <= hitResultOffset[GameData.HIT_100])
|
||||
result = GameData.HIT_100;
|
||||
else if (timeDiff < hitResultOffset[GameData.HIT_50])
|
||||
else if (timeDiff <= hitResultOffset[GameData.HIT_50])
|
||||
result = GameData.HIT_50;
|
||||
else if (timeDiff < hitResultOffset[GameData.HIT_MISS])
|
||||
else if (timeDiff <= hitResultOffset[GameData.HIT_MISS])
|
||||
result = GameData.HIT_MISS;
|
||||
//else not a hit
|
||||
|
||||
@@ -137,8 +142,7 @@ public class Circle implements GameObject {
|
||||
@Override
|
||||
public boolean mousePressed(int x, int y, int trackPosition) {
|
||||
double distance = Math.hypot(this.x - x, this.y - y);
|
||||
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||
if (distance < circleRadius) {
|
||||
if (distance < diameter/2) {
|
||||
int timeDiff = trackPosition - hitObject.getTime();
|
||||
int result = hitResult(timeDiff);
|
||||
|
||||
@@ -158,7 +162,7 @@ public class Circle implements GameObject {
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
boolean isAutoMod = GameMod.AUTO.isActive();
|
||||
|
||||
if (overlap || trackPosition > time + hitResultOffset[GameData.HIT_50]) {
|
||||
if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
|
||||
if (isAutoMod) // "auto" mod: catch any missed notes due to lag
|
||||
data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0, HitObjectType.CIRCLE, null, true);
|
||||
|
||||
@@ -193,4 +197,9 @@ public class Circle implements GameObject {
|
||||
this.x = hitObject.getScaledX();
|
||||
this.y = hitObject.getScaledY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,9 @@ public class DummyObject implements GameObject {
|
||||
this.x = hitObject.getScaledX();
|
||||
this.y = hitObject.getScaledY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,4 +69,11 @@ public interface GameObject {
|
||||
* Updates the position of the hit object.
|
||||
*/
|
||||
public void updatePosition();
|
||||
|
||||
/**
|
||||
* Resets the hit object so that it can be reused.
|
||||
*/
|
||||
public void reset();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ public class Slider implements GameObject {
|
||||
|
||||
/** Rate at which slider ticks are placed. */
|
||||
private static float sliderTickRate = 1.0f;
|
||||
|
||||
private static float followRadius;
|
||||
|
||||
private static float diameter;
|
||||
|
||||
/** The amount of time, in milliseconds, to fade in the slider. */
|
||||
private static final int FADE_IN_TIME = 375;
|
||||
@@ -100,6 +104,8 @@ public class Slider implements GameObject {
|
||||
|
||||
/** Container dimensions. */
|
||||
private static int containerWidth, containerHeight;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the Slider data type with images and dimensions.
|
||||
@@ -110,10 +116,12 @@ public class Slider implements GameObject {
|
||||
public static void init(GameContainer container, float circleSize, Beatmap beatmap) {
|
||||
containerWidth = container.getWidth();
|
||||
containerHeight = container.getHeight();
|
||||
|
||||
int diameter = (int) (104 - (circleSize * 8));
|
||||
diameter = (int) (diameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
||||
|
||||
|
||||
diameter = (104 - (circleSize * 8));
|
||||
diameter = (diameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
||||
int diameterInt = (int)diameter;
|
||||
|
||||
followRadius = diameter / 2 * 3f;
|
||||
// slider ball
|
||||
if (GameImage.SLIDER_BALL.hasSkinImages() ||
|
||||
(!GameImage.SLIDER_BALL.hasSkinImage() && GameImage.SLIDER_BALL.getImages() != null))
|
||||
@@ -121,11 +129,11 @@ public class Slider implements GameObject {
|
||||
else
|
||||
sliderBallImages = new Image[]{ GameImage.SLIDER_BALL.getImage() };
|
||||
for (int i = 0; i < sliderBallImages.length; i++)
|
||||
sliderBallImages[i] = sliderBallImages[i].getScaledCopy(diameter * 118 / 128, diameter * 118 / 128);
|
||||
sliderBallImages[i] = sliderBallImages[i].getScaledCopy(diameterInt * 118 / 128, diameterInt * 118 / 128);
|
||||
|
||||
GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameter * 259 / 128, diameter * 259 / 128));
|
||||
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter));
|
||||
GameImage.SLIDER_TICK.setImage(GameImage.SLIDER_TICK.getImage().getScaledCopy(diameter / 4, diameter / 4));
|
||||
GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameterInt * 259 / 128, diameterInt * 259 / 128));
|
||||
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameterInt, diameterInt));
|
||||
GameImage.SLIDER_TICK.setImage(GameImage.SLIDER_TICK.getImage().getScaledCopy(diameterInt / 4, diameterInt / 4));
|
||||
|
||||
sliderMultiplier = beatmap.sliderMultiplier;
|
||||
sliderTickRate = beatmap.sliderTickRate;
|
||||
@@ -272,6 +280,55 @@ public class Slider implements GameObject {
|
||||
* @return the hit result (GameData.HIT_* constants)
|
||||
*/
|
||||
private int hitResult() {
|
||||
/*
|
||||
time scoredelta score-hit-initial-tick= unaccounted
|
||||
(1/4 - 1) 396 - 300 - 30 46
|
||||
(1+1/4 - 2) 442 - 300 - 30 - 10
|
||||
(2+1/4 - 3) 488 - 300 - 30 - 2*10 896 (408)5x
|
||||
(3+1/4 - 4) 534 - 300 - 30 - 3*10
|
||||
(4+1/4 - 5) 580 - 300 - 30 - 4*10
|
||||
(5+1/4 - 6) 626 - 300 - 30 - 5*10
|
||||
(6+1/4 - 7) 672 - 300 - 30 - 6*10
|
||||
|
||||
difficultyMulti = 3 (+36 per combo)
|
||||
|
||||
score =
|
||||
(t)ticks(10) * nticks +
|
||||
(h)hitValue
|
||||
(c)combo (hitValue/25 * difficultyMultiplier*(combo-1))
|
||||
(i)initialHit (30) +
|
||||
(f)finalHit(30) +
|
||||
|
||||
s t h c i f
|
||||
626 - 10*5 - 300 - 276(-216 - 30 - 30) (all)(7x)
|
||||
240 - 10*5 - 100 - 90 (-60 <- 30>) (no final or initial)(6x)
|
||||
|
||||
218 - 10*4 - 100 - 78 (-36 - 30) (4 tick no initial)(5x)
|
||||
196 - 10*3 - 100 - 66 (-24 - 30 ) (3 tick no initial)(4x)
|
||||
112 - 10*2 - 50 - 42 (-12 - 30 ) (2 tick no initial)(3x)
|
||||
96 - 10 - 50 - 36 ( -6 - 30 ) (1 tick no initial)(2x)
|
||||
|
||||
206 - 10*4 - 100 - 66 (-36 - 30 ) (4 tick no initial)(4x)
|
||||
184 - 10*3 - 100 - 54 (-24 - 30 ) (3 tick no initial)(3x)
|
||||
90 - 10 - 50 - 30 ( - 30 ) (1 tick no initial)(0x)
|
||||
|
||||
194 - 10*4 - 100 - 54 (-24 - 30 ) (4 tick no initial)(3x)
|
||||
|
||||
170 - 10*4 - 100 - 30 ( - 30 ) (4 tick no final)(0x)
|
||||
160 - 10*3 - 100 - 30 ( - 30 ) (3 tick no final)(0x)
|
||||
100 - 10*2 - 50 - 30 ( - 30 ) (2 tick no final)(0x)
|
||||
|
||||
198 - 10*5 - 100 - 48 (-36 ) (no initial and final)(5x)
|
||||
110 - 50 - ( - 30 - 30 ) (final and initial no tick)(0x)
|
||||
80 - 50 - ( <- 30> ) (only final or initial)(0x)
|
||||
|
||||
140 - 10*4 - 100 - 0 (4 ticks only)(0x)
|
||||
80 - 10*3 - 50 - 0 (3 tick only)(0x)
|
||||
70 - 10*2 - 50 - 0 (2 tick only)(0x)
|
||||
60 - 10 - 50 - 0 (1 tick only)(0x)
|
||||
|
||||
|
||||
*/
|
||||
float tickRatio = (float) ticksHit / tickIntervals;
|
||||
|
||||
int result;
|
||||
@@ -308,8 +365,7 @@ public class Slider implements GameObject {
|
||||
return false;
|
||||
|
||||
double distance = Math.hypot(this.x - x, this.y - y);
|
||||
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||
if (distance < circleRadius) {
|
||||
if (distance < diameter / 2) {
|
||||
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
|
||||
@@ -365,26 +421,29 @@ public class Slider implements GameObject {
|
||||
}
|
||||
|
||||
// end of slider
|
||||
if (overlap || trackPosition > hitObject.getTime() + sliderTimeTotal) {
|
||||
if (trackPosition > hitObject.getTime() + sliderTimeTotal) {
|
||||
tickIntervals++;
|
||||
|
||||
// check if cursor pressed and within end circle
|
||||
if (keyPressed || GameMod.RELAX.isActive()) {
|
||||
float[] c = curve.pointAt(getT(trackPosition, false));
|
||||
double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
|
||||
int followCircleRadius = GameImage.SLIDER_FOLLOWCIRCLE.getImage().getWidth() / 2;
|
||||
if (distance < followCircleRadius)
|
||||
if (distance < followRadius)
|
||||
sliderClickedFinal = true;
|
||||
}
|
||||
|
||||
// final circle hit
|
||||
if (sliderClickedFinal)
|
||||
if (sliderClickedFinal){
|
||||
ticksHit++;
|
||||
data.sliderFinalResult(hitObject.getTime(), GameData.HIT_SLIDER30, this.x, this.y, hitObject, currentRepeats);
|
||||
}
|
||||
|
||||
// "auto" mod: always send a perfect hit result
|
||||
if (isAutoMod)
|
||||
ticksHit = tickIntervals;
|
||||
|
||||
//TODO missing the final shouldn't increment the combo
|
||||
|
||||
// calculate and send slider result
|
||||
hitResult();
|
||||
return true;
|
||||
@@ -417,8 +476,7 @@ public class Slider implements GameObject {
|
||||
// holding slider...
|
||||
float[] c = curve.pointAt(getT(trackPosition, false));
|
||||
double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
|
||||
int followCircleRadius = GameImage.SLIDER_FOLLOWCIRCLE.getImage().getWidth() / 2;
|
||||
if (((keyPressed || GameMod.RELAX.isActive()) && distance < followCircleRadius) || isAutoMod) {
|
||||
if (((keyPressed || GameMod.RELAX.isActive()) && distance < followRadius) || isAutoMod) {
|
||||
// mouse pressed and within follow circle
|
||||
followCircleActive = true;
|
||||
data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER);
|
||||
@@ -501,4 +559,16 @@ public class Slider implements GameObject {
|
||||
return (floor % 2 == 0) ? t - floor : floor + 1 - t;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
sliderClickedInitial = false;
|
||||
sliderClickedFinal = false;
|
||||
followCircleActive = false;
|
||||
currentRepeats = 0;
|
||||
tickIndex = 0;
|
||||
ticksHit = 0;
|
||||
tickIntervals = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,11 +45,10 @@ public class Spinner implements GameObject {
|
||||
private static float overallDifficulty = 5f;
|
||||
|
||||
/** The number of rotation velocities to store. */
|
||||
// note: currently takes about 200ms to spin up (4 * 50)
|
||||
private static final int MAX_ROTATION_VELOCITIES = 50;
|
||||
private int maxStoredDeltaAngles;
|
||||
|
||||
/** The amount of time, in milliseconds, before another velocity is stored. */
|
||||
private static final int DELTA_UPDATE_TIME = 4;
|
||||
private static final float DELTA_UPDATE_TIME = 1000 / 60f;
|
||||
|
||||
/** The amount of time, in milliseconds, to fade in the spinner. */
|
||||
private static final int FADE_IN_TIME = 500;
|
||||
@@ -64,6 +63,8 @@ public class Spinner implements GameObject {
|
||||
TWO_PI = (float) (Math.PI * 2),
|
||||
HALF_PI = (float) (Math.PI / 2);
|
||||
|
||||
private static final float MAX_ANG_DIFF = DELTA_UPDATE_TIME * AUTO_MULTIPLIER; // ~95.3
|
||||
|
||||
/** The associated HitObject. */
|
||||
private HitObject hitObject;
|
||||
|
||||
@@ -83,19 +84,25 @@ public class Spinner implements GameObject {
|
||||
private float rotationsNeeded;
|
||||
|
||||
/** The remaining amount of time that was not used. */
|
||||
private int deltaOverflow;
|
||||
private float deltaOverflow;
|
||||
|
||||
/** The sum of all the velocities in storedVelocities. */
|
||||
private float sumVelocity = 0f;
|
||||
private float sumDeltaAngle = 0f;
|
||||
|
||||
/** Array holding the most recent rotation velocities. */
|
||||
private float[] storedVelocities = new float[MAX_ROTATION_VELOCITIES];
|
||||
private float[] storedDeltaAngle;
|
||||
|
||||
/** True if the mouse cursor is pressed. */
|
||||
private boolean isSpinning;
|
||||
|
||||
/** Current index of the stored velocities in rotations/second. */
|
||||
private int velocityIndex = 0;
|
||||
private int deltaAngleIndex = 0;
|
||||
|
||||
/** The remaining amount of the angle that was not used. */
|
||||
private float deltaAngleOverflow = 0;
|
||||
|
||||
/** The RPM that is drawn to the screen. */
|
||||
private int drawnRPM = 0;
|
||||
|
||||
/**
|
||||
* Initializes the Spinner data type with images and dimensions.
|
||||
@@ -117,7 +124,46 @@ public class Spinner implements GameObject {
|
||||
public Spinner(HitObject hitObject, Game game, GameData data) {
|
||||
this.hitObject = hitObject;
|
||||
this.data = data;
|
||||
|
||||
/*
|
||||
1 beat = 731.707317073171ms
|
||||
RPM at frame X with spinner Y beats long
|
||||
10 20 30 40 50 60 <frame#
|
||||
1.00 306 418 457 470
|
||||
1.25 323 424 459 471 475
|
||||
1.5 305 417 456 470 475 477
|
||||
1.75 322 417 456 471 475
|
||||
2.00 304 410 454 469 474 476
|
||||
2.25 303 410 451 467 474 476
|
||||
2.50 303 417 456 470 475 476
|
||||
2.75 302 416 456 470 475 476
|
||||
3.00 301 416 456 470 475 <-- ~2sec
|
||||
4.00 274 414 453 470 475
|
||||
5.00 281 409 454 469 475
|
||||
6.00 232 392 451 467 472 476
|
||||
6.25 193 378 443 465
|
||||
6.50 133 344 431 461
|
||||
6.75 85 228 378 435 463 472 <-- ~5sec
|
||||
7.00 53 154 272 391 447
|
||||
8.00 53 154 272 391 447
|
||||
9.00 53 154 272 400 450
|
||||
10.00 53 154 272 400 450
|
||||
15.00 53 154 272 391 444 466
|
||||
20.00 61 154 272 400 447
|
||||
25.00 53 154 272 391 447 466
|
||||
^beats
|
||||
*/
|
||||
//TODO not correct at all, but close enough?
|
||||
//<2sec ~ 12 ~ 200ms
|
||||
//>5sec ~ 48 ~ 800ms
|
||||
final int minVel = 12;
|
||||
final int maxVel = 48;
|
||||
final int minTime = 2000;
|
||||
final int maxTime = 5000;
|
||||
maxStoredDeltaAngles = (int) Utils.clamp(
|
||||
(hitObject.getEndTime() - hitObject.getTime() - minTime) * (maxVel-minVel)/(maxTime-minTime) + minVel
|
||||
, minVel, maxVel);
|
||||
storedDeltaAngle = new float[maxStoredDeltaAngles];
|
||||
|
||||
// calculate rotations needed
|
||||
float spinsPerMinute = 100 + (overallDifficulty * 15);
|
||||
rotationsNeeded = spinsPerMinute * (hitObject.getEndTime() - hitObject.getTime()) / 60000f;
|
||||
@@ -144,12 +190,11 @@ public class Spinner implements GameObject {
|
||||
}
|
||||
|
||||
// rpm
|
||||
int rpm = Math.abs(Math.round(sumVelocity / storedVelocities.length * 60));
|
||||
Image rpmImg = GameImage.SPINNER_RPM.getImage();
|
||||
rpmImg.setAlpha(alpha);
|
||||
rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f);
|
||||
if (timeDiff < 0)
|
||||
data.drawSymbolString(Integer.toString(rpm), (width + rpmImg.getWidth() * 0.95f) / 2f,
|
||||
data.drawSymbolString(Integer.toString(drawnRPM), (width + rpmImg.getWidth() * 0.95f) / 2f,
|
||||
height - data.getScoreSymbolImage('0').getHeight() * 1.025f, 1f, 1f, true);
|
||||
|
||||
// spinner meter (subimage)
|
||||
@@ -205,7 +250,10 @@ public class Spinner implements GameObject {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int x, int y, int trackPosition) { return false; } // not used
|
||||
public boolean mousePressed(int x, int y, int trackPosition) {
|
||||
lastAngle = (float) Math.atan2(x - (height / 2), y - (width / 2));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
|
||||
@@ -222,17 +270,18 @@ public class Spinner implements GameObject {
|
||||
|
||||
// spin automatically
|
||||
// http://osu.ppy.sh/wiki/FAQ#Spinners
|
||||
float angle;
|
||||
|
||||
deltaOverflow += delta;
|
||||
|
||||
float angleDiff = 0;
|
||||
if (GameMod.AUTO.isActive()) {
|
||||
lastAngle = 0;
|
||||
angle = delta * AUTO_MULTIPLIER;
|
||||
angleDiff = delta * AUTO_MULTIPLIER;
|
||||
isSpinning = true;
|
||||
} else if (GameMod.SPUN_OUT.isActive() || GameMod.AUTOPILOT.isActive()) {
|
||||
lastAngle = 0;
|
||||
angle = delta * SPUN_OUT_MULTIPLIER;
|
||||
angleDiff = delta * SPUN_OUT_MULTIPLIER;
|
||||
isSpinning = true;
|
||||
} else {
|
||||
angle = (float) Math.atan2(mouseY - (height / 2), mouseX - (width / 2));
|
||||
float angle = (float) Math.atan2(mouseY - (height / 2), mouseX - (width / 2));
|
||||
|
||||
// set initial angle to current mouse position to skip first click
|
||||
if (!isSpinning && (keyPressed || GameMod.RELAX.isActive())) {
|
||||
@@ -240,35 +289,52 @@ public class Spinner implements GameObject {
|
||||
isSpinning = true;
|
||||
return false;
|
||||
}
|
||||
angleDiff = angle - lastAngle;
|
||||
if(Math.abs(angleDiff) > 0.01f){
|
||||
lastAngle = angle;
|
||||
}else{
|
||||
angleDiff = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// make angleDiff the smallest angle change possible
|
||||
// (i.e. 1/4 rotation instead of 3/4 rotation)
|
||||
float angleDiff = angle - lastAngle;
|
||||
if (angleDiff < -Math.PI)
|
||||
angleDiff += TWO_PI;
|
||||
else if (angleDiff > Math.PI)
|
||||
angleDiff -= TWO_PI;
|
||||
|
||||
// spin caused by the cursor
|
||||
float cursorVelocity = 0;
|
||||
|
||||
//may be a problem at higher frame rate due to float point round off
|
||||
if (isSpinning)
|
||||
cursorVelocity = Utils.clamp(angleDiff / TWO_PI / delta * 1000, -8f, 8f);
|
||||
|
||||
deltaOverflow += delta;
|
||||
deltaAngleOverflow += angleDiff;
|
||||
|
||||
while (deltaOverflow >= DELTA_UPDATE_TIME) {
|
||||
sumVelocity -= storedVelocities[velocityIndex];
|
||||
sumVelocity += cursorVelocity;
|
||||
storedVelocities[velocityIndex++] = cursorVelocity;
|
||||
velocityIndex %= storedVelocities.length;
|
||||
// spin caused by the cursor
|
||||
float deltaAngle = 0;
|
||||
if (isSpinning){
|
||||
deltaAngle = deltaAngleOverflow * DELTA_UPDATE_TIME / deltaOverflow;
|
||||
deltaAngleOverflow -= deltaAngle;
|
||||
deltaAngle = Utils.clamp(deltaAngle, -MAX_ANG_DIFF, MAX_ANG_DIFF);
|
||||
}
|
||||
sumDeltaAngle -= storedDeltaAngle[deltaAngleIndex];
|
||||
sumDeltaAngle += deltaAngle;
|
||||
storedDeltaAngle[deltaAngleIndex++] = deltaAngle;
|
||||
deltaAngleIndex %= storedDeltaAngle.length;
|
||||
deltaOverflow -= DELTA_UPDATE_TIME;
|
||||
}
|
||||
float rotationAngle = sumVelocity / storedVelocities.length * TWO_PI * delta / 1000;
|
||||
rotate(rotationAngle);
|
||||
if (Math.abs(rotationAngle) > 0.00001f)
|
||||
data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER);
|
||||
|
||||
float rotationAngle = sumDeltaAngle / maxStoredDeltaAngles;
|
||||
rotationAngle = Utils.clamp(rotationAngle, -MAX_ANG_DIFF, MAX_ANG_DIFF);
|
||||
float rotationPerSec = rotationAngle * (1000/DELTA_UPDATE_TIME) / TWO_PI;
|
||||
|
||||
lastAngle = angle;
|
||||
drawnRPM = (int)(Math.abs(rotationPerSec * 60));
|
||||
|
||||
rotate(rotationAngle);
|
||||
if (Math.abs(rotationAngle) > 0.00001f)
|
||||
data.changeHealth(DELTA_UPDATE_TIME * GameData.HP_DRAIN_MULTIPLIER);
|
||||
|
||||
}
|
||||
//TODO may need to update 1 more time when the spinner ends?
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -311,15 +377,38 @@ public class Spinner implements GameObject {
|
||||
|
||||
// added one whole rotation...
|
||||
if (Math.floor(newRotations) > rotations) {
|
||||
//TODO seems to give 1100 points per spin but also an extra 100 for some spinners
|
||||
if (newRotations > rotationsNeeded) { // extra rotations
|
||||
data.changeScore(1000);
|
||||
|
||||
SoundController.playSound(SoundEffect.SPINNERBONUS);
|
||||
} else {
|
||||
}
|
||||
data.changeScore(100);
|
||||
SoundController.playSound(SoundEffect.SPINNERSPIN);
|
||||
|
||||
}
|
||||
/*
|
||||
//The extra 100 for some spinners (mostly wrong)
|
||||
if (Math.floor(newRotations + 0.5f) > rotations + 0.5f) {
|
||||
if (newRotations + 0.5f > rotationsNeeded) { // extra rotations
|
||||
data.changeScore(100);
|
||||
SoundController.playSound(SoundEffect.SPINNERSPIN);
|
||||
}
|
||||
}
|
||||
//*/
|
||||
|
||||
rotations = newRotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
deltaAngleIndex = 0;
|
||||
sumDeltaAngle = 0;
|
||||
for(int i=0; i<storedDeltaAngle.length; i++){
|
||||
storedDeltaAngle[i] = 0;
|
||||
}
|
||||
drawRotation = 0;
|
||||
rotations = 0;
|
||||
deltaOverflow = 0;
|
||||
isSpinning = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user