Facebook Twitter YouTube Frictional Games | Forum | Privacy Policy | Dev Blog | Dev Wiki | Support | Gametee


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Script Help Entity's Location / Distance to Entity
craven7 Offline
Member

Posts: 50
Threads: 8
Joined: Aug 2012
Reputation: 1
#1
Entity's Location / Distance to Entity

Hi

is there any way to get an entity's location or the distance to an other entity or the player?


If not, does that mean that the only way to let an entity react with other entities nearby is to place a scriptarea for every one?

Also when using the PlayerLookAtCallback a maxDistance would be nice... For example when looking at a picture a message like "What a beautiful picture" should appear, but not when the player is like 20 m away and can hardly see the picture at all. Any solution?

Thanks
(This post was last modified: 09-04-2012, 12:29 PM by craven7.)
09-04-2012, 11:06 AM
Find
Apjjm Offline
Is easy to say

Posts: 496
Threads: 18
Joined: Apr 2011
Reputation: 52
#2
RE: Entity's Location / Distance to Entity

If distance is all you are interested in there are some pretty simple hacks that can be used. How precise do you want the distance calculation to be, and how frequently will it be called - if you want too much precision or too much frequency then you will struggle.

Also, do you want object origin->object origin distance, or object origin->nearest point on another object distance?
(This post was last modified: 09-04-2012, 12:12 PM by Apjjm.)
09-04-2012, 12:11 PM
Find
craven7 Offline
Member

Posts: 50
Threads: 8
Joined: Aug 2012
Reputation: 1
#3
RE: Entity's Location / Distance to Entity

It doesn't have to be that precise... for example player is walking down a corridor and everytime he comes near a door, the door closes. Let's say, check for a nearby door every 0.5 seconds... shouldn't be too costly?
09-04-2012, 12:33 PM
Find
Apjjm Offline
Is easy to say

Posts: 496
Threads: 18
Joined: Apr 2011
Reputation: 52
#4
RE: Entity's Location / Distance to Entity

Okay, I have written up a distance checking example map:
Download

The sample map will report the distance between the barrel and the box when you use the lantern, and also has a distance callback if the barrel and box are ever within 2 units-of-distance of each other.


How to use it
Spoiler below!

Firstly, I have included python
(3.2) script which generates entities based on a file called "unitSphere.txt". This is in ->entities->SphereGen.

If you want to alter the precision / max range, just delete all the existing entities in that folder, alter the python script accordingly and run again. Note that the precision must be a negative power of two (e.g. 0.125, which is what is currently used).

The map script file also contains some constants (which refer directly to the parameters at the start of the python file) which you would need to alter.


The script file contains a couple of helper functions:
string GetRangeFileName(float range)
float GetRangeValCeil(float range)
You shouldn't need to use these, but their purpose is commented in the script file if you're interested.

I create a variant of "AddEntityCollideCallback", which allows a range to specified:
AddEntityWithinRangeCollideCallback(string &in asBase, string &in asEntity,  string &in asCallback, int alStates, float maxRange)
The callback works is the same as the one from AddEntityCollideCallback. Note that if you want the routine to work with the player, specify "Player" in the asEntity field (* is also supported here, but not in asBase). asBase MUST be an entity which supportes AddAttachedPropToProp. Also note that the asParent feild in the collide callback will be the entity matched by asEntity, and asChild will be the name of the range finder entity (Not asBase).

There is also a RemoveEntityCollideCallback variant, which takes a range parameter.
RemoveEntityWithinRangeCollideCallback(string &in asBase, string &in asEntity, float maxRange)
You may specify multiple range callbacks per entity pairs (E.g. a callback for distance =4, 5 and 6), but not multiple callbacks for the same combination of parent,child and distance.


Finally, there are two find-distance between entity functions. These are FAR slower than the range callback stuff, so use that if you just want to test if x within a certain distance of y. But if you MUST know the distance:
getEntityDistance(string &in asBase, string &in asEntity)
getEntityDistanceLinear(string &in asBase, string &in asEntity)

These both do the same thing. GetEntityDistanceLinear is slower except when the objects are extremely close.
asBase must again be a prop which allows attachments, whereas asEntity can be anything, including "Player", and maybe astrix too.

09-04-2012, 02:22 PM
Find
craven7 Offline
Member

Posts: 50
Threads: 8
Joined: Aug 2012
Reputation: 1
#5
RE: Entity's Location / Distance to Entity

First, thanks for you effort.


So basically you create a sphere which origin is the entity which I check for its closeness? If we take my example with the doors which shall open when the player approaches, every door "gets" a sphere around itself and if the player collides with it, we know that he's in range.

Imho pretty strange that you have to do a workaround with loading the needed sphere entity instead of supporting a function for distance but ok.


Strangely when i first started your testmap, ED was always -1 || -1.
I reloaded and now it's working.

Thank you very much, I will use this method in my custom story. Should I
ever come to release it, how do you want to be mentioned in credits?
(This post was last modified: 09-04-2012, 04:44 PM by craven7.)
09-04-2012, 04:20 PM
Find
Apjjm Offline
Is easy to say

Posts: 496
Threads: 18
Joined: Apr 2011
Reputation: 52
#6
RE: Entity's Location / Distance to Entity

Yeah, amnesia scripting doesn't expose positions, as I'm assuming frictional didn't think such behaviour would be needed (also, it probably simplified saving the state of the game, as only stuff using SetLocalVar/SetGlobalVar is saved - rather than saving the state of classes etc in the script).

You are correct that my approach is using attached spheres to the origin of props, the callback code just attaches one sphere and creates a collision callback on that sphere. The distance code uses binary (or linear) search over the range of sphere sizes to find the first distance at which the range spheres and the target prop intersect.


With regards to the reload - amnesia can do that if you add the entities to the folder whilst it is running. It probably caches a mapping from file names -> file paths so that no file paths need to be specified in scripting, but that cache wasn't updated (i'm guessing it's probably constructed when the resources file is loaded).


Don't worry about putting me in the credits, but if you want to include me it's entirely up to you how you mention me Smile.

Edit 2:
I think it is just that the "In Range" message is a little deceptive. The range message is displaying the name of the child entity, rather than the parent entity. Try the following:

void cbTestRange(string &in asParent, string &in asChild, int alState)
{
    AddDebugMessage("In Range: "  + asParent + " (" + alState + ")",false);
}
(This post was last modified: 09-04-2012, 04:54 PM by Apjjm.)
09-04-2012, 04:44 PM
Find
craven7 Offline
Member

Posts: 50
Threads: 8
Joined: Aug 2012
Reputation: 1
#7
RE: Entity's Location / Distance to Entity

Hm i can't get this to work for enemies? Any hint?
for(int i = 1; i <= 7; i++)
{
    AddEntityWithinRangeCollideCallback("servant_grunt_1" ,"door_" + i,"cbTestRange",0,2.5f);
}
This doesn't work at all.
With the wood_box01 it's working.

If i replace it with this:
for(int i = 1; i <= 7; i++)

{

    AddEntityWithinRangeCollideCallback("door_" + i" ,"servant_grunt_1,"cbTestRange",0,2.5f);

}
then I can't tell the door anything because I don't have its name because of:

string attachName = "RANGECB_ BASE: "+asBase+ " ENTITY: " + asEntity+ " RANGE: " +range;

Is there a more beautiful ^^ way to get the name of the door than searching for a keyword in the attachName?
09-04-2012, 05:42 PM
Find
Your Computer Offline
SCAN ME!

Posts: 3,456
Threads: 32
Joined: Jul 2011
Reputation: 235
#8
RE: Entity's Location / Distance to Entity

Grunts don't have bodies, and so you can't attach entities to it.

Tutorials: From Noob to Pro
09-04-2012, 05:52 PM
Website Find
craven7 Offline
Member

Posts: 50
Threads: 8
Joined: Aug 2012
Reputation: 1
#9
RE: Entity's Location / Distance to Entity

Yes, that's why I replaced the grunt(base) with the doors(entity). But now I have to get the entities name's by using string operations which isn't so nice after all. I'd appreciate to have a more "direct" reference, despite knowing that it's only a string and not an object.
09-04-2012, 05:55 PM
Find
Apjjm Offline
Is easy to say

Posts: 496
Threads: 18
Joined: Apr 2011
Reputation: 52
#10
RE: Entity's Location / Distance to Entity

Replace the Entity Within Range callback section with the following:
///////////////////////////////
//+ Entity Within Range Callback
///////////////////////////////
//Add a callback for when asEntity is within <maxRange> of asBase (collision callback). asBase must allow attachments.
//Duplicate identical attachments (range+base+entity are identical) behaviour is undefined.
void AddEntityWithinRangeCollideCallback(string &in asBase, string &in asEntity,  string &in asCallback, int alStates, float maxRange)
{
    float range = GetRangeValCeil(maxRange);
    string attachName = "RANGECB_"+asBase+asEntity+range;
    AddAttachedPropToProp(asBase,attachName,GetRangeFileName(range),0,0,0,0,0,0);
    AddEntityCollideCallback(asEntity,attachName,asCallback,false,alStates);
    //Set local vars for getter functions
    SetLocalVarString("Base_" + attachName,asBase);
    SetLocalVarFloat("Range_" + attachName,maxRange);
}

//Remove a range callback and associated attachments
void RemoveEntityWithinRangeCollideCallback(string &in asBase, string &in asEntity, float maxRange)
{
    float range = GetRangeValCeil(maxRange);
    string attachName = "RANGECB_"+asBase+asEntity+range;
    RemoveEntityCollideCallback(asEntity,attachName);
    RemoveAttachedPropFromProp(asBase,attachName);
    //Reset Local vars
    SetLocalVarString("Base_" + attachName,"");
    SetLocalVarFloat("Range_" + attachName,0);
}

//Get the base entity from the range callback
string GetBaseFromRangeCallback(string &in asChild)
{
    return GetLocalVarString("Base_" + asChild);
}
//Get the base entity from the range callback
float GetMaxRangeFromRangeCallback(string &in asChild)
{
    return GetLocalVarFloat("Range_" + asChild);
}
///////////////////////////////
//- Entity Within Range Callback
///////////////////////////////

You then have access to two new functions:
string GetBaseFromRangeCallback(string &in asChild)
float GetMaxRangeFromRangeCallback(string &in asChild)
These will let you get params from the callback "asChild" parameter without any string operations.

Edit:
Alternative solution using string parsing:
Spoiler below!

change how the attach name is formed into:
string attachName = "RANGECB_"+"$"+asBase+"$"+asEntity+"$"+range;
Add the following stringSplitting function:
string[] stringSplit(string &in asString, string asDelim)
{
  string[] output = {""};
  //For each character in the input, check against the output.
  int s1 = int(asString.length()); int s2 = int(asDelim.length());
  int lastMatch = 0;
  //Add all but final elements
  for(int i=0; i<=s1 - s2; i++)
   {
    if(StringSub(asString,i,s2) == asDelim)
     {
      //Add element to output      
      output[output.length() - 1] = StringSub(asString,lastMatch,i-lastMatch);
      output.resize(output.length() + 1);
      //Move search along
      i += s2;
      lastMatch = i;
     }
   }
  //Add lastMatch -> final
  output[output.length() - 1] = StringSub(asString,lastMatch,s1 - lastMatch);
  return output;
}
You can then manually split asChild into an array using:
stringSplit(asChild,"$")

(This post was last modified: 09-04-2012, 06:11 PM by Apjjm.)
09-04-2012, 06:08 PM
Find




Users browsing this thread: 1 Guest(s)