tl;dr – player.CharacterAdded:Wait() is acting inconsistent and I need help.
I’m trying to make it so when I start a game, it teleports both players given as arguments p1 and p2 to their respective game board.
function startGame(p1, p2)
if p1 ~= p2 then
print("#boards =",#boards)
for i,v in pairs(boards) do
if v.InUse == false then -- if we found a board to use, then insert the players in the board's table
--print(boards[i])
v.InUse = true
boards[i].p1 = {["Wins"]=0} --Boards[Board1][Player1] = {[Player1's Stats Here]}
boards[i].p2 = {["Wins"]=0}
local character1 = p1.Character or p1.CharacterAdded:Wait()
character1.HumanoidRootPart.CFrame = workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(5,2,0)
local character2 = p2.Character or p2.CharacterAdded:Wait()
character2.HumanoidRootPart.CFrame = workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(-5,2,0)
print(p1,"and",p2,"have started a game on",i)
break
end
print(boards[v.Name])
end
else print("Error: can't play against self")
end
end
This is not giving me the results I’d expect. I’m currently reworking my code to be cleaner, so this is a let down that it does not work. I’m referencing the thread Avoid wait() and why to get my characters without repeat wait() in my code.
The result is that it only teleports one player and only some of the time. The odd part is there is also no error reported.
The important part of the log is that the startGame function is working as intended and says that the two players involved start a game on their respective board.
Objective: Why is it being inconsistent and how can i fix it? I thought :Wait() was supposed to be better than the worse method of doing things. I get why it should be better, but it’s not looking that way right now.
Thanks for your help in advance, I appreciate the time you guys take to respond to my posts!
why are you moving character by changing the humanoid root part CFrame? The two methods of in-game character movement that you should use are the MoveTo function or the SetPrimaryPartCFrame, like this:
--for example this is how you would use SetPrimaryPartCFrame()
character:SetPrimaryPartCFrame(workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(5,2,0))
--you can also use the MoveTo
character:MoveTo(--[[A vector 3 position here]])
You can either SetPrimaryPartCFrame like @RomeoEDD mentioned, or you can use MoveTo()
Example here:
local board = workspace.Boards:FindFirstChild(i).BaseBoardsParts.Bottom
local character1 = p1.Character
character1:MoveTo(board.Positon + Vector3.new(5,2,0))
local character2 = p2.Character
character2:MoveTo(board.Position + Vector3.new(-5,2,0))
print(p1,"and",p2,"have started a game on",i)
It seems a consensus has been reached: I’m using a depricated method to teleport players!
I appreciate your feedback as it helps me with moving on to non-depricated scripting methods!
Do you think by switching to one of the two methods mentioned in your posts it would fix my script’s inconsistent behavior? It was working before with my repeat wait(), the problem was mainly with the :Wait() function I was sure.
there is a bug with using wait() like that, meaning sometimes it may not work you could also try getting the character by doing this
local player = game.Players.LocalPlayer
local character = player.Character or workspace:WaitForChild(Player.Name) or player.CharacterAdded:Wait()
--ofcourse if you have things directly parented to the workspace named after the character this will not work
define your character in the following way so that it can yield if the character isn’t there inside of workspace. This should guarantee that the character value won’t ever be nil.
local Character = Player.Character and Player.Character.Parent and Player.Character or Player.CharacterAdded:Wait()
I think the logic here is flawed, if I was to break it down, it doesn’t matter whether p2.Character is nil, it is always returned to character2 with the mode “1”:
p2.Character, “1” or workspace:WaitForChild(p2.Name)
is equivalent to
p2.Character, (“1” or workspace:WaitForChild(p2.Name))
which is the same as
p2.Character, (“1”) -- Since strings are truthy
Hence, your script doesn’t actually yield if there’s no character.
Utilising the method
local character2 = p2.Character or p2.CharacterAdded:Wait()
Okay so basically, the first portion of this line Player. Character just checks if the property of Player. Character isn’t nil. When using an and statement you are verifying more than one check with the last one being used. So when I did Player. Character and Player.Character.Parent and Player. Character I checked if Player. Character is there if so I go onto check if Player.Character.Parent is present (because when a part is destroyed it is parented under nil so if the character wasn’t in workspace this check would be false and would wait for the character added event to fire). It then goes on to say and Player.Character which as I stated above, now since the other checks came out to be true, this one just sets the Character variable to it (because the last of the and operator is used). If at any point the and operator sees that the statement is false it goes on to the or operator which just waits for the characteradded event to fire to set the character variable. In all honesty, this is just a shorter way to use if statements.
if Player.Character then
if Player.Character.Parent then
local Character = Player.Character
else
local Character = Player.CharacterAdded:Wait()
end
else
local Character = Player.CharacterAdded:Wait()
end
-- Or I guess if you wanted to condense this
if Player.Character and Player.Character.Parent then
local Character = Player.Character
else
local Character = Player.CharacterAdded:Wait()
end
Although there is a much more understandable method of doing this that I think could better illustrate to you what exactly is happening
local Character;
while not Player.Character or not Player.Character.Parent do
wait()
end
Character = Player.Character
-- Shortened version
local Character; while not Player.Character or not Player.Character.Parent do wait() end; Character = Player.Character
As you can see aside from the if statement these two do the same thing but the one I provided earlier is much cleaner (the if statements were for visualization purposes on how the and and or operators work)
@PirateOnThePlank, I appreciate the tip, but that’s why I made this thread. I was following advice exactly akin to what you’re saying and it isn’t working for me, see the OP above for more info. I always appreciate the time you guys take to reply to my posts, I’m just trying to figure this out. It should work, but it’s not.
According to @RomeoEDD, it’s buggy that way, so I’m just trying to figure out what I can do until that is fixed. Or am I implementing the :Wait() function incorrectly?
Here’s my test with your code, it’s inconsistent still, not sure what is causing this.
It doesn’t give an error out, the following line prints the character’s name like it should, but it just doesn’t teleport both players. It seems to not find a character, then not yield, and move on like it doesn’t matter. This is confusing for me particularly as I use the error log extensively to debug.
function startGame(p1, p2)
if p1 ~= p2 then
print("#boards =",#boards)
for i,v in pairs(boards) do
if v.InUse == false then -- if we found a board to use, then insert the players in the board's table
--print(boards[i])
v.InUse = true
boards[i].p1 = {["Wins"]=0} --Boards[Board1][Player1] = {[Player1's Stats Here]}
boards[i].p2 = {["Wins"]=0}
local Character = p1.Character and p1.Character.Parent and p1.Character or p1.CharacterAdded:Wait()
Character.HumanoidRootPart.CFrame = workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(5,2,0)
print(Character.Name)
local Character = p2.Character and p2.Character.Parent and p2.Character or p2.CharacterAdded:Wait()
Character.HumanoidRootPart.CFrame = workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(5,2,0)
print(Character.Name)
print(p1,"and",p2,"have started a game on",i)
break
end
print(boards[v.Name])
end
else print("Error: can't play against self")
end
end
For reference, this is the full code with your edits @HumbledDragon
function startGame(p1, p2)
if p1 ~= p2 then
print("#boards =",#boards)
for i,v in pairs(boards) do
if v.InUse == false then -- if we found a board to use, then insert the players in the board's table
--print(boards[i])
v.InUse = true
boards[i].p1 = {["Wins"]=0} --Boards[Board1][Player1] = {[Player1's Stats Here]}
boards[i].p2 = {["Wins"]=0}
local Character1 = p1.Character and p1.Character.Parent and p1.Character or p1.CharacterAdded:Wait()
local Character2 = p2.Character and p2.Character.Parent and p2.Character or p2.CharacterAdded:Wait()
if Character1 and Character2 then
Character1:SetPrimaryPartCFrame( workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(5,2,0))
Character2:SetPrimaryPartCFrame( workspace.Boards:FindFirstChild(i).BaseBoardParts.Bottom.CFrame * CFrame.new(5,2,0))
print(p1,"and",p2,"have started a game on",i)
break
end
end
print(boards[v.Name])
end
else print("Error: can't play against self")
end
end
Guys, I really appreciate the patience. I feel like I’m losing it or something… the logic is and always has been sound, but it’s just not doing what we expect it to do and I can’t explain it. I’ve checked and double checked everything I’m passing to the function, printed out characters and it should work, but it never teleports player 2… This is so weird!
oh wait are you testing it in studio, if you are trying testing it in an actual server there was onetime i was doing something in my code and i didn’t work in solo mode it only worked when i tested it online with a friend of mine
Uh, yes I’ve been doing all of my tests in studio’s “Local Server” with anywhere from 2 to 8 players. Do you think it would be different if I turned on Network Simulator or do you think I really just need real players in a real server?