How do I prevent players from going threw walls with raycasts?

I’m trying to write a script that prevents players from going threw walls by projecting a raycast from the last saved position to the current position and pushing the player in the correct position, however it’s proving to be rather difficult to figure out how to pull off as the player seem to teleport in front of the wall and get stuck. I also attempted to simply just set the player to the last position to no avail. How do I solve this?

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local rootPart = character:WaitForChild("HumanoidRootPart")
local cam = character:WaitForChild("Camera")

local BlackList = {character, game.ReplicatedStorage.Resources}

local Players = game:GetService("Players")
local Char = Players.LocalPlayer.Character
local Hum = Char:WaitForChild("Humanoid")
local Root = Char:WaitForChild("HumanoidRootPart")

local lastRootPosition = rootPart.Position

local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
--raycastParams.FilterDescendantsInstances = BlackList
raycastParams.CollisionGroup = "Players"

--local viewpart = Instance.new("Part")
--viewpart.CanCollide = false
--viewpart.CanQuery = false
--viewpart.Parent = workspace

local function createRay(dt)
	--viewpart.Position = lastRootPosition
	local currentRootPosition = rootPart.Position
	local ray = workspace:Raycast(lastRootPosition, (currentRootPosition - lastRootPosition).Unit * (currentRootPosition - lastRootPosition).Magnitude, raycastParams)
	if ray then
		local part = ray.Instance
		if part and part.CanCollide then
			rootPart.Position = lastRootPosition + ray.Normal
			rootPart.AssemblyLinearVelocity = Vector3.new(0, 0, 0)
			rootPart.AssemblyAngularVelocity = Vector3.new(0, 0, 0)
		else
			lastRootPosition = currentRootPosition
		end
	else
		lastRootPosition = currentRootPosition
	end
end

RunService.RenderStepped:Connect(createRay)

Have you tried offsetting the raycast .Normal value? Players are being teleported into the wall because you’re positioning the rootPart. The rootPart is not directly in front of the player but rather directly on the inside of the character model, hence, ~50% of the character model will be stuck into the wall when you try to position the rootPart at the exact point of the .Normal coordinate. Instead, try offsetting the .Normal value by say 5 or so studs and this should suffice in teleporting the player in front of the wall, and not halfway inside the wall.

1 Like

Yes I have done this, however when I do it. It seems to depend on luck if it works or not, so I have to make it a larger value like 10 which risks teleporting outside another wall if they are too close to each other. I want the exact point where to place the player while keeping them in bounds.

1 Like

Can you send a video displaying the issue?

1 Like
1 Like

Before I say anything… This occurs only when the player dashes right?

1 Like

not always, but it is one of the main ways.

1 Like

I have a couple of solutions to this so I’ll start with the first one that came to mind. When a player dashes shoot ray casts rapidly until the dashing stops. While the ray casts are being fired, detect how close a player is to a wall then cancel the dash

1 Like

I could do that, but I want to have this checked for simply when a player clips threw a wall, not just for the long jump.

1 Like

You’re offsetting it in the direction of the starting position right?

1 Like

in the position of the raycast.normal

1 Like

Isn’t that the direction perpendicular to the surface hit? If thats the case, wouldn’t the offset become too large/small if you hit the surface at an angle? (and wouldn’t the direction be wrong since you should be going by the angle of the ray not the surface you hit)

or am I stupid and misunderstood how this works

1 Like

You would be right, this code assumes the player went entire threw the wall in the past frame and the current frame, however since from what the first person mentioned the normal seems to be hitting at the opposite angle of what I should be using 50% of the time.

1 Like

In that case, perhaps try to calculate the actual correct angle using a bit of trig and the start and end position, since that the actual direction you want to offset in to send the player back where they came from.

1 Like

What would be a good way to calculate that?

1 Like

I can’t think of a method at the top of my head, but theres only a single right triangle between 2 points in a 2D space, and so you can probably use the 3 right triangles (one on each of the 3 planes formed by the 3 axises) to find the angle you want.

(this might actually be an appropriate question to ask ChatGPT lol)

1 Like

Actually I rethought about this a bit and i’m pretty sure the idea is that you want to find a point 5 studs away from the final point on the line formed by the final and initial point. That might (or might not) help.

The answer from ChatGPT was that the location of the 3rd point is

(X+N*(X2-X)/Magnitude, Y+N*(Y2-Y)/Magnitude, Z+N*(Z2-Z)/Magnitude)
For points (X, Y, Z) and (X2, Y2, Z2) with offset N
Magnitude is just the distance between the first and last point

(I can’t garantee that works, I haven’t actually tried it myself)

1 Like

Im deducing that you’re using AssemblyLinearVelocity for your dash.

Instead of raycasting, why not just detect when the player hits a wall? Its much simpler

local wall = script.Parent
wall.Touched:Connect(function(hit)
   if not hit.Parent:FindFirstChild("Humanoid") then return end
   local char = hit.Parent
   if not char:GetAttribute("IsDashing") then return end
   char:SetAttribute("IsDashing",false)
   char.HumanoidRootPart.AssemblyLinearVelocity = Vector3.zero
   char.HumanoidRootPart.CFrame *= CFrame.new(-char.HumanoidRootPart.CFrame.LookVector * 5)
end)
1 Like

This isn’t a very good solution, because that would mean I would have to put a wall touched in every single part in the game which is also very expensive.

1 Like

wait actually, I just realized, DrMystery’s solution does offer an important thing:
the line

   char.HumanoidRootPart.CFrame *= CFrame.new(-char.HumanoidRootPart.CFrame.LookVector * 5)

should function as a way to move you back correctly. try using that instead of the raycast normal