public SpinnerRotationTracker(DrawableSpinner drawableSpinner)
        {
            this.drawableSpinner              = drawableSpinner;
            drawableSpinner.HitObjectApplied += resetState;

            RelativeSizeAxes = Axes.Both;
        }
예제 #2
0
        private void load(DrawableHitObject drawableHitObject, ISkinSource source)
        {
            RelativeSizeAxes = Axes.Both;

            DrawableSpinner = (DrawableSpinner)drawableHitObject;

            AddRangeInternal(new[]
            {
                spin = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Depth   = float.MinValue,
                    Texture = source.GetTexture("spinner-spin"),
                    Scale   = new Vector2(SPRITE_SCALE),
                    Y       = 120 - 45 // offset temporarily to avoid overlapping default spin counter
                },
                clear = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Depth   = float.MinValue,
                    Alpha   = 0,
                    Texture = source.GetTexture("spinner-clear"),
                    Scale   = new Vector2(SPRITE_SCALE),
                    Y       = -60
                },
            });
        }
예제 #3
0
        public void TestApplyNewSpinner()
        {
            DrawableSpinner dho = null;

            AddStep("create spinner", () => Child = dho = new DrawableSpinner(prepareObject(new Spinner
            {
                Position            = new Vector2(256, 192),
                IndexInCurrentCombo = 0,
                Duration            = 500,
            }))
            {
                Clock = new FramedClock(new StopwatchClock())
            });

            AddStep("rotate some", () => dho.RotationTracker.AddRotation(180));
            AddAssert("rotation is set", () => dho.Result.RateAdjustedRotation == 180);

            AddStep("apply new spinner", () => dho.Apply(prepareObject(new Spinner
            {
                Position   = new Vector2(256, 192),
                ComboIndex = 1,
                Duration   = 1000,
            })));

            AddAssert("rotation is reset", () => dho.Result.RateAdjustedRotation == 0);
        }
예제 #4
0
        private void addObjectsStep(Func <OsuHitObject[]> ctorFunc)
        {
            AddStep("add hitobjects", () =>
            {
                var objects = ctorFunc();

                for (int i = 0; i < objects.Length; i++)
                {
                    objects[i].StartTime = Time.Current + 1000 + 500 * (i + 1);
                    objects[i].ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

                    DrawableOsuHitObject drawableObject = null;

                    switch (objects[i])
                    {
                    case HitCircle circle:
                        drawableObject = new DrawableHitCircle(circle);
                        break;

                    case Slider slider:
                        drawableObject = new DrawableSlider(slider);
                        break;

                    case Spinner spinner:
                        drawableObject = new DrawableSpinner(spinner);
                        break;
                    }

                    hitObjectContainer.Add(drawableObject);
                    followPointRenderer.AddFollowPoints(objects[i]);
                }
            });
        }
예제 #5
0
        public override void SetUpSteps()
        {
            base.SetUpSteps();

            AddUntilStep("wait for track to start running", () => track.IsRunning);
            AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.First());
        }
예제 #6
0
        private void load(DrawableHitObject drawableHitObject, ISkinSource source)
        {
            Anchor = Anchor.Centre;
            Origin = Anchor.Centre;

            // osu!stable positions spinner components in window-space (as opposed to gamefield-space). This is a 640x480 area taking up the entire screen.
            // In lazer, the gamefield-space positional transformation is applied in OsuPlayfieldAdjustmentContainer, which is inverted here to make this area take up the entire window space.
            Size     = new Vector2(640, 480);
            Position = new Vector2(0, -8f);

            DrawableSpinner = (DrawableSpinner)drawableHitObject;

            AddRangeInternal(new[]
            {
                spin = new Sprite
                {
                    Anchor  = Anchor.TopCentre,
                    Origin  = Anchor.Centre,
                    Depth   = float.MinValue,
                    Texture = source.GetTexture("spinner-spin"),
                    Scale   = new Vector2(SPRITE_SCALE),
                    Y       = SPINNER_TOP_OFFSET + 335,
                },
                clear = new Sprite
                {
                    Alpha   = 0,
                    Anchor  = Anchor.TopCentre,
                    Origin  = Anchor.Centre,
                    Depth   = float.MinValue,
                    Texture = source.GetTexture("spinner-clear"),
                    Scale   = new Vector2(SPRITE_SCALE),
                    Y       = SPINNER_TOP_OFFSET + 115,
                },
            });
        }
예제 #7
0
        public void TestSpinnerAutoCompleted()
        {
            DrawableSpinner spinner    = null;
            JudgementResult lastResult = null;

            CreateModTest(new ModTestData
            {
                Mod           = new OsuModSpunOut(),
                Autoplay      = false,
                Beatmap       = singleSpinnerBeatmap,
                PassCondition = () =>
                {
                    // Bind to the first spinner's results for further tracking.
                    if (spinner == null)
                    {
                        // We only care about the first spinner we encounter for this test.
                        var nextSpinner = Player.ChildrenOfType <DrawableSpinner>().SingleOrDefault();

                        if (nextSpinner == null)
                        {
                            return(false);
                        }

                        lastResult = null;

                        spinner              = nextSpinner;
                        spinner.OnNewResult += (o, result) => lastResult = result;
                    }

                    return(lastResult?.Type == HitResult.Great);
                }
            });
        }
        public TestSceneSpinnerSelectionBlueprint()
        {
            var spinner = new Spinner
            {
                Position  = new Vector2(256, 256),
                StartTime = -1000,
                EndTime   = 2000
            };

            spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty {
                CircleSize = 2
            });

            DrawableSpinner drawableSpinner;

            Add(new Container
            {
                RelativeSizeAxes = Axes.Both,
                Size             = new Vector2(0.5f),
                Child            = drawableSpinner = new DrawableSpinner(spinner)
            });

            AddBlueprint(new SpinnerSelectionBlueprint(spinner)
            {
                Size = new Vector2(0.5f)
            }, drawableSpinner);
        }
예제 #9
0
        private void load(ISkinSource source, DrawableHitObject drawableObject)
        {
            drawableSpinner = (DrawableSpinner)drawableObject;

            Scale = new Vector2(final_scale);

            InternalChildren = new Drawable[]
            {
                discBottom = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Texture = source.GetTexture("spinner-bottom")
                },
                discTop = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Texture = source.GetTexture("spinner-top")
                },
                fixedMiddle = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Texture = source.GetTexture("spinner-middle")
                },
                spinningMiddle = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Texture = source.GetTexture("spinner-middle2")
                }
            };
        }
예제 #10
0
        public void TestSpunOut()
        {
            DrawableSpinner spinner = null;

            AddStep("create spinner", () => spinner = createSpinner());

            AddUntilStep("wait for end", () => Time.Current > spinner.LifetimeEnd);

            AddAssert("spinner is completed", () => spinner.Progress >= 1);
        }
예제 #11
0
        private void load(ISkinSource source, DrawableHitObject drawableObject)
        {
            spinnerBlink = source.GetConfig <OsuSkinConfiguration, bool>(OsuSkinConfiguration.SpinnerNoBlink)?.Value != true;

            drawableSpinner = (DrawableSpinner)drawableObject;

            RelativeSizeAxes = Axes.Both;

            InternalChild = new Container
            {
                // the old-style spinner relied heavily on absolute screen-space coordinate values.
                // wrap everything in a container simulating absolute coords to preserve alignment
                // as there are skins that depend on it.
                Width    = 640,
                Height   = 480,
                Anchor   = Anchor.Centre,
                Origin   = Anchor.Centre,
                Children = new Drawable[]
                {
                    new Sprite
                    {
                        Anchor  = Anchor.Centre,
                        Origin  = Anchor.Centre,
                        Texture = source.GetTexture("spinner-background"),
                        Scale   = new Vector2(sprite_scale)
                    },
                    disc = new Sprite
                    {
                        Anchor  = Anchor.Centre,
                        Origin  = Anchor.Centre,
                        Texture = source.GetTexture("spinner-circle"),
                        Scale   = new Vector2(sprite_scale)
                    },
                    metre = new Container
                    {
                        AutoSizeAxes = Axes.Both,
                        // this anchor makes no sense, but that's what stable uses.
                        Anchor = Anchor.TopLeft,
                        Origin = Anchor.TopLeft,
                        // adjustment for stable (metre has additional offset)
                        Margin = new MarginPadding {
                            Top = 20
                        },
                        Masking = true,
                        Child   = metreSprite = new Sprite
                        {
                            Texture = source.GetTexture("spinner-metre"),
                            Anchor  = Anchor.TopLeft,
                            Origin  = Anchor.TopLeft,
                            Scale   = new Vector2(0.625f)
                        }
                    }
                }
            };
        }
예제 #12
0
        private void load(DrawableHitObject drawableHitObject, ISkinSource source)
        {
            Anchor = Anchor.Centre;
            Origin = Anchor.Centre;

            // osu!stable positions spinner components in window-space (as opposed to gamefield-space). This is a 640x480 area taking up the entire screen.
            // In lazer, the gamefield-space positional transformation is applied in OsuPlayfieldAdjustmentContainer, which is inverted here to make this area take up the entire window space.
            Size     = new Vector2(640, 480);
            Position = new Vector2(0, -8f);

            DrawableSpinner = (DrawableSpinner)drawableHitObject;

            Container overlayContainer;

            AddInternal(overlayContainer = new Container
            {
                Depth            = float.MinValue,
                RelativeSizeAxes = Axes.Both,
                Children         = new Drawable[]
                {
                    spin = new Sprite
                    {
                        Anchor  = Anchor.TopCentre,
                        Origin  = Anchor.Centre,
                        Texture = source.GetTexture("spinner-spin"),
                        Scale   = new Vector2(SPRITE_SCALE),
                        Y       = SPINNER_TOP_OFFSET + 335,
                    },
                    clear = new Sprite
                    {
                        Alpha   = 0,
                        Anchor  = Anchor.TopCentre,
                        Origin  = Anchor.Centre,
                        Texture = source.GetTexture("spinner-clear"),
                        Scale   = new Vector2(SPRITE_SCALE),
                        Y       = SPINNER_TOP_OFFSET + 115,
                    },
                }
            });

            bonusCounter = (source.GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreText)) as LegacySpriteText)?.With(c =>
            {
                c.Alpha  = 0f;
                c.Anchor = Anchor.TopCentre;
                c.Origin = Anchor.Centre;
                c.Font   = c.Font.With(fixedWidth: false);
                c.Scale  = new Vector2(SPRITE_SCALE);
                c.Y      = SPINNER_TOP_OFFSET + 299;
            });

            if (bonusCounter != null)
            {
                overlayContainer.Add(bonusCounter);
            }
        }
예제 #13
0
        private void load(DrawableHitObject drawableHitObject)
        {
            drawableSpinner = (DrawableSpinner)drawableHitObject;

            AddRangeInternal(new Drawable[]
            {
                new DefaultSpinnerDisc
                {
                    RelativeSizeAxes = Axes.Both,
                    Anchor           = Anchor.Centre,
                    Origin           = Anchor.Centre,
                },
                bonusCounter = new OsuSpriteText
                {
                    Alpha  = 0,
                    Anchor = Anchor.Centre,
                    Origin = Anchor.Centre,
                    Font   = OsuFont.Numeric.With(size: 24),
                    Y      = -120,
                },
                spmContainer = new Container
                {
                    Alpha    = 0f,
                    Anchor   = Anchor.Centre,
                    Origin   = Anchor.Centre,
                    Y        = 120,
                    Children = new[]
                    {
                        spmCounter = new OsuSpriteText
                        {
                            Anchor = Anchor.TopCentre,
                            Origin = Anchor.TopCentre,
                            Text   = @"0",
                            Font   = OsuFont.Numeric.With(size: 24)
                        },
                        new OsuSpriteText
                        {
                            Anchor = Anchor.TopCentre,
                            Origin = Anchor.TopCentre,
                            Text   = @"SPINS PER MINUTE",
                            Font   = OsuFont.Numeric.With(size: 12),
                            Y      = 30
                        }
                    }
                }
            });
        }
예제 #14
0
        public void TestSpinnerGetsNoBonusScore()
        {
            DrawableSpinner        spinner = null;
            List <JudgementResult> results = new List <JudgementResult>();

            CreateModTest(new ModTestData
            {
                Mod           = new OsuModSpunOut(),
                Autoplay      = false,
                Beatmap       = singleSpinnerBeatmap,
                PassCondition = () =>
                {
                    // Bind to the first spinner's results for further tracking.
                    if (spinner == null)
                    {
                        // We only care about the first spinner we encounter for this test.
                        var nextSpinner = Player.ChildrenOfType <DrawableSpinner>().SingleOrDefault();

                        if (nextSpinner == null)
                        {
                            return(false);
                        }

                        spinner              = nextSpinner;
                        spinner.OnNewResult += (o, result) => results.Add(result);

                        results.Clear();
                    }

                    // we should only be checking the bonus/progress after the spinner has fully completed.
                    if (results.OfType <OsuSpinnerJudgementResult>().All(r => r.TimeCompleted == null))
                    {
                        return(false);
                    }

                    return
                    (results.Any(r => r.Type == HitResult.SmallBonus) &&
                     results.All(r => r.Type != HitResult.LargeBonus));
                }
            });
        }
        public void TestApplyNewCircle()
        {
            DrawableSpinner dho = null;

            AddStep("create spinner", () => Child = dho = new DrawableSpinner(prepareObject(new Spinner
            {
                Position            = new Vector2(256, 192),
                IndexInCurrentCombo = 0,
                Duration            = 0,
            }))
            {
                Clock = new FramedClock(new StopwatchClock())
            });

            AddStep("apply new spinner", () => dho.Apply(prepareObject(new Spinner
            {
                Position   = new Vector2(256, 192),
                ComboIndex = 1,
                Duration   = 1000,
            })));
        }
예제 #16
0
        private void load(ISkinSource source, DrawableHitObject drawableObject)
        {
            drawableSpinner = (DrawableSpinner)drawableObject;

            RelativeSizeAxes = Axes.Both;

            InternalChildren = new Drawable[]
            {
                new Sprite
                {
                    Anchor  = Anchor.BottomCentre,
                    Origin  = Anchor.BottomCentre,
                    Texture = source.GetTexture("spinner-background"),
                    Y       = background_y_offset,
                    Scale   = new Vector2(sprite_scale)
                },
                disc = new Sprite
                {
                    Anchor  = Anchor.Centre,
                    Origin  = Anchor.Centre,
                    Texture = source.GetTexture("spinner-circle"),
                    Scale   = new Vector2(sprite_scale)
                },
                metre = new Container
                {
                    Anchor  = Anchor.BottomCentre,
                    Origin  = Anchor.BottomCentre,
                    Y       = background_y_offset,
                    Masking = true,
                    Child   = new Sprite
                    {
                        Texture = source.GetTexture("spinner-metre"),
                        Anchor  = Anchor.BottomCentre,
                        Origin  = Anchor.BottomCentre,
                    },
                    Scale = new Vector2(0.625f)
                }
            };
        }
예제 #17
0
        private void load(DrawableHitObject drawableHitObject)
        {
            drawableSpinner = (DrawableSpinner)drawableHitObject;

            AddRangeInternal(new Drawable[]
            {
                new DefaultSpinnerDisc
                {
                    RelativeSizeAxes = Axes.Both,
                    Anchor           = Anchor.Centre,
                    Origin           = Anchor.Centre,
                },
                bonusCounter = new OsuSpriteText
                {
                    Alpha  = 0,
                    Anchor = Anchor.Centre,
                    Origin = Anchor.Centre,
                    Font   = OsuFont.Numeric.With(size: 24),
                    Y      = -120,
                }
            });
        }
예제 #18
0
        private void load(OsuColour colours, DrawableHitObject drawableHitObject)
        {
            drawableSpinner = (DrawableSpinner)drawableHitObject;
            spinner         = (Spinner)drawableSpinner.HitObject;

            normalColour   = colours.BlueDark;
            completeColour = colours.YellowLight;

            InternalChildren = new Drawable[]
            {
                mainContainer = new Container
                {
                    RelativeSizeAxes = Axes.Both,
                    Anchor           = Anchor.Centre,
                    Origin           = Anchor.Centre,
                    Children         = new Drawable[]
                    {
                        background = new SpinnerBackgroundLayer(),
                        fill       = new SpinnerFill
                        {
                            Alpha        = idle_alpha,
                            AccentColour = normalColour
                        },
                        ticks = new SpinnerTicks
                        {
                            Anchor       = Anchor.Centre,
                            Origin       = Anchor.Centre,
                            AccentColour = normalColour
                        },
                    }
                },
                centre = new SpinnerCentreLayer
                {
                    Anchor = Anchor.Centre,
                    Origin = Anchor.Centre,
                },
            };
        }
예제 #19
0
        private DrawableSpinner createSpinner()
        {
            var spinner = new Spinner
            {
                StartTime = Time.Current + 500,
                EndTime   = Time.Current + 2500
            };

            spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

            var drawableSpinner = new DrawableSpinner(spinner)
            {
                Anchor = Anchor.Centre
            };

            foreach (var mod in SelectedMods.Value.OfType <IApplicableToDrawableHitObjects>())
            {
                mod.ApplyToDrawableHitObjects(new[] { drawableSpinner });
            }

            Add(drawableSpinner);
            return(drawableSpinner);
        }
예제 #20
0
        private void load(DrawableHitObject drawableHitObject)
        {
            spinner = (DrawableSpinner)drawableHitObject;

            InternalChildren = new Drawable[]
            {
                glow   = new GlowPiece(),
                circle = new CirclePiece
                {
                    Position = Vector2.Zero,
                    Anchor   = Anchor.Centre,
                },
                new RingPiece(),
                symbol = new SpriteIcon
                {
                    Anchor = Anchor.Centre,
                    Origin = Anchor.Centre,
                    Size   = new Vector2(48),
                    Icon   = FontAwesome.Solid.Asterisk,
                    Shadow = false,
                },
            };
        }
예제 #21
0
        public SpinnerRotationTracker(DrawableSpinner drawableSpinner)
        {
            this.drawableSpinner = drawableSpinner;

            RelativeSizeAxes = Axes.Both;
        }
예제 #22
0
        private void load(DrawableHitObject drawableHitObject, ISkinSource source)
        {
            Anchor = Anchor.Centre;
            Origin = Anchor.Centre;

            // osu!stable positions spinner components in window-space (as opposed to gamefield-space). This is a 640x480 area taking up the entire screen.
            // In lazer, the gamefield-space positional transformation is applied in OsuPlayfieldAdjustmentContainer, which is inverted here to make this area take up the entire window space.
            Size     = new Vector2(640, 480);
            Position = new Vector2(0, -8f);

            DrawableSpinner = (DrawableSpinner)drawableHitObject;

            AddInternal(new Container
            {
                Depth            = float.MinValue,
                RelativeSizeAxes = Axes.Both,
                Children         = new Drawable[]
                {
                    spin = new Sprite
                    {
                        Anchor  = Anchor.TopCentre,
                        Origin  = Anchor.Centre,
                        Texture = source.GetTexture("spinner-spin"),
                        Scale   = new Vector2(SPRITE_SCALE),
                        Y       = SPINNER_TOP_OFFSET + 335,
                    },
                    clear = new Sprite
                    {
                        Alpha   = 0,
                        Anchor  = Anchor.TopCentre,
                        Origin  = Anchor.Centre,
                        Texture = source.GetTexture("spinner-clear"),
                        Scale   = new Vector2(SPRITE_SCALE),
                        Y       = SPINNER_TOP_OFFSET + 115,
                    },
                    bonusCounter = new LegacySpriteText(source, LegacyFont.Score)
                    {
                        Alpha  = 0f,
                        Anchor = Anchor.TopCentre,
                        Origin = Anchor.Centre,
                        Scale  = new Vector2(SPRITE_SCALE),
                        Y      = SPINNER_TOP_OFFSET + 299,
                    }.With(s => s.Font = s.Font.With(fixedWidth: false)),
                    spmBackground      = new Sprite
                    {
                        Anchor   = Anchor.TopCentre,
                        Origin   = Anchor.TopLeft,
                        Texture  = source.GetTexture("spinner-rpm"),
                        Scale    = new Vector2(SPRITE_SCALE),
                        Position = new Vector2(-87, 445 + spm_hide_offset),
                    },
                    spmCounter = new LegacySpriteText(source, LegacyFont.Score)
                    {
                        Anchor   = Anchor.TopCentre,
                        Origin   = Anchor.TopRight,
                        Scale    = new Vector2(SPRITE_SCALE * 0.9f),
                        Position = new Vector2(80, 448 + spm_hide_offset),
                    }.With(s => s.Font = s.Font.With(fixedWidth: false)),
                }
            });
        }
예제 #23
0
        public void TestLegacyKiaiParticles()
        {
            LegacyCursorParticles cursorParticles = null;
            DrawableSpinner spinner = null;
            DrawableSlider slider = null;

            createLegacyTest(true, () =>
                {
                    var controlPointInfo = new ControlPointInfo();
                    controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true });
                    controlPointInfo.Add(5000, new EffectControlPoint { KiaiMode = false });

                    return new Beatmap
                    {
                        ControlPointInfo = controlPointInfo,
                        HitObjects =
                        {
                            new Spinner
                            {
                                StartTime = 0,
                                Duration = 1000,
                                Position = OsuPlayfield.BASE_SIZE / 2,
                            },
                            new Slider
                            {
                                StartTime = 2500,
                                RepeatCount = 0,
                                Position = OsuPlayfield.BASE_SIZE / 2,
                                Path = new SliderPath(new[]
                                {
                                    new PathControlPoint(Vector2.Zero),
                                    new PathControlPoint(new Vector2(100, 0)),
                                })
                            },
                            new HitCircle
                            {
                                StartTime = 4500,
                                Position = OsuPlayfield.BASE_SIZE / 2,
                            },
                        },
                    };
                }
            );

            AddUntilStep("fetch cursor particles", () =>
            {
                cursorParticles = this.ChildrenOfType<LegacyCursorParticles>().SingleOrDefault();
                return cursorParticles != null;
            });

            AddUntilStep("wait for spinner tracking", () =>
            {
                spinner = this.ChildrenOfType<DrawableSpinner>().SingleOrDefault();
                return spinner?.RotationTracker.Tracking == true;
            });
            AddAssert("particles are being spawned", () => cursorParticles.Active);

            AddUntilStep("spinner tracking stopped", () => !spinner.RotationTracker.Tracking);
            AddAssert("particle spawning stopped", () => !cursorParticles.Active);

            AddUntilStep("wait for slider tracking", () =>
            {
                slider = this.ChildrenOfType<DrawableSlider>().SingleOrDefault();
                return slider?.Tracking.Value == true;
            });
            AddAssert("particles are being spawned", () => cursorParticles.Active);

            AddUntilStep("slider tracking stopped", () => !slider.Tracking.Value);
            AddAssert("particle spawning stopped", () => !cursorParticles.Active);
        }
예제 #24
0
 public SpinnerSelectionBlueprint(DrawableSpinner spinner)
     : base(spinner)
 {
     InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject);
 }