Aller au contenu

Photo

Finding objects


  • Veuillez vous connecter pour répondre
22 réponses à ce sujet

#1
Leurnid

Leurnid
  • Members
  • 271 messages
For purposes of this query, let us assume a switch when used, does something to one or more objects in the area.

The most common means of doing this, when the number of objects is variable, is to GetFirstObjectInArea (oArea); then in a while loop, check tags, GetNextObjectInArea, rinse and repeat.

If this script is firing in an area with hundreds of placeables, and only a few are going to be tagged by the script, is there a more efficient means of finding those objects? 

#2
Leurnid

Leurnid
  • Members
  • 271 messages
I am thinking that using GetObjectInShape would be a good way to avoid cycling hundreds of items in an area, as long as the target object is fairly close to the switch (which it will be), but based on another recent topic, that sounds as if it may have it's own performance issues associated.... if the sphere or cylinder shape being checked is targeted on the first object by tag, and if any additional objects are to be influenced by the switch, they will be within 1 tile of the first object (by tag), then it seems like a good targeted method of switching things.

snippet:
[code=auto:0]
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 10.0, GetObjectByTag(sTag), TRUE, OBJECT_TYPE_PLACEABLE);

while(GetIsObjectValid(oTarget))
{
//do stuff here
oTarget = GetNextObjectInShape(SHAPE_SPHERE, 10.0, GetObjectByTag(sTag), TRUE, OBJECT_TYPE_PLACEABLE);
}
[code=auto:0]


EDIT:  Lexicon states that GetFirstObjectInShape is bugged and will not return a placeable....  bugger!

Modifié par Leurnid, 21 mai 2012 - 07:42 .


#3
_Guile

_Guile
  • Members
  • 685 messages
I believe you need an "/" before code in the last [ code]

like so
[/code]

-------------------------

I really need to know what your script will do (in essence) to help you further mate...

You aren't being very informative. :D

Anyway, it's best to use GetNearestObjectByTag(oArea, "thistag", #);

Then use a For Loop to suppliment the # using the i Integer...

e.g.

object oArea = ????; ///Define oArea...
int nWhich = 11;   // (e.g. 1 - 10)
int i;
for(i=1; i<nWhich;i++)
{
  oSomething = GetNearestObjectByTag(oArea, "thistag", i);
}

Obviously nWhich would need to be the # of objects you want to look at (Plus 1), if you are wanting to look at them all, then enter that number plus one, e.g. if 20 put nWhich = 21;

Otherwise yes, you may be able to use the while loop as you shew above...

However you have an error in that script, as you are using "GetObjectByTag(sTag)" in the actual definition of oObject....  which GetObjectByTag(sTag) is a loop in itself, so it would kick out an error...

If you want to use a double loop, then write a custom function / prototype to do another loop once oObject has been defined by the first loop, this should prevent the TMI (Too Many Instructions) error, but that's NOT guaranteed.

:wizard:

I could probably help you a lot more if I knew exactly what you were trying to achieve, ultimately.. ^_^

Modifié par _Guile, 21 mai 2012 - 08:30 .


#4
Leurnid

Leurnid
  • Members
  • 271 messages
I was just spit balling that... thinking aloud, in a manner of speaking... this is a snippet from an actual switch I am currently using, and it works fine:

 //declarations removed
   object oLight = GetFirstObjectInArea(oArea);
 //stuff removed
        while(GetIsObjectValid(oLight))
        {
            if (GetTag(oLight) == sLights )
            {
                if (GetLocalInt(oLight, "iStandardLight"))
                {
                    AssignCommand(oLight, ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE));
                    SetPlaceableIllumination(oLight, TRUE);
                }
                else
                {
                    sColor = "White 5";
                    if (GetLocalInt(oLight,"iHaveVFX")) sColor = (GetLocalString (oLight, "sColor"));
                    else if (GetLocalInt(OBJECT_SELF,"iHaveVFX")) sColor = (GetLocalString (OBJECT_SELF, "sColor"));
                    int nColor = FindSubString (sColors, GetStringLowerCase( GetStringLeft (sColor, 3)));
                    int nSize = (StringToInt (GetStringRight (sColor, 2)) / 5) - 1;
                    if (nSize < 0) nSize = 0;
                    else if (nSize > 3) nSize = 3;
                    eLight = EffectVisualEffect(153 + nColor + nSize);
                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLight, oLight);
                }
            }
        oLight = GetNextObjectInArea(oArea);
        }
//more stuff removed


There isn't a specific case I am working with where I want somebody to wave a magic wand and make it work. I am trying to figure alternate and conditionally better ways to script solutions.

My current query is: Are there alternate ways to script the sort of loop used above that will process more quickly in areas with a lot of placeables to process.

Modifié par Leurnid, 21 mai 2012 - 08:45 .


#5
_Guile

_Guile
  • Members
  • 685 messages
I set variables on the placeables, like so...

PERM_VFX_1  /  int  /   #
PERM_VFX_2  /  int  /  #
etc..
Where # = the VFX Constant #...

Then from the OnEnter Event of the area (OBJECT_SELF), I run the loop to apply the Permanent VFXs to Placeables.. (provided VFXs haven't been set before, I use a variable set on the area to check this from the same script)...

You could do the same for just a trigger (onenter) as well, but the PC's would probably see the VFXs being applied, instead of all ready being applied when they walked by...

Don't know the intents of your scripting, but I hope that helps in some way...

Modifié par _Guile, 21 mai 2012 - 10:59 .


#6
Leurnid

Leurnid
  • Members
  • 271 messages
Now, here is something interesting: I took the basic script routine above, and tweaked it so it was looking for sound objects with a designated tag to toggle on. I can bullseye a single sound object just fine, but if I try to use a while-loop to find sounds by tag, they won't play. I am about to slap some floating texts in there to see if/where things are and aren't popping.

void main()
{
    object oObject  = OBJECT_SELF;
    object oArea  = GetArea(oObject);
    object oSound = GetFirstObjectInArea(oArea);

    while(GetIsObjectValid(oSound))    // Loop all objects in the area
    {
        if (GetTag(oSound) == (GetTag(oObject)+"_sound"))
        {   
        //DelayCommand(0.3,SoundObjectPlay(oSound)); //this variant failed
        SoundObjectPlay(oSound); //this variant failed too
        }
        oSound = GetNextObjectInArea(oArea);
    }
//    SoundObjectPlay(GetObjectByTag(GetTag(oObject)+"_sound"));  //this variant works fine.
}


My initial guess is that sound objects do not track as objects for either the 'GetIsObjectValid' or the 'GetFirst- GetNextObjectInArea'


Just to be clear, I am not trying to do accomplish anything in particular, I am experimenting with what can be done. I don't want solutions, I want options.

Modifié par Leurnid, 21 mai 2012 - 11:55 .


#7
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
One thing I recommend is trying NOT to use any GetFirst/NextObjectInXxxxx function unless you absolutely have to. GetObjectByTag has been shown in past threads to be a lot faster. That being said, one option for your experiment would be to do something more like so:

void main()
{
    int iNth = 0;
    object oSound = GetObjectByTag("AREA_1_SOUND", iNth);
    while (GetIsObjectValid(oSound))
    {
        SoundObjectPlay(oSound);
        iNth++;
        oSound = GetObjectByTag("AREA_1_SOUND", iNth);
    }
}

For thist test I placed 3 different sound objects and gave them the same but unique tags( If the tags were not unique to this area than any sound object in the mod with the same tags would play) This script searches for the 1st, 2nd, 3rd, etc objects with a particular tag and then plays them. And if for some reason you need to separate out a particular sound, since they all have the same tag, you can use the GetName function to then single one out (assuming they have different "names").

Hope that makes sense.

As to why yours didn't work I'm not sure. At first glance it seems like it should. The first things that came to mind;
-The placeable tag didn't match the sound tag as you intended.
-The sound was too far away to hear and wasn't flagged to play everywhere in area.

You can also use the same idea for other placeables and use the resref as an alternative check.

Modifié par GhostOfGod, 22 mai 2012 - 02:49 .


#8
Failed.Bard

Failed.Bard
  • Members
  • 774 messages
If GetObjectByTag is working for selecting them, you would just need to standardize the naming so that you can get them using a loop on that function instead. Area tag + sound + night/day, perhaps, so you can toggle on/off certain sound placeables based on time of day as well.

#9
_Guile

_Guile
  • Members
  • 685 messages
Interesting, with lots of sounds in an area, I wonder if this would kick out a TMI?

#10
Leurnid

Leurnid
  • Members
  • 271 messages

GhostOfGod wrote...

One thing I recommend is trying NOT to use any GetFirst/NextObjectInXxxxx function unless you absolutely have to. GetObjectByTag has been shown in past threads to be a lot faster. That being said, one option for your experiment would be to do something more like so:

void main()
{
    int iNth = 0;
    object oSound = GetObjectByTag("AREA_1_SOUND", iNth);
    while (GetIsObjectValid(oSound))
    {
        SoundObjectPlay(oSound);
        iNth++;
        oSound = GetObjectByTag("AREA_1_SOUND", iNth);
    }
}

For thist test I placed 3 different sound objects and gave them the same but unique tags( If the tags were not unique to this area than any sound object in the mod with the same tags would play) This script searches for the 1st, 2nd, 3rd, etc objects with a particular tag and then plays them. And if for some reason you need to separate out a particular sound, since they all have the same tag, you can use the GetName function to then single one out (assuming they have different "names").

Hope that makes sense.

As to why yours didn't work I'm not sure. At first glance it seems like it should. The first things that came to mind;
-The placeable tag didn't match the sound tag as you intended.
-The sound was too far away to hear and wasn't flagged to play everywhere in area.

You can also use the same idea for other placeables and use the resref as an alternative check.


I tested the placeable name by using the commented out line and commenting the while-loop, so the object tag was good, and the placeable sound was about 1 meter in front of the door... but your method is a bit cleaner anyway, and still caters to my love of generic-ness.

Thank you.

#11
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
So I got a bit curious and experimented with the "GetFirst/NextObject" funtions as well. It seems that sound objects return both "OBJECT_TYPE_ALL" and "OBJECT_TYPE_INVALID" which is just the same thing as 32767. So you can use the "GetFirst/NextObjectInShape" functions if you needed to, to get sounds as well. Like so:

void main()
{
    object oPC = GetLastUsedBy();
    //debug line
    SendMessageToPC(oPC, "Sound Test Script Run!");
    location lLoc = GetLocation(OBJECT_SELF);
    object oArea = GetArea(OBJECT_SELF);
    //object oSound = GetFirstObjectInArea(oArea);
    object oSound = GetFirstObjectInShape(SHAPE_SPHERE, 10.0, lLoc, FALSE, 32767);
    while (GetIsObjectValid(oSound))
    {
        if (GetTag(oSound) == "AREA_1_SOUND")
        {
            SoundObjectPlay(oSound);
            //debug line
            SendMessageToPC(oPC, "1 sound found!");
        }
        //oSound = GetNextObjectInArea(oArea);
        oSound = GetNextObjectInShape(SHAPE_SPHERE, 10.0, lLoc, FALSE, 32767);
    }
}

I still can't get it to work with "GetFirst/NextObjectInArea" though. This function most likely skips this particular object type.

P.S. You can just replace the 32767 with OBJECT_TYPE_ALL or OBJECT_TYPE_INVALID. I was just being lazy and wanted to keep the script a bit shorter.

Modifié par GhostOfGod, 22 mai 2012 - 04:59 .


#12
Leurnid

Leurnid
  • Members
  • 271 messages
I was going to try the Get...ObjectInShape, but I read in the Lexicon that it was bugged when used to get placeables, and I assumed that a sound object qualified as a placeable, so skipped it without trying. Glad to see it actually works, and happier still to see a viable example of it coded. I would have spent a day or two at it just to wind up with a much uglier version of your code, and it probably still wouldn't work.

I prefer the 'ByTag' solution anyway, it's a slimmer bit of code all around, and seems to offer more flexibility in a 'generic' implementation. I might want to trip sounds or lights in other areas, or at least spread out far enough to make InShape impractical.


*Right now, I am just trying to hone a collection of generic scripts that use tags and local variables to control multiple effects consolidated into as few scripts as possible. Finding tight and tidy solutions that work for the broadest range of outcomes is my ultimate goal.

#13
Leurnid

Leurnid
  • Members
  • 271 messages

Failed.Bard wrote...

If GetObjectByTag is working for selecting them, you would just need to standardize the naming so that you can get them using a loop on that function instead. Area tag + sound + night/day, perhaps, so you can toggle on/off certain sound placeables based on time of day as well.


Using the GetObjectByTag script snip of GoG's, you don't need area or day/night checks:  Place the sound objects, then on the advanced tab, uncheck 'active' but set the time the sound should play.  When the script runs, those sounds turn active until you use another script similar to it to deactive them, but they will only play according to the time params. So when the object with the script event is tripped, all the correctly tagged sounds will activate, but only play based on time of day. :D

Modifié par Leurnid, 22 mai 2012 - 07:51 .


#14
Shadooow

Shadooow
  • Members
  • 4 470 messages

Leurnid wrote...

EDIT:  Lexicon states that GetFirstObjectInShape is bugged and will not return a placeable....  bugger!

Unfortunately one can really believe neither to lexicon or wiki. The informations there are old and uproofed.

For the InShape functions, they return placeables and door fine.

Modifié par ShaDoOoW, 22 mai 2012 - 10:30 .


#15
Failed.Bard

Failed.Bard
  • Members
  • 774 messages

Leurnid wrote...

Failed.Bard wrote...

If GetObjectByTag is working for selecting them, you would just need to standardize the naming so that you can get them using a loop on that function instead. Area tag + sound + night/day, perhaps, so you can toggle on/off certain sound placeables based on time of day as well.


Using the GetObjectByTag script snip of GoG's, you don't need area or day/night checks:  Place the sound objects, then on the advanced tab, uncheck 'active' but set the time the sound should play.  When the script runs, those sounds turn active until you use another script similar to it to deactive them, but they will only play according to the time params. So when the object with the script event is tripped, all the correctly tagged sounds will activate, but only play based on time of day. :D


  I'm just not personally a fan of global switching, since it implies being HB driven.  Area tagged day/night specific sounds can be easily turned on or off in an areas OnEnter script, and the mods HB script can toggle them twice a day in the areas currently occupied by PCs if needed.
  That way, short of putting 5000+ sounds in a given area, you're never risking a TMI error or noticeable lag to the script.

  Now, if you're planning to have some sounds that only play during a specific hour, then you'd be best with on and off time ints stored to the sound objects, but tagging them Area Tag + sound (or sound + area tag) allows for them to be toggled specifically where needed off a single compact generic script.

#16
Leurnid

Leurnid
  • Members
  • 271 messages

Failed.Bard wrote...

Leurnid wrote...

Failed.Bard wrote...

If GetObjectByTag is working for selecting them, you would just need to standardize the naming so that you can get them using a loop on that function instead. Area tag + sound + night/day, perhaps, so you can toggle on/off certain sound placeables based on time of day as well.


Using the GetObjectByTag script snip of GoG's, you don't need area or day/night checks:  Place the sound objects, then on the advanced tab, uncheck 'active' but set the time the sound should play.  When the script runs, those sounds turn active until you use another script similar to it to deactive them, but they will only play according to the time params. So when the object with the script event is tripped, all the correctly tagged sounds will activate, but only play based on time of day. :D


  I'm just not personally a fan of global switching, since it implies being HB driven.  Area tagged day/night specific sounds can be easily turned on or off in an areas OnEnter script, and the mods HB script can toggle them twice a day in the areas currently occupied by PCs if needed.
  That way, short of putting 5000+ sounds in a given area, you're never risking a TMI error or noticeable lag to the script.

  Now, if you're planning to have some sounds that only play during a specific hour, then you'd be best with on and off time ints stored to the sound objects, but tagging them Area Tag + sound (or sound + area tag) allows for them to be toggled specifically where needed off a single compact generic script.


If you are planning to have sounds play at specific hours, just tell the
sounds to play at specific hours, no script, no HB, no fuss. Running a script to do what the engine is designed to do natively is less efficent.

If you use the sound's default time settings, you never need to use a HB Event to fire them, on the mod, on the area, on the anything.

In this case, I am talking about toggling sounds to 'active' with switches, doors, or triggers, in the on-enter, on-open, or on-use events, but again, no HB involved. I spare myself a lot of scripting headache trying to determine the time by simply toggling sound 'active', then letting the built in functionality of the sound determine when it actually makes noise. I am not trying to turn every sound object in a mod on/off, just a few local to the activating object with the script, and the time-to-play settings on the sound objects circumvent the need to run HB scripts to fire sounds at specific times.

This arrangement seems the ideal case for when you open a door, you have sound objects parked right behind it play.

For example: 
You have a door tagged 'OgreLair', and 5 'inactive' sound objects tagged 'OgreLair_sound'.
When the door opens, it cycles and activates all 5 sound with the door's tag +'_sound' using a generic script.
All 5 sounds turn on, but using the built in times on sounds, only the ones you want will play at specific times, so you hear ogre grunts, ominous evil entrance, and wailing women at night, but during the day, you hear ominous evil entrance, snoring, and wimpering women.

A no script use of the built in sound timing function, that never requires scripts, let alone HB, is blacksmith's shop... set all the sounds to daytime only, when the smithy and apprentice are supposed to be present; place sound objects for the bellows, hammering, the fire, and one or two random bump-thump-and-scrape, all set in the sound properties to only play during the day.

Modifié par Leurnid, 22 mai 2012 - 04:06 .


#17
henesua

henesua
  • Members
  • 3 867 messages
Another way to have dynamic sounds that respond to events is to use PlaySound in a script executed by the event.

In the case of a trigger (which can not play a sound) or when you want a sound to play at a particular location other than the object with the event, you can create an invisible object (associate this invisible object with the object executing the event, and Assign the PlaySound command to play on that invisible object.

This technique is not perfect, as sometimes the sound does not play when you first create the invisible sound object, but it usually works, and once the invisible sound object is created it is thereafter always capable of playing the sound.

Modifié par henesua, 22 mai 2012 - 04:16 .


#18
Leurnid

Leurnid
  • Members
  • 271 messages

henesua wrote...

Another way to have dynamic sounds that respond to events is to use PlaySound in a script executed by the event.

In the case of a trigger (which can not play a sound) or when you want a sound to play at a particular location other than the object with the event, you can create an invisible object (associate this invisible object with the object executing the event, and Assign the PlaySound command to play on that invisible object.

This technique is not perfect, as sometimes the sound does not play when you first create the invisible sound object, but it usually works, and once the invisible sound object is created it is thereafter always capable of playing the sound.


I experimented with that, but was disappointed to find there were no range and volume control for the PlaySound action, and have been using SoundObjectPlay in most cases to circumvent those limitations.  PlaySound seems ideally suited for when you want one-off sounds centered at or near the player's location and the max volume is irrelevant or desired.

*oddly, this sound conversation started because I was looking for alternate and possibly more efficient ways of toggling lights... but curiosity lead me down the rabbit hole into the wonderland of sound.

#19
henesua

henesua
  • Members
  • 3 867 messages
You may not be able to adjust the radius of PlaySound but it works well. I've created triggers for undergrowth and whenever a creature blunders into a shrub one of the bush rustle sounds is set to play which makes for a dynamic set of sounds when you set a bunch of boar loose in a forest.

I agree that you need more flexibility in some instances, but in many this technique works very well, and does not require you to place sounds or objects in an area. (although, it does require you to make the triggers to define the undergrowth's extents)

Sound and lighting are important. Enjoy your trip through the wonderland, and bring back treasures for us.

#20
Leurnid

Leurnid
  • Members
  • 271 messages

henesua wrote...

You may not be able to adjust the radius of PlaySound but it works well. I've created triggers for undergrowth and whenever a creature blunders into a shrub one of the bush rustle sounds is set to play which makes for a dynamic set of sounds when you set a bunch of boar loose in a forest.

I agree that you need more flexibility in some instances, but in many this technique works very well, and does not require you to place sounds or objects in an area. (although, it does require you to make the triggers to define the undergrowth's extents)

Sound and lighting are important. Enjoy your trip through the wonderland, and bring back treasures for us.


That *sounds* awesome.  I will have to experiment with that.

On a side note, if you are already painting triggers, which won't play sounds (amongst many other things, those poor triggers), you need to drop an object to anchor the sound on anyway, so why, OOC, at that point not use a sound object?

#21
GhostOfGod

GhostOfGod
  • Members
  • 863 messages

Leurnid wrote...

henesua wrote...

You may not be able to adjust the radius of PlaySound but it works well. I've created triggers for undergrowth and whenever a creature blunders into a shrub one of the bush rustle sounds is set to play which makes for a dynamic set of sounds when you set a bunch of boar loose in a forest.

I agree that you need more flexibility in some instances, but in many this technique works very well, and does not require you to place sounds or objects in an area. (although, it does require you to make the triggers to define the undergrowth's extents)

Sound and lighting are important. Enjoy your trip through the wonderland, and bring back treasures for us.


That *sounds* awesome.  I will have to experiment with that.

On a side note, if you are already painting triggers, which won't play sounds (amongst many other things, those poor triggers), you need to drop an object to anchor the sound on anyway, so why, OOC, at that point not use a sound object?


For "PlaySound" I usually just have the Player or entering object play the sound. So no need to create any objects or anything. Doing as henesua suggests does make for a good quick way to play a sound from any location instantly and then you can just destroy the object right after the sound. So I suppose it could aslo cut down on the number of permanent objects in an area by not having to place many sound objects.

#22
henesua

henesua
  • Members
  • 3 867 messages
I don't have to place anything manually. Its all done by script. The script that wants to play a sound, creates the object the sound will play on and stores the association. If a trigger already has an associated object with which it uses for sounds, rather than create a new object, it plays the sound on that object. I have not yet added the functionality to destroy those objects, but I could if I needed to, since the association is stored. At present server resets handle this garbage collection and its not a big deal.

Why did I do it this way? It is simpler than the alternative which is to place countless sound objects throughout the area.

I don't want to place more objects in the area than I absolutely have to to achieve my goal. Simplicity is better in my opinion. Despite all the detail I put into my area design, I try to keep game objects to a bare minimum. Each object should serve an important function. If I don't have to place it, then I avoid doing so. Dynamically creating and destroying game objects when needed is thus appealing to me.

Furthermore, its already a TON of work to draw all of these triggers, decorate an area with placeables, and set up the non-dynamic sound objects. I'd rather not increase that workload.

Lastly I already have many sound objects in an area, adding fifty or so more would make it very difficult to keep track of the sounds that regularly play. I tend to put a lot of effort into creating day/night cycles that are expressed via a combo of various sound objects in different parts of each area. At dawn and dusk in rural areas for example insect sounds and rodent sounds play near rock walls. Wetlands have frog and toad sounds etc.... There are many of these which PCs can't really interact with. They just happen and define the character of the area. If I cluttered up an area with other sound objects that were meant to be dynamic it would be very difficult to keep track of which is which. Given that I regularly edit areas, I might accidentally delete something that I shouldn't have etc...

#23
henesua

henesua
  • Members
  • 3 867 messages

GhostOfGod wrote...

For "PlaySound" I usually just have the Player or entering object play the sound. So no need to create any objects or anything. Doing as henesua suggests does make for a good quick way to play a sound from any location instantly and then you can just destroy the object right after the sound. So I suppose it could aslo cut down on the number of permanent objects in an area by not having to place many sound objects.


One reason why I developed this technique was to solve a problem I noticed. When a PCs action queue is full it can not play a sound. I had to clear all actions prior to the sound playing. So if a PC clicks on a location to walk to, and thus crosses a trigger that Assigns playsound to the PC, the sound won't play because the PCs action queue is busy.

Another reason is that triggers can't play sounds.