Sik wrote:
This works when an object is deleting itself, it won't work when you're deleting another object instead.
Only an object can delete itself in my engine, and I think this is a good thing, because objects may have a bit of cleaning up to do before dying, and it's not nice to let others clean up your mess.
An object can request another one to delete itself, though.
Anyway, since this is a thread about programming techniques, I guess I'll show how I handle my linked lists. This is 6502 code though, since my console of choice is the NES, hopefully that won't be a problem. I also use some ca65 features, but those should be self-explanatory.
I use several linked lists to control my objects: one for the empty slots, and one for each group of active objects. When the level first starts, the groups are all empty, so the indices that indicate the start of each list are all invalid pointers:
Code:
;empty all groups
lda #$ff
.repeat Object::GROUP_COUNT, Group
sta Object::FirstObjects+Group
.endrepeat
The list of empty slots, on the other hand, is full, so this is how it's initialized:
Code:
;create a linked list of 24 empty object slots
lda #$ff
ldx #$17
: sta Object::InstancesNext, x
txa
dex
bpl :-
sta Object::FirstEmptySlot
This just makes each slot point to the next (except the last slot, gets an invalid index to signal the end of the list), and makes the
Object::FirstEmptySlot variable indicate the first slot. I do it backwards because it's slightly faster.
This function removes an empty slot from the list so you can use it:
Code:
;get the index of the second empty slot
lda Object::InstancesNext, x
;get the index of the first empty slot
ldx Object::FirstEmptySlot
bmi Return
;make the second empty slot the first
sta Object::FirstEmptySlot
Return:
;slot index now in X
rts
If there are no more free slots, $ff is returned.
I should move the lda to the top though, so the state of the N flag after the ldx is preserved, and I can just check N to see whether X contains a valid slot index. EDIT: DONE!
Now this adds the slot specified in the X register to one of the groups:
Code:
;add the current object to a group of objects
lda Object::FirstObjects+Group
sta Object::InstancesNext, x
stx Object::FirstObjects+Group
rts
I made one function for each group to keep things fast, but you could just as well specify the group using the Y register and accomplish the task with a few more instructions.
Anyway, once the object dies, comes a slightly more complicated procedure, which is removing the slot specified in the X register from the group:
Code:
;remove the current object from a group of objects
lda Object::InstancesNext, x
ldy Object::Previous
bmi :+
sta Object::InstancesNext, y
rts
: sta Object::FirstObjects+Group
rts
If there's no previous object (the current one is the first), the next one becomes the first. Otherwise, overwrite the previous object's "next" field. Again, the group index is hardcoded and I have one function for each group, but you can generalize it at the cost of making the code slightly more complex.
The last step is to return the slot specified in the X register to the list of free slots:
Code:
;make the first empty slot the second
lda Object::FirstEmptySlot
sta Object::InstancesNext, x
;make this the first empty slot
stx Object::FirstEmptySlot
;return
rts
As you can see, all the functions are fairly short and straightforward. I can only see advantages in managing slots using linked lists instead of searches, specially if you have many slots. Grouping objects is also great for performance, because you can limit the object interactions (collisions!) by checking only the groups that are relevant to each object.