Revision Difference
CLuaLocomotion:Approach#546572
<function name="Approach" parent="CLuaLocomotion" type="classfunc">
<description>Sets the location we want to get to. Each call of <page text="Approach">CLuaLocomotion:Approach</page> moves the <page text="NextBot">NextBot</page> 1 unit towards the specified goal. The size of this unit is determined by <page text="SetDesiredSpeed()">CLuaLocomotion:SetDesiredSpeed</page>; the default is 0 (each call of <page text="Approach">CLuaLocomotion:Approach</page> moves the <page text="NextBot">NextBot</page> 0). To achieve smooth movement with <page text="Approach">CLuaLocomotion:Approach</page>, it should be called in a hook like <page text="Think()">ENTITY:Think</page>, as shown in the example.</description>⤶
<description>⤶
Sets the location we want to get to.⤶
⤶
Each call of <page text="Approach">CLuaLocomotion:Approach</page> moves the <page text="NextBot">NextBot</page> 1 unit towards the specified goal. The size of this unit is determined by <page text="SetDesiredSpeed">CLuaLocomotion:SetDesiredSpeed</page>; the default is `0` (each call of <page text="Approach">CLuaLocomotion:Approach</page> moves the <page text="NextBot">NextBot</page> 0).⤶
⤶
To achieve smooth movement with <page text="Approach">CLuaLocomotion:Approach</page>, it should be called in a hook like <page text="Think">ENTITY:Think</page>, as shown in the example.⤶
</description>⤶
<realm>Server</realm>
<args>
<arg name="goal" type="Vector">The vector we want to get to</arg>⤶
<arg name="goalweight" type="number">If unsure then set this to 1</arg>⤶
<arg name="goal" type="Vector">The vector we want to get to.</arg>⤶
<arg name="goalweight" type="number">If unsure then set this to `1`.</arg>⤶
</args>
</function>
<example>
<description>
A <page text="NextBot">NextBot</page> follows Player 1 & shoots Player 2 (if applicable). The <page text="NextBot">NextBot</page> doesn't require a <page text="Navigation Mesh">navmesh</page>. Notice that <page text="Approach">CLuaLocomotion:Approach</page> is in the <page text="Think()">ENTITY:Think</page> hook while functions for controlling the bot's animation & orientation are in the <page text="RunBehavior()">NEXTBOT:RunBehaviour</page> hook.
</description>⤶
<code>⤶
ENT.Type = "nextbot"⤶
<description>
A <page text="NextBot">NextBot</page> follows `Player 1` & shoots `Player 2` (if applicable). The <page text="NextBot">NextBot</page> doesn't require a <page text="Navigation Mesh">navmesh</page>.
⤶
Notice that <page text="Approach">CLuaLocomotion:Approach</page> is in the <page text="Think">ENTITY:Think</page> hook while functions for controlling the bot's animation & orientation are in the <page text="RunBehavior">NEXTBOT:RunBehaviour</page> hook.⤶
</description>⤶
<code>⤶
AddCSLuaFile()⤶
⤶
ENT.Type = "nextbot"⤶
ENT.Base = "base_nextbot"
AddCSLuaFile()⤶
if CLIENT then⤶
⤶
if CLIENT then⤶
return
end
util.PrecacheModel("models/police.mdl")
util.PrecacheModel("models/combine_soldier.mdl")
function ENT:Initialize()
self.BotTeam = math.random(1,2)
self:SetCollisionGroup(COLLISION_GROUP_WORLD)
self:SetHealth(100)
self:AddFlags(FL_OBJECT)
self:SetNWInt("BotTeam",self.BotTeam)
⤶
util.PrecacheModel( "models/police.mdl" )
util.PrecacheModel( "models/combine_soldier.mdl" )
⤶
function ENT:Initialize()
self.BotTeam = math.random( 1, 2 )
self:SetCollisionGroup( COLLISION_GROUP_WORLD )
self:SetHealth( 100 )
self:AddFlags( FL_OBJECT )
self:SetNWInt( "BotTeam", self.BotTeam )
⤶
if self.BotTeam == 1 then
self:SetModel("models/police.mdl")
self:SetModel( "models/police.mdl" )
else
self:SetModel("models/combine_soldier.mdl")
self:SetModel( "models/combine_soldier.mdl" )
end
self.WeaponMount = self:LookupAttachment("anim_attachment_RH") --The bot's weapon will mount to the bot's hand.
self.WeaponPosition = self:GetAttachment(self.WeaponMount) --Before parenting; the bot's weapon will be set to the orientation & position of the bot's hand.
self.Weapon = ents.Create("prop_dynamic") --The bot will hold a weapon-looking entity that'll fire bullets on its behalf.
self.Weapon:SetPos(self.WeaponPosition.Pos)
self.Weapon:SetAngles(self.WeaponPosition.Ang)
self.Weapon:SetModel("models/weapons/w_smg1.mdl")
⤶
self.WeaponMount = self:LookupAttachment( "anim_attachment_RH" ) -- The bot's weapon will mount to the bot's hand.
self.WeaponPosition = self:GetAttachment( self.WeaponMount ) -- Before parenting; the bot's weapon will be set to the orientation & position of the bot's hand.
⤶
self.Weapon = ents.Create( "prop_dynamic" ) -- The bot will hold a weapon-looking entity that'll fire bullets on its behalf.
self.Weapon:SetPos( self.WeaponPosition.Pos )
self.Weapon:SetAngles( self.WeaponPosition.Ang )
self.Weapon:SetModel( "models/weapons/w_smg1.mdl" )
self.Weapon:Spawn()
self.Weapon:SetParent(self,self.WeaponMount)
self:StartActivity(ACT_IDLE_SMG1)
self.head = self:LookupBone("ValveBiped.Bip01_Head1") --The bot's head will be used to simulate vision.
self.Active = true --Used for breaking loops when the bot dies.
self.loco:SetDesiredSpeed(GetConVar("dni_playerspeed"):GetInt())
self.Weapon:SetParent( self, self.WeaponMount )
⤶
self:StartActivity( ACT_IDLE_SMG1 )
⤶
self.head = self:LookupBone( "ValveBiped.Bip01_Head1" ) -- The bot's head will be used to simulate vision.
self.Active = true -- Used for breaking loops when the bot dies.
⤶
self.loco:SetDesiredSpeed( 100 )
end
function ENT:Think()
self.targetLocation = Entity(1) --Temporary; a different block of code shall determine the bot's target location.
self.targetEnemy = Entity(2) --Temporary; a different block of code shall determine the bot's enemy in the future.
if self.targetLocation then --If the bot has a target location (i.e., an ally), go for it.
self.loco:Approach(self.targetLocation:GetPos(),1)
⤶
function ENT:Think()
self.targetLocation = Entity( 1 ) -- Temporary; a different block of code shall determine the bot's target location.
self.targetEnemy = Entity( 2 ) -- Temporary; a different block of code shall determine the bot's enemy in the future.
⤶
if self.targetLocation then -- If the bot has a target location (i.e., an ally), go for it.
self.loco:Approach( self.targetLocation:GetPos(), 1 )
end
if IsValid(self.targetEnemy) then --If the bot is shooting an enemy while following an ally, its pose parameters must be updated so it animates appropriately.
self.faceDir = self:GetForward() --Where is the bot facing @ this instant?
self.moveDir = self:WorldToLocal(self.targetEnemy:GetBonePosition(self.head)) --Where is the bot headed @ this instant? (The bot may be walking sideways as it shoots the enemy while following the ally.)
self.yaw = self.moveDir:AngleEx(self.faceDir) --What is the difference ≬ these directions?
self:SetPoseParameter("move_yaw",self.yaw.yaw)
self:SetPoseParameter("aim_pitch",self.yaw.pitch)
self:SetPoseParameter("aim_yaw",self.yaw.yaw)
self.Weapon:FireBullets({Attacker = self,Callback = DisplayTurretDamageInfo,Damage = GetConVar("dni_turretdamage"):GetInt(),Force = 1,Distance = 2400,HullSize = 1,Num = 2,Tracer = 4,AmmoType = "smg1",TracerName = "MuzzleEffect",Dir = self.Weapon:GetForward(),Spread = Vector(0,0,0),Src = self.Weapon:GetPos(),IgnoreEntity = self},true)
else --If the bot is just following an ally, it'll face the ally. Pose parameters will be used to insure that the bot's animation is always consistant with where it's facing vs. where it's moving.
self.faceDir = self:GetForward() --Where is the bot facing @ this instant?
self.moveDir = self:WorldToLocal(self.targetLocation:GetPos()) --Where is the bot headed @ this instant? (The bot may take a few frames to be fully facing its ally.)
self.yaw = self.moveDir:AngleEx(self.faceDir) --What is the difference ≬ these directions?
self:SetPoseParameter("move_yaw",self.yaw.yaw)
⤶
if IsValid( self.targetEnemy ) then -- If the bot is shooting an enemy while following an ally, its pose parameters must be updated so it animates appropriately.
self.faceDir = self:GetForward() -- Where is the bot facing @ this instant?
self.moveDir = self:WorldToLocal( self.targetEnemy:GetBonePosition( self.head ) ) -- Where is the bot headed @ this instant? (The bot may be walking sideways as it shoots the enemy while following the ally.)
self.yaw = self.moveDir:AngleEx( self.faceDir ) -- What is the difference ≬ these directions?
self:SetPoseParameter( "move_yaw", self.yaw.yaw )
self:SetPoseParameter( "aim_pitch", self.yaw.pitch )
self:SetPoseParameter( "aim_yaw", self.yaw.yaw )
self.Weapon:FireBullets( {
Attacker = self,
Callback = DisplayTurretDamageInfo,
Damage = 5,
Force = 1,⤶
Distance = 2400,⤶
HullSize = 1,⤶
Num = 2,⤶
Tracer = 4,⤶
AmmoType = "smg1",⤶
TracerName = "MuzzleEffect",⤶
Dir = self.Weapon:GetForward(),⤶
Spread = vector_origin,⤶
Src = self.Weapon:GetPos(),⤶
IgnoreEntity = self⤶
}, true )⤶
else -- If the bot is just following an ally, it'll face the ally. Pose parameters will be used to insure that the bot's animation is always consistant with where it's facing vs. where it's moving.⤶
self.faceDir = self:GetForward() -- Where is the bot facing @ this instant?⤶
self.moveDir = self:WorldToLocal( self.targetLocation:GetPos() ) -- Where is the bot headed @ this instant? (The bot may take a few frames to be fully facing its ally.)⤶
self.yaw = self.moveDir:AngleEx( self.faceDir ) -- What is the difference ≬ these directions?⤶
⤶
self:SetPoseParameter( "move_yaw", self.yaw.yaw )⤶
end
end
function ENT:RunBehaviour()
⤶
function ENT:RunBehaviour()
repeat
--Now updating the nextbot's animation…⤶
if self.targetLocation && self:GetActivity() != ACT_RUN_RIFLE then --If the bot is chasing something (it has a target) & the bot isn't appropriately animated already…⤶
self:StartActivity(ACT_RUN_RIFLE) --…set its animation.
elseif !self.targetLocation && self:GetActivity() != ACT_IDLE_SMG1 then --Evidentely, the bot isn't chasing anything. If its animation isn't set already…⤶
self:StartActivity(ACT_IDLE_SMG1) --…do so now.
-- Now updating the nextbot's animation...⤶
if self.targetLocation && self:GetActivity() != ACT_RUN_RIFLE then -- If the bot is chasing something (it has a target) & the bot isn't appropriately animated already...⤶
self:StartActivity( ACT_RUN_RIFLE ) -- ...set its animation.
elseif !self.targetLocation && self:GetActivity() != ACT_IDLE_SMG1 then -- Evidentely, the bot isn't chasing anything. If its animation isn't set already...⤶
self:StartActivity( ACT_IDLE_SMG1 ) -- ...do so now.
end
--Now updating the nextbot's bearings…⤶
if IsValid(self.targetEnemy) then
self.loco:FaceTowards(self.targetEnemy:GetPos()) --Face the enemy.
⤶
-- Now updating the nextbot's bearings...⤶
if IsValid( self.targetEnemy ) then
self.loco:FaceTowards( self.targetEnemy:GetPos() ) -- Face the enemy.
else
self.loco:FaceTowards(self.targetLocation:GetPos()) --Face the ally.
self.loco:FaceTowards( self.targetLocation:GetPos() ) -- Face the ally.
end
coroutine.wait(0.1)
until (!self.Active)
⤶
coroutine.wait( 0.1 )
until ( !self.Active )
end
function ENT:OnKilled(kinfo)
self:StartActivity(ACT_DIERAGDOLL)
local drop = ents.Create("weapon_smg1")
drop:SetPos(self.Weapon:GetPos())
⤶
function ENT:OnKilled()
self:StartActivity( ACT_DIERAGDOLL )
local drop = ents.Create( "weapon_smg1" )
drop:SetPos( self.Weapon:GetPos() )⤶
drop:Spawn()
self.Active = false --The NEXTBOT:RunBehaviour() will now terminate.
self:AddFlags(FL_KILLME)
self.Weapon:Remove()
⤶
self.Active = false -- The NEXTBOT:RunBehaviour() will now terminate.
self:AddFlags( FL_KILLME )
⤶
self.Weapon:Remove()
self:Remove()
end
</code>
</code>
</example>