GetElementsByType()

BlitzMax Forums/BlitzMax Programming/GetElementsByType()

Kistjes(Posted 2009) [#1]
Hello,

I have a quite familiar object structure in my game (don't worry, example code is provided below):

TElement type
TPlayer extends TElement
TEnemy extends TElement
TBullet extends TElement

TElement controls a global list with all created TElements

Now I want to write a TElement method GetElementsByType:TList(typeID) to receive all elements of that type.

Example:


I can write a function for every extended type, like
TElement.GetBullets()
TElement.GetEnemies()
but I would like to have a generic function where I can call every extended type without writing a function for each and every extended type.

Is there a way to do this?


tonyg(Posted 2009) [#2]
Why not make GetElements an abstract method and use polymorphism?
Or have I misunderstood?
<edit> In fact I think I have misunderstood.... don't mind me.


Kistjes(Posted 2009) [#3]
Imagine TElement is a type defined in a module.

During project progress I create all kind of abstract types of TElement.
Now I need to write a GetElement() function for every abstract type. Instead it would be nice and handy if TElement could have a generic GetElementByType() function.

In my project, things are a little different. TElement does also have a field polLinks:TList containing links to other TElement objects.
I want to be able to ask to a TPlayer instance "Which TEnemies do you have (are linked)?"
or "TEnemy, give me a list of all your TBullets."
I can do all this by calling GetElementsByType()
GetElementsByType() will run through the polLinks list of course.


Brucey(Posted 2009) [#4]
Here is one way...

SuperStrict

Framework BRL.Map
Import BRL.LinkedList
Import BRL.StandardIO

Type TElement

	Const TYPE_PLAYER:Int = 1
	Const TYPE_ENEMY:Int = 2
	Const TYPE_BULLET:Int = 3

	Global golElements:TMap = New TMap
	
	Method Init()
		Local id:String = GetId()
		Local list:TList = TList(golElements.ValueForKey(id))
		If Not list Then
			list = New TList
			golElements.Insert(id, list)
		End If
		
		list.AddLast(Self)
	End Method
	
	Function GetElementsByType:TList(typeId:Int)
		' can return Null TList
		Return TList(golElements.ValueForKey(String(typeId)))
	End Function

	Method GetId:Int() Abstract	
End Type

Type TPlayer Extends TElement

	Method New()
		Init()
	End Method

	'.. create function etc.
	
	Method GetId:Int()
		Return TYPE_PLAYER
	End Method	
	
End Type

Type TEnemy Extends TElement

	Method New()
		Init()
	End Method

	'.. create function etc.

	Method GetId:Int()
		Return TYPE_ENEMY
	End Method	
End Type

Type TBullet Extends TElement

	Method New()
		Init()
	End Method

	'.. create function etc.

	Method GetId:Int()
		Return TYPE_BULLET
	End Method	
End Type


'receive all bullets:
Local olBullets:TList = TElement.GetElementsByType(TElement.TYPE_BULLET)
If olBullets Then
	Print olBullets.count()
End If

New TBullet
New TBullet

olBullets = TElement.GetElementsByType(TElement.TYPE_BULLET)
Print olBullets.count()

If you want all types, you could implement some extra functionality in GetElementsByType().
One advantage to this, is that your type lists are already built, so access of those is faster.
It depends what information you need more often.


tonyg(Posted 2009) [#5]
I would consider sending a string and do a select/case on it to check which object to extract from the list.
Not elegant but might be good enough for now and then revisit if you have to.
<edit>... or use a tmap :)


Kistjes(Posted 2009) [#6]
Nice example Brucey! Thanks. I'll experiment a little with TMaps.


Kistjes(Posted 2009) [#7]
Brucey,
Based on your example code I was able to make exactly what I need.
Thanks again!