diff --git a/src/awlex/ospu/polymover/Arc.java b/src/awlex/ospu/polymover/Arc.java index ee7e7a77..a479a0bc 100644 --- a/src/awlex/ospu/polymover/Arc.java +++ b/src/awlex/ospu/polymover/Arc.java @@ -30,16 +30,16 @@ public class Arc extends PolyMover { private void init() { Matrix m = prepareMatrix(p1, middle, p2); - xm = m.get(2, 1); - ym = m.get(3, 1); - r = pow(xm, 2) + pow(ym, 2) - m.get(1, 1); + xm = m.get(1, 0) * 0.5; + ym = m.get(2, 0) * 0.5; + r = sqrt(pow(xm, 2) + pow(ym, 2) - m.get(0, 0)); alpha = atan2(p1.end.y - ym, p1.end.x - xm); beta = atan2(middle.end.y - ym, middle.end.x - xm); gamma = atan2(p2.start.y - ym, p2.start.x - xm); } @Override - public double[] getPoint(int time) { + public double[] getPointAt(int time) { double percent; double angle; if (time < middle.getTime()) { diff --git a/src/awlex/ospu/polymover/PolyMover.java b/src/awlex/ospu/polymover/PolyMover.java index 32f71a20..bf51c6f7 100644 --- a/src/awlex/ospu/polymover/PolyMover.java +++ b/src/awlex/ospu/polymover/PolyMover.java @@ -6,7 +6,7 @@ import itdelatrisu.opsu.objects.GameObject; * Created by Awlex on 18.11.2016. */ public abstract class PolyMover { - public abstract double[] getPoint(int time); + public abstract double[] getPointAt(int time); public abstract GameObject[] getItems(); } \ No newline at end of file diff --git a/src/awlex/ospu/polymover/factory/ArcFactory.java b/src/awlex/ospu/polymover/factory/ArcFactory.java index 41ec329a..ea2e3923 100644 --- a/src/awlex/ospu/polymover/factory/ArcFactory.java +++ b/src/awlex/ospu/polymover/factory/ArcFactory.java @@ -7,19 +7,18 @@ import itdelatrisu.opsu.objects.GameObject; /** * Created by Awlex on 18.11.2016. */ -public class ArcFactory implements MultiMoverFactory { +public class ArcFactory implements PolyMoverFactory { private static final int PREFFERED_BUFFER_SIZE = 3; private PolyMover arc1, arc2; - @Override - public double[] getPoint(int time) { + public double[] getPointAt(int time) { if (arc2 == null) { - return arc1.getPoint(time); + return arc1.getPointAt(time); } - double[] point1 = arc1.getPoint(time); - double[] point2 = arc2.getPoint(time); + double[] point1 = arc1.getPointAt(time); + double[] point2 = arc2.getPointAt(time); return new double[]{ (point1[0] + point2[0]) * 0.5, @@ -31,15 +30,18 @@ public class ArcFactory implements MultiMoverFactory { public void init(GameObject[] objects, int startIndex) { if (objects == null) throw new NullPointerException("Objects musn't be null"); - if (objects.length < startIndex + 2) arc1 = new Arc(objects[startIndex], objects[startIndex + 1], objects[startIndex + 2]); arc2 = null; } public void update(GameObject p) { - if (arc2 != null) - arc1 = arc2; - arc2 = new Arc(arc1, p); + GameObject[] items = (arc2 == null ? arc1 : arc2).getItems(); + GameObject last = items[items.length - 1]; + if (last != p) { + if (arc2 == null) + arc2 = arc1; + arc1 = new Arc(arc2, p); + } } @Override @@ -51,4 +53,9 @@ public class ArcFactory implements MultiMoverFactory { public String toString() { return "Arcs"; } + + @Override + public boolean isInitialized() { + return arc1 != null; + } } diff --git a/src/awlex/ospu/polymover/factory/MultiMoverFactory.java b/src/awlex/ospu/polymover/factory/PolyMoverFactory.java similarity index 82% rename from src/awlex/ospu/polymover/factory/MultiMoverFactory.java rename to src/awlex/ospu/polymover/factory/PolyMoverFactory.java index 9e750c1f..dd6d739c 100644 --- a/src/awlex/ospu/polymover/factory/MultiMoverFactory.java +++ b/src/awlex/ospu/polymover/factory/PolyMoverFactory.java @@ -5,14 +5,13 @@ import itdelatrisu.opsu.objects.GameObject; /** * Created by Awlex on 18.11.2016. */ -public interface MultiMoverFactory { - +public interface PolyMoverFactory { /** * @param time point in time whose cursor position has to be calculated * @return [x, y] */ - double[] getPoint(int time); + double[] getPointAt(int time); void init(GameObject[] objects, int startIndex); @@ -24,4 +23,6 @@ public interface MultiMoverFactory { * @return */ int getPrefferedBufferSize(); + + boolean isInitialized(); } diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index cb7fbdc9..5e16234e 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -594,30 +594,51 @@ public class Options { DISABLE_UPDATER ("Disable Automatic Updates", "DisableUpdater", "Disable automatic checking for updates upon starting opsu!.", false), ENABLE_WATCH_SERVICE ("Enable Watch Service", "WatchService", "Watch the beatmap directory for changes. Requires a restart.", false), + DANCE_MOVER_TYPE("Mover Type", "Mover type", "More Points", Dancer.multipoint) { + @Override + public void click(GameContainer container) { + bool = !bool; + Dancer.multipoint = bool; + } + + @Override + public void read(String s) { + super.read(s); + Dancer.multipoint = bool; + } + }, + DANCE_MOVER ("Mover algorithm", "Mover", "Algorithm that decides how to move from note to note" ) { @Override public Object[] getListItems() { - return Dancer.moverFactories; + return Dancer.multipoint ? Dancer.polyMoverFactories : Dancer.moverFactories; } @Override public void clickListItem(int index) { - Dancer.instance.setMoverFactoryIndex(index); + if (Dancer.multipoint) + Dancer.instance.setMoverFactoryIndex(index); + else + Dancer.instance.setMoverFactoryIndex(index); } @Override public String getValueString() { - return Dancer.moverFactories[Dancer.instance.getMoverFactoryIndex()].toString(); + return Dancer.multipoint ? Dancer.polyMoverFactories[Dancer.instance.getPolyMoverFactoryIndex()].toString() : Dancer.moverFactories[Dancer.instance.getMoverFactoryIndex()].toString(); } @Override public String write() { - return Dancer.instance.getMoverFactoryIndex() + ""; + return String.valueOf(Dancer.multipoint ? Dancer.instance.getPolyMoverFactoryIndex() : Dancer.instance.getMoverFactoryIndex()); } @Override public void read(String s) { - Dancer.instance.setMoverFactoryIndex(Integer.parseInt(s)); + int i = Integer.parseInt(s); + if (Dancer.multipoint) + Dancer.instance.setPolyMoverFactoryIndex(i); + else + Dancer.instance.setMoverFactoryIndex(i); } }, diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index cd9b9329..d3a593d5 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -421,15 +421,20 @@ public class Game extends BasicGameState { autoMousePressed = false; if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { Vec2f autoPoint; - if (objectIndex < beatmap.objects.length) { - GameObject p; - if (objectIndex > 0) { - p = gameObjects[objectIndex - 1]; - } else { - p = Dancer.d; - } + if (objectIndex < beatmap.objects.length - (Dancer.multipoint ? Dancer.polyMoverFactories[Dancer.instance.getPolyMoverFactoryIndex()].getPrefferedBufferSize() : 0)) { Dancer d = Dancer.instance; - d.update(trackPosition, p, gameObjects[objectIndex]); + if (Dancer.multipoint) { + d.update(trackPosition, gameObjects, objectIndex); + } else { + GameObject p; + if (objectIndex > 0) { + p = gameObjects[objectIndex - 1]; + } + else { + p = Dancer.d; + } + d.update(trackPosition, p, gameObjects[objectIndex]); + } autoPoint = new Vec2f(d.x, d.y); if (trackPosition < gameObjects[objectIndex].getTime()) { autoMousePressed = true; diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index 817933dd..bfe7d048 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -112,6 +112,7 @@ public class OptionsMenu extends BasicGameState { GameOption.ENABLE_WATCH_SERVICE }), DANCE ("Dance", new GameOption[] { + GameOption.DANCE_MOVER_TYPE, GameOption.DANCE_MOVER, GameOption.DANCE_MOVER_DIRECTION, GameOption.DANCE_SLIDER_MOVER_TYPE, diff --git a/src/yugecin/opsudance/Dancer.java b/src/yugecin/opsudance/Dancer.java index 64aa23db..13c5328c 100644 --- a/src/yugecin/opsudance/Dancer.java +++ b/src/yugecin/opsudance/Dancer.java @@ -19,6 +19,9 @@ package yugecin.opsudance; import awlex.ospu.movers.factories.CenterSpiralMoverFactory; import awlex.ospu.movers.factories.SpiralMoverFactory; +import awlex.ospu.polymover.PolyMover; +import awlex.ospu.polymover.factory.ArcFactory; +import awlex.ospu.polymover.factory.PolyMoverFactory; import awlex.ospu.spinners.SpiralSpinner; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; @@ -36,8 +39,8 @@ import yugecin.opsudance.movers.slidermovers.SliderMoverController; import yugecin.opsudance.spinners.*; public class Dancer { - - public static MoverFactory[] moverFactories = new MoverFactory[] { + + public static MoverFactory[] moverFactories = new MoverFactory[]{ new AutoMoverFactory(), new AutoEllipseMoverFactory(), new CircleMoverFactory(), @@ -50,8 +53,8 @@ public class Dancer { new SpiralMoverFactory(), new CenterSpiralMoverFactory(), }; - - public static Spinner[] spinners = new Spinner[] { + + public static Spinner[] spinners = new Spinner[]{ new RektSpinner(), new BeamSpinner(), new CircleSpinner(), @@ -64,14 +67,19 @@ public class Dancer { new ApproachCircleSpinner(), new SpiralSpinner(), }; - - public static SliderMoverController[] sliderMovers = new SliderMoverController[] { + + public static SliderMoverController[] sliderMovers = new SliderMoverController[]{ new DefaultSliderMoverController(), new InheritedSliderMoverController(), }; - + + public static PolyMoverFactory[] polyMoverFactories = new PolyMoverFactory[]{ + new ArcFactory() + }; + public static Dancer instance = new Dancer(); - + + public static boolean multipoint = false; public static boolean mirror = false; // this should really get its own place somewhere... public static boolean drawApproach = true; // this should really get its own place somewhere... public static boolean removebg = true; // this should really get its own place somewhere... @@ -87,32 +95,34 @@ public class Dancer { public static int cursortraillength = 20; public static boolean hidewatermark = false; public static boolean onlycolortrail = false; - + private int dir; public static final GameObject d = new DummyObject(); private GameObject p; - + private MoverFactory moverFactory; + private PolyMoverFactory polyMoverFactory; private Mover mover; private Spinner spinner; public static SliderMoverController sliderMoverController; - + private int moverFactoryIndex; + private int polyMoverFactoryIndex; private int spinnerIndex; - + public float x; public float y; - + private boolean isCurrentLazySlider; - + public static boolean LAZY_SLIDERS; - + public Dancer() { moverFactory = moverFactories[0]; spinner = spinners[0]; sliderMoverController = sliderMovers[0]; } - + public void reset() { isCurrentLazySlider = false; p = null; @@ -121,11 +131,11 @@ public class Dancer { s.init(); } } - + public int getSpinnerIndex() { return spinnerIndex; } - + public void setSpinnerIndex(int spinnerIndex) { if (spinnerIndex < 0 || spinnerIndex >= spinners.length) { spinnerIndex = 0; @@ -133,11 +143,11 @@ public class Dancer { this.spinnerIndex = spinnerIndex; spinner = spinners[spinnerIndex]; } - + public int getMoverFactoryIndex() { return moverFactoryIndex; } - + public void setMoverFactoryIndex(int moverFactoryIndex) { if (moverFactoryIndex < 0 || moverFactoryIndex >= moverFactories.length) { moverFactoryIndex = 0; @@ -145,7 +155,19 @@ public class Dancer { this.moverFactoryIndex = moverFactoryIndex; moverFactory = moverFactories[moverFactoryIndex]; } - + + public int getPolyMoverFactoryIndex() { + return polyMoverFactoryIndex; + } + + public void setPolyMoverFactoryIndex(int polyMoverFactoryIndex) { + if (polyMoverFactoryIndex < 0 || polyMoverFactoryIndex >= polyMoverFactories.length) { + polyMoverFactoryIndex = 0; + } + this.polyMoverFactoryIndex = polyMoverFactoryIndex; + polyMoverFactory = polyMoverFactories[polyMoverFactoryIndex]; + } + public void update(int time, GameObject p, GameObject c) { GameObject[] e = sliderMoverController.process(p, c, time); p = e[0]; @@ -175,27 +197,100 @@ public class Dancer { double[] spinnerStartPoint = spinner.getPoint(); c.start = new Vec2f((float) spinnerStartPoint[0], (float) spinnerStartPoint[1]); } - if (p == d) { - mover = new LinearMover(p, c, dir); - } else { - mover = moverFactory.create(p, c, dir); - } + if (mover == null || mover.getEnd() != c) + if (p == d) { + mover = new LinearMover(p, c, dir); + } + else { + mover = moverFactory.create(p, c, dir); + } } - + if (time < c.getTime()) { if (!p.isSpinner() || !c.isSpinner()) { double[] point = mover.getPointAt(time); x = (float) point[0]; y = (float) point[1]; } - } else { + } + else { if (c.isSpinner()) { Spinner.PROGRESS = (double) (time - c.getTime()) / (double) (c.getEndTime() - c.getTime()); double[] point = spinner.getPoint(); x = (float) point[0]; y = (float) point[1]; c.end = new Vec2f(x, y); - } else { + } + else { + Vec2f point = c.getPointAt(time); + if (isCurrentLazySlider) { + point = c.start; + } + x = point.x; + y = point.y; + } + } + Pippi.dance(time, c, isCurrentLazySlider); + x = Utils.clamp(x, 10, Options.width - 10); + y = Utils.clamp(y, 10, Options.height - 10); + } + + public void update(int time, GameObject[] gameObjects, int objectIndex) { + GameObject p, c; + GameObject[] e = objectIndex > 0 ? sliderMoverController.process(gameObjects[objectIndex - 1], gameObjects[objectIndex], time) + : sliderMoverController.process(d, gameObjects[objectIndex], time); + p = e[0]; + c = e[1]; + if (this.p != p) { + this.p = p; + if (this.p == d) { + if (c.isSpinner()) { + double[] spinnerStartPoint = spinner.getPoint(); + c.start.set((float) spinnerStartPoint[0], (float) spinnerStartPoint[1]); + } + } + isCurrentLazySlider = false; + // detect lazy sliders, should work pretty good + if (c.isSlider() && LAZY_SLIDERS && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= Circle.diameter * 0.8f) { + Slider s = (Slider) c; + Vec2f mid = s.getCurve().pointAt(1f); + if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= Circle.diameter * 0.8f) { + mid = s.getCurve().pointAt(0.5f); + if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= Circle.diameter * 0.8f) { + isCurrentLazySlider = true; + } + } + } + dir = moverDirection.getDirection(dir); + if (c.isSpinner()) { + double[] spinnerStartPoint = spinner.getPoint(); + c.start = new Vec2f((float) spinnerStartPoint[0], (float) spinnerStartPoint[1]); + } + GameObject g = gameObjects[objectIndex + 2]; + if (!g.isSpinner() && !g.isSlider()) + if (polyMoverFactory.isInitialized()) { + polyMoverFactory.update(g); + } else { + polyMoverFactory.init(gameObjects, objectIndex); + } + } + + if (time < c.getTime()) { + if (!p.isSpinner() || !c.isSpinner()) { + double[] point = polyMoverFactory.getPointAt(time); + x = (float) point[0]; + y = (float) point[1]; + } + } + else { + if (c.isSpinner()) { + Spinner.PROGRESS = (double) (time - c.getTime()) / (double) (c.getEndTime() - c.getTime()); + double[] point = spinner.getPoint(); + x = (float) point[0]; + y = (float) point[1]; + c.end = new Vec2f(x, y); + } + else { Vec2f point = c.getPointAt(time); if (isCurrentLazySlider) { point = c.start; @@ -208,5 +303,4 @@ public class Dancer { x = Utils.clamp(x, 10, Options.width - 10); y = Utils.clamp(y, 10, Options.height - 10); } - } diff --git a/src/yugecin/opsudance/movers/Mover.java b/src/yugecin/opsudance/movers/Mover.java index 2f12f4e6..46cace14 100644 --- a/src/yugecin/opsudance/movers/Mover.java +++ b/src/yugecin/opsudance/movers/Mover.java @@ -31,6 +31,8 @@ public abstract class Mover { protected double endX; protected double endY; + + private GameObject end; public Mover(GameObject start, GameObject end, int dir) { this.dir = dir; @@ -40,6 +42,7 @@ public abstract class Mover { this.endY = end.start.y; this.startT = start.getEndTime(); this.totalT = end.getTime() - startT; + this.end = end; } protected final double getT(int time) { @@ -48,5 +51,8 @@ public abstract class Mover { public abstract double[] getPointAt(int time); public abstract String getName(); - + + public GameObject getEnd() { + return end; + } }