Need some Object advice

Monkey Forums/Monkey Programming/Need some Object advice

Supertino(Posted 2013) [#1]
Hey all

So I know about objects and stuff but I want to put all my classes for buttons, screens, text, gui, texture packs, etc. Into a more manageable and unified framework. Managed from one top level class.

At the moment I have different classes for each feature such as;

button1 = new Button(image,x,y)
screen1 = new Screen
texPack1 = new TexturePack(file)


What I want is to prefex all these calls with an initial class (in this example its called FRAMEWORK, such as;

button1 = new FRAMEWORK.Button(image,x,y)
screen1 = new FRAMEWORK.Screen
texPack1 = new FRAMEWORK.TexturePack(file)



So ill be keeping them all as different classes I just want to call FRAMEWORK and from that IntelliSense takes over and give me routes in the Button, Screen, texture pack classes etc.

I hope that makes sense. =)


muddy_shoes(Posted 2013) [#2]
I generally have a few top-level classes that are just containers for global data. A few are "organised" groups like colour palette, fonts etc. but I also usually have something like GameGlobals for just chucking odds and ends into.


Gerry Quinn(Posted 2013) [#3]
I guess you could use a factory class for Framework, e.g. the call would be something like:

button1 = Framework.CreateButton( x, y, image )

I'm not sure if it's worth the trouble, though - simply constructing a Button seems simple enough.

What you might consider is having your controls all implement an interface with common functions such as GetRect:Rect(), MouseHitEvent:Int( mouse:Point ), Draw:Void()... things like that. So you could replace a button with a slider without changing much code etc.

I haven't bothered with that myself, but I would do it if I were making an interface library. Or maybe have all controls inherit from a window class, like in MFC.


Shinkiro1(Posted 2013) [#4]
A file counts as a namespace.
That's why you can call
mojo.DrawImage(...)


So just create a framework.monkey file which import buttons, screens, etc


Supertino(Posted 2013) [#5]
Thanks guys - I ended up doing the following;


' --- init

Global Engine:= New FrameWorkClass
Global button1:= New ButtonClass

' --- calls

Engine.Button.Create(button1, 20, 20, 250, 100)
Engine.Button.Render(button1)
Engine.Button.Update(button1)

' --- classes

Class FrameWorkClass
	Field Button:ButtonClass = New ButtonClass
	Field DebugLog:DebugLogClass = New DebugLogClass
End Class

Class ButtonClass
	Private Field x:Int, y:Int, width:Int, height:Int

	Method Create:Void(a:ButtonClass, x:int, y:Int, width:Int, height:int)
		a.x = x
		a.y = y
		a.width = width
		a.height = height
	End Method
	
	Method Render:Void(a:ButtonClass)
		DrawRect a.x, a.y, a.width, a.height
	End Method

        Method Update:Void(a:ButtonClass)
		' blah
	End Method
	
End Class



Now I can just call Engine and go from there, just what I wanted.


Jesse(Posted 2013) [#6]
Personally I think it's a bit clunky but maybe that's just me.

I would do it like this:
' --- init

Global Engine:= New FrameWorkClass
Global button1 := Engine.CreateButton(20, 20, 250, 100)


' --- calls

Engine.Render(button1)
Engine.Update(button1)

' --- classes

Class FrameWorkClass
	Field DebugLog:DebugLogClass = New DebugLogClass
	
	Function CreateButton:Button(x:Int,y:Int,width:Int,height)
		Return New Button(x,y,width,height)
	End Function
	
	
	Function Render:Void(button:ButtonClass)
		button.Render()
	End Function
	
	Function Update:Void(button:ButtonClass)
		button.Update()
	End Function
End Class

Class ButtonClass
	Private Field x:Int, y:Int, width:Int, height:Int

	Method New(x:Int, y:Int, width:Int, height:Int)
		Self.x = x
		Self.y = y
		Self.width = width
		self.height = height
	End Method
	
	Method Render:Void()
		DrawRect x, y, width, height
	End Method

	Method Update:Void()
		' blah
	End Method
	
End Class



muddy_shoes(Posted 2013) [#7]
If it works for you then fine but you're really just ignoring OO and using objects as buckets of procedures. The giveaway is that you're passing object references into your methods just like a procedural language. If you're going to do that then you may as well declare your "methods" as static functions on the class.


Jesse(Posted 2013) [#8]
yes that too.


Supertino(Posted 2013) [#9]
@Jess - that seems like more work TBH, harder to implement additional classes

@Muddy - yeah screw OO I don't play the rules :p, I'll use proper OO so to speak for things outside my framework but I'd rather this method when using my frame work as I tend to forget what it can do. The only reason for doing it this way is for intellisense, no other reason.


Gerry Quinn(Posted 2013) [#10]
I agree it is clunky from an OO viewpoint (means you need a New AND a Create for every button) but I think Supertino wants to leverage his Intellisense. [Edit: I see he just said that.]


Jesse(Posted 2013) [#11]
I don't see how it's harder to implement additional classes. it's the same principle with every other class you add to it. it doesn't have to be any different. And the title do say that you want object advice. but whatever nothing to gain here for me. :)


Midimaster(Posted 2013) [#12]
Would this be a solution?

A container class which has a field for a 'first undefined' object :
Class FrameWork
	Global FrameWorkList := New List<FrameWork>
	
	
	Field Typ%, Obj:Object
	
	Function Add:FrameWork(Typ%,x%,y%,width%,height%)
		Local loc:= New FrameWork
		loc.Typ=Typ
		Select loc.Typ
			Case BUTTON
				loc.Obj = New ButtonClass (x,y,width,height)
		End
		Return loc
	End


	Function Add:FrameWork(Typ%,t$)
		Local loc:= New FrameWork
		loc.Typ=Typ
		Select loc.Typ
			Case BUTTON
			Case TEXTUREPACK
				'loc.Obj = New TextureClass (t$)
		End
		Return loc
	End

	
	Function RenderAll:Void()
		For Local loc:FrameWork=Eachin FrameWorkList
		Select loc.Typ
			Case BUTTON
				ButtonClass(loc.Obj).Render
			Case TEXTUREPACK
				'TextureClass(loc.Obj).Render
		End
		Next
	End
End




And here the complete code:


I did not test the code... only an idea...


Jesse(Posted 2013) [#13]
if that is the case than using a base class would be even better:

' --- init

Global Engine:= New FrameWorkClass
Global button1 := Engine.CreateButton(20, 20, 250, 100)
Global slider1 := engine.CreateSlider(100,100,45,200,0,100)

' --- calls

Engine.Render(button1)
Engine.Update(button1)
Engine.Render(slider1)
Engine.Update(slider1)

' --- classes

Class FrameWorkClass
	Field DebugLog:DebugLogClass = New DebugLogClass
	
	Function CreateButton:Button(x:Int,y:Int,width:Int,height)
		Return New Button(x,y,width,height)
	End Function
	
	Function CreateSlider:Slider(x:Int,y:Int,width:Int,height:Int,min:Int,max:Int)
		Return New Slider(x,y,width,height,min:Int,max:Int)
	End Function
	
	Function Render:Void(obj:BaseClass)
		obj.Render()
	End Function
	
	Function Update:Void(Obj:BaseClass)
		obj.Update()
	End Function
End Class

Class BaseClass
	Field x:Float,y:Float
	
	Method Update:Void() Abstract
	Method Render:Void() Abstract
End Class

Class ButtonClass Extends BaseClass
	Private Field width:Int, height:Int

	Method New(x:Int, y:Int, width:Int, height:Int)
		Self.x = x
		Self.y = y
		Self.width = width
		self.height = height
	End Method
	
	Method Render:Void()
		DrawRect x, y, width, height
	End Method

	Method Update:Void()
		' blah
	End Method
	
End Class

Class Slider Extends BaseClass
	Private Field width:Int,Height:Int,min:Int,max:Int
	
	Method New(x:Int, y:Int,width:Int,height:Int,min:Int,max:Int)
		Self.x = x
		Self.y = y
		Self.width = width
		Self.height = height
		Self.min = min
		Self.max = max
	End Method
	
	Method Update:Void()
		'dodododo
	End Method
	
	Method Render:Void()
		'dodododo
	End Method
	
End Class


on either case I don't think the Framework/engine idea is of any real use as it stands. As muddy mentioned, it's just a bucket of procedures. There needs to be more meaningful purpose for it to be of any real use.