Nextbot is what the AI in Team Fortress 2 and Left 4 Dead
use. This tutorial will go over the steps for a simple AI that will search for
enemies (you) and chase them until they die or are too far away. It will also
do some random other stuff when there are not any enemies.
Lets get started
First create the .lua file for your entity. The one I made
for this tutorial is in "addons/Nextbot_tut/lua/entities" and is
named "simple_nextbot.lua". Now open that file so you can start
adding the code.
The code
The basic stuff we need for entities
Start off with defining the base entity to use and making it
spawnable. Pretty much the same as any other entity so far Here we set the
model and define some variables we will use later.
AddCSLuaFile()
ENT.Base =
"base_nextbot"
ENT.Spawnable =
true
function ENT:Initialize()
self:SetModel(
"models/hunter.mdl" )
self.LoseTargetDist = 2000 --
How far the enemy has to be before we lose them
self.SearchRadius
= 1000 -- How far to search for enemies
end
Enemy related stuff
This adds some useful functions for enemy related stuff. An
NPC/bot isn't complete if it can't target stuff, right? These include a
function to check if there is still an enemy or if it got away and a function
to search for enemies. I've added all sorts of comments so you know exactly
what they do.
----------------------------------------------------
-- ENT:Get/SetEnemy()
-- Simple functions used in keeping our enemy saved
----------------------------------------------------
function ENT:SetEnemy( ent )
self.Enemy
= ent
end
function ENT:GetEnemy()
return
self.Enemy
end
----------------------------------------------------
-- ENT:HaveEnemy()
-- Returns true if we have an enemy
----------------------------------------------------
function ENT:HaveEnemy()
-- If
our current enemy is valid
if (
self:GetEnemy() and IsValid( self:GetEnemy() ) ) then
--
If the enemy is too far
if
( self:GetRangeTo( self:GetEnemy():GetPos() ) > self.LoseTargetDist ) then
--
If the enemy is lost then call FindEnemy() to look for a new one
--
FindEnemy() will return true if an enemy is found, making this function return
true
return
self:FindEnemy()
--
If the enemy is dead( we have to check if its a player before we use Alive() )
elseif
( self:GetEnemy():IsPlayer() and !self:GetEnemy():Alive() ) then
return
self:FindEnemy() --
Return false if the search finds nothing
end
--
The enemy is neither too far nor too dead so we can return true
return
true
else
--
The enemy isn't valid so lets look for a new one
return
self:FindEnemy()
end
end
----------------------------------------------------
-- ENT:FindEnemy()
-- Returns true and sets our enemy if we find one
----------------------------------------------------
function ENT:FindEnemy()
--
Search around us for entities
-- This
can be done any way you want eg. ents.FindInCone() to replicate eyesight
local
_ents = ents.FindInSphere( self:GetPos(), self.SearchRadius )
-- Here
we loop through every entity the above search finds and see if it's the one we
want
for k,
v in pairs( _ents ) do
if
( v:IsPlayer() ) then
--
We found one so lets set it as our enemy and return true
self:SetEnemy(
v )
return
true
end
end
-- We
found nothing so we will set our enemy as nil ( nothing ) and return false
self:SetEnemy(
nil )
return
false
end
Coroutines
Now that the bot can find enemies we need to get it to
actually do something other then just having an enemy. This next part is where
most of our AI will be set up. The function is a coroutine, or pretty much a
giant looping section of code, except you can pause it for a period of time
using coroutine.wait( time ). Coroutines allow you to do things in a timed
order, letting you pause the function so we can make the bot face the player or
play an animation. And since its all inside a while true loop, it will run for
as long as the bot exists. So after your ai has finished running everything it
can do, it will go back and do it again. Here is an example of a very simple
bot.
No comments:
Post a Comment