// Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; using osu.Game.Rulesets.Judgements; using osu.Framework.Allocation; using System.Collections.Generic; using System.Linq; namespace osu.Game.Rulesets.UI { public abstract class Playfield : Container where TObject : HitObject where TJudgement : Judgement { /// /// The HitObjects contained in this Playfield. /// public HitObjectContainer HitObjects { get; protected set; } internal Container ScaledContent; /// /// Whether we are currently providing the local user a gameplay cursor. /// public virtual bool ProvidingUserCursor => false; protected override Container Content => content; private readonly Container content; /// /// A container for keeping track of DrawableHitObjects. /// /// Whether we want our internal coordinate system to be scaled to a specified width. protected Playfield(float? customWidth = null) { // Default height since we force relative size axes Size = Vector2.One; AddInternal(ScaledContent = new ScaledContainer { CustomWidth = customWidth, RelativeSizeAxes = Axes.Both, Children = new[] { content = new Container { RelativeSizeAxes = Axes.Both, } } }); HitObjects = new HitObjectContainer { RelativeSizeAxes = Axes.Both, }; } [BackgroundDependencyLoader] private void load() { Add(HitObjects); } public override Axes RelativeSizeAxes { get { return Axes.Both; } set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); } } /// /// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield. /// public virtual void PostProcess() { } /// /// Adds a DrawableHitObject to this Playfield. /// /// The DrawableHitObject to add. public virtual void Add(DrawableHitObject h) => HitObjects.Add(h); /// /// Remove a DrawableHitObject from this Playfield. /// /// The DrawableHitObject to remove. public virtual void Remove(DrawableHitObject h) => HitObjects.Remove(h); /// /// Triggered when an object's Judgement is updated. /// /// The object that Judgement has been updated for. public virtual void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { } public class HitObjectContainer : CompositeDrawable { public virtual IEnumerable Objects => InternalChildren.OfType(); public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject); public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject); } private class ScaledContainer : Container { /// /// A value (in game pixels that we should scale our content to match). /// public float? CustomWidth; //dividing by the customwidth will effectively scale our content to the required container size. protected override Vector2 DrawScale => CustomWidth.HasValue ? new Vector2(DrawSize.X / CustomWidth.Value) : base.DrawScale; } } }