Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement visibility reduction mods #210

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions osu.Game.Rulesets.Rush/Mods/RushModFadeIn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Shane Woolcock. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Game.Rulesets.Rush.UI;

namespace osu.Game.Rulesets.Rush.Mods
{
public class RushModFadeIn : RushModPlayfieldCover
{
public override string Name => "Fade In";
public override string Acronym => "FI";

public override string Description => @"Keys fade in before you hit them!";
public override double ScoreMultiplier => 1;

protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll;
}
}
15 changes: 15 additions & 0 deletions osu.Game.Rulesets.Rush/Mods/RushModHidden.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Shane Woolcock. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Game.Rulesets.Rush.UI;

namespace osu.Game.Rulesets.Rush.Mods
{
public class RushModHidden : RushModPlayfieldCover
{
public override string Description => @"Keys fade out before you hit them!";
public override double ScoreMultiplier => 1;

protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll;
}
}
50 changes: 50 additions & 0 deletions osu.Game.Rulesets.Rush/Mods/RushModPlayfieldCover.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Shane Woolcock. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Rush.Objects;
using osu.Game.Rulesets.Rush.UI;
using osu.Game.Rulesets.UI;

namespace osu.Game.Rulesets.Rush.Mods
{
public abstract class RushModPlayfieldCover : ModHidden, IApplicableToDrawableRuleset<RushHitObject>
{
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight<RushHitObject>) };

/// <summary>
/// The direction in which the cover should expand.
/// </summary>
protected abstract CoverExpandDirection ExpandDirection { get; }

public virtual void ApplyToDrawableRuleset(DrawableRuleset<RushHitObject> drawableRuleset)
{
RushPlayfield rushPlayfield = (RushPlayfield)drawableRuleset.Playfield;

Container hitObjectArea = rushPlayfield.HitObjectArea;
Container hocParent = (Container)hitObjectArea.Parent;
hocParent.Remove(hitObjectArea);

PlayfieldCoveringWrapper wrapper = new PlayfieldCoveringWrapper(hitObjectArea)
{
RelativeSizeAxes = Axes.Both,
Direction = ExpandDirection,
Coverage = 0.5f,
};

hocParent.Add(wrapper);
}

protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
{
}

protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
{
}
}
}
1 change: 1 addition & 0 deletions osu.Game.Rulesets.Rush/RushRuleset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public override IEnumerable<Mod> GetModsFor(ModType type)
{
new MultiMod(new RushModSuddenDeath(), new RushModPerfect()),
new MultiMod(new RushModDoubleTime(), new RushModNightcore()),
new MultiMod(new RushModHidden(), new RushModFadeIn()),
new RushModFlashlight()
};

Expand Down
15 changes: 3 additions & 12 deletions osu.Game.Rulesets.Rush/UI/LanePlayfield.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Rush.Objects;
using osu.Game.Rulesets.Rush.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning;
using osuTK;
Expand All @@ -18,9 +16,6 @@ namespace osu.Game.Rulesets.Rush.UI
{
public class LanePlayfield : ScrollingPlayfield
{
private readonly JudgementContainer<DrawableJudgement> judgementContainer;
private readonly Container effectsContainer;

private readonly LanedHitLane lane;

public LanePlayfield(LanedHitLane type)
Expand All @@ -30,9 +25,10 @@ public LanePlayfield(LanedHitLane type)

Name = $"{(isAirLane ? "Air" : "Ground")} Playfield";
Padding = new MarginPadding { Left = RushPlayfield.HIT_TARGET_OFFSET };
Anchor = Origin = isAirLane ? Anchor.TopCentre : Anchor.BottomCentre;
Anchor = isAirLane ? Anchor.TopLeft : Anchor.BottomLeft;
Origin = Anchor.CentreLeft;
RelativeSizeAxes = Axes.Both;
Size = new Vector2(1, 0);
Size = new Vector2(1, 0.5f);

AddRangeInternal(new Drawable[]
{
Expand All @@ -47,8 +43,6 @@ public LanePlayfield(LanedHitLane type)
RelativeSizeAxes = Axes.Both,
}, confineMode: ConfineMode.ScaleToFit),
},
effectsContainer = new Container(),
judgementContainer = new JudgementContainer<DrawableJudgement>(),
HitObjectContainer,
});
}
Expand Down Expand Up @@ -81,9 +75,6 @@ protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObje
RegisterPool<TObject, TDrawable>(new DrawableLanedObjectPool<TDrawable>(lane, initialSize, maximumSize));
}

public void AddExplosion(Drawable drawable) => effectsContainer.Add(drawable);
public void AddJudgement(DrawableRushJudgement judgement) => judgementContainer.Add(judgement);

// This pool pre-initializes created DrawableLanedObjects with a predefined lane value
// The lane value needs to be set beforehand so that the pieces (Minion, etc) can load using the correct information
private class DrawableLanedObjectPool<T> : DrawablePool<T> where T : PoolableDrawable, IDrawableLanedHit, new()
Expand Down
62 changes: 55 additions & 7 deletions osu.Game.Rulesets.Rush/UI/RushPlayfield.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,17 @@ public class RushPlayfield : ScrollingPlayfield, IKeyBindingHandler<RushAction>
private readonly Container halfPaddingOverEffectContainer;
internal readonly Container OverPlayerEffectsContainer;

// The container housing all HitObjectAreas
public readonly Container HitObjectArea;

// playfield for each lanes
private readonly LanePlayfield airLane;
private readonly LanePlayfield groundLane;

// These are used to hold onto judgement and effect drawables
private readonly Container airLaneEffectContainer;
private readonly Container groundLaneEffectContainer;

public IEnumerable<DrawableHitObject> AllAliveHitObjects
{
get
Expand Down Expand Up @@ -77,15 +85,50 @@ public RushPlayfield()
Anchor = Origin = Anchor.Centre;
InternalChildren = new Drawable[]
{
airLane = new LanePlayfield(LanedHitLane.Air),
groundLane = new LanePlayfield(LanedHitLane.Ground),
// Contains miniboss and duals for now
new Container
{
Name = "Hit Objects",
RelativeSizeAxes = Axes.Both,
Child = HitObjectArea = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
airLane = new LanePlayfield(LanedHitLane.Air),
groundLane = new LanePlayfield(LanedHitLane.Ground),
// Contains miniboss and duals for now
new Container
{
Name = "Hit Objects",
RelativeSizeAxes = Axes.Both,
Child = new Container
{
Name = "Hit Objects",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
Child = HitObjectContainer
},
},
}
}
},
new Container{
Name = "Judgement and Effects container",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
Child = HitObjectContainer
Children = new Drawable[]{
airLaneEffectContainer = new Container()
{
Name = "Top Container",
Anchor = Anchor.TopLeft,
Origin = Anchor.CentreLeft
},
groundLaneEffectContainer = new Container()
{
Name = "Bottom Container",
Anchor = Anchor.BottomLeft,
Origin = Anchor.CentreLeft
}
}
},
halfPaddingOverEffectContainer = new Container
{
Expand Down Expand Up @@ -184,7 +227,10 @@ private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
};

if (rushJudgedObject is IDrawableLanedHit laned)
playfieldForLane(laned.Lane).AddExplosion(explosion);
{
var effectsContainer = laned.Lane == LanedHitLane.Air ? airLaneEffectContainer : groundLaneEffectContainer;
effectsContainer.Add(explosion);
}
}

// Display health point difference if the judgement result implies it.
Expand Down Expand Up @@ -215,7 +261,9 @@ private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
break;
}

playfieldForLane(judgementLane).AddJudgement(judgementDrawable);
var judgementContainer = judgementLane == LanedHitLane.Air ? airLaneEffectContainer : groundLaneEffectContainer;

judgementContainer.Add(judgementDrawable);
}
}

Expand Down
128 changes: 128 additions & 0 deletions osu.Game.Rulesets.Rush/UI/RushPlayfieldCoveringWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) Shane Woolcock. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Rulesets.Rush.UI
{
/// <summary>
/// A <see cref="Container"/> that has its contents partially hidden by an adjustable "cover". This is intended to be used in a playfield.
/// </summary>
public class PlayfieldCoveringWrapper : CompositeDrawable
{
/// <summary>
/// The complete cover, including gradient and fill.
/// </summary>
private readonly Drawable cover;

/// <summary>
/// The gradient portion of the cover.
/// </summary>
private readonly Box gradient;

/// <summary>
/// The fully-opaque portion of the cover.
/// </summary>
private readonly Box filled;

public PlayfieldCoveringWrapper(Drawable content)
{
InternalChild = new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Height = 2,
Children = new[]
{
new Container{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Height = 0.5f,
Child = content,
},
cover = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Blending = new BlendingParameters
{
// Don't change the destination colour.
RGBEquation = BlendingEquation.Add,
Source = BlendingType.Zero,
Destination = BlendingType.One,
// Subtract the cover's alpha from the destination (points with alpha 1 should make the destination completely transparent).
AlphaEquation = BlendingEquation.Add,
SourceAlpha = BlendingType.Zero,
DestinationAlpha = BlendingType.OneMinusSrcAlpha
},
Children = new Drawable[]
{
gradient = new Box
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Both,
Width = 0.25f,
Colour = ColourInfo.GradientHorizontal(
Color4.White.Opacity(1f),
Color4.White.Opacity(0f)
)
},
filled = new Box
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
Width = 0
}
}
}
}
};
}


/// <summary>
/// The relative area that should be completely covered. This does not include the fade.
/// </summary>
public float Coverage
{
set
{
filled.Width = value;
gradient.X = value;
}
}

/// <summary>
/// The direction in which the cover expands.
/// </summary>
public CoverExpandDirection Direction
{
set => cover.Scale = value == CoverExpandDirection.AlongScroll ? new Vector2(-1, 1) : Vector2.One;
}
}

public enum CoverExpandDirection
{
/// <summary>
/// The cover expands along the scrolling direction.
/// </summary>
AlongScroll,

/// <summary>
/// The cover expands against the scrolling direction.
/// </summary>
AgainstScroll
}
}