Building the Turret AI
In this series of blogs I am going to describe my implementation of AI for a new Workshop Store model, the Leadwerks turret. The model is shown below, without the weapon inserted.
Before writing any code I first decided the main behaviors I wanted this script to involve.
- The turret should scan the area to identify an enemy (using the team ID to differentiate between enemy types) and choose the closest target. Unlike the soldier AI, the turret AI will not change targets when another enemy attacks it.
- If the target is lost or occluded, another target will be chosen.
- The turret will fire a continuous rapid stream of bullets whenever an enemy is in view. We want this to be an obstacle you have to take cover from, or you will quickly be killed.
- The turret can be killed by either incurring enough damage to bring the health down to zero, or by knocking it over to deactivate it. If the turret is damaged to the point of "death" it will shoot sparks out once and then emit a cloud of smoke. The smoke will be continuous, to clearly indicate the turret is inactive.
- The turret movement will not use the physics system. The model is relatively small and I can't think of any really useful reasons I would want the motion to interact with physics, so I'm not going to implement this.
The first draft of the script uses the World:ForEachEntityInAABB() function to perform a search and find a target enemy within a certain range. I set a breakpoint at line 18 to confirm that the script was successfully finding the player: Notice that a distance check is used so the turret will locate the closest enemy.
Script.target = nil--enemy to shoot
Script.mode = "idle"
Script.lastsearchtime=0
Script.searchfrequency = 500
Script.range = 20
function TurretSearchHook(entity,extra)
if entity.script~=nil then
if type(entity.script.health)=="number" then
if entity.script.health>0 then
local d = extra:GetDistance(entity)
if d<extra.script.range then
if extra.script.target~=nil then
if extra.script:GetDistance(extra.script.target)>d then
extra.script.target = entity.script
end
else
extra.script.target = entity.script
end
end
end
end
end
end
function Script:UpdateWorld()
--Search for target
if self.target==nil then
local currenttime = Time:GetCurrent()
if currenttime - self.lastsearchtime > self.searchfrequency then
self.lastsearchtime = currenttime
local pos = self.entity:GetPosition(true)
local aabb = AABB(pos - Vec3(self.range), pos + Vec3(self.range))
self.entity.world:ForEachEntityInAABBDo(aabb,"TurretSearchHook",self.entity)
end
end
end
-
6
0 Comments
Recommended Comments
There are no comments to display.