public override void Dispose() { if (ManiaStage != null) { ManiaStage.Dispose(); } base.Dispose(); }
private ScrollingTestContainer createStage(ScrollingDirection direction, ManiaAction action) { var specialAction = ManiaAction.Special1; var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); stages.Add(stage); return(new ScrollingTestContainer(direction) { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, TimeRange = 2000, Child = stage }); }
internal void ReCalculate(int audioTime) { bool paused = false; bool upsideDown = ManiaStage.Skin.UpsideDown; if (audioTime > LastNoteTime) { return; } if (AudioEngine.AudioState == AudioStates.Playing) { AudioEngine.TogglePause(); paused = true; } //Clear anything from a previous ReCalculate if (barLines != null) { barLines.ForEach(b => b.Transformations.Clear()); barLines.Clear(); } else { barLines = new List <pSprite>(); } foreach (HitObject h in hitObjects) { if (((HitCircleMania)h).IsFinished) { continue; } h.SpriteCollection.ForEach(s => s.Transformations.RemoveAll(t => (t.Type & transformationsToClear) > 0)); } //Start a fresh forward play queue foreach (StageMania stage in ManiaStage) { stage.SpriteManagerNotes.Clear(false); stage.SpriteManagerNotes.ForwardPlayOptimisedAdd = true; } //Mania-specific maps use all control points while autoconverts only use BPM changes List <ControlPoint> beatmapControlPoints = Beatmap.PlayMode != PlayModes.OsuMania ? Beatmap.TimingPoints : Beatmap.ControlPoints; if (beatmapControlPoints.Count == 0 || hitObjects.Count == 0) { return; } //For moving things on the play field at the correct speed. It is "collapsed" so you can iterate it in both directions speedChanges = new List <ControlPoint>(); //For placing bar lines timingChanges = new List <ControlPoint>(); double lastBeatLength = beatmapControlPoints[0].BeatLength; foreach (ControlPoint p in beatmapControlPoints) { ControlPoint t = new ControlPoint(); t.TimingChange = false; //So that we can guarantee the ordering when searching t.BeatLength = p.BeatLength < 0 ? lastBeatLength * p.BpmMultiplier : p.BeatLength; t.TimeSignature = p.TimeSignature; t.Offset = p.Offset; //If an SV change right after the initial BPM is before the first note, apply it from the start of time just like the initial BPM if (speedChanges.Count == 1 && p.BeatLength < 0 && t.Offset < FirstNoteTime) { t.Offset = speedChanges[0].Offset; } //Collapse changes at the same offset if (speedChanges.Count > 0 && t.Offset <= speedChanges[speedChanges.Count - 1].Offset) { speedChanges.RemoveAt(speedChanges.Count - 1); } //Collapse changes that leave us at the same beat length if (speedChanges.Count == 0 || t.BeatLength != speedChanges[speedChanges.Count - 1].BeatLength) { speedChanges.Add(t); } //Uncollapsed timing changes if (p.BeatLength >= 0) { timingChanges.Add(t); lastBeatLength = t.BeatLength; } } //Move the first offset of the control points to before the song starts //Doing this after collapsing speed changes makes it so that SV changes to the opening BPM apply from the very start of the song double preTimeStart = beatmapControlPoints[0].Offset; while (preTimeStart >= 0) { preTimeStart -= beatmapControlPoints[0].BeatLength * (int)beatmapControlPoints[0].TimeSignature; } preTimeStart -= beatmapControlPoints[0].BeatLength * (int)beatmapControlPoints[0].TimeSignature; speedChanges[0].Offset = preTimeStart; timingChanges[0].Offset = preTimeStart; //Add a final control point to speed changes which is useful as an endpoint speedChanges.Add(new ControlPoint() { Offset = Double.PositiveInfinity }); //Add notes for (int i = 0; i < hitObjects.Count; i++) { HitCircleMania note = (HitCircleMania)hitObjects[i]; HitCircleManiaLong noteLong = hitObjects[i] as HitCircleManiaLong; if (note.IsFinished) { continue; } float headHeight = SpriteHeight(note.s_note); addTransformations(note.s_note, note.StartTime, headHeight); if (noteLong != null) { float rearHeight = SpriteHeight(noteLong.s_rear); addTransformations(noteLong.s_rear, note.EndTime, rearHeight); addTransformations(noteLong.s_body, note.StartTime, headHeight / 2f, -headHeight / 2f, note.EndTime - note.StartTime); //addTransformations very deliberately breaks up the transformations into three parts //From offscreen to the StartTime -> from the StartTime to the EndTime -> from the end time to offscreen //Using these StartTime and EndTime endpoints, we can find the distance between the head and rear sprites float start = 0, end = 0; if (noteLong.Length > 0) { start = noteLong.s_body.Transformations.Find(t => t.Type == TransformationType.MovementY && t.TagNumeric == TransformationTag.BetweenStartEndTime).StartFloat; end = noteLong.s_body.Transformations.FindLast(t => t.Type == TransformationType.MovementY && t.TagNumeric == TransformationTag.BetweenStartEndTime).EndFloat; } float length = Math.Abs(end - start) * 1.6f; noteLong.s_body.VectorScale.Y = noteLong.s_body.FlipVertical ? -1f : 1f; if (noteLong.s_body.DrawDimensionsManualOverride) { noteLong.s_body.WrapTexture = false; noteLong.s_body.DrawDimensionsManualOverride = false; noteLong.s_body.UpdateTextureSize(); } ManiaNoteBodyStyle style = ManiaStage.Skin.GetNoteBodyStyle(note.Column); if (style == ManiaNoteBodyStyle.Stretch) { noteLong.s_body.VectorScale.Y *= length / noteLong.s_body.DrawHeight; } else { noteLong.s_body.WrapTexture = true; noteLong.s_body.VectorScale.Y *= ManiaStage.HeightRatio; float height = noteLong.s_body.DrawHeight / ManiaStage.HeightRatio; noteLong.s_body.DrawHeight = noteLong.s_body.Height = (int)(length / ManiaStage.HeightRatio); noteLong.s_body.DrawDimensionsManualOverride = true; switch (style) { case ManiaNoteBodyStyle.RepeatBottom: default: noteLong.s_body.DrawTop = 0; break; case ManiaNoteBodyStyle.RepeatTop: noteLong.s_body.DrawTop = (int)(height - length); break; case ManiaNoteBodyStyle.RepeatTopAndBottom: noteLong.s_body.DrawTop = (int)((height - length) / 2f); break; } } noteLong.s_body.UpdateTextureAlignment(); if (noteLong.IsFrozen || noteLong.IsUnfrozen) { FreezeNote(noteLong); } if (noteLong.IsUnfrozen) { UnfreezeNote(noteLong); } } note.Column.Host.SpriteManagerNotes.Add(note.SpriteCollection); } //Add barlines if (!Configuration.ConfigManager.sIgnoreBarline) { Color c = ManiaStage.Skin.GetColour(@"Barline"); for (int i = 0; i < timingChanges.Count; i++) { double beatTime = timingChanges[i].Offset; double timeEnd = LastNoteTime + 1; if (i + 1 < timingChanges.Count) { timeEnd = timingChanges[i + 1].Offset - 1; } if (timeEnd < audioTime - 1000) { continue; } while (beatTime < timeEnd) { foreach (StageMania stage in ManiaStage) { pSprite p = new pSprite(GameBase.WhitePixel, Fields.TopLeft, Origins.CentreLeft, Clocks.Audio, new Vector2(0, -100), 0.62F, false, c); p.VectorScale = new Vector2(stage.Width * 1.6f, ManiaStage.Skin.BarlineHeight); addTransformations(p, beatTime, ManiaStage.Skin.BarlineHeight); barLines.Add(p); stage.SpriteManagerNotes.Add(p); } beatTime += timingChanges[i].BeatLength * (int)timingChanges[i].TimeSignature; } } } //Add arrows int arrowTime = FirstNoteTime - 1000; for (int arrowCount = 0; arrowTime > speedChanges[0].Offset && arrowCount < 3; arrowCount++) { foreach (StageMania stage in ManiaStage) { pSprite arrow = new pSprite(ManiaStage.Skin.Load(@"WarningArrow", @"mania-warningarrow", ManiaStage.SkinSource), Fields.TopLeft, ManiaStage.FlipOrigin(Origins.TopCentre), Clocks.Audio, new Vector2(stage.Width / 2, 0), 0.63F, false, Color.White); if (SkinManager.Current.Version >= 2.4 || stage.HeightRatio < 1f) { arrow.Scale = stage.MinimumRatio; } arrow.FlipVertical = upsideDown; //The origin of the arrow is the end of its tail. This is because the tail needs to be 1 second before the first note addTransformations(arrow, arrowTime, -SpriteHeight(arrow)); barLines.Add(arrow); stage.SpriteManagerNotes.Add(arrow); } arrowTime -= 1000; } //Stop adding to the forward play queue foreach (StageMania stage in ManiaStage) { stage.SpriteManagerNotes.ForwardPlayOptimisedAdd = false; } if (paused) { AudioEngine.TogglePause(); } }
private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
private bool barsInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor);