Hey IanM, two ideas for your excellent utilities.
1) On the object grouping, I've worked out a little modified version that allows objects to be assigned to each other, as in a parent-child style relationship. This is very useful for managing dependent groups of objects. One example would be stars-->planets-->satellites. There are far more uses - such as buildings-->furniture-->smallStuff, perhaps for un-excluding objects within the building when the building is entered. Below is a little demo of this coded in DBPro. It works pretty fast (it's the 2D lines that are slowing things down - rem them out to see).
REM Project: Object Association
REM Created: 4/14/2009 9:19:45 AM
REM
REM ***** Main Source File *****
REM
`==========================================================================
`Demo======================================================================
`==========================================================================
`Remstart
Sync On:Sync Rate 0:AutoCam Off
Color Backdrop 0
_Initialize_Object_Association()
`Create a set of objects
Color as DWord
For i = 1 to 200
Make Object Cube i,2
Color=RGB(128,128,128)
Color Object i,Color
Set Object Emissive i,Color
Repeat
Position Object i,Rnd(100)-50,Rnd(100)-50,100
Until Object Collision(i,0)=0
If i=1
Position Object i,-60,0,100
Color Object i,RGB(0,255,0)
EndIf
If i=200
Position Object i,60,0,100
Color Object i,RGB(255,0,255)
EndIf
Next i
`Create random links
For i = 1 to 1000
Repeat
Obj1=Rnd(199)+1
Repeat
Obj2=Rnd(199)+1
Until Obj1<>Obj2
Until _Objects_Are_Linked(Obj1,Obj2)<>1 and _Objects_Are_Linked(Obj1,Obj2)<>3
_Associate_Objects(Obj1,Obj2)
Next i
StartFlag=1
Do
If StartFlag
ObjID=1
StartFlag=0
Else
ObjID=Pick Object(MouseX(),MouseY(),1,200)
EndIf
For i = 2 to 199
Color Object i,RGB(128,128,128)
Next i
Color Object 1,RGB(0,255,0)
Color Object 200,RGB(255,0,255)
ConnectFlag=0
If ObjID>0
_Create_Child_Association_List(ObjID)
_Create_Parent_Association_List(ObjID)
x1=Object Screen X(ObjID)
y1=Object Screen Y(ObjID)
EndIf
Lock Pixels
For i=0 to Array Count(ChildList())
x2=Object Screen X(ChildList(i))
y2=Object Screen Y(ChildList(i))
Line x1,y1,x2,y2,Rgb(255,0,0)
Color Object ChildList(i),RGB(255,0,0)
Next i
For i=0 to Array Count(ParentList())
x2=Object Screen X(ParentList(i))
y2=Object Screen Y(ParentList(i))
Line x1,y1,x2,y2,Rgb(0,0,255)
Color Object ParentList(i),RGB(0,0,255)
Next i
Unlock Pixels
Set Cursor 0,0
Print Screen FPS()
Sync
Loop
`Remend
`==========================================================================
`Object Association========================================================
`==========================================================================
REM No Child Object Left Behind
Function _Initialize_Object_Association()
Dim InitObjAssoc(0)
If InitObjAssoc(0) Then ExitFunction
InitObjAssoc(0)=1
Dim ChildList(-1) as DWord
Dim ParentList(-1) as DWord
Initialize_Array_Object_Association()
EndFunction
`Creates a list [ChildList()] of all the child-objects of the provided parent object.
Function _Create_Child_Association_List(ParentObjectID as DWord)
_Initialize_Object_Association()
Dim ChildList(-1) as DWord
index=Object_Association_Find_Entity(ParentObjectID)
if index<0 Then ExitFunction
Split String Object_Association(index).ObjectList,","
For i = 1 to Split Count()
Array Insert At Bottom ChildList()
ChildList(i-1)=Val(Get Split Word$(i))
Next i
EndFunction
`Creates a list [ParentList()] of all the parent-objects of the provided child object.
Function _Create_Parent_Association_List(ChildObjectID as DWord)
_Initialize_Object_Association()
Dim ParentList(-1) as DWord
index=Child_Association_Find_Entity(ChildObjectID)
if index<0 Then ExitFunction
Split String Child_Association(index).ObjectList,","
For i = 1 to Split Count()
Array Insert At Bottom ParentList()
ParentList(i-1)=Val(Get Split Word$(i))
Next i
EndFunction
`Creates a new Parent-to-Child association between the two objects provided.
Function _Associate_Objects(ParentObjectID as DWord, ChildObjectID as DWord)
_Initialize_Object_Association()
`Debug(Str$(ParentObjectID)+" - "+Str$(ChildObjectID),0)
Link=_Objects_Are_Linked(ParentObjectID, ChildObjectID)
`Link already is established, so do nothing
If Link=1 or link=3 Then Exitfunction
index=Object_Association_Find_Entity(ParentObjectID)
If index<0
index=Object_Association_Add_EntityID(ParentObjectID)
Object_Association(index).ObjectList=""
EndIf
If Object_Association(index).ObjectList=""
Object_Association(index).ObjectList=Str$(ChildObjectID)
Else
Object_Association(index).ObjectList=Object_Association(index).ObjectList+","+Str$(ChildObjectID)
EndIf
`Debug(">>"+Str$(index)+": "+Object_Association(index).ObjectList,0)
index=Child_Association_Find_Entity(ChildObjectID)
If index<0
index=Child_Association_Add_EntityID(ChildObjectID)
Child_Association(index).ObjectList=""
EndIf
If Child_Association(index).ObjectList=""
Child_Association(index).ObjectList=Str$(ParentObjectID)
Else
Child_Association(index).ObjectList=Child_Association(index).ObjectList+","+Str$(ParentObjectID)
EndIf
`Debug(">>"+Str$(index)+": "+Child_Association(index).ObjectList,0)
EndFunction
`Returns a 0 if the objects are not linked
`Returns a 1 if Object1 is the parent object
`Returns a 2 if Object2 is the parent object
`Returns a 3 if objects are mutually linked (both directions)
Function _Objects_Are_Linked(Object1 as Dword, Object2 as DWord)
_Initialize_Object_Association()
LinkFlag=0
index=Object_Association_Find_Entity(Object1)
If index>-1
Split String Object_Association(index).ObjectList,","
For i = 1 to Split Count()
If val(Get Split Word$(i))=Object2
LinkFlag=1
Exit
EndIf
Next i
EndIf
index=Object_Association_Find_Entity(Object2)
If index>-1
Split String Object_Association(index).ObjectList,","
For i = 1 to Split Count()
If val(Get Split Word$(i))=Object1
LinkFlag=LinkFlag+2
ExitFunction LinkFlag
EndIf
Next i
EndIf
EndFunction LinkFlag
`=================Entity Data Navigation Array (E.D.N.A.)================
`======================Sort-n-Search Functionality=======================
`Note: This library of functions is intended for use a sub modules.
Type Object_Association_Type
EntityID as Integer
ObjectList as String
EndType
Function Initialize_Array_Object_Association()
Dim InitArrayObject_Association(0)
If InitArrayObject_Association(0) Then ExitFunction
InitArrayObject_Association(0)=1
Dim Object_Association(999) as Object_Association_Type
Dim Object_AssociationTop(0) as Integer
Object_AssociationTop(0)=-1
EndFunction
`Object_Association_Find_Entity(EntityID as Integer):Return Integer
`Binary searches through a sorted array for the specified EntityID.
`The return integer EntityID is the index of the array element for which the EntityID was found.
`If there are multiples of the same EntityID within the array, any one of the indexes may be returned.
`If the EntityID is not found, a -1 is returned.
Function Object_Association_Find_Entity(EntityID as Integer)
Initialize_Array_Object_Association()
Top=Object_AssociationTop(0)
Half=(Top+1)/2
If Top<0 Then ExitFunction -1
If EntityID<Object_Association(0).EntityID Then ExitFunction -1
If EntityID=Object_Association(0).EntityID Then ExitFunction 0
If EntityID=Object_Association(Top).EntityID Then ExitFunction Top
If EntityID>Object_Association(Top).EntityID Then ExitFunction -1
BSearch=Half
For i = 0 to 16:`Note, 15 is 2 Bytes worth of searching, or 2^15
If BSearch<1 then BSearch=1
If BSearch>Top then BSearch=Top
If EntityID=Object_Association(BSearch).EntityID Then ExitFunction BSearch
Half=(Half+1)/2
If Half<1 then Half=1
BSearch=BSearch+Half*(((EntityID=>Object_Association(BSearch).EntityID)-(EntityID<Object_Association(BSearch).EntityID)))
Next i
EndFunction -1
`Object_Association_Add_EntityID(EntityID As Integer):Return Integer
`Performs a binary search for an index location in which to insert a new array element
`for the specified EntityID in sort order of ascending EntityID's. The array element is added
`and the EntityID is recorded the new array element.
`The return value is the index (array element) where the new EntityID was placed.
Function Object_Association_Add_EntityID(EntityID As Integer)
Index=Object_Association_Find_EntityID_Place(EntityID)
Object_Association_Insert_Element(Index)
Object_Association(Index).EntityID=EntityID
EndFunction Index
`Object_Association_Insert_Element(Index as Integer)
`Increases the array by adding in an element at the specified index.
`If the Index is larger than the array size, the new element is added at
`the end of the array. Otherwise, the new element is inserted the specified
`index.
Function Object_Association_Insert_Element(Index as Integer)
Initialize_Array_Object_Association()
Object_AssociationTop(0)=Object_AssociationTop(0)+1
If Object_AssociationTop(0)=>Array Count(Object_Association())
Array Insert At Bottom Object_Association()
EndIf
If Index=>Object_AssociationTop(0) Then ExitFunction
For i =Object_AssociationTop(0)-1 To Index Step -1
Object_Association(i+1)=Object_Association(i)
Next i
EndFunction
`Object_Association_Find_EntityID_Place(EntityID as Integer):Return Integer
`This function is similar to the Object_Association_Find_EntityID() function in that it
`searches for a EntityID within a sorted array. However, if the EntityID is
`not found in this function, an index EntityID is returned where the search EntityID
`"fits" within the sorted array. For example: The array - 1,6,8,9 and the EntityID
`is 7, the return element will be 2 since 7 falls between elements 1 and 2 (6 & 9).
`If the EntityID is lower than any EntityID within the array, a 0 is returned.
`If the EntityID is larger than any EntityID within the array, Array Count()+1 is returned.
Function Object_Association_Find_EntityID_Place(EntityID as Integer)
Initialize_Array_Object_Association()
Top=Object_AssociationTop(0)
Half=(Top+1)/2
If Top<0 Then ExitFunction 0
If EntityID<=Object_Association(0).EntityID Then ExitFunction 0
If EntityID=>Object_Association(Top).EntityID Then ExitFunction Top+1
BSearch=Half
For i = 0 to 16:`Note, 15 is 2 Bytes worth of searching, or 2^15 elements.
If BSearch<1 then BSearch=1
If BSearch>Top then BSearch=Top
If EntityID=Object_Association(BSearch).EntityID Then ExitFunction BSearch
If EntityID>Object_Association(BSearch-1).EntityID And EntityID<=Object_Association(BSearch).EntityID then ExitFunction BSearch
Half=(Half+1)/2
If Half<1 then Half=1
BSearch=BSearch+Half*(((EntityID=>Object_Association(BSearch).EntityID)-(EntityID<Object_Association(BSearch).EntityID)))
Next i
Top=Top+1
EndFunction Top
`Object_Association_Delete_Element(Index as Integer)
`This function will delete an array element at the specified Index.
`If the index is not valid, the function will fail without exiting the program.
Function Object_Association_Delete_Element(Index as Integer)
Initialize_Array_Object_Association()
If Index<0 or Index>Object_AssociationTop(0) Then ExitFunction
Object_AssociationTop(0)=Object_AssociationTop(0)-1
For i = Index to Object_AssociationTop(0)
Object_Association(i)=Object_Association(i+1)
Next i
EndFunction
`=================Entity Data Navigation Array (E.D.N.A.)================
`======================Sort-n-Search Functionality=======================
`Created 04/14/09 11:03:26
`Note: This library of functions is intended for use a sub modules.
Type Child_Association_Type
EntityID as Integer
ObjectList as String
EndType
Function Initialize_Array_Child_Association()
Dim InitArrayChild_Association(0)
If InitArrayChild_Association(0) Then ExitFunction
InitArrayChild_Association(0)=1
Dim Child_Association(999) as Child_Association_Type
Dim Child_AssociationTop(0) as Integer
Child_AssociationTop(0)=-1
EndFunction
`Child_Association_Find_Entity(EntityID as Integer):Return Integer
`Binary searches through a sorted array for the specified EntityID.
`The return integer EntityID is the index of the array element for which the EntityID was found.
`If there are multiples of the same EntityID within the array, any one of the indexes may be returned.
`If the EntityID is not found, a -1 is returned.
Function Child_Association_Find_Entity(EntityID as Integer)
Initialize_Array_Child_Association()
Top=Child_AssociationTop(0)
Half=(Top+1)/2
If Top<0 Then ExitFunction -1
If EntityID<Child_Association(0).EntityID Then ExitFunction -1
If EntityID=Child_Association(0).EntityID Then ExitFunction 0
If EntityID=Child_Association(Top).EntityID Then ExitFunction Top
If EntityID>Child_Association(Top).EntityID Then ExitFunction -1
BSearch=Half
For i = 0 to 16:`Note, 15 is 2 Bytes worth of searching, or 2^15
If BSearch<1 then BSearch=1
If BSearch>Top then BSearch=Top
If EntityID=Child_Association(BSearch).EntityID Then ExitFunction BSearch
Half=(Half+1)/2
If Half<1 then Half=1
BSearch=BSearch+Half*(((EntityID=>Child_Association(BSearch).EntityID)-(EntityID<Child_Association(BSearch).EntityID)))
Next i
EndFunction -1
`Child_Association_Add_EntityID(EntityID As Integer):Return Integer
`Performs a binary search for an index location in which to insert a new array element
`for the specified EntityID in sort order of ascending EntityID's. The array element is added
`and the EntityID is recorded the new array element.
`The return value is the index (array element) where the new EntityID was placed.
Function Child_Association_Add_EntityID(EntityID As Integer)
Index=Child_Association_Find_EntityID_Place(EntityID)
Child_Association_Insert_Element(Index)
Child_Association(Index).EntityID=EntityID
EndFunction Index
`Child_Association_Insert_Element(Index as Integer)
`Increases the array by adding in an element at the specified index.
`If the Index is larger than the array size, the new element is added at
`the end of the array. Otherwise, the new element is inserted the specified
`index.
Function Child_Association_Insert_Element(Index as Integer)
Initialize_Array_Child_Association()
Child_AssociationTop(0)=Child_AssociationTop(0)+1
If Child_AssociationTop(0)=>Array Count(Child_Association())
Array Insert At Bottom Child_Association()
EndIf
If Index=>Child_AssociationTop(0) Then ExitFunction
For i =Child_AssociationTop(0)-1 To Index Step -1
Child_Association(i+1)=Child_Association(i)
Next i
EndFunction
`Child_Association_Find_EntityID_Place(EntityID as Integer):Return Integer
`This function is similar to the Child_Association_Find_EntityID() function in that it
`searches for a EntityID within a sorted array. However, if the EntityID is
`not found in this function, an index EntityID is returned where the search EntityID
`"fits" within the sorted array. For example: The array - 1,6,8,9 and the EntityID
`is 7, the return element will be 2 since 7 falls between elements 1 and 2 (6 & 9).
`If the EntityID is lower than any EntityID within the array, a 0 is returned.
`If the EntityID is larger than any EntityID within the array, Array Count()+1 is returned.
Function Child_Association_Find_EntityID_Place(EntityID as Integer)
Initialize_Array_Child_Association()
Top=Child_AssociationTop(0)
Half=(Top+1)/2
If Top<0 Then ExitFunction 0
If EntityID<=Child_Association(0).EntityID Then ExitFunction 0
If EntityID=>Child_Association(Top).EntityID Then ExitFunction Top+1
BSearch=Half
For i = 0 to 16:`Note, 15 is 2 Bytes worth of searching, or 2^15 elements.
If BSearch<1 then BSearch=1
If BSearch>Top then BSearch=Top
If EntityID=Child_Association(BSearch).EntityID Then ExitFunction BSearch
If EntityID>Child_Association(BSearch-1).EntityID And EntityID<=Child_Association(BSearch).EntityID then ExitFunction BSearch
Half=(Half+1)/2
If Half<1 then Half=1
BSearch=BSearch+Half*(((EntityID=>Child_Association(BSearch).EntityID)-(EntityID<Child_Association(BSearch).EntityID)))
Next i
Top=Top+1
EndFunction Top
`Child_Association_Delete_Element(Index as Integer)
`This function will delete an array element at the specified Index.
`If the index is not valid, the function will fail without exiting the program.
Function Child_Association_Delete_Element(Index as Integer)
Initialize_Array_Child_Association()
If Index<0 or Index>Child_AssociationTop(0) Then ExitFunction
Child_AssociationTop(0)=Child_AssociationTop(0)-1
For i = Index to Child_AssociationTop(0)
Child_Association(i)=Child_Association(i+1)
Next i
EndFunction
2) Based on the above work, it seems that the Split String could be expanded to include a form of data-storage. As you can see in the above code, string data was used to store the variable length array of data of children and parents for each object. This, of course, all came from your post a few back when you talked about storing data in strings and how fast your string manipulation is. So, here it is in a little more formal format. The ability to add data, modify data, and read data (I have not included a delete function). I have not tested this yet, but I expect this is slow and may ultimately have memory leak issues. But this code should be enough to demo what the heck I am talking about.
REM Project: String Data Storage
REM Created: 4/14/2009 10:23:25 PM
REM
REM ***** Main Source File *****
REM
TestString$=""
For i = 1 to 10
TestString$=_Store_Data_In_String(Str$(i),TestString$,i)
Print TestString$
Next i
For i = 1 to 10
n$=_Get_Data_From_String(TestString$,i)
n=val(n$)
Text i*30,170,n$
Next i
Print
Print
TestString$=_Store_Data_In_String(Str$(999),TestString$,5)
For i = 1 to 11
n$=_Get_Data_From_String(TestString$,i)
n=val(n$)
Text i*30,190,n$
Next i
TestString$=_Update_Data_In_String(Str$(4.5),TestString$,5)
For i = 1 to 11
n$=_Get_Data_From_String(TestString$,i)
n=val(n$)
Text i*30,210,n$
Next i
Wait Key
End
Function _Store_Data_In_String(Data$,String$,Position)
Delimiter$="|"
NewString$=""
If String$=""
ExitFunction data$
EndIf
If Position <2
NewString$=Data$+Delimiter$+String$
ExitFunction NewString$
EndIf
Split String String$,Delimiter$
If Position>Split Count()
NewString$=String$
For i = Split Count()+1 To Position-1
NewString$=NewString$+Delimiter$
Next i
NewString$=NewString$+Delimiter$+Data$
ExitFunction NewString$
EndIf
For i = 1 to Position-1
NewString$=NewString$+Get Split Word$(i)+Delimiter$
Next i
NewString$=NewString$+Data$
For i= Position to Split Count()
NewString$=NewString$+Delimiter$+Get Split Word$(i)
Next i
EndFunction NewString$
Function _Get_Data_From_String(String$,Position)
If String$="" Then ExitFunction ""
Delimiter$="|"
If Position <1 Then ExitFunction ""
Split String String$,Delimiter$
If Position >Split Count() Then ExitFunction ""
Data$=Get Split Word$(Position)
EndFunction Data$
Function _Update_Data_In_String(Data$,String$,Position)
NewString$=""
Delimiter$="|"
If String$="" or Position <1
NewString$=_Store_Data_In_String(Data$,String$,Position)
ExitFunction NewString$
EndIf
Split String String$,Delimiter$
If Position > Split Count()
NewString$=_Store_Data_In_String(Data$,String$,Position)
ExitFunction NewString$
EndIf
For i = 1 to Position-1
NewString$=NewString$+Get Split Word$(i)+Delimiter$
Next i
NewString$=NewString$+Data$
For i = Position+1 to Split Count()
NewString$=NewString$+Delimiter$+Get Split Word$(i)
Next i
EndFunction NewString$
Open MMORPG: It's your game!