How to detect gunfire with a Civilian AI

What I want to do
I have an open world GTA styled game, with one thing missing. Civilians. I can use the pathfinding service ok, and have found many posts and tutorials about it, but I can’t find a way for Civilians to be scared of you. To make it more realistic, I’m trying to make it so when you pull out a weapon, push the civilian a lot, or other stuff that normal people would find scary or annoying, the civilian will either run, or walk away from you. But, I’m not sure how the civilian could detect a player pulling out a gun in a near by area, I’ve never used stuff like magnitude and I’m not sure what to do here.

The Issue
If I used an invisible part around the gun as sort of a radius, and have CanCollide off, Civilians can’t detect if it’s touching them, and also, would causes certain ally-ways and cars to be inaccessible if CanCollide was on. So I’m kind of stuck here.

What I’ve tried
I’ve tried firing a remote event when tool.Equipped, and then have the server to check if any thing is near the tool position, but .Magnitude needs to positions, and I can’t know if a civilian is there or not before hand (then the problem would already be solved).

I’m not asking for a full block of code, but rather how to approach this situation. If you could give me any tips or pointers at the very least, that would be appreciated :slight_smile:

Thanks in advance


This is my first forum post, so tell me if I’m doing anything wrong!

A good idea might to just to grab all the AI within a radius of the player. Gun’s make noise and this noise is much more noticeable in areas closer to the player.

So if an NPC is closer to the player when shooting occurs then you tell them to escape.

A simple way to check the NPCs near you would be to store them all in an array and iterate over the array then compare the magnitude of the vector created when you subtract your position and their position.


for i, NPC in pairs(NPCs) do
    local distance = (NPC.PrimaryPart - MyCharacter.PrimaryPart).Magnitude

    if (distance < maxGunshotSoundDistance) then

When a gun “shoots”, fire a BindableEvent in ServerStorage.

Let’s say you put a bindable event in server storage called “GunShot” (Bindable events are like remote events but it communicates between the same scripts, meaning server scripts can communicate to other server scripts and local scripts with local script).

In the script where the player pulls out a gun, fire that remote event:

local SS = game:GetService("ServerStorage")
local Bindable = SS.GunShot
local Character = -- the players Character

local function PullOutGun()

And then in another server script, inside of ServerSriptService do something like:

local SS = game:GetService("ServerStorage")
local Bindable = SS.GunShot

local function CivilianScared(CivilianHRP, HRP)
    if (HRP.Position - CivilianHRP).Magnitude < 51 then
        -- run away

    local HRP = Character.HumanoidRootPart
    for i, Civilians in pairs(Civilians) do
        CivilianScared(Civilian.HumanoidRootPart, HRP)
1 Like

Alright, I’m testing that out, but I’m a little confused on CivilianScared(Civilian.HumanoidRootPart, HRP)
If you already give the function the Civilian HumanoidRootPart, then why do you also have HRP? I haven’t used local functions too much before, so thanks if you could explain that.

I think whatever you do to detecting it should be done by the client firing the gun. Otherwise the server is doing unnecessary calculating each time, and this could lead to performance problems with lots of people firing.

Oh, that one was just because I didn’t want to define the humanoidrootpart of the civilian inside of the function, it would just give that CivilianScared the civilians root part.

@RVVZ No, it shouldn’t because then people can exploit it and make the civilians lag .

Ohhhhh, ok, thanks. I’ll tell you if it works :slight_smile:

How? Each time a gunshot is fired you pass an argument of the civilians in a table, you check through all those civilians the same way.

Hm :confused:, I’m getting this error in the console form the ShotsFired Script that checks if the Civilian is close.

I just made it do print("RUN!") if it’s close enough, and it did that error.

Have you defined Civilians yet?

local Civilians = -- table of civilians

Well this explains it.

Also @acuaro If you have more than 10 civilians at once, lots of players, automatic guns then you should follow my advice about getting the civilians on the firing players client and passing it as an argument, and then checking this is valid on the server.

Alright, thanks, It works now! I didn’t realize it, but I defined ‘Civilian’ in another function, instead of out of it.

WAIT. This error just came out of no-where.

This might be a simple mistake, I’m not the best at Blindable events and for i,v paris loops also.

i dont know how you make your AI but in my AI i added something called “State” which is the state in what the AI currently does, this kind of AI is used in warcraft 3 so i just use the same thing, and it worked, so, basically if you use the same AI as mine. then, i would make a state where the AI panics, and to make the AI panics when the gun shots all i must do is pick all AI within a certain radius and change their state to “Panic”.

and to optimize it i would store all AI’s in a table rather than looping through workspace every gunshot.

Ok, so I think I forgot to put Position after the npc’s root part:

Simple fix:

if (HRP.Position - CivilianHRP.Position).Magnitude < 51 then