So, I’m making a destiny inspired game and I’m currently working on the bot, and I want it to find cover. So, Should I make specific parts that can work as cover and the figure out the best spot to hide behind (how would I do that? I want them to be hidden by the player and be able to peek out and shoot them).
I would show code, But its just a basic pathfinding system. I just need to know how to find the position to go to.
If you want to make the bot find cover, I would create an invisible part under the cover that you want the bot to pathfind to, then use MoveTo() to make him move there if a player is within a certain distance of the bot.
Yes, I know that part. but I bet there is a better way to do it. also, I want to make it so they are hidden.
also, I’m having an issue (off subject but is required). does anyone know how to make a character look at another part with it still being able to move.
Like the idea. issue though is that it will be terrible laggy. What I’m thinking is there are some parts marked as hidable. then it finds the closet, checks for good cover, if not good cover, then find the second closets and repeat.
Lag from raycasts depends mostly on length not amount, and many games fire multiple per frame. You could test it out by checking Script Performance if you have any concerns but as long as your bot isn’t a sniper at long distance it should be fine
In that case it would make sense to combine both like @mc7oof said. Make a folder of walls that can be hid behind or tag them with CollectionService and you can reduce the raycasts significantly
I’m currently thinking we find a way to calculate size thingy and make it check on the left of the part can it peek and the player? no then check the right if not then that’s an invalid hiding spot.
The way I’d probably go about doing it is manually marking “cover zones” with an invisible part/marker of some sort.
When a bot desires to move to cover, it’ll iterate through the cover zones, and put the ones within a set distance (maybe say, 100 studs or so) into a table.
Then, for each of those in-range cover zones in the table, it’ll do a raycast from the cover zone to each enemy within the bot’s sight radius. If the cover zone is visible to any enemies, it will be removed from the table. Then, after all cover zones are checked, it’ll pick a random cover zone from the remaining list, and pathfind to it.
If you want the bot’s behavior to be a bit less predictable, you could instead make it so each cover zone is given a “score” based on how many enemies it is visible to, and then it instead picks a cover zone based on a weighted random distribution, with the “score” of the cover point being it’s weight.
The first step would be to detect all nearby pieces of cover. You could try and define these procedurally, but this may be laggy if you have lots of NPCs. Tagging objects as cover works fine as well.
Then we need to find out the best direction to use the cover, which should be the opposite to the general direction of the enemy. This would be calculated from the opposite direction of the enemy team’s spawn and the direction of nearest 3-5 enemies combined.
Lastly we need to find the most optimal piece of cover. Factors in order of importance are:
Allies near cover (avoid grouping up)
Range of current weapon in relation to nearest enemy from cover.
Amount of enemy directions covered.
Height advantage (if desired).
Size and height of cover; how safe the cover is.
Time to to arrive.
Also, depending on the size of the cover, the NPC may need to peek to the left or right.
I already have an idea. I’m going to get each side of a part tagged as a hiding spot then get each side (expect top and bottom) and see if they can be spotted by the player. Issue though this raycast won’t work for some reason. Its supposed to be ok but its not
function RayCast(PositionA,PositionB,Params)
local raycastParams = RaycastParams.new()
table.insert(Params,Character)
raycastParams.FilterDescendantsInstances = Params
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
local raycastResult = workspace:Raycast(PositionA, PositionB, raycastParams)
print(raycastResult)
if raycastResult then
return raycastResult
else
return nil
end
end
function PlacePart(Pos,Color)
local p = Instance.new("Part")
p.Size = Vector3.new(1,1,1)
p.Shape = "Ball"
p.Material = "Neon"
p.CFrame = Pos
p.Anchored = true
p.CanCollide = false
p.Color = Color
p.Parent = workspace
return p
end
function CheckIfGoodSpot(Part)
local Sides = {}
local BestSpots = {}
table.insert(Sides,Part.CFrame * CFrame.new(Part.Size.X/1.5,1,Part.Size.Z/2.5))
for _, Side in pairs(Sides) do
for _, current in pairs(Targets) do
local cast = RayCast(Side.Position,current:FindFirstChildWhichIsA("Humanoid").RootPart.Position,{})
PlacePart(Side,Color3.new(1, 0.666667, 0))
if cast == nil then
local haystack = table.find(Sides,Side)
table.remove(Sides,haystack)
print("BAD")
end
end
end
end