Hello everybody. I decided I'd make a "public project" for lack of a better word. Now, I've always wanted deathmatch-oriented bots in Garry's Mod. So, I decided to look into pathfinding and GMod's built-in navmesh functions.
The end result so far was this mess:
[code]
local testnodes = {}
for i = 1, #navmesh.GetAllNavAreas() do
local area = navmesh.GetNavAreaByID( i )
if area:IsValid() then
testnodes[i] = {}
testnodes[i].id = i
testnodes[i].x = area:GetCenter().x
testnodes[i].y = area:GetCenter().y
end
end
function navmesh.FindExclude( excl, pos, radius, stepdown, stepup )
local checked_areas = {}
local unchecked_areas = navmesh.Find( pos, radius, stepdown, stepup )
for _, v in pairs(unchecked_areas) do
if v ~= excl then
checked_areas[#checked_areas + 1] = v
end
end
return checked_areas
end
nb_bots = {}
function nb_bots.GetAStarPath( ply )
local nav_start = navmesh.GetNearestNavArea( ply:GetPos() )
if !nav_start:IsValid() then return "nope" end
local nav_goal = table.Random(navmesh.FindExclude( nav_start, Entity(1):GetPos(), 9999, 9999, 9999 ))
if !nav_goal:IsValid() then return "nope" end
return astar.path( testnodes[nav_start:GetID()], testnodes[nav_goal:GetID()], testnodes, true, function() return true end ) or "nope"
end
function nb_bots.DecideEnemy( ply )
if ply.Enemy and ply.Enemy:Alive() and ply:Visible(ply.Enemy) then return end
local found = {}
for not_needed, playr in pairs( player.GetAll() ) do
if playr ~= ply and playr:Alive() and ply:Visible( playr ) then
found[#found + 1] = playr
end
end
if #found == 0 and ply.Enemy ~= nil then ply.Enemy = nil return end
ply.Enemy = table.Random( found )
end
function nb_bots.LookatPosXYZ( usercmd, ply, position )
--[[local our_position = ply:GetPos()
local distance = our_position:Distance( position )
local pitch = math.atan2( -(position.z - our_position.z), distance )
local yaw = math.deg(math.atan2(position.y - our_position.y, position.x - our_position.x))
ply:SetEyeAngles( Angle( pitch, yaw, 0 ) )
usercmd:SetViewAngles( Angle( pitch, yaw, 0 ) )]]
local ang = ((ply:EyePos() - Vector(0,0,10))-(position - Vector(0,0,10))):AngleEx(Vector(0,0,0))
local lClamp = ang + Angle(0,180,0)
local ideal = Angle(math.Clamp(-lClamp.p,-180,180),lClamp.y,math.Clamp(lClamp.r,-180,180))
ply:SetEyeAngles(ideal)
usercmd:SetViewAngles(ideal)
end
function nb_bots.LookatPosXY( usercmd, ply, position )
local our_position = ply:GetPos()
local distance = our_position:Distance( position )
local pitch = math.atan2( -(position.z - our_position.z), distance )
local yaw = math.deg(math.atan2(position.y - our_position.y, position.x - our_position.x))
ply:SetEyeAngles( Angle( pitch, yaw, 0 ) )
usercmd:SetViewAngles( Angle( pitch, yaw, 0 ) )
end
hook.Add( "StartCommand", "Bots_Control", function( ply, cmd )
if not ply:IsBot() then return end
cmd:ClearMovement()
cmd:ClearButtons()
if not ply.AstarPath then ply.AstarPath = nb_bots.GetAStarPath( ply ) ply.CurSegment = 1 end
if ply.CurSegment ~= (#ply.AstarPath+1) then
if ply.AstarPath == "nope" then return end
if math.Dist( ply:GetPos().x, ply:GetPos().y, ply.AstarPath[ply.CurSegment].x, ply.AstarPath[ply.CurSegment].y ) <= 1 then
print("moving on!")
ply.CurSegment = ply.CurSegment + 1
else
cmd:SetForwardMove( 200 )
end
if ply.CurSegment ~= #ply.AstarPath+1 then
local vec = Vector( ply.AstarPath[ply.CurSegment].x, ply.AstarPath[ply.CurSegment].y, 0 )
nb_bots.LookatPosXY( cmd, ply, vec )
end
else
ply.CurSegment = 1
end
--[[local valid = IsValid(ply:GetActiveWeapon())
if valid and ply:GetActiveWeapon():GetClass() ~= "weapon_ar2" then
ply:SelectWeapon("weapon_ar2")
end
nb_bots.DecideEnemy( ply )
if ply.Enemy then
nb_bots.LookatPos(cmd, ply, ply.Enemy:EyePos())--:GetPos())
if ply.Enemy:Alive() and ply:Visible(ply.Enemy) then
--if ply:GetPos().z - enemy:GetPos().z <= -30 or ply:GetPos().z - enemy:GetPos().z >= 30 then return end
--if valid and ply:GetActiveWeapon():Clip1() == 0 then
--cmd:SetButtons( IN_RELOAD )
--return
--end
cmd:SetSideMove(math.cos(RealTime())*400)
if ply:GetPos():Distance(ply.Enemy:GetPos()) < 801 then
cmd:SetButtons( IN_ATTACK )
else
cmd:SetForwardMove( 200 )
end
end
--[[if not ply.path then
local nav_area = table.Random( navmesh.Find( ply:GetPos(), 9000, 9000, 9000 ) )
ply.path = nav_area:GetRandomPoint()
end
if ply.path and ply:GetPos():Distance( ply.path ) ~= 0 then
nb_bots.Look_at_Position( cmd, ply, ply.path )
cmd:SetForwardMove( 200 )
else
ply.CompletedMoving = true
end]
end]]
end )[/code]
(with this a* module [url]https://github.com/lattejed/a-star-lua[/url])
Now, I made this thread to bring awareness to it and also to start a discussion about it. I want to see if anyone is willing to help. I'm interested in seeing what we can do with this.
[editline]12th January 2016[/editline]
If anyone wants to help clean the code up/has any ideas, be sure to post here!
Sorry, you need to Log In to post a reply to this thread.