Entraides et échanges autour de la technologie Scol - Informations and exchanges on the Scol technology
Vous pouvez changer la langue de l'interface une fois inscrit - You can change the language once registered
You are not logged in.
to re familiarize myself with scol for this winter's efforts (I hope to actually finish some project, however small, a plugit at least that others can use, maybe the throttle from last year, or using arkeon's avatar plugit to support user determined meshes for virtual meetings and, at my son's request, fps shooters), I made a script that creates objects, executes their functions, and destroys them by building and destroying lists. it puts the objects in one list and their unique indexes in another list, and minimizes the time consuming recursive list functions (searching through a list to find, do, add, or remove something) to one. maybe this could be used in a simple fps game, where the players are hiding behind structures that appear and disappear randomly.
i'm sure there are more elegant ways to do this. i wanted to write a script that could store unused indecies for objects in one list, so that when there were available indices, the vm would not have to iterate through an entire list. i was thinking of setting the maximum index each time a new object (cylinder) was created, but if the objects have different lifespans, I'm not sure if that would work.
struct Cylinder =[
Icylindernumber : I,
Icylinderindex : I,
Fradius : F,
Fheight : F,
funlifespan : Timer,
Ilifespanlength : I,
Sbirthfphrase : S,
Sdeathphrase : S,
fundyingclyinder : fun [Cylinder] S,
funreturnarea : fun [Cylinder] F,
funreturnvolume : fun[Cylinder] F,
fbirthfunction : fun[Cylinder] S,
fdeathfunction : fun[Cylinder] S
]mkCylinder;;
//global list of Cylinders to grow and shrink
typeof lCylinderlist=[Cylinder r1];;
//global list of intergers to grab for new cylinders if they are free and to hold indeces of dead cylinders
typeof lDeleted_cylinder_ids = [I r1];;
typeof ICylinder_counter= I;;
var Ihighest_Cylinder_Index= 0;;
//fun [Cylinder] F
fun returnarea(cylinder)=
PIf*. cylinder.Fradius;;
//fun [Cylinder] F
fun returnvolume(cylinder)=
(returnarea cylinder)*. cylinder.Fheight;;
//fun [Cylinder] S
fun birthphase(cylinder)=
_fooS strcatn "My name is: ":: (itoa(cylinder.Icylinderindex))::" and now I am being born, hello!"::nil;
_fooS strcatn "My lifespan is :":: (itoa (cylinder.Ilifespanlength)):: " milliseconds."::nil;;
//fun [Cylinder] S
fun deathphase(cylinder)=
_fooS strcatn "My name is: ":: (itoa(cylinder.Icylinderindex))::" and now I am dying, goodbye!"::nil;;
/* --------- */
// Miscelleanous
// Note : A function already exists for that in the standard library
fun removeItemInList (list, item)=
if list == nil then
nil
else
if item == hd list then
tl list
else
(hd list) :: removeItemInList tl list item;;
/* --------- */
//fun [] I
//get an id from lDeleted_cylinder_ids....if there are no ids available, return 0, once an index is encountered, return the index
fun get_deleted_cylinder_ID ()=
_fooS "get_deleted_cylinder_ID called";
let hd lDeleted_cylinder_ids -> head in
(
if (head == nil) then
(
// there are no available deleted cylinder indexes, they have been used up between the function calling this function and the execution
//of the line below
nil;
) else
(
_fooS strcatn "head of lDeleted_cylinder_ids is ":: (itoa head)::nil;
//remove head from lDeleted_cylinder_ids
set lDeleted_cylinder_ids= (tl lDeleted_cylinder_ids);
_fooS strcatn "the new head of the lDeleted_cylinder_ids list is: " ::(itoa(hd lDeleted_cylinder_ids))::nil;
_fooS strcatn "the head of the list in this function after resetting list is: ":: (itoa head)::nil;
head;
);
);;
//fun [[Cylinder r1] I] I
fun get_highest_id_from_cylinderlist (cylinderlist, id)=
//we want to get the highest Cylinder.Icylinderindex that exists in this list
if ((hd cylinderlist)==nil)&& ((sizelist lCylinderlist)==0) then
(
_fooS "there are no items in the list at all";
1;
)
else if ((hd cylinderlist)==nil)&& ((sizelist lCylinderlist)>0) then
(
_fooS "we are at the end of a list that has items in it";
_fooS strcat "the following value is the highest value found in the complete list is: " (itoa id);
//since we are making a new cylinder with an index that does not exist, increment global
//Ihighest_Cylinder_Index by 1 from the highest found id
set Ihighest_Cylinder_Index = id+1;
Ihighest_Cylinder_Index;
)
else
//we are not at the end of the list yet
(
//_fooS "there are items in the list and we are not at the end yet";
let hd cylinderlist -> cylinder in
let cylinder.Icylinderindex -> this_index in
if (this_index > id) then
(
set id = this_index;
//_fooS strcat "the highest id found so far is: " (itoa id);
//we havve the higghest id so far, recursively search through rest of list
//to see if we can find a higher id
get_highest_id_from_cylinderlist (tl cylinderlist) id;
)
else
(
//don't change the id, we have the highest found so far
//so we recursively search through rest of list
// _fooS strcat "the highest id found so far is: " (itoa id);
get_highest_id_from_cylinderlist (tl cylinderlist) id;
);
);;
//fun[] I
fun get_highest_id_from_all_lists()=
let get_deleted_cylinder_ID -> result in
(
//if there are no items in lDeleted_cylinder_ids, go search for highest id in lCylinderlist
if (result == nil) then
(
get_highest_id_from_cylinderlist lCylinderlist nil;
)
else
(
result;
);
);;
//fun [cylinder] lCylinderlist
fun delete_cylinder(timer, dcylinder)=
//destroy the timer
_deltimer timer;
//execute death function
exec dcylinder.fdeathfunction with [dcylinder];
//add the deleted cylinder index to the lDeleted_cylinder_ids list, so we can grab it if it is free and we add a new cylinder
let dcylinder.Icylinderindex -> lindex in
(
_fooS strcatn "cylinder with index number ":: (itoa lindex):: " has died"::nil;
//add index to lDeleted_cylinder_ids
set lDeleted_cylinder_ids =lindex:: lDeleted_cylinder_ids;
//decrement amount of cylinders in existence
set ICylinder_counter= ICylinder_counter-1;
//remove cylinder from lCylinderlist
set lCylinderlist= removeItemInList lCylinderlist dcylinder;
_fooS strcatn "there are now :" ::(itoa(sizelist lDeleted_cylinder_ids))::" cylinders in the lDeleted_cylinder_ids list."::nil;
_fooS "the list of deleted cylinder id's is below:";
_fooIdList lDeleted_cylinder_ids;
_fooS strcatn "there are now ":: (itoa (sizelist lCylinderlist))::" cylinders in the lCylinderlist. \n \n \n":: nil;
lCylinderlist;
);;
//fun [Cylinder Timer] Cylinder
fun makeCylinderTimer (sCylinder, lifespan)=
//assign the lifespan in milliseconds for our ephemeral cylinder
set sCylinder.Ilifespanlength = lifespan;
set sCylinder.funlifespan = _rfltimer _starttimer _channel lifespan @delete_cylinder sCylinder;
sCylinder;;
//fun [] Cylinder
fun add_cylinder()=
//whenever we add a cylinder, no matter where its id comes from, we are incemeneting the ICylinder_counter by one
set ICylinder_counter=ICylinder_counter+1;
//get cylinder id
let get_highest_id_from_all_lists -> id in
let mkCylinder [ICylinder_counter id 2.0 22.0 nil nil nil nil nil nil nil nil nil ]->lcylinder in
let rand/20 -> llifespan in
let makeCylinderTimer lcylinder llifespan-> lcylinder in
(
//assign birth and death functions
set lcylinder.fbirthfunction = @birthphase;
set lcylinder.fdeathfunction = @deathphase;
set lcylinder.funreturnarea = @returnvolume;
set lcylinder.funreturnvolume = @returnarea;
//execute birth function
_fooS "\n \n \n \n";
_fooS "new cylinder created!";
exec lcylinder.fbirthfunction with [lcylinder];
let exec lcylinder.funreturnarea with [lcylinder] ->result in
_fooS strcat "my area is " (ftoa result);
let exec lcylinder.funreturnvolume with [lcylinder] ->result in
_fooS strcat "my volume is " (ftoa result);
//add cylinder to global lCylinderlist
set lCylinderlist= lcylinder::lCylinderlist;
_fooS strcatn "there are now ":: (itoa (sizelist lCylinderlist))::" cylinders in the lCylinderlist.":: nil;
_fooS strcatn "the new cylinder id is: ":: (itoa id)::nil;
lcylinder;
);;
fun add_another_cylinder_after_timer(timer, param)=
_deltimer timer;
let 100 -> counter in
while (counter >0) do
(
add_cylinder;
set counter= counter-1;
);;
fun main()=
_showconsole;
let 20 -> counter in
while (counter >0) do
(
add_cylinder;
set counter= counter-1;
);
_rfltimer _starttimer _channel 4000 @add_another_cylinder_after_timer nil;;
[edited] as per most of Iri's suggestions.
Last edited by hebdemnobad (1-Dec-2015 20:47:37)
Offline
I still haven't figured how to configure bluefish so I can paste the code into posts correctly, here is the .pkg:
Offline
Well, few remarks in vrac.
//fun [] I
//get an id from lDeleted_cylinder_ids....if there are no ids available, return 0, once an index is encountered, return the index
fun get_deleted_cylinder_ID ()=
Are you sure that an index will never be equal at 0 ? If no, you should return nil instead if the deleted list is empty.
You should rename explicitely your variables. By example, in lDeleted_cylinder_ids, the first l for a list is ok. But lindex is an integer, not a list. Why this first l ? An i (iIndex by example) is more comprehensive for the reader. And if the second character is upper, keep this convention.
To optimize easily the memory, you should avoid to define uselessly some locale variables. By example :
fun add_cylinder()=
(...)
let @birthphase -> birth_function in
let @deathphase -> death_function in
let @returnvolume-> volume_function in
let @returnarea -> area_function in
(
//assign birth and death functions
set lcylinder.fbirthfunction = birth_function;
set lcylinder.fdeathfunction = death_function;
set lcylinder.funreturnarea = area_function;
set lcylinder.funreturnvolume = volume_function;
(...)
Write instead :
fun add_cylinder()=
(...)
(
//assign birth and death functions
set lcylinder.fbirthfunction = @birthphase ;
set lcylinder.fdeathfunction = @deathphase;
set lcylinder.funreturnarea = @returnvolume;
set lcylinder.funreturnvolume = @returnarea;
If i understand correctly, you want keep the index value when a cylinder is deleted ? Right ?
If several life span exist, set several lists may be another method, instead of a big list. One list by life span. It is an idea ...
Or, if you know, you could use an hash table (otherwise, forget that !).
A timer object (not only in Scol) is always a greedy object. Some timers are ok. A large number can be problematic, especially as they are destroyed to the first "top". Perhaps, one timer by life span and all cylinders (for a given life span) are created and destroyed in the same "top" ? Depending on your project, of course.
This is a good start !
Offline
Well, few remarks in vrac.
//fun [] I
//get an id from lDeleted_cylinder_ids....if there are no ids available, return 0, once an index is encountered, return the index
fun get_deleted_cylinder_ID ()=Are you sure that an index will never be equal at 0 ? If no, you should return nil instead if the deleted list is empty.
Thx I changed that, I don't know how the index could ever be zero, but nil does seem safer.
You should rename explicitely your variables. By example, in lDeleted_cylinder_ids, the first l for a list is ok. But lindex is an integer, not a list. Why this first l ? An i (iIndex by example) is more comprehensive for the reader. And if the second character is upper, keep this convention.
I'll do that when I work on my throttle plugit that I never finished.
To optimize easily the memory, you should avoid to define uselessly some locale variables. By example :
fun add_cylinder()=
(...)
let @birthphase -> birth_function in
let @deathphase -> death_function in
let @returnvolume-> volume_function in
let @returnarea -> area_function in
(
//assign birth and death functions
set lcylinder.fbirthfunction = birth_function;
set lcylinder.fdeathfunction = death_function;
set lcylinder.funreturnarea = area_function;
set lcylinder.funreturnvolume = volume_function;
(...)Write instead :
fun add_cylinder()=
(...)
(
//assign birth and death functions
set lcylinder.fbirthfunction = @birthphase ;
set lcylinder.fdeathfunction = @deathphase;
set lcylinder.funreturnarea = @returnvolume;
set lcylinder.funreturnvolume = @returnarea;
done
If i understand correctly, you want keep the index value when a cylinder is deleted ? Right ?
yes
If several life span exist, set several lists may be another method, instead of a big list. One list by life span. It is an idea ...
Or, if you know, you could use an hash table (otherwise, forget that !).
I set things up so the lifespan is anywhere from ms to around 1638 ms.
A timer object (not only in Scol) is always a greedy object. Some timers are ok. A large number can be problematic, especially as they are destroyed to the first "top". Perhaps, one timer by life span and all cylinders (for a given life span) are created and destroyed in the same "top" ? Depending on your project, of course.
If the vm had something like a built in frame by frame callback, I could build some sort of 'kill' function depending on the lifespan left in each cylinder. But os3d does, and that's where I want to apply this knowledge.
This is a good start !
Thanks! I think I'll end it here, these cylinders have had enough attention from me. Perhaps this example will help others who want to see how you can build simple objects and have them do things, albeit trival things. On to something some other people can actually use.
Offline
If the vm had something like a built in frame by frame callback, I could build some sort of 'kill' function depending on the lifespan left in each cylinder. But os3d does, and that's where I want to apply this knowledge.
Other methods exist : advantages and disadvantages ...
Offline