Hello all! So… i already have an npc system with multiple catagories of npcs. So far they include, Major, Minor, Shop, Passive Stationary, and Passive Mobile… now i’m ready to move on to something that i haven’t yet done before, that being enemy NPC’s.
My question is where do i begin with player detection and all of the various conditions that must be in play… aswell as causing the npc to attack?
some may be magical some may be melee, and some may be creatures.
Also, and i’m sure this will be simple enough for me to figure out once i get the basis of how this will work down… but the conditions on player level vs. npc level, and whether the enemy will be hostile or defensive.
Anyone have any thoughts on where to start? And how this should work?
Starting Out
Believe it or not, you have done quite a lot of creating your NPC; Planning. However, before you actually start creating the NPC, I suggest that you write down a couple of more things:
Create a couple of formulas (Enemy health, attack, etc.) These formulas will help you differentiate strong NPC’s and weak NPC’s. For example: (DifficultyOfNpc * 2) + 150 ; or something like that.
Create a battle plan. How will the player interact/attack the NPC’s?
I don’t know too much about enemy NPC’s, but here is what I know:
For Follow Script
I don’t know about others, but I used the basic follow script, (multiple of the same from the toolbox), except I modified it to fit for r15 (changing Torso to UpperTorso/HumanoidRootPart)
Attacking
This part of the NPC is the hardest for me, and I suggest that you don’t move onto this phase until you have decided your battle plan. Basically, I made a script so that when a player comes into range, they do something. For example, I had a “Thug” enemy which started punching as soon as a player came into view. If the Thug’s hitbox was touched, it would damage the player.
As for magic… I haven’t actually tried to make anything with magic abilities but I have a suggestion… For one thing, you could make an automatic attack when a player enters the enemy’s view (most likely area of effect attack) like the All Might NPC in Boku No Roblox.
Hostile Or Defensive?
What I do is name the hostile NPC’s humanoid “Enemy” but leave the defensive NPC’s humanoid name as it is. (If you do this method, you have to make all attacks that are directed towards the enemy damage “Enemy” instead of “Humanoid”.)
Thank you i will look into a lot of what you said… naturally i won’t put this as solution, as i want to hear other thoughts as well. I really appreciate your response
An NPC system is one of those systems in roblox lua that will change depending on what you intend on having it do, and on top of that; it will change based on how you code your game. Assuming you already have a basic combat formula that takes into account level, skill, weapons, abilities, etc, it’s not terribly difficult.
Notes
If you do not have a combat formula, I suggest writing one to take into account the things I listed, this way you don’t have to go through and change the NPC scripts once/if you make a combat formula in the future.
Following
Having an NPC track a player is one of the simplest things to do, though it is also one of the buggiest. What you can use is Pathfinding Service and consistently check for a player in a set follow range, say 10 studs, using magnitude or another similar method. Though as I mentioned; pathfinding service has some notable bugs that you should be weary of, such as being unable to traverse certain terrain/part formations.
Attacking
Attacking is one of the more complicated things to script for an NPC. To script an NPC to attack, I would recommend creating a ModuleScript with functions to perform magical abilities, or physical attacks that can then be called for each NPC that you’d be scripting. This way you wouldn’t have to constantly copy and paste functions for magical attacks into the NPC’s. You could have these magical/physical attacks be directed at a player within the NPC’s tracking distance.
Foot Notes
Obviously not every NPC you make is going to be an enemy. To avoid having your attacks hit a friendly NPC, you could do one of two things. The simple way: renaming the humanoid and then checking that whenever an attack is activated. The complex way: create a module that has the names of hostile NPCs and passive NPCs that you then refer to whenever an attack is activated against an NPC.
A disclaimer though, If you plan to use “the simple way”, and intend on having an in-game pvp system, you would run into an issue of having the combat system checking for “Humanoid”. The way around this is to just rename both NPC humanoids to something like; “Hostile” and “Passive”.
So… All of my npc’s so far are spawned locally on their own designated spawn locations. They each have an NPCType value within them where they live in the replicated storage in an NPCAssets folder… When the player spawns or respawns… or :ChildAdded() event is fired in the workspace for streaming enabled reasons… it goes to an activation function which loops through the NPCAssets folder in the replicated storage… it then loops through the NPCSpawn folder in the workspace to see if the (NameOfNPC…" Spawn") Exists… and if it does… it detects the type of the npc… and fires a function that does all the npc stuff in it depending on its type, Major, Minor, or Shop.
However… i believe that i should do hostile npc’s in the server. Am I correct in that? That way players can team. But… i’m having trouble deciding if i should already have the npc’s in the workspace… or spawn them around a designated spawnpoint with a set limit of say 5 enemies at this spawn. My question is how i should go about this? In detail.
Nevertheless I’m using Aero Game Framework for all of this… so everything is in modules right now… for everthing else in this project so far… it has been a godsend.
For the most part, having them pre-spawned in or not is up to you in designing your system. For mine, I have a mobcontroller module that controls my mobs for the most part, then modules inside that module that handle the specific mob.
The controller would handle the basic functions, while the mob module would handle its logic and data.
On server-startup the controller will loop through the mob modules and their spawns/spawn area and spawn the mob in. The server handles the positioning of the mob and the client handles the mob character and animations.
Well… i think i may need to do it server… All other npcs i have no need of being server… but the mobs i’d like all players to be able to see at the same time doing the same things. Why would i use client then for animations and rendering? I’m confused.
Also… i’d like to use raycasting to detect whether a player is within the magnitiude of the mob… so they have to be in line of sight… but i’m having trouble deciding how i want to index the players character in the server within a module. Idk if you are familiar with the Aero game framework… that is what i’m using.
As an example this is that part of the shop keeper architypes code.
local render = game:GetService("RunService").RenderStepped:connect(function(dt)
local NpcHRP = npc:WaitForChild("HumanoidRootPart")
local CharHRP = char:WaitForChild("HumanoidRootPart")
local dist = (NpcHRP.CFrame.p-CharHRP.CFrame.p).magnitude
if not cooldown and not vaus then
if dist <= settings.animationOffset then
local ray = Ray.new(npc.HumanoidRootPart.CFrame.p,npc.HumanoidRootPart.CFrame.LookVector*20)
local object,surfaceposition = workspace:FindPartOnRay(ray,npc)
if object then
local target = object.Parent
if target:FindFirstChild("Humanoid") and game.Players:FindFirstChild(target.Name) then
cooldown=true
local track = NPC_Controller:animate(507770239,npc.Humanoid)
local PassiveSounds = Shop_Keeper_Dialogue[NPCname]["Passive_Sounds"][Status.Value]
local RandomSoundId = Shop_Keeper_Dialogue[NPCname]["Passive_Sounds"][Status.Value][math.random(#PassiveSounds)]
print(RandomSoundId)
Passive_Sound.SoundId = RandomSoundId
Passive_Sound:Play()
wait(1.5)
track:Stop()
spawn(function()
wait(settings.animationCooldownTime)
cooldown=false
end)
end
end
end
end
But in context of in the server… i need to find the character… this code happens locally. Should i do this part of the Hostile npc’s code locally aswell? And then do server stuff?
Player detection can be calculated using simple vector math, and magnitude.
You will obviously need some health too, I reccommend making a script that runs from the conditions of a bunch of values (Name, health, damage etc), this way you can just copy and paste the program into any npc, and change the values.
I use this mechanic in my small project https://www.roblox.com/games/3822004783/RTMT-edition
It really does make things simpler, and you can continue to add my conditional values the more advanced your npc gets.
You could write all the enemie code in a block following an if statement, and the if statement will determin whether or not the NPC is hostile.
It will take a lot of extra, and unecessary code (depending on what values are true) but it really does make NPC creation easier; Especially if you are making many different varieties.
This is a very basic example, but the properties of the NPC will vary on values that are true (or strings for character dialog, etc) It shows the damage the hostile will do to the player (per hit), the health the hostile has, and the ammount of crystals (Reward) that the player will recieve after killing the hostile.