Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How to create NPCs that will wonder around and then do something when they see the player?

Asked by 1 year ago

Another question for my Gun game. This will have a part in the one player mode. I have no idea where to start

0
Well first you need a script or a simple function that would make the npc walk randomly then make a function that only trigger when a player is nearby, to do that you only need to put an invisible hitbox on your npc AltairCelestia 47 — 1y

2 answers

Log in to vote
0
Answered by 1 year ago
Edited 1 year ago

I dont think I can help you with the pathfinding, but if you want them to wander around randomly then try something like this

while true do
local randompos = Vector3.new(math.Random(0,100),0,Math.Random(0,100))
local hum = TheCharacter.Humanoid

hum:MoveTo(randompos)
wait(3)
end
1
Could you explain it please? wasdupup 12 — 1y
Ad
Log in to vote
0
Answered by 1 year ago
Edited 1 year ago

This is vague. But to answer fully, to randomly walk with simple scripting, theres gotta be a cooldown and then randomizer. Also I recommend use Random.new because its more random. math.random uses the same seed so depending on certain testing circumstances, you might see the same things happen again and again. Random.new() just gets a new seed everytime its called used so you wont see the same thing twice no matter what.

--settings START

local cooldown = 20 -- time in seconds inbetween new movement direction
local boundsCorner1 = Vector3.new(-255, -255, -255) -- square which will have points picked for humanoid to move to. This is bottom left corner.
local boundsCorner2 = Vector3.new(255, 255, 255) -- -- square which will have points picked for humanoid to move to. This is top right corner.

--settings END

while true do -- simple loop

    wait(cooldown) -- the actual cooldown

    local x = Random.new():ToNumber(boundsCorner1.X, boundsCorner2.X) -- random x between bounds' x values
    local y = [humanoidrootpart].Position.Y -- this is special. Gravity exists. If you want humanoid to go up stairs or something, thats pathfinding which i wont explain here. So this just keeps the current Y level the same.
    local z = Random.new():ToNumber(boundsCorner1.Z, boundsCorner2.Z) -- random z between bounds' z values
    local randPos = Vector3.new(x, y, z) -- combines values into compatible Vector3

    [Insert Humanoid Here]:MoveTo(randPos)

end

Now for the other part? Seeing the player can be done in different ways. I believe the easiest is to raycast, which is a standard way of checking for an npc being able to "see" a player which is used in npc's that chase players faster or something when they see them and stuff. This can be a repeating check, but i will use a debounce so that it toggles instead of repeats this "thing" the npc will do when it can see the player. This way it will do it once when it sees the player, and then stops when it cant see no more player.

-- settings START

local maxDetectDistance = 32767 -- in studs how far raycast can go before failing. Here i made it really far, this should be good enough for any game, but it also uses more processing power. Its just an idea.

-- settings END

local canSee = false -- the debounce variable

local function action()

    -- do whatever here. Example:

    npchumanoid.WalkSpeed = 50

end

local function stopAction()

    -- do whatever here. Example:

    npc.humanoid.WalkSPeed = 16

end

local function checkVariableCanSee(local_canSee)

if local_canSee == canSee then -- ignore because its already either doing it or undoing it. This makes it so it toggles. It checks if its already in the state it want to go in.

    -- do nothing

else -- this means its different, so it should toggle.

    canSee = local_canSee -- sets it to that so toggle works when this function is called 
later

    if local_canSee == true then -- can see, so do the action

        action()

    else -- cant see, so do ending action

        stopAction()

    end

end

local function checkSight()

    local rayOrigin = [npcHead].Position
local rayTargetPos = [playerhead].Position
local rayDirection = (rayTargetPos - rayOrigin).magnitude -- this is the way of getting the direction relative to rayOrigin pointing to rayTargetPos. WIthout magnitude its still pointing in same direction, magnitude just makes it only 1 stud away which is good for controlling how far the raycast is allowed to go. Raycasts cant go on forever because that would destroy processing because the world is infinite and the raycast would go on forever.


local raycastResult = workspace:Raycast(rayOrigin, rayDirection * maxDetectDistance) -- simulates raycast and returns the result. It just goes in rayDIrection direction and stops once its already calculated maxDetectDistance studs.

if raycastResult and raycastResult.Instance and raycastresult.Instance == [playerhead] then -- does multiple checks to prevent script errors and checks ultimately if it reached the players head, meaning the npc can "see" the player.

    checkVariableCanSee(true) -- this is better than putting the action code directly into this block incase you want to use another function. Its cleaner too.

else

    checkVariableCanSee(false)

end

end

while true do

    wait(1)

    checkSight()

end

hope this helps.

Answer this question