Implementing the Components-Pattern in monkey-x
Monkey Forums/Monkey Beginners/Implementing the Components-Pattern in monkey-x
| ||
Hi guys, I am looking to implement the components programming pattern in monkey-x, in order to decouple the different domains (graphics, controls, audio) from each other while retaining a scene-graph architecture. So far, my implementation looks like this: Strict Import mojo2 Interface IDrawable Method Surface:Canvas() Property Method Render:Void() End Strict Import interfaces.idrawable Interface IGraphicsComponent Method Render:Void(drawable:IDrawable) End Strict Import mojo2 Import interfaces.idrawable Import interfaces.igraphicscomponent Class cPlayfield Implements IDrawable Private Field surface:Canvas Field graphicsComponent:IGraphicsComponent = New cPlayfieldGraphicsComponent() Public Field Width:Int Field Height:Int Method Surface:Canvas() Property Return surface End Method New(_surface:Canvas, _width:Int, _height:Int) surface = _surface Width = _width Height = _height End Method Render:Void() graphicsComponent.Render(Self) End End Class cPlayfieldGraphicsComponent Implements IGraphicsComponent Method Render:Void(drawable:IDrawable) Local playfield:cPlayfield = cPlayfield(drawable) playfield.Surface.Clear(0, 0, 0) playfield.Surface.SetColor(0, 0, 1) playfield.Surface.DrawRect(0, 0, playfield.Width, playfield.Height) playfield.Surface.SetColor(1, 1, 1) playfield.Surface.DrawText("Hello World.", 10, 10) End End Do you think this is a valid approach to the component pattern in monkey-x? |
| ||
This is propably a better example:Strict Import interfaces.idrawable Import interfaces.icontrollable Import interfaces.igraphicscomponent Import interfaces.iinputcomponent Import config.settings Class cSlider Implements IDrawable, IControllable Private Field surface:Canvas Field graphicsComponent:IGraphicsComponent = New cSliderGraphicsComponent() Field inputComponent:IInputComponent = New cSliderInputComponent() Public Field PosX:Float Field PosY:Float Field Width:Float Field Radius:Float Field Value:Float Field MinValue:Float Field MaxValue:Float Field IsDown:Bool Method Surface:Canvas() Property Return surface End ' Constructor Method New(_surface:Canvas, _posX:Float, _posY:Float, _width:Float, _radius:Float = 10, _minValue:Float = 0, _maxValue:Float = 1, _value:Float = 0) surface = _surface PosX = _posX PosY = _posY Width = _width Radius = _radius MinValue = _minValue MaxValue = _maxValue Value = _value End ' Render Method Render:Void() graphicsComponent.Render(Self) End ' Handle Input Method HandleInput:Void() inputComponent.HandleInput(Self) End End Class cSliderGraphicsComponent Implements IGraphicsComponent Method Render:Void(drawable:IDrawable) Local slider:cSlider = cSlider(drawable) Local position:Float = slider.PosX + (slider.Value * (slider.Width / slider.MaxValue)) Local radius:Float = slider.Radius ' Draw Line slider.Surface.SetAlpha(1) slider.Surface.SetColor(1, 1, 1) slider.Surface.DrawLine(slider.PosX, slider.PosY, slider.PosX + slider.Width, slider.PosY) If slider.IsDown Then slider.Surface.SetColor(1, 0, 0) ' Draw Handle slider.Surface.DrawCircle(position, slider.PosY, radius) End End Class cSliderInputComponent Implements IInputComponent Private Field settings:cSettings = cSettings.Instance() Public Method HandleInput:Void(controllable:IControllable) Local slider:cSlider = cSlider(controllable) Local actualPosX:Float = settings.GridOffset_X + slider.PosX Local actualPosY:Float = settings.GridOffset_Y + slider.PosY If (MouseDown() And slider.IsDown) Or (MouseDown() And MouseY() >= actualPosY - slider.Radius And MouseY() <= actualPosY + slider.Radius And MouseX() >= actualPosX - (slider.Radius / 2) And MouseX() <= actualPosX + slider.Width + (slider.Radius / 2)) Local clickPosX:Float = MouseX() -actualPosX + (slider.Radius / 2) slider.Value = (clickPosX) / slider.Width slider.IsDown = True slider.Value = Clamp(slider.Value, slider.MinValue, slider.MaxValue) Print slider.Value Else slider.IsDown = False End End End |
| ||
I think it's properly done like this. Just, why are you hidding component acces from container class? You can provide readonly access to private component instances by using readonly properties. I'm not saying you should (hence the demeter principle https://en.wikipedia.org/wiki/Law_of_Demeter ) but, sometimes it's handly if not over abused! |
| ||
Hi ziggy, Thanks for you input. I am just not sure what your suggestion is. Are saying I should make the components readonly properties like so: Private Field graphicsComponent:IGraphicsComponent = New cSliderGraphicsComponent() Field inputComponent:IInputComponent = New cSliderInputComponent() Public Method GraphicsComponent:IGraphicsComponent Property Return graphicsComponent End Method InputComponent:IInputComponent Property Return inputComponent End and call the Render and HandleInput from the container class lile: Class cUITestScene Implements IDrawable, OnValueChangedEvent Private Field surface:Canvas Field alphaSlider:cSlider Field redSlider:cSlider Field greenSlider:cSlider Field blueSlider:cSlider Field settings:cSettings = cSettings.Instance() .. Method Update:Void() alphaSlider.InputComponent.HandleInput(alphaSlider) redSlider.InputComponent.HandleInput(redSlider) greenSlider.InputComponent.HandleInput(greenSlider) blueSlider.InputComponent.HandleInput(blueSlider) End Method Render:Void() alphaSlider.GraphicsComponent.Render(alphaSlider) redSlider.GraphicsComponent.Render(redSlider) greenSlider.GraphicsComponent.Render(greenSlider) blueSlider.GraphicsComponent.Render(blueSlider) End ? |
| ||
No no, I was not suggesting any change. I was just telling you that your design does not provide access to the components form outside the container class. Which is a good thing if you don't need them, but somehow limiting if you do. All in all, if you don't need it, don't change it! |
| ||
Oh I see. Sorry for the confusion. |