Garry's Mod Wiki

Revision Difference

CLuaLocomotion:Approach#546564

<function name="Approach" parent="CLuaLocomotion" type="classfunc"> <description>Sets the location we want to get to</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> </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"⤶ ENT.Base = "base_nextbot"⤶ AddCSLuaFile()⤶ 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(GetConVar("dni_playerspeed"):GetInt())⤶ 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 = 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)⤶ 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(kinfo)⤶ 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⤶ </code>⤶ </example>