Sortlist custom sorting function problem
BlitzMax Forums/BlitzMax Beginners Area/Sortlist custom sorting function problem
| ||
I`m having a few problems implementing a custom sorting function into one of my projects. I have a global list contained in a base type, TEntity, with all other types extended from this. Each time a new object is create in one of the other types it is added to the global list. I need to be able to my types by a field but only if they are of a certain type, for example only if they are TAliens. I then want to sort them by one of there fields, ZOrder or something like that. I am using the following code to try to implement this but I keep getting problems with the objects passed into the function being null. I cannot see why this is? Can anyone please help? Is it possible to tell what type an object is so that I can sort it only if it is of the required type? Is it not possible to sort only certain objects if they are all in the same global list? Thanks for any help, Jason. Function SortZOrder:Int(Object1:Object,Object2:Object) Local Alien1:TAlien=TAlien(Object1) Local Alien2:TAlien=TAlien(Object2) If Alien1 Or Alien2=Null Then End If Alien1.ZOrder<Alien2.ZOrder Return 1 Else Return -1 EndIf End Function SortList(TAlien.List,True,SortZOrder) |
| ||
Just guessing, butIf Alien1 Or Alien2=Null Then End should be If Alien1=Null Or Alien2=Null Then End As it is, it's quitting if Alien1 is a valid object! |
| ||
@Warpy, thanks I missed that. Still no joy though :( Jason. |
| ||
If the object passed in is not a TAlien, then Alien1 or Alien2 would be Null. You are not passing in objects that aren't TAliens are you? |
| ||
the reason you are not getting a null it's because of the base type. you are using the same basetype for allof them(polymorphing). I suggest you use a field in the base type that would allow your to determine what type the object is: at the craete function fill in the field for whatever type you are creating. when you pass the object convert the objects to the base type then test to see if the field type matches to what you want then if needed comver it to the extended type. I usually don't need to convert sence the abstracts in the base type solves that. I can post an example if you need more help. |
| ||
Please do Jesse if you can spare a moment. Jason. |
| ||
'this assumes all you are putting in the list are objects with a base type of "Tbase" 'if you store other base types in the list you do need to use "object" for the parameter and "Tbase(object) = null" comparison as an added test SuperStrict Type Tbase Field x:Int Field y:Int Field ZOrder:Int Field _type:Int Global list:TList = New TList Const cSHIP:Int = 1 Const cALIEN:Int = 2 Method draw() Abstract Method update() Abstract End Type Type TShip Extends Tbase Function Create:TShip(x:Int,y:Int,z:Int) Local s:TShip = New Tship s.x = x s.y = y s.ZOrder = z S._type = s.cSHIP s.list.addlast(s) Return s End Function Method update() x = x+3 y = y+2 End Method Method draw() DrawOval x,y,10,10 End Method End Type Type TAlien Extends Tbase Function Create:TAlien(x:Int, y:Int,z:Int) Local s:TAlien = New TAlien s.x = x s.y = y s.zOrder = z s._type = s.cALIEN s.list.addlast(s) Return s End Function Method update() x = x+x*.1 y = y+3 End Method Method draw() DrawRect x,y,10,10 End Method End Type Function SortZOrder:Int(alien1:Tbase,alien2:Tbase) ' you can use 'object' but then you have to convert to at least a Tbase If Alien1._type <> Alien1.cALIEN Or Alien2._type <> Alien2.cALIEN Then Print "other object" return 0 If Alien1.ZOrder<Alien2.ZOrder 'ZOrder is part of the Tbase Return 1 Else Return -1 EndIf End Function TShip.Create(120,120,10) TAlien.Create(215,230,12) Talien.Create(120,87,8) For Local a:Tbase = EachIn Tbase.list For Local b:Tbase = EachIn Tbase.list If a = b Continue If sortZOrder(b,a)= 1 Print "ok" Next Next Graphics 800,600 Cls For Local O:Tbase = EachIn Tbase.list O.update() ' this updates the ship and aliens Next For Local O:Tbase = EachIn Tbase.list O.draw() ' this draws the ship and aliens Next Flip() WaitKey() End some programmers use string as the _type and constants that way they can just Print _type and it displays the relevant information. I prefer to use integers as it's a bit faster. I hope this is clear. If not, just ask. ***************[edited]************************ |
| ||
If you can live with it, that the whole list is ordered try this approach: [edit] even if you filter your sort routine by a specific type - tlist and its sort function iterates over all items in the list, so in my opinion it is more efficient to sort the whole list [/edit] SuperStrict Type TEntity Abstract Field x:Double Field y:Double Field z:Double Field name:String Method Output() Abstract Method ZCompareTo:Int(other:TEntity) If Self.z < other.z Return -1 Else Return 1 EndIf EndMethod EndType Type TSpaceShip Extends TEntity Function Create:TSpaceShip(x:Double , y:Double , z:Double , name:String) Local this:TSpaceShip = New TSpaceShip this .x = x this .y = y this .z = z this .name = name Return this EndFunction Method Output() Print name + " @ "+Left(String(z),5) EndMethod EndType Type TAlien Extends TEntity Function Create:TAlien(x:Double , y:Double , z:Double , name:String) Local this:TAlien = New TAlien this .x = x this .y = y this .z = z this .name = name Return this EndFunction Method Output() Print name + " @ "+Left(String(z),5) EndMethod EndType Function TEntityZSorter:Int(o1:Object, o2:Object) If Not TEntity(o1) Return 0 If Not TEntity(o2) Return 0 Return TEntity(o1).ZCompareTo(TEntity(o2)) EndFunction Global entityList:TList = New TList entityList.AddLast( TSpaceShip.Create(0, 0, 10, "Space Ship #1") ) entityList.AddLast( TSpaceShip.Create(0, 0, 20, "Space Ship #2") ) entityList.AddLast( TSpaceShip.Create(0, 0, 30, "Space Ship #3") ) entityList.AddLast( TAlien.Create(0, 0, 15, "Alien #1") ) entityList.AddLast( TAlien.Create(0, 0, 25, "Alien #2") ) entityList.AddLast( TAlien.Create(0, 0, 35, "Alien #3") ) Print "~n===> Original Order" For Local e:TEntity=EachIn entityList e.Output() Next entityList.Sort(False, TEntityZSorter) Print "~n===> Globally Ordered" For Local e:TEntity=EachIn entityList e.Output() Next Print "~n===> SpaceShips Ordered" For Local e:TSpaceShip=EachIn entityList e.Output() Next Print "~n===> Aliens Ordered" For Local e:TAlien=EachIn entityList e.Output() Next |
| ||
Thanks for both of those examples, Jesse and Kurator, I understand what was going wrong in my program now thanks to your code. Thanks to all others that helped too :) Jason. |
| ||
@Kurator I have always been comfused by the abstract directly in the base type definition: Type TEntity Abstract you mind explaining its purpose? or anybody. |
| ||
Pretty simple: - you can not instanciate an Object from an Abstract Type. Try the following in my Code above: "test:TEntity = New TEntity" ..that will not work - because its abstract. The only thing ist, like in the above code, you can subclass / subtype from it. That has some nice advantages for object orientated programming: - All Subclasses have the same structure, fields. - You can also define some methods, that all subclasses share (as normal subtyping) - You can define "abstract" mehthods - these have to be implemented by the subclasses. When an abstract type is subtyped, the subtype usually provides implementations for all of the abstract methods in its parent type. However, if it does not, the subtype must also be declared abstract. |
| ||
I believe abstract means that you cannot create one of these types, you must inherit it into a new type to use it. Beat me to the punch. |
| ||
Thanks, now I know. |