Hey guys, I’ve been trying to create sonic movement inside studio and I’m really close to it
[TURN DOWN YOUR VOLUME ]
Example 1
Example 2
One thing that’s been holding me back is that you’re unable to run up straight walls
Problem
This is the function that handles the movement and the alignment
local function HandleMovement(delta)
local rayDirection = rootpart.CFrame.UpVector * -5
local ray = game.Workspace:Raycast(rootpart.Position, rayDirection, raycastParams)
if ray then
local position, normal = ray.Position, ray.Normal
local moveDirection = humanoid.MoveDirection
local projectedMoveDirection = ProjectVectorOntoNormal(moveDirection, normal)
local surfaceRight = projectedMoveDirection:Cross(normal)
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, normal)
local horizontalVelocity = projectedMoveDirection.Unit * walkSpeedValue.Value
local verticalVelocity = Vector3.new(0, -10, 0)
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and ((horizontalVelocity + verticalVelocity))) or Vector3.zero
lookGyro.CFrame = slopeRotation
else
moveVelocity.VectorVelocity = Vector3.new(0, -game.Workspace.Gravity, 0)
lookGyro.CFrame = CFrame.identity
end
end
One thing that I noticed is that the MoveVelocity's VectorVelocity's X changes to 0 which makes it so I can’t run up and down, but only left and right
And I wondering if any of you guys can help me since I’ve be struggling with this since the past day
I’m not familiar with coding movement, but I think you need to check if the wall is vertical using something like if math.abs(normal.Y) < 0.1 then
and do different movement if it is, so something like this?
local function HandleMovement(delta)
local rayDirection = rootpart.CFrame.UpVector * -5
local ray = game.Workspace:Raycast(rootpart.Position, rayDirection, raycastParams)
if ray then
local position, normal = ray.Position, ray.Normal
local moveDirection = humanoid.MoveDirection
-- check if the wall is vertical
if math.abs(normal.Y) < 0.1 then -- condition to detect vertical walls
-- the wall is vertical, move directly towards it
local wallDirection = normal.Unit
local horizontalVelocity = moveDirection.Unit * walkSpeedValue.Value
local verticalVelocity = Vector3.new(0, -10, 0)
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and (horizontalVelocity + verticalVelocity)) or Vector3.zero
local surfaceRight = wallDirection:Cross(Vector3.new(0, 1, 0)).Unit
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, wallDirection)
lookGyro.CFrame = slopeRotation
else
-- the wall isnt vertical
local projectedMoveDirection = ProjectVectorOntoNormal(moveDirection, normal)
local surfaceRight = projectedMoveDirection:Cross(normal)
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, normal)
local horizontalVelocity = projectedMoveDirection.Unit * walkSpeedValue.Value
local verticalVelocity = Vector3.new(0, -10, 0)
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and (horizontalVelocity + verticalVelocity)) or Vector3.zero
lookGyro.CFrame = slopeRotation
end
else
moveVelocity.VectorVelocity = Vector3.new(0, -game.Workspace.Gravity, 0)
lookGyro.CFrame = CFrame.identity
end
end
and probably add prints aswell so like when they run over slopes print(“running on slope”) and when they run over vertical walls print(“running on vertical wall”) so you can atleast know if its checking stuff correctly. again, sorry if my code doesnt work
One issue is that I can’t turn anymore since I’m using LookVector now
local function ProjectVectorOntoNormal(v: Vector3, n: Vector3) : Vector3
return v - n * v:Dot(n)
end
local function GetNormalAngle(normal)
return math.deg(math.acos(normal:Dot(Vector3.yAxis)))
end
local function HandleMovement(delta)
local rayDirection = rootpart.CFrame.UpVector * -5
local ray = game.Workspace:Raycast(rootpart.Position, rayDirection, raycastParams)
if ray then
local position, normal = ray.Position, ray.Normal
local moveDirection = humanoid.MoveDirection
local lookVector = rootpart.CFrame.LookVector
local projectedMoveDirection = ProjectVectorOntoNormal(moveDirection, normal)
local angle = GetNormalAngle(normal)
if angle >= 90 then
local surfaceRight = lookVector:Cross(normal)
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, normal)
local horizontalVelocity = lookVector.Unit * walkSpeedValue.Value
local verticalVelocity = Vector3.new(0, -10, 0)
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and (horizontalVelocity + verticalVelocity)) or Vector3.zero
lookGyro.CFrame = slopeRotation
else
local projectedMoveDirection = ProjectVectorOntoNormal(moveDirection, normal)
local surfaceRight = projectedMoveDirection:Cross(normal)
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, normal)
local horizontalVelocity = projectedMoveDirection.Unit * walkSpeedValue.Value
local verticalVelocity = Vector3.new(0, -10, 0)
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and (horizontalVelocity + verticalVelocity)) or Vector3.zero
lookGyro.CFrame = slopeRotation
end
else
moveVelocity.VectorVelocity = Vector3.new(0, -game.Workspace.Gravity, 0)
lookGyro.CFrame = CFrame.identity
end
print(`MoveVelocity {moveVelocity.VectorVelocity}`)
end
local function GetNormalAngle(normal)
return math.deg(math.acos(normal:Dot(Vector3.yAxis)))
end
function IsUpsideDown(rootPart)
return rootPart.CFrame.UpVector.Y < 0.3
end
local function HandleMovement(delta)
local rayDirection = rootpart.CFrame.UpVector * -5
local ray = game.Workspace:Raycast(rootpart.Position, rayDirection, raycastParams)
if ray then
local position, normal = ray.Position, ray.Normal
local moveDirection = humanoid.MoveDirection
local projectedMoveDirection = ProjectVectorOntoNormal(moveDirection, normal)
local lookVector = rootpart.CFrame.LookVector
local angle = GetNormalAngle(normal)
if angle >= 90 and IsUpsideDown(rootpart) then
local surfaceRight = lookVector:Cross(normal)
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, normal)
local horizontalVelocity = lookVector * walkSpeedValue.Value
local verticalVelocity = Vector3.new(0, -10, 0)
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and (horizontalVelocity + verticalVelocity)) or Vector3.zero
lookGyro.CFrame = slopeRotation
All I need now is to somehow make the character be able to turn if they pressed A or D while using LookVector
local function AlignMoveDirection(moveDirection : Vector3, surfaceNormal : Vector3) : Vector3
surfaceNormal = surfaceNormal.Unit
if surfaceNormal.Magnitude == 0 then
return moveDirection
end
local upVector = Vector3.yAxis
local axis = upVector:Cross(surfaceNormal)
if axis.Magnitude == 0 then
return moveDirection
end
axis = axis.Unit
local dotProduct = upVector:Dot(surfaceNormal)
dotProduct = math.clamp(dotProduct, -1, 1)
local angle = math.acos(dotProduct)
local rotation = CFrame.fromAxisAngle(axis, angle)
local alignedMoveDirection = rotation:VectorToWorldSpace(moveDirection)
return alignedMoveDirection
end
local function GetNormalAngle(normal : Vector3) : number
return math.deg(math.acos(Vector3.yAxis:Dot(normal)))
end
local function IsUpsideDown() : boolean
return rootpart.CFrame.UpVector.Y < 0
end
local function HandleMovement(delta : number) : any
local rayDirection = rootpart.CFrame.UpVector * -5
local ray = game.Workspace:Raycast(rootpart.Position + rootpart.CFrame.LookVector * 1.1, rayDirection, raycastParams)
local moveDirection = humanoid.MoveDirection
local walkSpeed = walkSpeedValue.Value
if ray then
local hit, position, normal = ray.Instance, ray.Position, ray.Normal
local alignedMoveDirection = AlignMoveDirection(moveDirection, normal)
local surfaceAngle = GetNormalAngle(normal)
local isUpsideDown = IsUpsideDown()
if surfaceAngle > 170 and isUpsideDown then
alignedMoveDirection = alignedMoveDirection.Unit
end
local surfaceRight = alignedMoveDirection:Cross(normal)
local slopeRotation = CFrame.fromMatrix(position, surfaceRight, normal)
local horizontalVelocity = alignedMoveDirection.Unit * walkSpeed
local verticalVelocity = rootpart.CFrame.UpVector * -10
moveVelocity.VectorVelocity = (moveDirection.Magnitude > 0.5 and (horizontalVelocity + verticalVelocity)) or Vector3.zero
lookGyro.CFrame = slopeRotation
else
moveVelocity.VectorVelocity = Vector3.new(moveDirection.X * walkSpeed, -(game.Workspace.Gravity), moveDirection.Z * walkSpeed)
lookGyro.CFrame = (moveDirection.Magnitude > 0.5 and CFrame.new(rootpart.Position, rootpart.Position + moveDirection)) or CFrame.identity
end
end