Exemple #1
0
  @Override
  public boolean mousePressed(int x, int y, int trackPosition) {
    if (sliderClickedInitial) // first circle already processed
    return false;

    double distance = Math.hypot(this.x - x, this.y - y);
    if (distance < diameter / 2) {
      int timeDiff = Math.abs(trackPosition - hitObject.getTime());
      int[] hitResultOffset = game.getHitResultOffsets();

      int result = -1;
      if (timeDiff < hitResultOffset[GameData.HIT_50]) {
        result = GameData.HIT_SLIDER30;
        ticksHit++;
      } else if (timeDiff < hitResultOffset[GameData.HIT_MISS]) result = GameData.HIT_MISS;
      // else not a hit

      if (result > -1) {
        data.addHitError(hitObject.getTime(), x, y, trackPosition - hitObject.getTime());
        sliderClickedInitial = true;
        data.sliderTickResult(
            hitObject.getTime(), result, this.x, this.y, hitObject, currentRepeats);
        return true;
      }
    }
    return false;
  }
Exemple #2
0
  /**
   * Constructor.
   *
   * @param hitObject the associated HitObject
   * @param game the associated Game object
   * @param data the associated GameData object
   * @param color the color of this slider
   * @param comboEnd true if this is the last hit object in the combo
   */
  public Slider(HitObject hitObject, Game game, GameData data, Color color, boolean comboEnd) {
    this.hitObject = hitObject;
    this.game = game;
    this.data = data;
    this.color = color;
    this.comboEnd = comboEnd;
    updatePosition();

    // slider time calculations
    this.sliderTime = game.getBeatLength() * (hitObject.getPixelLength() / sliderMultiplier) / 100f;
    this.sliderTimeTotal = sliderTime * hitObject.getRepeatCount();

    // ticks
    float tickLengthDiv =
        100f * sliderMultiplier / sliderTickRate / game.getTimingPointMultiplier();
    int tickCount = (int) Math.ceil(hitObject.getPixelLength() / tickLengthDiv) - 1;
    if (tickCount > 0) {
      this.ticksT = new float[tickCount];
      float tickTOffset = 1f / (tickCount + 1);
      float t = tickTOffset;
      for (int i = 0; i < tickCount; i++, t += tickTOffset) ticksT[i] = t;
    }
  }
Exemple #3
0
  @Override
  public boolean update(
      boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
    int repeatCount = hitObject.getRepeatCount();
    int[] hitResultOffset = game.getHitResultOffsets();
    boolean isAutoMod = GameMod.AUTO.isActive();

    if (!sliderClickedInitial) {
      int time = hitObject.getTime();

      // start circle time passed
      if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
        sliderClickedInitial = true;
        if (isAutoMod) { // "auto" mod: catch any missed notes due to lag
          ticksHit++;
          data.sliderTickResult(time, GameData.HIT_SLIDER30, x, y, hitObject, currentRepeats);
        } else data.sliderTickResult(time, GameData.HIT_MISS, x, y, hitObject, currentRepeats);
      }

      // "auto" mod: send a perfect hit result
      else if (isAutoMod) {
        if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) {
          ticksHit++;
          sliderClickedInitial = true;
          data.sliderTickResult(time, GameData.HIT_SLIDER30, x, y, hitObject, currentRepeats);
        }
      }

      // "relax" mod: click automatically
      else if (GameMod.RELAX.isActive() && trackPosition >= time)
        mousePressed(mouseX, mouseY, trackPosition);
    }

    // end of slider
    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);
        if (distance < followRadius) sliderHeldToEnd = true;
      }

      // final circle hit
      if (sliderHeldToEnd) ticksHit++;

      // "auto" mod: always send a perfect hit result
      if (isAutoMod) ticksHit = tickIntervals;

      // calculate and send slider result
      hitResult();
      return true;
    }

    // repeats
    boolean isNewRepeat = false;
    if (repeatCount - 1 > currentRepeats) {
      float t = getT(trackPosition, true);
      if (Math.floor(t) > currentRepeats) {
        currentRepeats++;
        tickIntervals++;
        isNewRepeat = true;
      }
    }

    // ticks
    boolean isNewTick = false;
    if (ticksT != null
        && tickIntervals < (ticksT.length * (currentRepeats + 1)) + repeatCount
        && tickIntervals < (ticksT.length * repeatCount) + repeatCount) {
      float t = getT(trackPosition, true);
      if (t - Math.floor(t) >= ticksT[tickIndex]) {
        tickIntervals++;
        tickIndex = (tickIndex + 1) % ticksT.length;
        isNewTick = true;
      }
    }

    // holding slider...
    float[] c = curve.pointAt(getT(trackPosition, false));
    double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
    if (((keyPressed || GameMod.RELAX.isActive()) && distance < followRadius) || isAutoMod) {
      // mouse pressed and within follow circle
      followCircleActive = true;
      data.changeHealth(delta * GameData.HP_DRAIN_MULTIPLIER);

      // held during new repeat
      if (isNewRepeat) {
        ticksHit++;
        if (currentRepeats % 2 > 0) { // last circle
          int lastIndex = hitObject.getSliderX().length;
          data.sliderTickResult(
              trackPosition,
              GameData.HIT_SLIDER30,
              curve.getX(lastIndex),
              curve.getY(lastIndex),
              hitObject,
              currentRepeats);
        } else // first circle
        data.sliderTickResult(
              trackPosition, GameData.HIT_SLIDER30, c[0], c[1], hitObject, currentRepeats);
      }

      // held during new tick
      if (isNewTick) {
        ticksHit++;
        data.sliderTickResult(
            trackPosition, GameData.HIT_SLIDER10, c[0], c[1], hitObject, currentRepeats);
      }

      // held near end of slider
      if (!sliderHeldToEnd
          && trackPosition
              > hitObject.getTime() + sliderTimeTotal - hitResultOffset[GameData.HIT_300])
        sliderHeldToEnd = true;
    } else {
      followCircleActive = false;

      if (isNewRepeat)
        data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, hitObject, currentRepeats);
      if (isNewTick)
        data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, hitObject, currentRepeats);
    }

    return false;
  }
Exemple #4
0
  @Override
  public void draw(Graphics g, int trackPosition) {
    int timeDiff = hitObject.getTime() - trackPosition;
    float scale = timeDiff / (float) game.getApproachTime();
    float fadeinScale = (timeDiff - game.getApproachTime() + FADE_IN_TIME) / (float) FADE_IN_TIME;
    float approachScale = 1 + scale * 3;
    float alpha = Utils.clamp(1 - fadeinScale, 0, 1);
    boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();

    float oldAlpha = Utils.COLOR_WHITE_FADE.a;
    Utils.COLOR_WHITE_FADE.a = color.a = alpha;
    Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
    Image hitCircle = GameImage.HITCIRCLE.getImage();
    float[] endPos = curve.pointAt(1);

    curve.draw(color);
    color.a = alpha;

    // end circle
    hitCircle.drawCentered(endPos[0], endPos[1], color);
    hitCircleOverlay.drawCentered(endPos[0], endPos[1], Utils.COLOR_WHITE_FADE);

    // start circle
    hitCircle.drawCentered(x, y, color);
    if (!overlayAboveNumber) hitCircleOverlay.drawCentered(x, y, Utils.COLOR_WHITE_FADE);

    // ticks
    if (ticksT != null) {
      Image tick = GameImage.SLIDER_TICK.getImage();
      for (int i = 0; i < ticksT.length; i++) {
        float[] c = curve.pointAt(ticksT[i]);
        tick.drawCentered(c[0], c[1], Utils.COLOR_WHITE_FADE);
      }
    }
    if (sliderClickedInitial) ; // don't draw current combo number if already clicked
    else
      data.drawSymbolNumber(
          hitObject.getComboNumber(),
          x,
          y,
          hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(),
          alpha);
    if (overlayAboveNumber) hitCircleOverlay.drawCentered(x, y, Utils.COLOR_WHITE_FADE);

    // repeats
    for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1; tcurRepeat++) {
      if (hitObject.getRepeatCount() - 1 > tcurRepeat) {
        Image arrow = GameImage.REVERSEARROW.getImage();
        if (tcurRepeat != currentRepeats) {
          if (sliderTime == 0) continue;
          float t = Math.max(getT(trackPosition, true), 0);
          arrow.setAlpha((float) (t - Math.floor(t)));
        } else arrow.setAlpha(1f);
        if (tcurRepeat % 2 == 0) {
          // last circle
          arrow.setRotation(curve.getEndAngle());
          arrow.drawCentered(endPos[0], endPos[1]);
        } else {
          // first circle
          arrow.setRotation(curve.getStartAngle());
          arrow.drawCentered(x, y);
        }
      }
    }

    if (timeDiff >= 0) {
      // approach circle
      GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
    } else {
      // Since update() might not have run before drawing during a replay, the
      // slider time may not have been calculated, which causes NAN numbers and flicker.
      if (sliderTime == 0) return;

      float[] c = curve.pointAt(getT(trackPosition, false));
      float[] c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);

      float t = getT(trackPosition, false);
      //			float dis = hitObject.getPixelLength() * HitObject.getXMultiplier() * (t - (int) t);
      //			Image sliderBallFrame = sliderBallImages[(int) (dis / (diameter * Math.PI) * 30) %
      // sliderBallImages.length];
      Image sliderBallFrame =
          sliderBallImages[(int) (t * sliderTime * 60 / 1000) % sliderBallImages.length];
      float angle = (float) (Math.atan2(c2[1] - c[1], c2[0] - c[0]) * 180 / Math.PI);
      sliderBallFrame.setRotation(angle);
      sliderBallFrame.drawCentered(c[0], c[1]);

      // follow circle
      if (followCircleActive) {
        GameImage.SLIDER_FOLLOWCIRCLE.getImage().drawCentered(c[0], c[1]);

        // "flashlight" mod: dim the screen
        if (GameMod.FLASHLIGHT.isActive()) {
          float oldAlphaBlack = Utils.COLOR_BLACK_ALPHA.a;
          Utils.COLOR_BLACK_ALPHA.a = 0.75f;
          g.setColor(Utils.COLOR_BLACK_ALPHA);
          g.fillRect(0, 0, containerWidth, containerHeight);
          Utils.COLOR_BLACK_ALPHA.a = oldAlphaBlack;
        }
      }
    }

    Utils.COLOR_WHITE_FADE.a = oldAlpha;
  }