ZOrdering Question
BlitzMax Forums/BlitzMax Beginners Area/ZOrdering Question
| ||
Hello, hopefully someone can help me with this small problem that I am trying to implement in my game. I have a base type, in this case TEntity, which all other game objects are extended from. I have TPlayers, Enemies and so on. When a new instance of one of these types is created it is added to a single, global, list inside of TEntity. OK, now on to the problem. I have a field inside TEntity that allows me to set a ZOrder for my extended types and I want to be able to draw them in the correct order based on those ZOrder values which will change dynamically throughout the game. Normally I would just do a simple, ... TPlayer.Draw TEnemy.Draw ... in my main drawing loop in the order that I want them drawn but this will not work in this case. Can anyone see a simple way that I can get the code below to draw my objcts in their correct ZOrder positions? Thanks for any help, Jason. SuperStrict Type TEntity Global List:TList=New TList Field XPosition:Int Field YPosition:Int Field ZOrder:Int Method New() ListAddLast(List,Self) End Method Method Draw() Abstract Function DrawAll() Local Entity:TEntity For Entity=EachIn TEntity.List Entity.Draw DrawText Entity.ZOrder,Entity.XPosition+20,Entity.YPosition+18 Next End Function End Type Type TPlayer Extends TEntity Method Draw() SetColor 255,0,0 DrawRect XPosition,YPosition,50,50 SetColor 255,255,255 End Method End Type Type TEnemy Extends TEntity Method Draw() SetColor 255,255,0 DrawRect XPosition,YPosition,50,50 SetColor 255,255,255 SetColor 0,0,255 DrawRect XPosition+5,YPosition+5,50-10,50-10 SetColor 255,255,255 End Method End Type Graphics(640,480,0,60) Local Player:TPlayer=New TPlayer Player.XPosition=50 Player.YPosition=50 Player.ZOrder=1 Local Enemy1:TEnemy=New TEnemy Enemy1.XPosition=80 Enemy1.YPosition=80 Enemy1.ZOrder=2 Local Enemy2:TEnemy=New TEnemy Enemy2.XPosition=110 Enemy2.YPosition=110 Enemy2.ZOrder=3 While Not KeyHit(KEY_ESCAPE) Cls If KeyHit(KEY_SPACE) Player.ZOrder=Rand(1,3) Enemy1.ZOrder=Rand(1,3) Enemy2.ZOrder=Rand(1,3) EndIf TEntity.DrawAll() Flip Wend End |
| ||
You can make your own comparison function for the TList.Sort method:Function DrawAll() Local Entity:TEntity Function zordercmp:Int(o1:Object,o2:Object) Local e1:tentity,e2:tentity e1:tentity=tentity(o1) e2:tentity=tentity(o2) If e1.zorder<e2.zorder Return 1 Else Return -1 EndIf End Function Tentity.List.Sort True,zordercmp For Entity=EachIn TEntity.List Entity.Draw DrawText Entity.ZOrder,Entity.XPosition+20,Entity.YPosition+18 Next End Function |
| ||
You need to create a sort function.Function SortEntityList_Z:Int(p1:TEntity, p2:TEntity) If p1 And p2 Return p1.ZOrder - p2.ZOrder End If End Function And just before you start drawing: TEntity.List.Sort(True, SortEntityList_Z) Edit: Ah, Warpy beat me to it. Must say that in my original code my SortEntityList_Z function also only accepted Object types. I'm not sure anymore if it's required, but it think so. Couldn't test it. |
| ||
Thanks guys, I was doing something like, Select Entity.ZOrder Case 1 Entity.DrawAll Case 2 Entity.DrawAll Case 3 Entity.DrawAll End Select Which I assumed would work and I couldn`t see why it didn`t. Is there a flaw in my logic? Actually, are there any other ways to do this without using this list sorting method as I`m finding it a little hard to understand in practice. I`ve implemented it and it works but I`d rather have a way that I can understand. The BMax docs aren`t helping as they offer no real explanation to the technique that you are both using. The parts that I do not understand are the (o1:object,o2:object) part, what are objects in this case exactly? and the e1:tentity=tentity(o1) part. We have already declared e1 as a tentity type so why do we then go on to say =tentity(o1)? Why is the (o1) in brackets here? Sorry if this sounds stupid but I haven`t encountered this before. Thanks for any further help. Jason. Function zordercmp:Int(o1:Object,o2:Object) Local e1:tentity,e2:tentity e1:tentity=tentity(o1) e2:tentity=tentity(o2) If e1.zorder<e2.zorder Return 1 Else Return -1 EndIf End Function |
| ||
changing your draw function in your first post to this will helpFunction DrawAll(zmax:Int) Local Entity:TEntity For Local i:Int = 1 To zmax For Entity=EachIn TEntity.List If entity.zorder = i Then Entity.Draw DrawText Entity.ZOrder,Entity.XPosition+20,Entity.YPosition+18 EndIf Next Next End Function now when you call drawall you must include the maximum z order and the zorder variable cannot be 0 or it won't be drawn |
| ||
I was doing something like, Select Entity.ZOrder Case 1 Entity.DrawAll Case 2 Entity.DrawAll Case 3 Entity.DrawAll End Select Shouldn't that be Entity.Draw() in each case instead of DrawAll() From the looks of your code above, you're drawing every entity multiple times on multiple layers. EDIT: Didn't see Nate's reply above. He kinda already covered this. |
| ||
I do it kind of a lame way but it works for me:Method Sortz() list.clear() Local link:TLink List.addfirst(point[0]) For Local i:Int = 1 Until 13 Local p:t3point = point[i] link = list.FirstLink() Repeat If p.sc <= t3point(link.value()).sc Then 'sc is the z component in my point List.insertbeforelink(p,link) Exit EndIf link = link.nextlink() If link = Null Then list.addlast(p) Exit EndIf Forever Next End Method I don't need it to be too fast so its fine. |
| ||
So, to explain the List Sort method: Every TList has a built-in method which sorts the objects. Normally, it sorts based on the memory address, I think, but you can define your own comparison function to do what you want. The comparison function has to take two Objects as its arguments. An 'Object' is like the base class in blitzmax - every data type is derived from the Object type. What this means is that once the entities have been passed into our comparison function, they need to be 'cast' back to the type TEntity so that the program can have access to the entity's fields and methods. You can cast something by using the form 'userobject:UserType = UserType( baseobject )'. It's a bit like a function that turns the given object into the right type. (by the way, the 'True' argument in the TList.Sort line just means that you want things in ascending order, not descending) |
| ||
That`s much clearer thanks. I wish the docs included clear explanations like yours. Thanks to everyone else as well for your examples, each of them has helped me to understand the concept in different ways. Jason. |