Garry's Mod Wiki

CLuaLocomotion:Approach

  CLuaLocomotion:Approach( Vector goal, number goalweight )

Description

Sets the location we want to get to.

Each call of Approach moves the NextBot 1 unit towards the specified goal. The size of this unit is determined by SetDesiredSpeed; the default is 0 (each call of Approach moves the NextBot 0).

To achieve smooth movement with Approach, it should be called in a hook like Think, as shown in the example.

Arguments

1 Vector goal
The vector we want to get to.
2 number goalweight
If unsure then set this to 1.

Example

A NextBot follows Player 1 & shoots Player 2 (if applicable). The NextBot doesn't require a Navigation Mesh.

Notice that Approach is in the Think hook while functions for controlling the bot's animation & orientation are in the RunBehavior hook.

AddCSLuaFile() ENT.Type = "nextbot" ENT.Base = "base_nextbot" 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 ) if self.BotTeam == 1 then self:SetModel( "models/police.mdl" ) else 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.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( 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 ) 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 = 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() 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. end -- 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. end coroutine.wait( 0.1 ) until ( !self.Active ) end 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:Remove() end