Problem with removing items from TList
BlitzMax Forums/BlitzMax Programming/Problem with removing items from TList
| ||
Hi In our game - Maggie the Gardener - we store every plant in TList. When player press right mouse button to remove a plant very often soft removes plants that are far away from the mouse pointer. As we can not see bugs in our code we believe that there is something wrong with TLists mechanism. Here is the code example: Method RemoveObjects(all=False) If(all) ClearList(objectsList) Return Else If(deleteTimer._ticks<4) Return For temp=EachIn objectsList If(temp.CollideWithCursor()) ListRemove(objectsList,temp) deleteTimer._ticks=0 soundEngine.PlaySfx("usowanie") Return EndIf Next EndIf End Method Method CollideWithCursor() ' If(MouseX()>x and MouseX()<x+ImageWidth(brush.bitmap)) If(MouseY()>y and MouseY()<y+ImageHeight(brush.bitmap)) ResetCollisions() CollideImage(brush.bitmap,x,y,0,0,1) If(CollideRect(MouseX(),MouseY(),1,1,1,0)) Return True EndIf EndIf Return False End Method This piece of code should be enougth to say if we are wrong or not. |
| ||
I'm sorry, but if you can't post decently formatted code I just can't help... |
| ||
Anawiki, What datatype are you storing in the TList. From your code it looks like integers. TList and integers don't mix I'm afraid. |
| ||
TList and integers don't mix I'm afraid. Unfortunately I think they do in non strict mode. |
| ||
Code is written in Strict mode. Object in list are of custom type. Here is the code once again: Method RemoveObjects(all=False) If(all) ClearList(objectsList) Return Else If(deleteTimer._ticks<4) Return For temp=EachIn objectsList If(temp.CollideWithCursor()) ListRemove(objectsList,temp) deleteTimer._ticks=0 soundEngine.PlaySfx("usowanie") Return EndIf Next EndIf End Method Method CollideWithCursor() If(MouseX()>x And MouseX()<x+ImageWidth(brush.bitmap)) If(MouseY()>y And MouseY()<y+ImageHeight(brush.bitmap)) ResetCollisions() CollideImage(brush.bitmap,x,y,0,0,1) If(CollideRect(MouseX(),MouseY(),1,1,1,0)) Return True EndIf EndIf Return False End Method |
| ||
Are you sure you are using Strict, I do not think that would compile, you have a variable called temp which is not declared (in the Foreach loop). If temp is an Int I do not think it will work like that. You can either make it an object or make it a string. Let us say you have TPlants in that list, then I would do something like this to loop it: (using Strict) For local Plant:TPlant = Eachin ObjectList If Plant.Collide() ObjectList.Remove( Plant ) NextAlso I would recommend using ObjectsList.Remove( temp ) instead of ListRemove(objectsList,temp) as it is easier to read, but that is merly personal preference :) Hope that helps. |
| ||
temp is declared as field. More code, maybe this time you can point me in some direction. TObject is a type that represents plants or other stuff. TGarden represents garden :D In this type I left only RemoveObjects method as others are not necessary.Type TObject ' Klasa reprezentuje obiekty narysowane w ogrodzie Field x,y,brush:TBrush Function create:TObject(tX,tY,bsh:TBrush) Local temp:TObject = New TObject temp.brush = bsh temp.x = tX - (ImageWidth(bsh.bitmap)/2) temp.y = tY - (ImageHeight(bsh.bitmap)/2) Return temp End Function Method paintObject(drawShadow=False) SetBlend(ALPHABLEND) SetAlpha(1) If(Not drawShadow) If(brush.bitmap) DrawImage(brush.bitmap,x,y) If (drawShadow) If(brush.shadow) DrawImage(brush.shadow,x,y) End Method Method Compare(otherObject:Object) ' Metoda porownuje pionowe polozenie obiektow, uzywana jest przez funkcje wbudowana SortList, potrzebne jest to do rysowania obiektow w okreslonej kolejnosci (z gory na dol) Local temp:TObject = TObject(otherObject) Return (y+ImageHeight(brush.bitmap)) - (temp.y+ImageHeight(temp.brush.bitmap)) End Method Method CollideWithCursor() ' Metoda sprawdza czy obiekt koliduje z kursorem myszy If(MouseX()>x And MouseX()<x+ImageWidth(brush.bitmap)) If(MouseY()>y And MouseY()<y+ImageHeight(brush.bitmap)) ResetCollisions() CollideImage(brush.bitmap,x,y,0,0,1) If(CollideRect(MouseX(),MouseY(),1,1,1,0)) Return True EndIf EndIf Return False End Method End Type Type TGarden Field objectsList:TList, temp:TObject Field lockLeft, lockRight Field coursor:TImage Field deleteTimer:TTimer ..... Method RemoveObjects(all=False) If(all) ClearList(objectsList) Return Else If(deleteTimer._ticks<4) Return For temp=EachIn objectsList If(temp.CollideWithCursor()) ListRemove(objectsList,temp) deleteTimer._ticks=0 soundEngine.PlaySfx("usowanie") Return EndIf Next EndIf End Method ...... end type |
| ||
If the problem here is what I think it is, then it's a known bug. ListRemove uses the Compare function to know when it has the correct object in the list. The default Compare will return 0 when self = object. Since your overridden Compare will return 0 any time self.x = TObject.x, the ListRemove function will think it found the object when it hasn't. You either need to find a way to never return 0 except for ListRemove, or write your own sort method, or don't use lists. |
| ||
Hold on, I just discovered something looking at the mod source. The TList.Sort() method takes a function as a parameter. Method Sort( ascending=True,compareFunc( o1:Object,o2:Object )=CompareObjects ) That means you don't have to override the compare function, You can just write your own and pass it to TList.Sort() and leave the COmpare function alone for the TList.Remove function. Here is a test code to show how it works. Type MyGreatType Field name:String Function MyGreatSort(m1:Object,m2:Object) If MyGreatType(m1).name > MyGreatType(m2).name Then Return 1 If MyGreatType(m1).name < MyGreatType(m2).name Then Return -1 Return 0 End Function End Type Local MyType:MyGreatType Local MyTypeList:TList = CreateList() For t = 0 To 20 MyType = New MyGreatType MyType.name = Mid("abcd",Rand(1,4),1)+"MyType"+t ListAddLast(MyTypeList,MyType) Next For MyType = EachIn MyTypeList Print MyType.name Next Print "Sorting...." MyTypeList.sort(True,MyGreatType.MyGreatSort) Print "Sorted." For MyType = EachIn MyTypeList Print MyType.name Next This is in version 1.20, don't know how it'll behave in older versions. |
| ||
TomToad, thanks a bunch. I was wondering how to use the new sort function. So in essence, dont override the compare method, create a separate compare function instead and then call the sort function accordingly. |
| ||
Yeup, that's the way it seems to work. It's definately not in version 1.12 so I don't know exactly when it was added. Looking through the docs, I see that the SortList function was changed also. Function SortList( list:TList,ascending=True,compareFunc( o1:Object,o2:Object )=CompareObjects ) Here it is: ***** 1.20 Release ***** + (BRL.LinkedList) Added optional CompareFunc parameter to SortList So it was added in the latest version. |
| ||
Nice fix, I did not know that myself :) |