Closed smoogipoo closed 4 years ago
generates appropriate C# code upon compilation.
How about parsing it at runtime instead of complicating the build process with additional tools? We can use Reflection.Emit when we compile YAML so that the runtime cost is low.
it will have runtime parsing support, but we need c# code so we can intellisense and use stuff it creates, i believe.
I see. Sounds good.
Is it a correct assumption that Type
may hold the name of any class that is drawable?
Can a top level node be cut and pasted into a Children
list?
1) My idea for Type was to act as inheritance, i.e. Type: Container
translates to class MyLayout : Container
, or Type: FlowContainer
translates to class MyLayout : FlowContainer
.
2) While the top level node is a class construction, the plan is for children being object instantiations and not subclass constructions as it would get messy on all fronts real quick. Imo these should be really simple data structures, so you could define something like...
Button:
Type: Box
Width: 100
Height: 100
Properties:
- Name: HoverColour
Type: Color
States:
- Name: Hovered
Colour: HoverColour
- Name: Default
Colour: Color.White
Events:
- Name: OnHover
Transition:
State: Hovered
- Name: OnHoverLost
Transition:
State: Default
ButtonSystem:
Children:
- Type: FlowContainer
Children:
- Type: Button
HoverColour: Color.Red
- Type: Button
HoverColour: Color.Green
- Type: Button
HoverColour: Color.Blue
In one file. Can you give a use case for needing to copy-paste top-level nodes?
If it acts as inheritance, maybe renaming it to Extends
would be more appropriate?
Funny that, I had extends in my original proposal. I totally agree.
Can you give a use case for needing to copy-paste top-level nodes?
I was thinking about ease of definition for children. Sounds like you got it handled. :+1:
Are states defined by the objects themselves or just the behaviour of each state for that object? Is there a set of predefined states and we are just defining how they should behave in this state? If that's the case are user defined states allowed?
Are transitions defining behaviour by default?
- Name: HoveredTransition
State: Hovered # Named state
Duration: 500
- Name: ScaleTransition
State: # Anonymous state
Scale: 1.5
This is what I understand: HoveredTransition is basically saying when this is applied transition between the original state to the hovered state in 500 time units. But then ScaleTransition simply says that when you apply this scale the object by this amount, directly changing the state with no additional information provided. (Equivalent to something like: object.setState(scaleState);
).
What I am asking is: Is there some sort of predefined behaviour when a transition doesn't provide any information about how it should transition? If there isn't any (which I assume it is the case) then you can implicitly define empty transitions for states. Example:
Object:
States:
- Name: Scale
Scale: 1.5
This will implicitly have a "ScaleTransition" that would be the equivalent of writing:
Transitions:
- Name: ScaleTransition
State: Scale
There should be a way to define the transition type, i.e. CubicOut, Exponential, etc.. Possibly defaulting to some value if not set
Easing: EasingTypes.InOut
or whatever we have in osu! currently.
It seems that this isn't going to be necessary.
Reopened at request of @phosphene47. We still need this for (at very least) skinning – cases where we want to accept runtime-parsed drawables and a secure way.
We could also use JSON, right? I think JSON.net would allow us to parse this data at runtime and directly populate an existing container (+ we already have the parser included in the nuget packages).
yaml is a superset of json so we automatically get json support from yaml parsers (https://stackoverflow.com/questions/1726802/what-is-the-difference-between-yaml-and-json-when-to-prefer-one-over-the-other). no need for json.net
we can't simply directly populate existing Container
s. what if a custom Drawable
derives from an abstract class? we can't simply instantiate the base class to populate the properties, we have to emit the class using reflection at runtime. this is also necessary to implement Transitions
.
the only drawback to emitting at runtime is cross-platform incompatibility (specifically iOS).
It's definitely a consideration we need to keep in mind, since skins still need to work on iOS.
I may look into doing this, got some questions. Some of these are implementation details so I'm not sure if I'm supposed to chose these myself or not.
Are values of properties just the code representation of them? The examples show Color.Red
in Transitions, does that mean defining a Vector2 would be done as Vector2.One
and new Vector2(0.5f, 1f)
? If this is the case, it would be hard to provide runtime support, since we'd have to interpret the C# code somehow.
From what I can tell, the goal is to both generate C# code (for coding against them) and to dynamically make them at runtime (skinning, I assume). My idea was to generate a skeleton class (containing properties, events) which at runtime gets populated through an object holding all the information from the yaml file. Would this be a good way, or was another method planned?
Are properties always private?
A Property has a Type field, are these pre-defined (in some Dictionary<string, Type>) or resolved at runtime? osu-framework does not use a Color
class but ColourInfo
, this had me confused.
Since this was written, the scope has definitely changed. The primary use case is not for skins and such, where we want to allow users the ability to customise without the ability to break. They would only be able to touch properties exposed by a specific interface or attribute marking (and we would need to define these interfaces for clases which wish to expose them to the user).
I personally would prefer a markup language that allows following yaml code:
# Skin usecase: Backbutton
Target: Backbutton
Box:
Width: 200
Height: 50
Colour: Red
Alpha: 0.7
Origin: LeftBottom
Anchor: LeftBottom
OnHover:
- Scale: 1
To: 1.5
Duration: 300ms
Easing: InQuint
- FadeTo: 1
Duration: 300ms
Easing: OutQuint
OnClick:
- FadeTo: 0
Duration: 100ms
Children:
- SpriteText:
RelativeSizeAxes: Both
Width: 0.6
Height: 0.6
Anchor: Centre
Origin: Centre
FontColour: White
Text: "Go Back!"
---
# Skin Usecase: Healthbar
# Predefined variable:
# $healthValue
Target: Healthbar
Box:
RelativeSizeAxes: Width
Width: 0.3
Height: 100
Anchor: TopLeft
Colour: Black
Alpha: 0.9
OnUpdate:
- FadeColourTo: Red
Condition: $healthValue < 0.3
Trigger: Condition
- FadeColourTo: White
Condition: $healthValue >= 0.3
Trigger: Condition
Children:
- Box:
RelativeSizeAxes: Both
Width: 0.9 * $healthValue
Height: 0.3
Origin: Center
Anchor: Center
Colour: White
Each yaml document targets an ingame element. The elements may have variables that are inlined using $variableName. Everything can have children. And I would expect that transformations can have conditions.
The Trigger
can have following values:
Gonna close this issue to start afresh.
Initial draft spec of OML. It's changed a little bit since the last iteration in the transitional repository so you'd best go over this again and point out any inconsistencies/points of clarification or just general comments. Topic for the next pair programming session.
OML - osu! markup language
What is OML
OML is a markup language very similar to QML, oriented towards designing layouts for games that are built upon the osu!framework. The language is YAML-Validated and generates appropriate C# code upon compilation.
Basic syntax
The following is an object that represents a 100x100 red rectangle:
Width
,Height
andColour
are general properties of the Rectangle. These are applied when the object is constructed.Special Properties
Objects have special properties:
Extends
States
Transitions
Events
Properties
Children
The
Extends
PropertyObjects extend
Drawable
by default and inherit all ofDrawable
's properties. It is possible to change this behaviour where this is not intended by specifying theExtends
property of the object:The
States
PropertyA state defines how an object looks at a point in time by modifying the value of the general properties of the object. This special property may be used to define named states which may be referred to by multiple places in further code.
The property named "Default" is optional but will be applied when the object is first constructed.
The
Transitions
PropertyA transition defines how an object should transition towards a state. This special property may be used to define named transitions which may be referred to by multiple places in further code. These can be used to transition to either named or anonymous states.
The
Events
PropertyAn event defines the transitions that should be applied to an object when the event is called. Events are exposed in the generated C# code. These can be used to apply either named or anonymous transitions.
Todo: Reserved events
The
Properties
PropertyAn object may define properties as private members for it to use.
The
Children
PropertyAn object may be composited by several children that are directly affected by the containing object. In this way it is possible to transition an object and all of its children together by applying the transition to the containing object.
Children may be either named - allowing them to be referenced as private members from generated code, or anonymous.