Note: For access to GameDriver's support for ECS and DOTS, please contact us at support@gamedriver.io
While GameDriver's HierarchyPath reference language allows for any object in the standard Unity object tree to be queried using a conditional hierarchal query system, it is also possible to use a variation of HierarchyPath to query entities and their components when using Unity's ECS (Entity Component System).
Much like standard HierarchyPath, ECS queries involve a reference string to target an entity and/or its components. However, since in ECS objects are not identified by their position in a hierarchy but instead based solely on what components exist on the entity, we do not begin queries with absolute or relative path tokens ('/' and '//' respectively) but instead rely on the function 'fn:entityquery()'. The 'entityquery' function can be passed any number of parameters, which consist of three types of functions: 'fn:withany()', 'fn:withall()', and 'fn:withnone()'. All three of these sub-functions take any amount of component types as their parameters.
"fn:entityquery(fn:withany('SpeedComponent', 'Unity.Transforms.LocalTransform'))"
The above query utilized the 'withany' function to target entities that have either a 'SpeedComponent' or 'LocalTransform' component, or even both. This can be thought of as the "Inclusive OR" function, targeting entities that have any combination of the listed components.
"fn:entityquery(fn:withall('MovementComponent', 'TestIDComponent'))"
Alternatively, the 'withall' function acts as the equivalent of an "AND" operation, targeting only entities that have all the listed component types. For example, the above query would only target an entity that has both a 'MovementComponent' and a 'TestIDComponent'.
"fn:entityquery(fn:withnone('ColorComponent'))"
Lastly, the 'withnone' function can be used when we want to exclude entities from being targeted by the query that have certain active component types, effectively acting as a "NOT" operator. The given example would only target entities that do not have an active 'ColorComponent'. Alternatively, 'withabsent' can be used when we want to target entities that lack the component completely, or 'withdisabled' when we want the component to exist but be disabled.
These sub-functions can be used together in a single 'entityquery' call in order to target entities with more complex conditions. For instance, the following example would target an entity that has both a 'MovementComponent' and a 'Unity.Transforms.Parent' component, but that also does not have a 'TestIDComponent':
"fn:entityquery(fn:withall('MovementComponent', 'Unity.Transforms.Parent'), fn:withnone('TestIDComponent'))"
These queries can be used with GameDriver API calls such as 'Click/TapObject', 'RotateObject', and 'GetObjectPosition/Distance', assuming the targeted entities have the relevant components (e.g. transforms, colliders, etc.).
For the sake of API calls that require a reference to a component itself or the component's data, such as with 'GetObjectFieldValue', we can utilize the 'fn:ecscomponent()' function in tandem with an entity query.
api.GetObjectFieldValue<float>("fn:entityquery(fn:withall('SpeedComponent'))[0]/fn:ecscomponent('SpeedComponent')/@Speed");
The above API call would receive the "Speed" value of a 'SpeedComponent' by finding the first entity with a 'SpeedComponent' (i.e. 'fn:entityquery(fn:withall('SpeedComponent'))[0]') and then using the 'ecscomponent' function to target its 'SpeedComponent' in order to access the "Speed" attribute (i.e. appending on '/fn:ecscomponent('SpeedComponent')/@Speed').