Model Primary Part Possibly Broken?

Greetings everyone,

I am currently trying to move a model via primary parts, however when trying to get the primary part into a variable I get the following error.

Error:

16:06:20.921 - PrimaryPart is not a valid member of Folder
16:06:20.922 - Stack Begin
16:06:20.923 - Script 'ServerScriptService.MainOperatingScripts.ObstacleManagement.LeadObstacleModule', Line 6
16:06:20.924 - Script 'Workspace.Logs.LeadObstacle', Line 10
16:06:20.924 - Stack End
ObstacleHandler was successfully initiated.

Code:

-->: Services
local runService = game:GetService("RunService")
local scriptService = game:GetService("ServerScriptService")

-->: Variables
local obstacleLead = script.Parent.PrimaryPart --Line 6 --ERROR ORIGIN
local leadModule = require(scriptService.MainOperatingScripts.ObstacleManagement.LeadObstacleModule)

-->: Calls
leadModule.LeadObstacle(obstacleLead) --Line 10

--[[ Notes 

]]

Script Location:
image

PrimaryPart:

The script is probably looking for an instance named “PrimaryPart” inside of your model, rather than looking for the actual PrimaryPart of your model.

1 Like

That’s a good point but I was able to tab-select .PrimaryPart and I don’t have a part called “PrimaryPart”. Not only that though, the error specifies the model as a Folder and not a Model as its class.

This has been resolved, thanks to all who helped me in discord.

Would you please share what was done to fix this so others may learn.

1 Like

The culprit was the module script being improperly coded, I completely re-did the script and I will run you through it.


Lead Obstacle:

-->: Services
local scriptService = game:GetService("ServerScriptService")

-->: Variables
local obstacle = script.Parent
local obstacleLead = script.Parent.PrimaryPart
local obstacleProperties = require(scriptService.MainOperatingScripts.ObstacleManagement.ObstacleProperties)
local obstacleSpeed = obstacleProperties.obstacleSpeed
local obstacleFrequency = obstacleProperties.obstacleFrequency
local obstacleDecay = obstacleProperties.obstacleDecay
local decayState = 0

-->: Runs
while wait(obstacleFrequency) do
	if decayState == obstacleDecay then
		obstacle:Destroy()
		break
	end
	obstacle:SetPrimaryPartCFrame(obstacle.PrimaryPart.CFrame + Vector3.new(0,0,obstacleSpeed))
	decayState = decayState + 1
end

Obstacle Properties Module:

local module = {}

module.obstacleSpeed = 0.2 -- In Studs
module.obstacleFrequency = 0.001-- In Seconds
module.obstacleDecay = 600 -- In Frequency Ticks

return module

The reason I am using a module is because these obstacles are generated once every few seconds, and there are hundreds of different obstacles. So rather than having to go into each obstacle and change its mover code when I want to make a change, I can just head to settings and adjust them from there.

However let’s say I do need to edit the mover script! I have a script that handles all of the obstacles by assigning them a number and copying the mover script into the models. So each model wont have the mover script in it until the game starts. Here is that code:

Obstacle Prepper:

-->: Services
local serverStorage = game:GetService("ServerStorage")
local scriptStorage = game:GetService("ServerScriptService")

-->: Variables
local obstacleStorage = serverStorage.ObstacleStorage.Active
local baseScript = script.Parent.ObstaclePrepper.LeadObstacle
local children = obstacleStorage:GetChildren()

-->: Runs
for i, child in pairs(children)do
	if child:IsA("Model") then
		child.Name = i
		local replicated = baseScript:Clone()
		replicated.Parent = child
		replicated.Disabled = false
	end
end

You can see near the end, specifically here replicated.Disabled = false that I enable the script, however that script will not run until the obstacle has been called and cloned by the Obstacle Handler because it is inside of Server Storage (which does not run scripts). As I mentioned earlier that script creates a number and assigns it to each obstacle so that the Obstacle Handler can find it easier. This also allows me to give the obstacles names that are easy to recognize in studio too.

Studio Mode: image

Play Mode: image

Obstacle Handler:

-->: Services
local serverStorage = game:GetService("ServerStorage")
local scriptStorage = game:GetService("ServerScriptService")

-->: Variables
local initiated = false

local obstacleStorage = serverStorage:WaitForChild("ObstacleStorage")

-->: Functions
function addPiece()
	local obsID = math.random(2) --: # Of Active Obstacles.
	local selected = obstacleStorage.Active:FindFirstChild(obsID)
	local obstacle = selected:Clone()
	obstacle.Parent = workspace
end

-->: Runs
while wait(9 --[[Interval]]) do
	addPiece()
	
	if initiated == false then --: Check If Operating As Expected.
		initiated = true
		print("ObstacleHandler was successfully initiated.")
	end
end

This last bit is really simple, the Obstacle Handler uses math.random() to generate a random number and then finds a model in Obstacle Storage with that number and clones it. This occurs once every 9 seconds.

Hierarchy:
image

1 Like