예제 #1
0
        private void Reload(bool loadNewSkin)
        {
            spriteManager.Clear();



            if (loadNewSkin)
            {
                SkinManager.LoadSkin(true);
                AudioEngine.CurrentSampleSet = SampleSet.None;
                if (BeatmapManager.Current != null)
                {
                    HitObjectManager.LoadFile();
                }
            }

            pAnimation back = new pAnimation(SkinManager.LoadAll("menu-back"), FieldTypes.Window, OriginTypes.TopLeft, ClockTypes.Game, new Vector2(0, 480), 0.8F, true, new Color(255, 255, 255, (byte)(255 * 0.6)));

            back.SetFramerateFromSkin();
            back.OriginPosition = new Vector2(0, 146);
            back.OnClick       += back_OnClick;
            back.IsClickable    = true;
            back.HoverEffect    = new Transformation(TransformationType.Fade, 0.6F, 1, 0, 300);
            spriteManager.Add(back);

            pButton pbutton = new pButton("Get more skins", new Vector2(440, 400), new Vector2(200, 30), 1, Color.White, delegate { GameBase.ChangeMode(Modes.UpdateSkin); });

            pbutton.Text.StartColour = Color.Black;
            spriteManager.AddRange(pbutton.SpriteCollection);

            pbutton = new pButton("Random Beatmap", new Vector2(440, 440), new Vector2(200, 30), 1, Color.White, newSong);
            pbutton.Text.StartColour = Color.Black;
            spriteManager.AddRange(pbutton.SpriteCollection);

            int verticalSpacing = 0;

            pText   pt;
            pSprite pb;

            spriteManager.Add(new pText("Available Skins:", 20, new Vector2(460, 20), Vector2.Zero, 1, true, Color.White, true));

            for (int i = page * skinsPerPage; i < (page + 1) * skinsPerPage; i++)
            {
                if (i < Skins.Count)
                {
                    Skin skin = Skins[i];
                    if (skin.RawName == ConfigManager.sSkin)
                    {
                        pt =
                            new pText(SkinManager.Current.SkinName, 15, new Vector2(444, 50 + verticalSpacing),
                                      new Vector2(200, 0), 0.9f,
                                      true, Color.White, false);
                        pt.Tag              = skin.RawName;
                        pt.TextAlignment    = Alignment.LeftFixed;
                        pt.BackgroundColour = Color.Black;
                        pt.BorderWidth      = 2;
                        pt.BorderColour     = Color.LimeGreen;
                        pt.OnClick         += pt_OnClick;
                        spriteManager.Add(pt);
                    }
                    else
                    {
                        pt =
                            new pText(skin.SkinName, 15, new Vector2(480, 50 + verticalSpacing), new Vector2(200, 0),
                                      0.9f,
                                      true, Color.White, false);
                        pt.Tag              = skin.RawName;
                        pt.IsClickable      = true;
                        pt.TextAlignment    = Alignment.LeftFixed;
                        pt.BackgroundColour = Color.Black;
                        pt.BorderWidth      = 2;
                        pt.BorderColour     = Color.OrangeRed;
                        pt.HoverEffect      =
                            new Transformation(pt.StartPosition, pt.StartPosition - new Vector2(36, 0), 0, 200);
                        pt.HoverEffect.Easing = EasingTypes.In;
                        pt.OnClick           += pt_OnClick;

                        spriteManager.Add(pt);
                    }
                }
                verticalSpacing += 20;
            }

            if (page > 0)
            {
                pt =
                    new pText("<< Previous Page", 15, new Vector2(480, 50 + verticalSpacing), new Vector2(200, 0), 0.9f,
                              true, Color.White, false);
                pt.IsClickable        = true;
                pt.TextAlignment      = Alignment.LeftFixed;
                pt.BackgroundColour   = Color.Black;
                pt.BorderWidth        = 2;
                pt.BorderColour       = Color.Orange;
                pt.HoverEffect        = new Transformation(pt.StartPosition, pt.StartPosition - new Vector2(36, 0), 0, 200);
                pt.HoverEffect.Easing = EasingTypes.In;
                pt.OnClick           += prevPage;
                spriteManager.Add(pt);
            }


            verticalSpacing += 20;

            if (Skins.Count > (page + 1) * skinsPerPage)
            {
                pt =
                    new pText(">> Next Page", 15, new Vector2(480, 50 + verticalSpacing), new Vector2(200, 0), 0.9f,
                              true, Color.White, false);
                pt.IsClickable        = true;
                pt.TextAlignment      = Alignment.LeftFixed;
                pt.BackgroundColour   = Color.Black;
                pt.BorderWidth        = 2;
                pt.BorderColour       = Color.Orange;
                pt.HoverEffect        = new Transformation(pt.StartPosition, pt.StartPosition - new Vector2(36, 0), 0, 200);
                pt.HoverEffect.Easing = EasingTypes.In;
                pt.OnClick           += nextPage;
                verticalSpacing      += 20;
                spriteManager.Add(pt);
            }
            verticalSpacing += 60;

            pCheckbox skinSamples = new pCheckbox("Use skin's sound samples", new Vector2(445, verticalSpacing), 0.9f, ConfigManager.sSkinSamples);

            skinSamples.Tooltip         = "If this is selected, the default osu!sounds will be used for hit samples";
            skinSamples.OnCheckChanged += skinSamples_OnCheckChanged;
            spriteManager.AddRange(skinSamples.SpriteCollection);

            verticalSpacing += 20;

            pCheckbox useTaikoSkin = new pCheckbox("Use Taiko skin for Taiko Mod", new Vector2(445, verticalSpacing), 0.9f, ConfigManager.sUseTaikoSkin);

            useTaikoSkin.Tooltip         = "If this is selected and the Taiko skin is present,\nit will automatically be used when playing Taiko Mod.";
            useTaikoSkin.OnCheckChanged += useTaikoSkin_OnCheckChanged;
            spriteManager.AddRange(useTaikoSkin.SpriteCollection);

            pAnimation pa =
                new pAnimation(SkinManager.LoadAll("scorebar-colour"), FieldTypes.Window, OriginTypes.TopLeft, ClockTypes.Game, new Vector2(3, 10), 0.95F, true, Color.White, null);

            pa.frameSkip = 60 / pa.TextureCount;
            pa.DrawWidth = 460;
            spriteManager.Add(pa);
            pb =
                new pSprite(SkinManager.Load("scorebar-ki"), OriginTypes.Centre, new Vector2(287, 16), 0.97F, true, Color.White);
            spriteManager.Add(pb);
            pb =
                new pSprite(SkinManager.Load("scorebar-kidanger"), OriginTypes.Centre,
                            new Vector2(160, 16), 0.98F, true, Color.White);
            spriteManager.Add(pb);
            pb =
                new pSprite(SkinManager.Load("scorebar-kidanger2"), OriginTypes.Centre, new Vector2(100, 16), 0.99F, true, Color.White);
            spriteManager.Add(pb);

            pb = new pSprite(SkinManager.Load("scorebar-bg"), Vector2.Zero, 0.9F, true, Color.White);
            spriteManager.Add(pb);


            pSprite detailsBack = new pSprite(GameBase.WhitePixel, new Vector2(440, 0), 0.2F, true, new Color(0, 0, 0, 160));

            detailsBack.VectorScale    = new Vector2(320, 768);
            detailsBack.UseVectorScale = true;
            spriteManager.Add(detailsBack);

            currentSkin =
                new pText(SkinManager.Current.SkinName + " by " + SkinManager.Current.SkinAuthor, 24, new Vector2(0, 30), Vector2.Zero,
                          1, true, Color.White, true);
            currentSkin.TextBold = true;
            currentSkin.FadeInFromZero(1500);
            spriteManager.Add(currentSkin);
        }
예제 #2
0
        internal override void Update()
        {
            if (AudioEngine.Time < EndTime && IsHit)
            {
                Disarm();
            }

            if (IsHit || AudioEngine.Time < StartTime)
            {
                return;
            }

            double decay = Math.Pow(0.9, InputManager.ElapsedAudioTime / GameBase.SIXTY_FRAME_TIME);

            rpm = rpm * decay + (1.0 - decay) * (Math.Abs(velocityCurrent) * 1000) / (Math.PI * 2) * 60;

            if (spriteRpmText != null)
            {
                spriteRpmText.Text = string.Format(@"{0:#,0}", rpm);
            }

            Player.Instance?.LogSpinSpeed(rpm);

            if (spriteMiddleTop != null)
            {
                spriteMiddleTop.InitialColour = ColourHelper.ColourLerp(Color.White, Color.Red, (float)(AudioEngine.Time - StartTime) / Length);
            }

            if (GameBase.Mode == OsuModes.Edit)
            {
                editorCircleRotation.EndFloat = (float)(rotationRequirement * Math.PI);
                floatRotationCount            = (float)((AudioEngine.Time - StartTime) / 1000 * hitObjectManager.SpinnerRotationRatio);
            }
            else if (AudioEngine.Time < EndTime && AudioEngine.Time > StartTime && !Player.Recovering)
            {
                // Mod time is applied here to keep discrepancies between DT, HT and nomod to preserve integrity of older scores. :(
                double maxAccelThisFrame = HitObjectManager.ApplyModsToTime(maxAccel * InputManager.ElapsedAudioTime, hitObjectManager.ActiveMods);

                if ((GameBase.Mode == OsuModes.Play && ModManager.CheckActive(hitObjectManager.ActiveMods, Mods.SpunOut)) || Player.Relaxing2)
                {
                    velocityCurrent = 0.03;
                }
                else if (velocityTheoretical > velocityCurrent)
                {
                    velocityCurrent += Math.Min(velocityTheoretical - velocityCurrent, velocityCurrent < 0 && Player.Relaxing ? maxAccelThisFrame / RELAX_BONUS_ACCEL : maxAccelThisFrame);
                }
                else
                {
                    velocityCurrent += Math.Max(velocityTheoretical - velocityCurrent, velocityCurrent > 0 && Player.Relaxing ? -maxAccelThisFrame / RELAX_BONUS_ACCEL : -maxAccelThisFrame);
                }


                velocityCurrent = Math.Max(-0.05, Math.Min(velocityCurrent, 0.05));

                float rotationAddition = (float)(velocityCurrent * InputManager.ElapsedAudioTime);
                float turnRatio        = spriteMiddleBottom != null && spriteMiddleBottom.Texture != null ? 0.5f : 1;

                // We don't want the spinner sprite to spin faster / slower when DT / HT are active. It should always spin proportionally to the cursor spinning rate.
                SpriteCircleTop.Rotation += (float)HitObjectManager.ApplyModsToTime(rotationAddition * turnRatio, hitObjectManager.ActiveMods);
                if (spriteMiddleBottom != null)
                {
                    spriteMiddleBottom.Rotation += (float)HitObjectManager.ApplyModsToTime(rotationAddition, hitObjectManager.ActiveMods);
                    spriteCircleBottom.Rotation  = SpriteCircleTop.Rotation / 3f;
                }

                if (velocityCurrent != 0)
                {
                    StartSound();
                }
                else
                {
                    StopSound();
                }

                floatRotationCount += Math.Abs((float)(rotationAddition / Math.PI));
            }

            updateCompletion(Math.Abs(floatRotationCount) / rotationRequirement * 100);

            switch (state)
            {
            case SpinningState.NotStarted:
                if (scoringRotationCount == 0 || AudioEngine.Time < StartTime + 500)
                {
                    break;
                }

                spriteSpin?.FadeOut(300);
                state = SpinningState.Started;
                break;

            case SpinningState.Started:
                if (scoringRotationCount < rotationRequirement)
                {
                    break;
                }

                if (spriteGlow != null)
                {
                    spriteGlow.InitialColour = new Color(3, 151, 255);
                }

                if (spriteSpin != null)
                {
                    spriteSpin.FadeOut(100);
                    spriteClear.Transformations.Clear();
                    spriteClear.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, AudioEngine.Time, Math.Min(EndTime, AudioEngine.Time + 400), EasingTypes.Out));
                    spriteClear.Transformations.Add(new Transformation(TransformationType.Scale, 2, 0.8f, AudioEngine.Time, Math.Min(EndTime, AudioEngine.Time + 240), EasingTypes.Out));
                    spriteClear.Transformations.Add(new Transformation(TransformationType.Scale, 0.8f, 1, Math.Min(EndTime, AudioEngine.Time + 240), Math.Min(EndTime, AudioEngine.Time + 400), EasingTypes.None));
                    spriteClear.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, EndTime - 50, EndTime));
                }

                state = SpinningState.Passed;
                break;
            }
        }
예제 #3
0
        internal override IncreaseScoreType GetScorePoints(Vector2 currentMousePos)
        {
            if (!InputManager.ScorableFrame)
            {
                return(0);
            }

            //First update the spinner velocity...
            Vector2 mouseVector    = currentMousePos - SpriteCircleTop.drawPosition;
            double  mouseAngle     = Math.Atan2(mouseVector.Y, mouseVector.X);
            double  mouseAngleDiff = mouseAngle - lastMouseAngle;

            if (mouseAngle - lastMouseAngle < -Math.PI)
            {
                mouseAngleDiff = (2 * Math.PI) + mouseAngle - lastMouseAngle;
            }
            else if (lastMouseAngle - mouseAngle < -Math.PI)
            {
                mouseAngleDiff = (-2 * Math.PI) - lastMouseAngle + mouseAngle;
            }

            double timeDiff = InputManager.LastScorableFrameTime > 0 ? AudioEngine.Time - InputManager.LastScorableFrameTime : GameBase.SIXTY_FRAME_TIME;

            double decay = Math.Pow(0.999, timeDiff);

            totalScoreFrameVariance = decay * totalScoreFrameVariance + (1 - decay) * timeDiff;

            if (mouseAngleDiff == 0)
            {
                velocityTheoretical = zeroCount++ < 1 ? velocityTheoretical / 3 : 0;
            }
            else
            {
                zeroCount = 0;

                if (!Player.Relaxing && ((InputManager.leftButton == ButtonState.Released && InputManager.rightButton == ButtonState.Released) || AudioEngine.Time < StartTime || AudioEngine.Time > EndTime))
                {
                    mouseAngleDiff = 0;
                }

                if (Math.Abs(mouseAngleDiff) < Math.PI)
                {
                    if (HitObjectManager.ApplyModsToTime(totalScoreFrameVariance, hitObjectManager.ActiveMods) > GameBase.SIXTY_FRAME_TIME * 1.04f)
                    {
                        //after a certain lenience we need to stop allowing for SIXTY_FRAMEs and take frames for their actual elapsed time.
                        //this is to handle the case where users are running at sub-60fps.
                        //in a simple world, we could always use this timeDiff calculation, but due to historical reasons,
                        //we were always slightly in the user's favour when calculating velocity here.
                        velocityTheoretical = mouseAngleDiff / HitObjectManager.ApplyModsToTime(timeDiff, hitObjectManager.ActiveMods);
                    }
                    else
                    {
                        velocityTheoretical = mouseAngleDiff / GameBase.SIXTY_FRAME_TIME;
                    }
                }
                else
                {
                    velocityTheoretical = 0;
                }
            }

            lastMouseAngle = mouseAngle;

            //If we have actually progressed, let's return some score...
            if (rotationCount == lastRotationCount)
            {
                return(IncreaseScoreType.Ignore);
            }

            scoringRotationCount++;

            IncreaseScoreType score = IncreaseScoreType.Ignore;

            if (SkinManager.Current.SpinnerFrequencyModulate)
            {
                AudioEngine.UpdateSpinSample((float)scoringRotationCount / rotationRequirement);
            }

            if (scoringRotationCount > rotationRequirement + 3 && (scoringRotationCount - (rotationRequirement + 3)) % 2 == 0)
            {
                if (spriteGlow != null)
                {
                    spriteGlow.FlashColour(Color.White, 200);
                }

                score = IncreaseScoreType.SpinnerBonus;
                if (!ModManager.CheckActive(Mods.Cinema))
                {
                    AudioEngine.PlaySample(@"spinnerbonus", AudioEngine.VolumeSample, SkinSource.All);
                }
                SpriteBonusCounter.Text = (1000 * (scoringRotationCount - (rotationRequirement + 3)) / 2).ToString();
                SpriteBonusCounter.Transformations.Clear();
                SpriteBonusCounter.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, AudioEngine.Time, AudioEngine.Time + 800));
                SpriteBonusCounter.Transformations.Add(new Transformation(TransformationType.Scale, 2f, 1.28f, AudioEngine.Time, AudioEngine.Time + 800));
                SpriteBonusCounter.Transformations[0].Easing = EasingTypes.Out;
                SpriteBonusCounter.Transformations[1].Easing = EasingTypes.Out;
                //Ensure we don't recycle this too early.
                SpriteBonusCounter.Transformations.Add(new Transformation(TransformationType.Fade, 0, 0, EndTime + 800, EndTime + 800));
            }
            else if (scoringRotationCount > 1 && scoringRotationCount % 2 == 0)
            {
                score = IncreaseScoreType.SpinnerSpinPoints;
            }
            else if (scoringRotationCount > 1)
            {
                score = IncreaseScoreType.SpinnerSpin;
            }

            lastRotationCount = rotationCount;
            return(score);
        }
예제 #4
0
        /// <summary>
        ///     Handles an individual key press during gameplay.
        /// </summary>
        /// <param name="manager"></param>
        /// <param name="gameplayHitObject"></param>
        /// <param name="objectIndex"></param>
        private void HandleKeyPress(HitObjectManagerKeys manager, GameplayHitObjectKeys gameplayHitObject)
        {
            // Play the HitSounds of closest hit object.
            HitObjectManager.PlayObjectHitSounds(gameplayHitObject.Info);

            // Get Judgement and references
            var time          = (int)manager.CurrentAudioPosition;
            var hitDifference = gameplayHitObject.Info.StartTime - time;
            var judgement     = ((ScoreProcessorKeys)Ruleset.ScoreProcessor).CalculateScore(hitDifference, KeyPressType.Press);
            var lane          = gameplayHitObject.Info.Lane - 1;

            // Ignore Ghost Taps
            if (judgement == Judgement.Ghost)
            {
                return;
            }

            // Remove HitObject from Object Pool. Will be recycled/killed as necessary.
            gameplayHitObject = manager.ActiveNoteLanes[lane].Dequeue();

            // Update stats
            Ruleset.ScoreProcessor.Stats.Add(
                new HitStat(
                    HitStatType.Hit,
                    KeyPressType.Press,
                    gameplayHitObject.Info, time,
                    judgement,
                    hitDifference,
                    Ruleset.ScoreProcessor.Accuracy,
                    Ruleset.ScoreProcessor.Health
                    ));

            // Update Scoreboard
            var view = (GameplayScreenView)Ruleset.Screen.View;

            view.UpdateScoreboardUsers();
            view.UpdateScoreAndAccuracyDisplays();

            // Update Playfield
            var playfield = (GameplayPlayfieldKeys)Ruleset.Playfield;

            playfield.Stage.ComboDisplay.MakeVisible();
            playfield.Stage.HitError.AddJudgement(judgement, gameplayHitObject.Info.StartTime - manager.CurrentAudioPosition);
            playfield.Stage.JudgementHitBurst.PerformJudgementAnimation(judgement);

            // Update Object Pooling
            switch (judgement)
            {
            // Handle early miss cases here.
            case Judgement.Miss when gameplayHitObject.Info.IsLongNote:
                manager.KillPoolObject(gameplayHitObject);
                break;

            // Handle miss cases.
            case Judgement.Miss:
                manager.RecyclePoolObject(gameplayHitObject);
                break;

            // Handle non-miss cases. Perform Hit Lighting Animation and Handle Object pooling.
            default:
                playfield.Stage.HitLightingObjects[lane].PerformHitAnimation(gameplayHitObject.Info.IsLongNote);
                if (gameplayHitObject.Info.IsLongNote)
                {
                    manager.ChangePoolObjectStatusToHeld(gameplayHitObject);
                    gameplayHitObject.StartLongNoteAnimation();
                }
                else
                {
                    manager.RecyclePoolObject(gameplayHitObject);
                }
                break;
            }
        }