EntityFinder Tutorial

The EntityFinder class, unsurprisingly, is used to find entities. You can supply condition functions that are used to filter out entities, or select the specific ones you want. We'll go through some example of how to use EntityFinders in this tutorial. The sample mission has several different ships which we will progressively filter out. The different approaches that can be used will be presented.

Finding all Craft

As a first step we will just look for entities that are crafts. We'll also introduce three different approaches: using a named function, using an inline function and using an object. The advantages and drawbacks will be discussed as well.

Named Function

A named function is one that is declared and named outside of the EntityFinder constructor call. They can be useful for reusability as they can be referenced from different places.

--Named function to test if the entity passed is
--a craft.    
function isCraft( e )
    return e:isType( Entity.Type.Craft )
end

--Finder created using a named function
local finder = EntityFinder( isCraft )

Inline Function

If you don't want to use a filter anywhere else, such as for a specific one off usage you can declare the funciton inline.

--To find all crafts, we look for entities that are of the type
--Craft, using an inline function.
local finder = EntityFinder( function(e)
                                return e:isType(Entity.Type.Craft)
                             end )

Object

The third option is a bit more heavyweight than either of the two function options - using an object with an evaluate function. This can be useful if you want to create a resuable filter that also has some parameters; you can see that the class below can be used for any type filtering.

--EntityTypeFilter class
class 'EntityTypeFilter'

--Storing the entity type so that we can check later in the
--evaluate function
function EntityTypeFilter:__init( entityType )
    self.entityType = entityType
end

--Evaluate is essentially the same as the
--filter functions
function EntityTypeFilter:evaluate( e )
    return e:isType( self.entityType )
end
    
--To find all crafts, we look for entities that are of the type
--Craft, using an inline function.
local finder = EntityFinder( EntityTypeFilter( Entity.Type.Craft ) )

For simplicity we'll just use inline functions for now.

When we want to actually find the entities we once again have several options available to us. We can either find just one entity or we can find several - depending on the situation one may be more useful than the other. The following examples show the different options; finding one entity, finding all matching entities and finding up to a certain amount of entities.

--Finds just one entity - the returned value is either an entity or nil (if
--no matching entities were found)
local ent = finder:findOne()
--Finds all matching entities - the returned value is a table of all entities.
--0 length if no matches.
local ents = finder:find()
--Finds up to 5 entities. The returned value is a table of up to 5 entities.
--Can be 0 length if no matches.
local ents = finder:find(5)

We'll use the second option, which finds every entity that matches the criteria.

Script so Far

Here's what we have so far, adding in the two options chosen above. As you can see we have used an inline function and have selected all matching entities. If we look at the ents table now, we would see every craft in there.

class 'EntityFinderTutorial'

function EntityFinderTutorial:__init( )
    
end

function EntityFinderTutorial:setup( )
       
    --To find all crafts, we look for entities that are of the type
    --Craft, using an inline function.
    local finder = EntityFinder( function(e)
                                    return e:isType(Entity.Type.Craft)
                                 end )

    --Finds all matching entities - the returned value is a table of all entities.
    --0 length if no matches.
    local ents = finder:find()
    
end

MMM.register( EntityFinderTutorial( ) )

Narrowing the Criteria

Suppose we have decided that we just want small ships - that is, ships with a crew complement of less than 100. We can do this by adding another filter, or by extending the one we already have. Again, both options will be demonstrated below.

--We can pass multiple filters in a table.
local finder  = EntityFinder(
                                {
                                    function(e) return e:isType(Entity.Type.Craft) end,
                                    function(e) return e.maxCrew < 100 end
                                }
                            )--We can extend the current one as well
local finder = EntityFinder(
                                function (e) return e:isType(Entity.Type.Craft) and
                                                    e.maxCrew < 100 end
                            )

Now, we'll just print the names of the ships we've found.

for _, v in pairs( ents ) do
    print( v.name )
end

Final Script

Here's the final script for the mission. Hopefully you can see how filters can be combined to select the entities that you want and all the different ways you can create them are clear.

class 'EntityFinderTutorial'

function EntityFinderTutorial:__init( )
    
end

function EntityFinderTutorial:setup( )

    --EntityFinder using two conditions in one function - coudl also pass
    --two functions in a table
    local finder = EntityFinder(
                                    function (e) return e:isType(Entity.Type.Craft) and
                                                        e.maxCrew < 100 end
                                )
                               
    --Finds all matching entities - the returned value is a table of all entities.
    --0 length if no matches.
    local ents = finder:find()
    
    for _, v in pairs( ents ) do
        print( v.name )
    end

    Objectives:load( "EntityFinderTutorialObjectives.txt" )
    Objectives.visible = true
    
end

MMM.register( EntityFinderTutorial( ) )