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 )
Next
Also 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 :) |