I don't know what's wrong with this. I'm just trying to make an opening zone system and it says
Requirement is not a valid member of Part "Workspace.Door"
The script:
script.Parent.Touched:Connect(function(hit)
if hit then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player.leaderstats.Coin.Value >= script.Parent.Requirement.Value then
player.leaderstats.Coin.Value -= script.Parent.Requirement.Value
script.Parent.Transparency = 10
script.Parent.CanCollide = false
end
end
end)
Related
My goal here is to send the player object and the object name through to the client script to display the object name on a text label.
When I run this, it prints nil and nil. I want player.Name and name as you will see in the second code sample. Another error I get is "attempt to concatenate nil with string" from the client script.
Here is my server-side code:
script.onTouch.OnInvoke = function(button, sellObj, sellObjValue, buyObj, buyObjValue, afterWave, isLoadedPart)
if isLoadedPart == true then
local info = script.Parent.Parent.info
local player = info.player.Value
local owner = info.owner.Value
local savedItems = info.savedItems.Value
local builds = script.Parent.Parent.activeBuilds
if afterWave > info.activeWave.Value then
info.activeWave.Value = afterWave
end
button.Parent = savedItems.buttons
button.jobDone.Value = true
if sellObj ~= nil then
sellObj.Parent = savedItems.builds
end
if buyObj ~= nil then
buyObj.Parent = builds
end
local td = require(script.Parent.tycoonDictionary)
if not table.find(td.boughtButtons, button.objectId.Value) then
table.insert(td.boughtButtons, button.objectId.Value)
end
local ui = game.ReplicatedStorage:FindFirstChild('onPartLoad')
if ui then
ui:FireClient(player, 'buyObj.Name')
print('yes')
else
print('no')
end
else
local info = script.Parent.Parent.info
local player = info.player.Value
local owner = info.owner.Value
local money = info.player.Value.leaderstats.Money
local savedItems = info.savedItems.Value
local builds = script.Parent.Parent.activeBuilds
if money.Value >= buyObjValue or money.Value == buyObjValue then
if afterWave > info.activeWave.Value then
info.activeWave.Value = afterWave
end
button.Parent = savedItems.buttons
button.jobDone.Value = true
if sellObj ~= nil then
sellObj.Parent = savedItems.builds
money.Value += sellObjValue
end
if buyObj ~= nil then
buyObj.Parent = builds
money.Value -= buyObjValue
end
local td = require(script.Parent.tycoonDictionary)
if not table.find(td.boughtButtons, button.objectId.Value) then
table.insert(td.boughtButtons, button.objectId.Value)
warn(td.boughtButtons)
end
else
player.PlayerGui.inGame.error.label.invokeScript.errorInvoke:Invoke("Insufficient Funds")
end
end
script.Parent.waveChecker.afterRun:Invoke()
end
And here is my client-side code:
game.ReplicatedStorage.onPartLoad.OnClientEvent:Connect(function(player, name)
print(player.Name, name)
print(script.Parent.Text)
script.Parent.Text = name .. 'is loaded.'
print(script.Parent.Text)
end)
Here I will tell you a little about this game. It is a tycoon that saves data using a table with all button Ids in it. When it loads, it gets the button associated with the id and fires the server code for every button. If the button is a load button, it fires the client with the player and the buyObj.Name.
Is there just a little mistake or can I not send arguments to the client at all? Any help will be appreciated!
The OnInvoke callback's first argument is always the player that fired it, so you should change line 1 of the first script to:
script.onTouch.OnInvoke = function(playerFired, button, sellObj, sellObjValue, buyObj, buyObjValue, afterWave, isLoadedPart)
And :FireClient() requires a player argument as its first argument, so you should change
ui:FireClient(player, 'buyObj.Name')
to
ui:FireClient(playerFired, player, 'buyObj.Name')
Here is the solution I came up with;
First, I read through some Roblox documentation to find that the first argument I had to send when using :FireClient was the player, and because I already had the player there, it was just sending the function to that player. Now, I had 2 choices, I could send the player twice, or delete the player variable from the script. I chose the second one.
Here is what the :FireClient line in the server script looks like now:
game.ReplicatedStorage:WaitForChild('onPartLoad'):FireClient(player, buyObj.Name)
And here is what the client function script looks like now:
game.ReplicatedStorage.onPartLoad.OnClientEvent:Connect(function(name)
if name ~= 'starterFoundation' then
script.Parent.Text = name .. ' is loaded.'
end
end)
Thank you #TypeChecked for helping me realize this!
I'm sorry if this is a really simple or easy question, but I am trying to set the player leaderstat "Money" to 0, but it keeps coming back as the old value. The only thing that I can think of that may be causing this problem is that the moneyGain script is on repeat.
Here is my moneyGain script:
local playerMoney
while wait(0.24) do
local buttons = script.Parent.Parent.info.savedItems.Value.buttons:GetChildren()
for button = 1, #buttons, 1 do
if buttons[button].Parent.Parent.tycoon.Value ~= nil then
if buttons[button].Parent.Parent.tycoon.Value.info.owner ~= nil then
if buttons[button].jobDone.Value == true then
script.Parent.moneyEnforcer.enforce:Invoke(buttons[button].gainVal.Value)
end
end
end
end
--OWNERDOOR:
if script.Parent.Parent.info.owner.Value ~= nil then
script.Parent.moneyEnforcer.enforce:Invoke(1)
end
end
Here is my moneyEnforcer script:
local rs = game:GetService("ReplicatedStorage")
local dictionary = require(rs.dictionary)
local vipPlayers = dictionary.vipPlayers
script.enforce.OnInvoke = function(amount)
print(amount)
if script.Parent.Parent.info.player.Value ~= nil then
if game:GetService("GamePassService"):PlayerHasPass(script.Parent.Parent.info.player.Value, 25494219) then
amount = amount * 2
else
for i = 1, #vipPlayers, 1 do
if script.Parent.Parent.info.player.Value.Name == vipPlayers[i] then
amount = amount * 2
end
end
end
local playerMoney = script.Parent.Parent.info.player.Value.leaderstats.Money
script.Parent.Parent.info.player.Value.leaderstats.Money.Value = script.Parent.Parent.info.player.Value.leaderstats.Money.Value + amount
end
end
And here is the tycoon reseter:
local player = script.Parent.Parent.Parent.Parent.Parent.Parent
script.Parent.Parent.Parent.Visible = false
script.Parent.MouseButton1Click:Connect(function()
player.leaderstats.Money.Value = 0
script.Parent.Parent.Parent.Visible = false
local savedItems = player.claimedTycoon.Value.info.savedItems.Value
local builds = player.claimedTycoon.Value.activeBuilds:GetChildren()
local buttons = player.claimedTycoon.Value.activeButtons:GetChildren()
for i = 1, #builds, 1 do
builds[i].Parent = savedItems.builds
end
for j = 1, #buttons, 1 do
buttons[j].Parent = savedItems.buttons
end
savedItems.builds.dirtStarterBase.Parent = player.claimedTycoon.Value
player.claimedTycoon.Value.info:WaitForChild("activeWave").Value = 1
end)
I have tried putting the "script.Parent.Parent.info.player.Value.leaderstats.Money.Value = script.Parent.Parent.info.player.Value.leaderstats.Money.Value + amount" on the moneyGain script, but that made no difference.
Any help is appriciated!
I believe your problem is that you're setting the value of money from the client. When you change the value from a local script, it will not update on the server. To fix this update the value from the server
In tycoon reseter, try resetting the value from the server using a RemoteEvent
When the game timer ends it kills the players & resets the teams and sends them to spawn to choose a Team again... idk how to reset the script to start from the beginning and have reset all the values and functions called... I tried making a copy of the script and destroy the current one with script:Destroy() but doesn't work & continues with the same function so breaks my game when the players choose the teams again & respawn.
-- Get Service Variables
local Teams = game:GetService("Teams")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local plr = game:GetService("Players").LocalPlayer
-- Wait for Child Variables
local TeamResetter = game.ReplicatedStorage.TeamResetter
local TimeCountdown = ReplicatedStorage:WaitForChild("Timer")
--Scripts Resets the entire script after GameTime is up
local function ResetGame(Player,Teams)
local copy = script:Clone()
copy.Parent = script.Parent
script:Destroy()
end
-- Destroy Gate when thieves touch it
game.Workspace.CarGate4.GateRod.Touched:Connect(function(hit,Player)
local h = hit.Parent:FindFirstChild("Humanoid")
if h ~= nil then
local n = hit.Parent
local p = game.Players:FindFirstChild(n.Name)
if p.Team.Name == "Thieves" then
game.Workspace.CarGate4.GateRod:Destroy()
end
end
end)
--Thieves function for winning
--[[humanoid.Seated:Connect(function(active,currentSeat, Player, Team)
if active then
if currentSeat.Name == "DriveSeat" then
if Player.TeamColor == game.Teams.Thieves.TeamColor then
game.StarterGui.ThiefWinScreen.Frame.TextLabel.Script.Disabled = false
end
end
end
end)]]
local function PoliceWinReset(Player,Team)
game.StarterGui.PoliceWinScreen.Frame.TextLabel.Script.Disabled = false
wait(2)
for i,v in pairs(game.Teams.Thieves:GetPlayers()) do
Player.TeamColor = game.Teams.ChoosingTeam.TeamColor
game.StarterGui.ThiefWinScreen.Frame.TextLabel.KillPlayer.Disabled = false
Player.Character:BreakJoints()
game.StarterGui.ChooseTeamGUI.Enabled = true
ResetGame(Player,Teams)
end
for i,v in pairs(game.Teams.Police:GetPlayers()) do
Player.TeamColor = game.Teams.ChoosingTeam.TeamColor
game.StarterGui.PoliceWinScreen.Frame.TextLabel.KillPlayer.Disabled = false
Player.Character:BreakJoints()
game.StarterGui.ChooseTeamGUI.Enabled = true
ResetGame(Player,Teams)
end
end
--Starts Global timer for game after user chooses a team & Police win code
--Resets Player Teams and respawns them back at spawn and have to choose a team again
local function PlayGame(Player, Team)
local timerAmount = 120
local timerText = ""
while timerAmount >= 0 do
TimeCountdown:FireAllClients(timerAmount,timerText)
wait(1)
timerAmount -= 1
if timerAmount == 0 then
PoliceWinReset(Player,Team)
end
end
return timerAmount
end
--Checks wether the user is on the Thieves or Police Teama
local function Thieves_Police(Player, Team)
if Player.TeamColor == game.Teams.Police.TeamColor then
game.StarterGui.ChooseTeamGUI.Enabled = false
game.StarterGui.TimerGUI.Enabled = true
wait(5)
PlayGame(Player, Team)
return Player, Team
elseif Player.TeamColor == game.Teams.Thieves.TeamColor then
game.StarterGui.ChooseTeamGUI.Enabled = false
game.StarterGui.TimerGUI.Enabled = true
wait(5)
PlayGame(Player, Team)
return Player, Team
end
end
--Team Chooser
game.ReplicatedStorage.TeamChooser.OnServerEvent:Connect(function(Player, Team)
local PhysicalTeamColor = Teams:FindFirstChild(Team).TeamColor
Player.TeamColor = PhysicalTeamColor
game.StarterGui.PoliceWinScreen.Enabled = false
game.StarterGui.ThiefWinScreen.Enabled = false
Thieves_Police(Player, Team)
end)
--Gives the Users on the Police Team a Weapon on Spawn
function teamFromColor(color)
for _,t in pairs(game:GetService("Teams"):GetChildren()) do
if t.TeamColor==color then return t end
end
return nil
end
function onSpawned(plr)
local tools = teamFromColor(plr.TeamColor):GetChildren()
for _,c in pairs(tools) do
c:Clone().Parent = plr.Backpack
end
end
function onChanged(prop,plr)
if prop=="Character" then
onSpawned(plr)
end
end
function onAdded(plr)
plr.Changed:connect(function(prop)
onChanged(prop,plr)
end)
end
--Calls the Functions
game.Players.PlayerAdded:connect(onAdded)
You can just wrap the script in a while loop to repeat from the beginning when the round ends. At the end of the loop, right before the end tag, you can reset all the values that are supposed to be reset for the next round.
The titles explains it all, I'm trying to make a roblox npc walk around the maze normally, then when it sees the player, it starts running after the player to kill it, I have the NPC, I have the killing part, I just need the code for the NPC walking around normally and the code for the NPC detecting the player then running after them. Thanks! :D
edited: heres my code
debugMode = false
targetNPCs = false
--
h = script.Parent.Parent:WaitForChild("Humanoid")
pathService = game:GetService("PathfindingService")
targetV = script.Parent:WaitForChild("Target")
function closestTargetAndPath()
local humanoids = {}
if targetNPCs then
local function recurse(o)
for _,obj in pairs(o:GetChildren()) do
if obj:IsA("Model") then
if obj:findFirstChild("Humanoid") and obj:findFirstChild("Torso") and obj.Humanoid ~= h and obj.Humanoid.Health > 0 and not obj:findFirstChild("ForceField") then
table.insert(humanoids,obj.Humanoid)
end
end
recurse(obj)
end
end
recurse(workspace)
else
for _,v in pairs(game.Players:GetPlayers()) do
if v.Character and v.Character:findFirstChild("HumanoidRootPart") and v.Character:findFirstChild("Humanoid") and v.Character.Humanoid.Health > 0 and not v:findFirstChild("ForceField") then
table.insert(humanoids,v.Character.Humanoid)
end
end
end
local closest,path,dist
for _,humanoid in pairs(humanoids) do
local myPath = pathService:ComputeRawPathAsync(h.Torso.Position,humanoid.Torso.Position,500)
if myPath.Status ~= Enum.PathStatus.FailFinishNotEmpty then
-- Now that we have a successful path, we need to figure out how far we need to actually travel to reach this point.
local myDist = 0
local previous = h.Torso.Position
for _,point in pairs(myPath:GetPointCoordinates()) do
myDist = myDist + (point-previous).magnitude
previous = point
end
if not dist or myDist < dist then -- if true, this is the closest path so far.
closest = humanoid
path = myPath
dist = myDist
end
end
end
return closest,path
end
function goToPos(loc)
h:MoveTo(loc)
local distance = (loc-h.Torso.Position).magnitude
local start = tick()
while distance > 4 do
if tick()-start > distance/h.WalkSpeed then -- Something may have gone wrong. Just break.
break
end
distance = (loc-h.Torso.Position).magnitude
wait()
end
end
while wait() do
local target,path = closestTargetAndPath()
local didBreak = false
local targetStart
if target and h.Torso then
targetV.Value = target
targetStart = target.Torso.Position
roaming = false
local previous = h.Torso.Position
local points = path:GetPointCoordinates()
local s = #points > 1 and 2 or 1
for i = s,#points do
local point = points[i]
if didBreak then
break
end
if target and target.Torso and target.Health > 0 then
if (target.Torso.Position-targetStart).magnitude < 1.5 then
local pos = previous:lerp(point,.5)
local moveDir = ((pos - h.Torso.Position).unit * 2)
goToPos(previous:lerp(point,.5))
previous = point
end
else
didBreak = true
break
end
end
else
targetV.Value = nil
end
if not didBreak and targetStart then
goToPos(targetStart)
end
end
I won't provide any code as you have not shown any efforts to solve that problem.
Enter "roblox npc" into www.google.com. Click the second hit:
https://developer.roblox.com/en-us/articles/Moving-NPCs-Between-Points
This covers the walking around part and also links this
https://developer.roblox.com/en-us/articles/Pathfinding
which covers more complex movements.
The seeing part is done with ray casting
https://developer.roblox.com/en-us/articles/Raycasting
If you can cast a ray from the NPC to your player calculate a path to that player and attack.
I'm trying to make a cutscene sorta thing for a dorr in roblox studio. My solution was to set up a collision detector on the door which would then make a gui template and set its parent to the playergui component.
I did this using the code
local afterIntoTransform = script.Parent.Parent.DoorUnion.Position.Z -6
local afterOutwardsTransform = script.Parent.Parent.DoorUnion.Position.Z + 6
local debounce = false
local function executeFadeSceneAndTpPlayer(player)
local fadeScene = Instance.new("ScreenGui")
local fadeSceneFrame = Instance.new("Frame")
fadeScene.Name = "fadeScene"
fadeSceneFrame.Name = "fadeFrame"
fadeSceneFrame.Size = UDim2.new(1,0,1,0)
fadeSceneFrame.Parent = fadeScene
fadeSceneFrame.BorderSizePixel = 0
fadeSceneFrame.BackgroundColor3 = Color3.new(1, 1, 1)
fadeSceneFrame.BackgroundTransparency = 1
print(game.Players:GetPlayerFromCharacter(player).Name)
fadeScene.Parent = game.Players:GetPlayerFromCharacter(player).PlayerGui
for i = 0, 20, 1 do
fadeSceneFrame.BackgroundTransparency -= 0.05
wait(0.01)
end
player.HumanoidRootPart.Position = Vector3.new(player.HumanoidRootPart.Position.X, player.HumanoidRootPart.Position.Y, afterOutwardsTransform)
for i = 0, 20, 1 do
fadeSceneFrame.BackgroundTransparency += 0.05
wait(0.01)
end
fadeScene:Destroy()
end
script.Parent.Touched:Connect(function(hit)
if not debounce then
debounce = true
executeFadeSceneAndTpPlayer(hit.Parent)
wait(0.2)
debounce = false
end
end)
It tells me: Attempted to index nil with name on line 15.
It works sometimes and sometimes doesnt but recently Ive noticed a trend that I can walk into the door then out again and then it breaks. I haven't coded in a while so I'm a little rusty but I hope I can get some help.
You are running into the same issue as this person : Roblox - attempt to index nil with 'leaderstats'
You are not accounting for the fact that the Touched event fires for every single part that touches it, and some of those parts might not belong to a player.
You can protect against this error by making sure that the object belongs to a player before you call executeFadeSceneAndTpPlayer()
script.Parent.Touched:Connect(function(hit)
local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
if not plr then
return
end
if not debounce then
debounce = true
executeFadeSceneAndTpPlayer(hit.Parent)
wait(0.2)
debounce = false
end
end)