Cannot find value I'm sure is there

My first shot at OOP in Roblox is starting off right. On line 25 of the Enemy object (the only line inside of Enemy:MoveTo()), there’s an exception:

22:29:10.795 - ServerStorage.Enemy:25: attempt to index field 'EnemyModel' (a nil value)

Weird part is, the method that calls Enemy:MoveTo() uses EnemyModel, so if it really didn’t exist, then why would Enemy:Move() be working?

Enemy Object

local Enemy = {}
Enemy.__index = Enemy

function Enemy:Move()
	--Get all the player in line of sight
	--Find closest player
	--Charge player
	
	local closest = {nil, nil} -- closest[1] = player, closest[2] = distance
	
	for _,player in pairs(game.Players:GetChildren()) do
		--Add check to see if the zombie is within line of sight of the player
		if player.Character then
			local dist = (player.Character.PrimaryPart.Position - self.EnemyModel.PrimaryPart.Position).magnitude
			if closest[2] == nil or dist < closest[2] then closest = {player, dist} end
		end
	end
	
	if closest[1] == nil then return end
	
	Enemy:MoveTo(closest[1].Character.PrimaryPart.Position)
end

function Enemy:MoveTo(pos)
	self.EnemyModel:MoveTo(pos)
end

function Enemy.new(enemyModel)
	local enemy = { --enemy fields
		EnemyModel = enemyModel
	}
	setmetatable(enemy, Enemy) --enemy methods
	
	enemyModel.Name = "" --get rid of the nametag
	
	return enemy
end

return Enemy

Zombie Object

local Enemy = require(game.ServerStorage.Enemy)

local Zombie = {}
Zombie.__index = Zombie
setmetatable(Zombie, Enemy)

function Zombie.new(enemyModel)
	local zombie = Enemy.new(enemyModel)
	setmetatable(zombie, Zombie)
	
	--Zombie animation, make the arms go up
	local animation = Instance.new("Animation")
	animation.AnimationId = "http://roblox.com/Asset?ID=04842071021"
	enemyModel.Humanoid:LoadAnimation(animation):Play()
	
	return zombie
end

return Zombie

Zombie script

local zombie = require(game.ServerStorage.Zombie).new(script.Parent)

while true do
	zombie:Move()
	
	wait()
end
1 Like

This is a very simple problem which many people tend to make.

You should use the WaitForChild function, if that doesn’t work then let me know.

Generally, if you’re sure there is a model, you use Parent:FindFirstChild(ModelName), which will either return the model or return nil. WaitForChild can and will yield if the script doesn’t find anything.

That wouldn’t make sense because the zombie script, the script making an instance of Zombie, is inside of zombie model and wouldn’t change anything. I still changed

local zombie = require(game.ServerStorage.Zombie).new(script.Parent)

to

local zombie = require(game.ServerStorage.Zombie).new(script.Parent.Parent:WaitForChild(script.Parent.Name))

to no effect.

This has been a test and you all fail. As per usual I figured it out by myself at random.

The reasoning is because I’m calling Enemy:MoveTo() as if it were a static method (to those who don’t know OOP lingo, that is a function of an object that can be run without the object being instanced. See all of the table functions). Simply change the line calling Enemy:MoveTo() to self:MoveTo() and the problem is solved.