I’m attempting to make a vaulting system. I need to check if the player is facing the part they’re going to vault over, because it wouldn’t make sense if you were able to vault backwards. I’m pretty sure I’d have to use raycasting for something like this, but I’m not exactly sure how I would achieve what I’m desiring.
This is what I have so far. The transparent red part is the zone. The yellow part is the part the player will vault over. I want to make it so the player can only vault if they’re facing the yellow part. I want to make it so they don’t have to be looking at the part up and down, just left and right.
This would work, but there are some problems. I’m doing this on server, not local script, so I used Stepped instead of RenderStepped, but I’m having problems with the player who entered the zone.
zone.playerEntered:Connect(function(player)
-- player works here
print(player)
local RunService = game:GetService("RunService")
RunService.Stepped:Connect(function(player)
-- player does not work here
print(player)
end)
end)
you could make a ray from the head and check if the ray hit the part but if you want it to see like us players maybe you could add the dot product and some mangnitude
You can, but you really shouldn’t. This wouldn’t work if the part is above or below your head while still in your field of view. It’s also inefficient compared to the previous method, as it would need to cast a ray constantly.
After doing some experimenting, I’ve ended up with this code.
zone.playerEntered:Connect(function(player)
local function dotProduct()
local str = "workspace.%s"
return string.format(str, player.Name).Head.CFrame.LookVector:Dot(zoneGroup.CFrame.LookVector)
end
local str = "workspace.%s"
local product = dotProduct(string.format(str, player.Name), zoneGroup)
end)
It’s probably really inefficient but who cares. I’m not very good with CFrames. I keep getting the error “attempt to index nil with ‘CFrame’” Do I just need to create CFrames in the part and the player? I was thinking they’d already be in the player by default.
You are on the right track with using dot products, and they are not inefficient at all, actually dot product by itself is very fast.
By doing the dot product between the two LookVectors you can very quickly compare how closely their directions match (since they are by definition unit vectors). So when you place your activation zone, their LookVector should point in the direction that you want to allow the jump, and at runtime each frame you make sure that the character is within a certain range of this direction, by using the dot product (you want it that to be close to 1, which means both vectors are pointing exactly in the same direction)
However there only inefficient part in your code is having to do the string format to get the player’s model, which is very slow to do every frame. I would say you probably need to either cache that value (e.g. a table indexed by name) or find a way to get a direct reference to it from the parameter object (e.g. by using Tags or similar). good luck!
Ah gotcha. Well good thing it’s still useful. One more tip: if you want to ignore the difference in vertical orientation like you mention in your first post, you can just “flatten” both LookVectors by creating new vectors with same X and Z components but 0 for Y. then you do the dot product as usual, and it tells you how much their horizontal directions match, ignoring up/down look difference
RunService.Heartbeat:Connect(function()
for i,v in pairs(workspace:GetChildren()) do
if v.ClassName == "Model" then
local character = v:findFirstChildOfClass("Humanoid").Parent
local characterToNpc = (npc.HumanoidRootPart.Position - character.HumanoidRootPart.Position).Unit
local characterLook = character.HumanoidRootPart.CFrame.LookVector
local dotProduct = characterToNpc:Dot(characterLook)
if character.Humanoid.Health > 0 and not game.Players:GetPlayerFromCharacter(character.Parent) then
print(dotProduct)
if dotProduct > 0 and not looking then
looking = true
elseif looking then
looking = false
end
end
end
end
end)