Problem with Types ... Guru needed please!

Blitz3D Forums/Blitz3D Programming/Problem with Types ... Guru needed please!

Aaaaarggghhhhh!
Help me please... !

After I thought I got it with types - I must admit that I *don't*

This is my Problem:

I have some characters moving around my gamespace (animMeshes)
with bones animating...

I want to be able to record their movement in space
using a simple event system, that stores a characters
x,y,z, rotation and some other data on a "stack".
Each character has its own stack.

This is what I would like to have... in a very short version :D

First I tried types within types like this:

type character
   field id$
   ...
   eventstack.evnt
end type


Then I figured out, that they obviously dont work...
I used a workaround that I found somewhere on the net
but that was to complicated/confusing in the end...

--> So I came to this idea:
I simply use an array of types and every character gets
one of these arrayentries as their eventlist, when I create it
So I can do something like this to loop through all events:

for eventlist(myCharacter\eventlist_id).evnt = each evnt
   ...
next


And I tried out this little code to see if it is possible at all
Type evnt
	Field a
	Field b
End Type

Dim eventlist.evnt(5)

For i = 1 To 5

	eventlist(i) = New evnt

	eventlist(i)\a = i
	eventlist(i)\b = i * 10	
		
Next

For i = 1 To 5

	Print "Eventlist " + i + ":"
	
	For eventlist.evnt(i) = Each evnt
		Print eventlist(i)\a
		Print eventlist(i)\b
	Next

	Print "---"

Next

WaitKey()


The program should output this:
(At least I think it should...)

Eventlist 1:
1
10
---
Eventlist 2:
2
20
---
Eventlist 3:
3
30
--- etc...

But it outputs:

Eventlist 1:
1
10
2
20
3
30
4
40
5
50
--- etc.

Am I doing something wrong? If yes, what?

I have also read this in the Language Reference:

"You can create variables or arrays of custom types using a '.' type tag followed by the type name. For example:

Global mine.MyType Dim all_mine.MyType( 100 ) "

But how do I access this array then...


******* Please help me folks! *******
It's probably just a little typo in my code... But I dont
get it...

And sorry, if this has been asked 1000 times before...
No search at the moment...

Nice day, and thanks for your attention

hed

Type evnt
	Field ID
	Field a
	Field b
End Type

Dim eventlist.evnt(5)

For i = 1 To 5

	eventlist(i) = New evnt

	eventlist(i)\ID=i
	eventlist(i)\a = i
	eventlist(i)\b = i * 10	
		
Next

For i = 1 To 5

	Print "Eventlist " + i + ":"
	
	For eventlist.evnt(i) = Each evnt
		If eventlist(i)\ID=I
			Print eventlist(i)\a
			Print eventlist(i)\b
		EndIf
	Next

	Print "---"

Next

WaitKey()


For each always count all the records of the type.

Yeah, types are confusing!! Your output loop should be like this:

For i = 1 To 5

Print "Eventlist " + i + ":"

Print eventlist(i)\a
Print eventlist(i)\b

Print "---"

Next

Rhy :)

Or, you could use a blitz array in a type collection:
BUT, you would be limited. You would have to say how many array slots you want before hand.


Type Character
   Field x,y,z
   Field mesh
   Field health
   Field Prev_X_Pos[100]
   Field Prev_Y_Pos[100]
   Field Prev_Z_Pos[100]
End Type


But, that way, you could simply loop round once you got to 100, that way, keeping the record smaller, and keep a pointer saying the last record.

The types within types must be fields, and have to be created separately. You could also use banks within types to save the handles (Handle()) for the types within types, and get them with Object(). Note that if you use For Each with the types within types, it'll go through every instance of the type, no matter are they in arrays or within other types.

Const Max_Events% = 50

Type Event
	Field a%
	Field b%
End Type


Type Character
	Field id$
	;...
	Field Eventstack.Event[Max_Events%]		;'Blitz' array of types
End Type

;Blitz arrays can be used as local arrays in functions
;or as arrays within types. Use a[n] instead of Dim a(n)
;B-arrays have the following limitations:
;-Number of cells must be constant (Here I've used a constant (Const Max_Events), but you can use normal number (Event[50])
;-Just one dimension  (can't do [50, 50])


;Function to create a new Character-instance and the Event-types within it
Function CreateCharacterType.Character()
	Local C.Character	;Local type instance-handle, returned by the function
	Local i%			;Loop-index

	;Create a new instance of Character named C
	C.Character = New Character

	;Create the Event-types within the Character-type
	For i = 0 To Max_Events
		C\EventStack.Event[i] = New Event
	Next

	Return C.Character
End Function



;Test program:

;Create 21 instances of type Character
For i = 0 To 20
	C.Character = CreateCharacterType.Character()		;.Character can be omitted
	;Fill the id
	C\id$ = "Character " + i
	
	;Fill the Event-types for each
	For j = 0 To Max_Events
		C\EventStack[j]\a% = j * i
		C\EventStack[j]\b% = j + (i*i)
	Next
Next

;Print out the arrays
For C.Character = Each Character
	Print "Character ID:" + C\id$
	
	;Go through the event-types
	For i = 0 To Max_Events%
		;Locate 20, 0
		Print "C\EventStack["+i+"]\A% = "+C\EventStack[i]\a% + "  ...\B% = " + C\EventStack[i]\b%
		Delay 5
	Next
Next

WaitKey


Thanks guys for your replies! And all the ideas!

But I think it just can't be done in Blitz :(
At least not this way...

@Ezbe: You idea works pretty good - thanks a ton for the
work on the code. The only problem is that this wouldnt be
a "stack" - what I would need in my app. It's limited
by MaxEvents%... And character can have 1 event or 100.000 (worst case - most unlikely... but possible)

But I had a better idea today: I simply write "event-tracks"
to the harddisk and read them in some sort of a cache with
a fixed number of events ala Ezbe's idea. Would be also more
flexible to me for the app I have in mind.

But thanks a ton again for your replies!

hed

As I posted earlier, you could use banks to hold the handles to subtypes (types within types), this way you could have any number of event-types within the another type. I'll edit the example code to use banks for the event-type handles.


Edit: Here's the example with banks:


Type Event
	Field a%
	Field b%
End Type


Type Character
	Field id$

	Field SubTypeBank%			;Bank to hold subtype handles
End Type


;Function to create a new Character-instance and the bank to hold the subtype-handles
Function CreateCharacterType.Character()
	Local C.Character	;Local type instance-handle, returned by the function
	Local i%			;Loop-index

	;Create a new instance of Character named C
	C.Character = New Character

	;Create the bank
	C\SubTypeBank% = CreateBank(0)
	
	Return C.Character
End Function


;Function to add a event-type within the character-type, and store the handle in a bank
Function AddEvent(C.Character, A% = 0, B% = 0)
	
	Local Size%, Index%
	Local Event.Event

	;Check that we got valid character-type
	If C.Character = Null Then
		DebugLog "AddEvent: Character-parameter is null"
		Return -1
	EndIf
	
	;Get the current bank size
	Size% = BankSize(C\SubTypeBank%)
	
	;Get the index
	Index% = (Size% + 4) / 4
	
	;Add one byte to bank size
	ResizeBank C\SubTypeBank, Size% + 4
	
	;Create new event-instance
	Event.Event = New Event
	
	;Set the values for Event-fields
	Event\A% = A%
	Event\B% = B%

	;Save the type-handle to bank
	PokeInt C\SubTypeBank, Size, Handle(Event.Event)

	Return Index% 	;Returns the index of event
End Function


;Get event from within Character-type
Function GetEvent.Event(C.Character, Index%)

	Local Size%, TypeHandle%
	Local Event.Event

	;Check that we got valid character-type
	If C.Character = Null Then
		DebugLog "GetEvent: Character-parameter is null"
		Return Null
	EndIf
	
	
	;Get the current bank size
	Size% = BankSize(C\SubTypeBank%)

	;Change the index to match offset
	Index% = (Index%-1) * 4

	If (Size%-4) < Index% Then
		DebugLog "GetEvent: Index out of range: " + (Index/4 +1)
		Return Null
	EndIf

	TypeHandle% = PeekInt(C\SubTypeBank, Index%)
	

	Event.Event = Object.Event(TypeHandle%)

	Return Event.Event

End Function


;Get number of event-types within characters subtype-bank
Function GetNumberOfEvents(C.Character)

	;Check that we got valid character-type
	If C.Character = Null Then
		DebugLog "GetNumberOfEvents: Character-parameter is null"
		Return 0
	EndIf

	Return (BankSize(C\SubTypeBank) / 4)

End Function



;Function to delete a 4-byte value from bank and move all the values after it one step 'backwards'
;Originally by Noel Cower, I think(?), made some changes
Function EraseObject(Bank, Index%)
	Local Size%, N%, R%
	Local Event.Event

	Size% = BankSize(Bank)

	Index% = Index% - 1

    If Size > Index*4 Then

    	If Index <= Size Then
    	   	R% =  PeekInt(Bank,Index*4)

			;Get the event
			Event.Event = Object.Event(R%)
			;Delete the event
			Delete Event.Event

			;Get rid of the handle in the bank
	       	If (Index * 4) = Size-4 Then
	       		PokeInt(Bank,(Index)*4,0)
		      	ResizeBank(Bank,Size-4)
       		Else
	       		n = Index * 4
		      	While n < Size - 4
			     	PokeInt(Bank,n,PeekInt(Bank,n+4))
    				n = n + 4
	       		Wend
		      	ResizeBank(Bank,Size-4)
    		EndIf
   	    EndIf

        Return R
    Else
        DebugLog("EraseObject: Index out of range: " + Index%)
        Return 0
    EndIf
End Function



;Test program:

;Create 20 instances of type Character
For i = 1 To 20
	C.Character = CreateCharacterType.Character()		;.Character can be omitted
	;Fill the id
	C\id$ = "Character " + i
	
	;Create 10 events to each
	For j = 1 To 10
		AddEvent(C.Character, i*i, i+j)
	Next
Next

;Let's remove event number 5 from the last characters event list
EraseObject(C\SubTypeBank%, 5)

;Now, when we print out the events, the last character has only 9 events, and others have 10
;The event number 5 was removed, so event nr 6 = 5, 7 = 6, 8 = 7 etc. as the events after the deleted
;were rearranged 'one step backwards' within the bank (Thanks to Noel's EraseObject -function)
;You can notice the change in the B%-value after the 4th event


;Print out the arrays
For C.Character = Each Character
	Print "Character ID:" + C\id$

	For i = 1 To GetNumberOfEvents(C.Character)
		Event.Event = GetEvent(C.Character, i%)
		;After you get the Event-type, you can change the fields, pass it to functions, etc.
		;If the index is out of range, GetEvent will return a null-type, in which case the print-line
		;will cause an error message about 'object not existing'
		Print i+". Event\A% = "+Event\a% + "  ...\B% = " + Event\b%
	Next

Next

WaitKey




Edit #2: Whoopsie, forgot to make the EraseObject-function delete the erased event-type instance too, fixed now ;)

hed, if you really want to store your events for each character in a stack (LIFO - Last In First Out) then you can do something like the following:

Type eventT
	Field a
	Field b
	Field next_event.eventT
End Type

Type characterT
	Field ID
	Field stack.eventT
End Type

; Create a character.
my_char.characterT = New characterT
my_char\ID = 1

; Create an event.
event.eventT = New eventT
event\a = 1
event\b = 2

; Push (add) event to character's stack.
push_event(my_char,event)

; Pop (get) event from top of character's stack.
event.eventT = pop_event(my_char)

If event <> Null
	; Do stuff with the event.
	Print event\a
	Print event\b
	
	; Delete it.
	Delete event
EndIf

;
; Place specified event on top of character's stack.
;
Function push_event(c.characterT, e.eventT)

	e\next_event = c\stack
	c\stack = e
	
End Function

;
; Retrieve event from top of character's stack.
;
Function pop_event.eventT(c.characterT)

	e.eventT = c\stack

	If e <> Null Then c\stack = e\next_event
	
	Return e

End Function


[EDIT] oops. had a couple of typos.

@Ezbe: Yes, I thought about using banks too...
The only thing that makes me some trouble (personally)
are the good old peek and poke commands... Not that I have
any fear into going verrrry deep into the cpu (ok the memory
chips in this case) - but I think thats horror to debug...

But your code looks really great! Thanks a ton for it...

@big10p: Not bad the idea of using a pointer to the next
event within one event! I think about it...
Thanks!

[cunfusion]Oh man... I had the feeling I fully understand types...
Now I have the certain feeling I know nothing about it...
[/confusion]

:D

nice day @ all,
hed