Skip to main content
Skip to main content

PlayerTargeter

PlayerTargeter

Description

Exists for the client's player, and handles raycasting and finding specific objects for them to interact with.

Functions

addFilterToTargetType

Description

Adds the given filter function to the given target type.

Definition

addFilterToTargetType(any targetKey, function filterFunction)

Arguments

anytargetKeyThe key of the objects to target.
functionfilterFunctionA function that is called for each raycast object that matches the mask and helps filter out unwanted items. bool function(hitObject, x, y, z)

Code

function PlayerTargeter:addFilterToTargetType(targetKey, filterFunction)

--#debug Assert.isType(filterFunction, "function", "Filter function must be a function!")
--#debug Assert.isTrue(self:getHasTargetedKey(targetKey), "Cannot add filter function to key that does not exist!")

-- Get the mask for the given target.
local targetedMask = self.targetedMasks[targetKey]
table.insert(targetedMask.filterFunctions, filterFunction)
end

addTargetType

Description

Adds the given target type to the targeter, so that the raycasts will include objects with these collision masks.

Definition

addTargetType(any targetKey, CollisionFlag targetMask, float? minDistance, float maxDistance)

Arguments

anytargetKeyAn object used as a key to later retrieve or remove the target type.
CollisionFlagtargetMaskThe mask of the objects to target.
float?minDistanceThe optional minimum distance that an object of this type can be targeted. Defaults to 0.
floatmaxDistanceThe maximum distance that an object of this type can be targeted.

Code

function PlayerTargeter:addTargetType(targetKey, targetMask, minDistance, maxDistance)

--#debug Assert.isNilOrType(minDistance, "number", "Minimum distance must be a number or nil!")
--#debug Assert.isType(maxDistance, "number", "Maximum distance must be a number!")

-- Check that the key is not already being targeted.
if self:getHasTargetedKey(targetKey) then
return
end

-- Set the highest max distance of the ray based on the given distance and the current max.
self.highestMaxDistance = math.max( self.highestMaxDistance, maxDistance)

-- Create the targeted mask table.
self.targetedMasks[targetKey] = { key = targetKey, mask = targetMask, minDistance = minDistance or 0 , maxDistance = maxDistance, filterFunctions = { } }

-- Recalculate the combined mask to use for the ray.
self:recalculateCombinedTargetMask()
end

debugDraw

Description

Displays the debug information.

Definition

debugDraw(float x, float y, float textSize)

Arguments

floatxThe x position on the screen to begin drawing the values.
floatyThe y position on the screen to begin drawing the values.
floattextSizeThe height of the text.

Return Values

floatyThe y position on the screen after the entire debug info was drawn.

Code

function PlayerTargeter:debugDraw(x, y, textSize)

-- Render the header.
y = DebugUtil.renderTextLine(x, y, textSize * 1.5 , "Targeter" , nil , true )

local combinedMaskName = CollisionFlag.getFlagsStringFromMask( self.combinedTargetMask)
y = DebugUtil.renderTextLine(x, y, textSize, string.format( "Combined mask: %q" , combinedMaskName), nil , true )
y = DebugUtil.renderTextLine(x, y, textSize, "Masks:" , nil , true )

for key, targetedMask in pairs( self.targetedMasks) do
local maskNode = self:getClosestTargetedNodeFromType(key)
local nodeName = (maskNode ~ = nil and entityExists(maskNode)) and getName(maskNode) or "none"

local maskName = CollisionFlag.getFlagsStringFromMask(targetedMask.mask)

y = DebugUtil.renderTextLine(x, y, textSize, string.format( "Mask %q: %q" , maskName, nodeName))
end

return y
end

getClosestTargetedNodeFromType

Description

Gets the last found node from the given target mask, or nil if none was found.

Definition

getClosestTargetedNodeFromType(any targetKey)

Arguments

anytargetKeyThe key of the objects to stop targeting.

Return Values

anynodeThe last found node from the given target mask, or nil if none was found.

Code

function PlayerTargeter:getClosestTargetedNodeFromType(targetKey)
local closestTarget = self.closestTargetsByKey[targetKey]
return closestTarget ~ = nil and closestTarget.node or nil
end

getHasTargetedKey

Description

Returns true if the given key is targeted; otherwise false.

Definition

getHasTargetedKey(CollisionFlag targetKey)

Arguments

CollisionFlagtargetKeyThe key of the objects to target.

Return Values

CollisionFlaghasTargetedMaskTrue if the mask is targeted; otherwise false.

Code

function PlayerTargeter:getHasTargetedKey(targetKey)
return self.targetedMasks[targetKey] ~ = nil
end

getLastLookRay

Description

Gets the last look ray components.

Definition

getLastLookRay()

Return Values

CollisionFlaglastRayXThe origin's x position.
CollisionFlaglastRayYThe origin's y position.
CollisionFlaglastRayZThe origin's z position.
CollisionFlaglastRayDirectionXThe ray's x direction.
CollisionFlaglastRayDirectionYThe ray's y direction.
CollisionFlaglastRayDirectionZThe ray's z direction.

Code

function PlayerTargeter:getLastLookRay()
return self.lastRayX, self.lastRayY, self.lastRayZ, self.lastRayDirectionX, self.lastRayDirectionY, self.lastRayDirectionZ
end

new

Description

Creates a new targeter for the given player.

Definition

new(Player player)

Arguments

PlayerplayerThe player for whom the targeter is made.

Return Values

PlayerselfThe created instance.

Code

function PlayerTargeter.new(player)

-- Create the instance.
local self = setmetatable( { } , PlayerTargeter _mt)

-- The player that this targeter belongs to.
self.player = player

-- The pool of unused target tables.
self.pooledTargets = ObjectPool.new()

-- The total combined mask.
self.combinedTargetMask = 0

-- The collection of specifically targeted masks.
self.targetedMasks = { }

self.closestTargetsByKey = { }
self.currentTargetsByKey = { }

-- The highest maximum distance that is targeted.
self.highestMaxDistance = 0

-- The components of the last ray that was fired by this targeter.
self.lastRayX, self.lastRayY, self.lastRayZ = nil , nil , nil
self.lastRayDirectionX, self.lastRayDirectionY, self.lastRayDirectionZ = nil , nil , nil

-- Return the created instance.
return self
end

recalculateCombinedTargetMask

Description

Resets and recalculates the combined target mask using all targeted masks.

Definition

recalculateCombinedTargetMask()

Code

function PlayerTargeter:recalculateCombinedTargetMask()
self.combinedTargetMask = 0
for _, targetedMask in pairs( self.targetedMasks) do
self.combinedTargetMask = bit32.bor( self.combinedTargetMask, targetedMask.mask)
end
end

removeTargetType

Description

Removes the given target type from this targeter.

Definition

removeTargetType(any targetKey)

Arguments

anytargetKeyThe key of the objects to stop targeting.

Code

function PlayerTargeter:removeTargetType(targetKey)

-- Remove the target from the collection.
self.targetedMasks[targetKey] = nil

-- Recalculate the combined target mask and maximum distance.
self:recalculateCombinedTargetMask()
self.highestMaxDistance = 0
for _, targetedMask in pairs( self.targetedMasks) do
self.highestMaxDistance = math.max( self.highestMaxDistance, targetedMask.maxDistance)
end
end

tryAddTargetWithMask

Description

Attempts to add the given information to the given target mask's target.

Definition

tryAddTargetWithMask(entityId hitNode, float x, float y, float z, table targetedMask, float distance)

Arguments

entityIdhitNodeThe node that was hit.
floatxThe hit x position.
floatyThe hit y position.
floatzThe hit z position.
tabletargetedMaskThe targeted mask table to attempt to add to.
floatdistanceThe distance of the ray.

Code

function PlayerTargeter:tryAddTargetWithMask(hitNode, x, y, z, targetedMask, distance)

-- If the distance is greater than the max distance or the hit node does not have the right mask, do nothing.
if distance > targetedMask.maxDistance or distance < targetedMask.minDistance or not CollisionFlag.getHasGroupFlagSet(hitNode, targetedMask.mask) then
return
end

-- If the ray already hit something with this mask that's closer, check the distances.If the hit object is further away than the existing one, do nothing.
local existingClosestTarget = self.currentTargetsByKey[targetedMask.key]
if existingClosestTarget ~ = nil and existingClosestTarget.distance < distance then
return
end

-- If the any of the filter functions from the targeted mask returns false; do nothing.
for i, filterFunction in ipairs(targetedMask.filterFunctions) do
if not filterFunction(hitNode, x, y, z) then
return
end
end

-- Set the closest target of the mask to the hit node.
local target = self.pooledTargets:getOrCreateNext()
target.x, target.y, target.z = x, y, z
target.node = hitNode
target.distance = distance
self.currentTargetsByKey[targetedMask.key] = target
end

update

Description

Updates the targeter to find targeted objects.

Definition

update(float dt)

Arguments

floatdtDelta time in ms.

Code

function PlayerTargeter:update(dt)
-- Get the position and direction from the player's camera, do nothing if it was invalid.
self.lastRayX, self.lastRayY, self.lastRayZ, self.lastRayDirectionX, self.lastRayDirectionY, self.lastRayDirectionZ = self.player:getLookRay()
if self.lastRayX = = nil then
return
end

self:resetState()

-- Cast the ray.
raycastAllAsync( self.lastRayX, self.lastRayY, self.lastRayZ, self.lastRayDirectionX, self.lastRayDirectionY, self.lastRayDirectionZ, self.highestMaxDistance, "raycastCallback" , self , self.combinedTargetMask)
end