Overiding the "Compare" method for Z ordering
BlitzMax Forums/BlitzMax Programming/Overiding the "Compare" method for Z ordering
| ||
Overiding the Compare method affects the SortList() command. Which means that you can sort and list of objects by whatever field you like. All you have to do in your main loop is call "SortList(YourList)". In the example below I've overidden the compare method to z order my sprites sprites: Strict 'The Sprite Type Type Sprite Field x:Float Field y:Float Field color:Int [3] '--- Create a Sprite Function Create:Sprite () Local s:Sprite = New Sprite s.x = Rand(0,640) s.y = Rand(0,480) s.color = [Rand(0,255),Rand(0,255),Rand(0,255)] SpriteList.AddLast(s) Return s End Function '--- Render the Sprite Method Render() SetColor color[0], color[1], color[2] DrawOval x-16,y-16,32,32 End Method '--- Here we overide the compare method to '--- look at the "Y" field and compare it with the '--- the given object. Method Compare( other:Object ) Return y-Sprite(other).y End Method EndType Graphics 640,480,0 'Create the Spritelist Global SpriteList:tList = CreateList() '--- Create the Player Sprite Local player:Sprite = Sprite.Create() '--- Create Some Sprites For Local i = 1 To 100 Sprite.Create() Next 'MAIN LOOP While Not KeyHit(KEY_ESCAPE) Cls '--- Sort the Sprites SortList (SpriteList) '--- Render All Sprites For Local s:Sprite = EachIn SpriteList s.Render() Next '--- Update Player Position player.x :+ (KeyDown(KEY_RIGHT) - KeyDown(KEY_LEFT))*2 player.y :+ (KeyDown(KEY_DOWN) - KeyDown(KEY_UP))*2 FlushMem Flip Wend |
| ||
Hi, Nice - but there's a potential bug in there. Compare is supposed to return an int <0, =0 or >0 depending on whether 'Self' is less than, equal to or greater than 'other'. However, your Compare is only returning 0 or 1. That fact that it's working is due to the way the sort routine works in TList. However, if this routine changes - or perhaps you have an array of Sprites and use Array.Sort (which uses a different algorithm) - you may have problems. So, you could go: If y<s.y Return -1 Else if y=s.y Return 0 Else Return 1 EndIf However, a more efficient way is: Return y-s.y Which, if you think about it, will return the correct value! It's also probably a good idea to think about whether trying to Compare a Sprite with a non-Sprite should be allowed - currently, your routine allows this and returns 0 for all such comparisons. But unless you can think of any reason this should be possible/desirable, it's probably best to generate an error, eg: Assert Sprite(other) Local s:Sprite=Sprite(other) Return y-s.y Which guards against Sprite/non-Sprite comparisons. In fact, you can roll it all up into one statement: Method Compare( other:Sprite ) Return y-Sprite(other).y End Method This will both generate a runtime error if 'other' is not a Sprite (with 'attempt to access field or method of Null Object') and return the correct range of values. |
| ||
Great! Your right it could cause problems, thankyou for pointing it out. I actualy did have it like this originaly: If y<s.y Return -1 Else if y=s.y Return 0 Else Return 1 EndIf I turned it into this: If s.y < y Then Return 1 so it would be more simplified :) But this is way simpler: Method Compare( other:Object ) Return y-Sprite(other).y End MethodThanks! |
| ||
The float from y - Sprite( other ).y is being cast to int - keep that in mind. |
| ||
ok? I'm not sure I understand your warning. I don't think it makes any difference. It's not actualy changing the value of the Y field or even its type, Y will remain the same and still be a float. The returned value will be a Integer, but thats what we want to return. :) |
| ||
Ahh... The conversion from float to int will drop the fraction, which might give problems, eg: Int(.75-.5) returns 0. Probably safest to go: Return Sgn( y-Sprite(other).y ) |
| ||
Yeah, but, the loss of accuracy means an object at 5.9 will have the same Z Order as 5.1. It doesn't really matter in this test program, but you'll want to keep it in mind for anything more complex. |