How would I be able to use module functions inside of table functions?

Heya There!!

I’m working on an entity script and I’m trying to use the module functions (Specifically, Wander). The issue is that it’s printing out “Attempt to index nil with 'PrimaryPart'” during the ComputeAsync part.

--[[SERVICES]]--
local ServerStorage = game:GetService("ServerStorage")
local PathfindingService = game:GetService("PathfindingService")

--[[FOLDERS]]--
local EntityFolder = ServerStorage:WaitForChild("Entities")
local RegularFolder = EntityFolder.Regular
local SpecialFolder = EntityFolder.Special

--[[MODULE]]--
local BaseEntity = {}
BaseEntity.__index = BaseEntity

--//Creating the entity
function BaseEntity:CreateEntity(EntityName)
	--//Finding entity
	local RequestedEntity = RegularFolder:FindFirstChild(EntityName) if not EntityName then
		RequestedEntity = SpecialFolder:FindFirstChild(EntityName) if not EntityName then
			warn("CANNOT FIND ENTITY: "..EntityName)
			return
		end
	end
	
	--//Creating entity
	local self = setmetatable({}, BaseEntity)
	
	self.Entity = RequestedEntity:Clone()
	self.Humanoid = RequestedEntity:FindFirstChildWhichIsA("Humanoid")
	self.Entity.Parent = game.Workspace
	
	--//List of entity behaviors & assinging them to their respective entity.
	self.EntityBehaviors = {
		["Starvlud"] = {
			["Behavior"] = function(self)
				BaseEntity:Wander()
			end,
		}
	}
	self.EntityBehaviors.Starvlud:Behavior()

	return self
end

--//Default functions
function BaseEntity:Wander()
	local Walkpoints = workspace:WaitForChild("Walkpoints"):GetChildren()
	local RandomWalkPoint = Walkpoints[math.random(1,#Walkpoints)]
	
	while task.wait() do
		local NewPath = game:GetService("PathfindingService"):CreatePath()
		NewPath:ComputeAsync(self.Entity.PrimaryPart.Position, RandomWalkPoint.Position)
		if NewPath.Status == Enum.PathStatus.Success then
			local Waypoints = NewPath:GetWaypoints()
			
			for _, Waypoint in pairs(Waypoints) do
				self.Humanoid:MoveTo(Waypoint.Position)
				self.Humanoid.MoveToFinished:Wait()
			end
		end
	end
end

function BaseEntity:InvestigateNoise()
	--//TBA
end

function BaseEntity:ChaseTarget()
	--//TBA
end

function BaseEntity:TryJumpscare()
	--//TBA
end

return BaseEntity

“Attempt to index nil” means the object you’re trying to index in doesn’t exist, e.g self.Entity.

This error message has tripped me up multiple times and still continues to do so. I honestly don’t know why, maybe it’s the quotations around what you try to index it with :person_shrugging:

1 Like

I think it’s because of this
this gets compiled as BaseEntity.Wander(BaseEntity) which i dont think you are trying to do, BaseEntity doesn’t have a Entity member so it’d error
if thats not the problem then i have no other idea

1 Like

yes but self in that context will be BaseEntity and BaseEntity doesn’t have Entity member

1 Like

Yeah, that’s probably the issue.

I also noticed the code will attempt to clone the requested entity even if it doesn’t exist. This is because the return condition only checks if a parameter isn’t passed to CreateEntity:

If nothing is passed you should honestly just return it. Also return if there is no Requestedentity. Also, use string interpolation, it’ll make your life easier:

function BaseEntity:CreateEntity(EntityName)
	if not EntityName then return warn("NO ENTITYNAME GIVEN") end
	
	--//Finding entity
	local RequestedEntity = RegularFolder:FindFirstChild(EntityName) 
	
	if not RequestedEntity then return warn(`CANNOT FIND ENTITY: {EntityName}`) end

This is a second error (i think?) I noticed. I may be wrong on this though.

You defined self in a function, overwriting self from earlier, meaning self:Wander() won’t work.

If you find a way to, I’d recommend having a data ModuleScript of all the entity behaviors and just indexing that whenever one is created. This’ll make it much easier to add new ones and organize.


One last thing, I’d recommend defining all your services at the top of the script, if this gets annoying you can try using SimpleComplete, but having a bunch of game:GetService calls in the middle of your script might get very annoying to read and hurt maintainability of your code in the future.

Actually, you already did, this variable is just repeating it lol:

1 Like

Removing the self seems to let me use module functions now. The wandering script isn’t working but that’s another issue that I think I can fix all by myself. Anyway, what should a data ModuleScript look like since I’m most likely gonna just be using that.

1 Like

Just a modulescript that returns information about something:

-- Module named EntityBehaviors?
return {
    ["Starvlud"] = {
		["Behavior"] = function()
			-- impossible to get entity?
		end,
	},

    ["OtherEntity"] = {
		["Behavior"] = function()
			-- impossible to get entity?
		end,
	}
}

You can then require it as so:

local EntityBehaviors = require(EntityBehaviors)

local currentEntityBehavior = EntityBehaviors[currentEntity] -- self.Entity.Name?
if not currentEntityBehavior then return end

currentEntityBehavior.Behavior()

With the way your system is set up, I don’t exactly think it’s possible to get the entity to use the wander function, so this is just a general idea.

Just saying, if you add a bunch of entities to self.EntityBehaviors it’ll create that whole table for every entity object in the game AND get pretty messy for the code.

1 Like

Alrighty then. I’ll look into data ModuleScripts. Though, I noticed that it might be impossible to use the functions in there, but wouldn’t moving the general functions into the EntityBehavior module work or good practice?

Probably. I’m not too sure.

Although now that I think of it, creating a function for every entity in the table might also be unnecessary when you can just reference back to a preexisting module function.

Yeah, I think that’s more reasonable. Still, thank you.

1 Like

Maybe you can add an entity parameter to the Wander function and then check:

local self = self or entity

Then you can just reference to Wander in the module behavior, and call Behavior(entityObject)

Edit: iirc you can just call BaseEntity.Wander(entity) and throw the entity object as the parameter, this should pass to self anyway. So your data module would look more like this:

return {
    ["Starvlud"] = {
		["Behavior"] = BaseEntity.Wander
	},
}

and you’d call:

local EntityBehaviors = require(EntityBehaviors)

local currentEntityBehavior = EntityBehaviors[currentEntity] -- self.Entity.Name?
if not currentEntityBehavior then return end

currentEntityBehavior.Behavior(entity)

Unsure if this is the best option, but it seems like it’ll work.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.