Hello! I am creating a horror game on roblox inspired on Isle and other roblox games, im currently trying to script the main monster of the game, but i never really worked with enemy npcs before
What i am trying to achieve is seeing if i can improve my attack system, im currently using distance checks to see if the player is in enough range, and applying a different cooldown for each of the attacks inside their function, but im sure there is more effective ways to do that
Heres my current script:
local Monster = script.Parent
local MonsterRoot = Monster:FindFirstChild("HumanoidRootPart")
local MonsterHumanoid = Monster:FindFirstChild("Humanoid")
local TweenService = game:GetService("TweenService")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SimplePath = require(ServerStorage.Modules.SimplePath)
------------
-- Functions
------------
local function GetClosestPlayer()
local ClosestPlayer
for _, Player in pairs(game:GetService("Players"):GetPlayers()) do
local Character = Player.Character
if Player:DistanceFromCharacter(MonsterRoot.Position) < 500 then
if not ClosestPlayer or Player:DistanceFromCharacter(MonsterRoot.Position) < ClosestPlayer:DistanceFromCharacter(MonsterRoot.Position) then
ClosestPlayer = Player
end
end
end
return ClosestPlayer
end
--------------
-- Core Script
--------------
repeat task.wait() until #game:GetService("Players"):GetPlayers() > 0
local Roaming = false
while true do
local ClosestPlayer = GetClosestPlayer()
if ClosestPlayer then
local Character = Workspace:WaitForChild(ClosestPlayer.Name)
coroutine.wrap(function()
repeat
if ClosestPlayer:DistanceFromCharacter(MonsterRoot.Position) < 5 then
--// Slash Attack
elseif ClosestPlayer:DistanceFromCharacter(MonsterRoot.Position) < 40 then
--// Bullet Attack
end
task.wait()
until
not ClosestPlayer or not ClosestPlayer.Character or ClosestPlayer:DistanceFromCharacter(MonsterRoot.Position) > 500 or ClosestPlayer.Character.Humanoid.Health == 0
end)()
repeat
local PathObject = SimplePath.new(Monster)
PathObject.Visualize = true
PathObject.Error:Connect(function()
PathObject:Run(Character.HumanoidRootPart)
end)
PathObject:Run(Character.HumanoidRootPart)
task.wait()
until
not ClosestPlayer or not Character or ClosestPlayer:DistanceFromCharacter(MonsterRoot.Position) > 500 or ClosestPlayer.Character.Humanoid.Health == 0
end
task.wait()
end
Both attack styles could end up being solved with Raycasting.
Such as with the “Slash Attack” you could shoot out a Raycast on the initial slash hit, get the character and damage it accordingly.
For the gun attacks it can follow the Raycasting method as well.
There is a wide variety of how you end up using Raycasting, but it is a very helpful WorldRoot function for stuff like attack damage detection. A different approach too could be touch detection with some sort of coordinated Hitbox, but it is honestly up to you.
Oh i completely forgot about using raycast for these functions, i already saw that module so im gonna use it, thanks for the tip!
But what i was looking for is an alternative and better way to do the magnitude checks for the attacks, since i am planning to add more attacks
It doesn’t look like there is much more you can do, I would imagine you could cut down all the If statements into some sort of Magnitude sorts into Attack type.
-- maybe some module or table of functions that handle the NPC's attacks
local function NPCAttack(magnitude : number)
-- code for determining what attack to do based on magnitude
end
the code at the bottom is just a different magnitude check, but you can combine magnitude and dot product to also check if the character is looking in the attacking direction.
^^ this is just an example, in the first picture i sent there is a green cube near my cursor it would turn red if my character was not looking at it because of this code.
basically if the vectors are looking the same direction the dot product returns a value of 1, and
90 degrees is 0 and completely opposite is -1
its a little weird im ngl, but if you mess with the numbers a little bit you might find values you like. They are not exactly 1 to 1 with 360 degrees for the first image the dot product had to be greater than 0.65 to turn the squares on the floor red.
Oh so it will only target players that are for example in his field of vision? I already saw that, i will implement it in my script, thanks for the tip!