I’ve made this post about 3 or 4 times and no one’s answered not one of them. I couldn’t think of a better name. How do I make a part apply gravity to itself without making him clip in the floor? Here’s a video of this glitch happening, I’m too tired to keep writing.
(video removed due to roblox recording at 1 fps and you couldnt see it. basically, sonic clips right into the white floor in this picture)
local inAir = script.Parent.Variables.inAir.Value
local speedY = script.Parent.Variables.speedY.Value
local collisionBtmRight = script.Parent.Variables.collisionBtmRight.Value
local collisionBtmLeft = script.Parent.Variables.collisionBtmLeft.Value
local dTime = 0.01
wait(10)
--COLLISIONS
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
print("hi")
collisionBtmLeft = true
end
end)
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
print("bye")
collisionBtmRight = true
end
end)
script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function()
collisionBtmLeft = false
end)
script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function()
collisionBtmRight = false
end)
game:GetService("RunService").Heartbeat:Connect(function()
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function() end)
local touching = script.Parent.Parent.btmRightAnchorPoint:GetTouchingParts()
for i=1,#touching do
if touching[i].Name == "Solid" and touching[i].BrickColor == BrickColor.new("Institutional white") then
speedY = 0
end
end
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function() end)
local touching = script.Parent.Parent.btmLeftAnchorPoint:GetTouchingParts()
for i=1,#touching do
if touching[i].Name == "Solid" and touching[i].BrickColor == BrickColor.new("Institutional white") then
speedY = 0
end
end
end)
repeat
--BASIC CHECKS
if collisionBtmLeft == false and collisionBtmRight == false then
inAir = 1
elseif collisionBtmLeft == true and collisionBtmRight == false then
inAir = 0.8
elseif collisionBtmLeft == false and collisionBtmRight == true then
inAir = 0.4
elseif collisionBtmLeft == true and collisionBtmRight == true then
inAir = 0
end
--GRAVITY
if inAir == 1 then
if collisionBtmLeft == false and collisionBtmRight == false then
speedY = speedY - 0.1
end
else
speedY = 0
end
--MOVE PLAYER AND ANCHOR POINTS
script.Parent.Parent.btmRightAnchorPoint.CFrame = script.Parent.Parent.btmRightAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.Parent.btmLeftAnchorPoint.CFrame = script.Parent.Parent.btmLeftAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, speedY, 0)
wait(0.01)
until false
To be honest, it would be nice if you could specify a little more, however, you mention that the piece “catches on the ground.” Maybe because you are moving the piece down continuously in the moveSonicDown loop. Instead of doing this, you could try letting Roblox’s physics system take care of gravity for you (That’s my understanding)
Try removing the moveSonicDown function and put this:
repeat
--BASIC CHECKS
if collisionBtmLeft == false and collisionBtmRight == false then
inAir = 1
elseif collisionBtmLeft == true and collisionBtmRight == false then
inAir = 0.8
elseif collisionBtmLeft == false and collisionBtmRight == true then
inAir = 0.4
elseif collisionBtmLeft == true and collisionBtmRight == true then
inAir = 0
end
if inAir == 1 then
if collisionBtmLeft == false and collisionBtmRight == false then
speedY = speedY - 0.1
end
else
speedY = 0
end
-- MOVE PLAYER AND ANCHOR POINTS
script.Parent.Parent.btmRightAnchorPoint.CFrame = script.Parent.Parent.btmRightAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.Parent.btmLeftAnchorPoint.CFrame = script.Parent.Parent.btmLeftAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, speedY, 0)
wait(0.01)
until false
Let me know if I understood you correctly and if it works
that is exactly what’s happening, i said that the function (in reference to this) goes unused but i probably should’ve just removed it from the code. also, the parts ARE unanchored but I set the world’s gravity to 0 because Roblox’s gravity doesn’t accelerate the longer you’re in the air.
Oops, in the previous code I have sent some extra things (my bad) Try this:
script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function()
collisionBtmLeft = false
end)
script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function()
collisionBtmRight = false
end)
local lastTime = tick()
game:GetService("RunService").Stepped:Connect(function()
--BASIC CHECKS
if collisionBtmLeft == false and collisionBtmRight == false then
inAir = 1
elseif collisionBtmLeft == true and collisionBtmRight == false then
inAir = 0.8
elseif collisionBtmLeft == false and collisionBtmRight == true then
inAir = 0.4
elseif collisionBtmLeft == true and collisionBtmRight == true then
inAir = 0
end
-- GRAVITY
local deltaTime = tick() - lastTime
if inAir == 1 then
if collisionBtmLeft == false and collisionBtmRight == false then
speedY = speedY - 0.1 * deltaTime
end
else
speedY = 0
end
-- MOVE PLAYER AND ANCHOR POINTS
script.Parent.Parent.btmRightAnchorPoint.CFrame = script.Parent.Parent.btmRightAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.Parent.btmLeftAnchorPoint.CFrame = script.Parent.Parent.btmLeftAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, speedY, 0)
lastTime = tick()
end)
Theoretically that should solve the problem , since I have added more actions in the RunService that have worked for me in Roblox Studio at the moment (just as a test) lmk
Hi, I noticed you are relying on touched events to detect when the part reaches the ground, however, depending on the speed of the part, the step in which the touched event is activated could well be the one where it overshoots the boundary of the ground causing it to clip.
Basically, parts render/calculate physics at most 60 times per second at a specific location, it just looks like they are traveling because it is so fast. But for higher speed events if the last render point of the part was closer than the distance it should travel on the next step it will clip.
To get around this I recommend raycasting in the direction of travel to the next expected render location, and if a hit is returned set the final cframe to that location (taking into account part size), and activating the code currently in the touched events.
local inAir = script.Parent.Variables.inAir
local speedY = script.Parent.Variables.speedY
local collisionBtmRight = script.Parent.Variables.collisionBtmRight
local collisionBtmLeft = script.Parent.Variables.collisionBtmLeft
local dTime = 0.01
-- No need for the 'wait(10)' statement at the beginning
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
collisionBtmLeft = true
end
end)
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
collisionBtmRight = true
end
end)
script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function()
collisionBtmLeft = false
end)
script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function()
collisionBtmRight = false
end)
game:GetService("RunService").Heartbeat:Connect(function()
local touchingBtmLeft = script.Parent.Parent.btmLeftAnchorPoint:GetTouchingParts()
local touchingBtmRight = script.Parent.Parent.btmRightAnchorPoint:GetTouchingParts()
local grounded = false
for i = 1, #touchingBtmLeft do
if touchingBtmLeft[i].Name == "Solid" and touchingBtmLeft[i].BrickColor == BrickColor.new("Institutional white") then
grounded = true
end
end
for i = 1, #touchingBtmRight do
if touchingBtmRight[i].Name == "Solid" and touchingBtmRight[i].BrickColor == BrickColor.new("Institutional white") then
grounded = true
end
end
if grounded then
speedY = 0
else
end
script.Parent.Parent.btmRightAnchorPoint.CFrame = script.Parent.Parent.btmRightAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.Parent.btmLeftAnchorPoint.CFrame = script.Parent.Parent.btmLeftAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, speedY, 0)
end)
local inAir = script.Parent.Variables.inAir.Value
local speedY = script.Parent.Variables.speedY.Value
local collisionBtmRight = script.Parent.Variables.collisionBtmRight.Value
local collisionBtmLeft = script.Parent.Variables.collisionBtmLeft.Value
wait(10)
--COLLISIONS
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
print("hi")
collisionBtmLeft = true
end
end)
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
print("bye")
collisionBtmRight = true
end
end)
script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function()
collisionBtmLeft = false
end)
script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function()
collisionBtmRight = false
end)
game:GetService("RunService").Heartbeat:Connect(function()
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function() end)
local touching = script.Parent.Parent.btmRightAnchorPoint:GetTouchingParts()
for i=1,#touching do
if touching[i].Name == "Solid" and touching[i].BrickColor == BrickColor.new("Institutional white") then
speedY = 0
end
end
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function() end)
local touching = script.Parent.Parent.btmLeftAnchorPoint:GetTouchingParts()
for i=1,#touching do
if touching[i].Name == "Solid" and touching[i].BrickColor == BrickColor.new("Institutional white") then
speedY = 0
end
end
end)
repeat
--BASIC CHECKS
if collisionBtmLeft == false and collisionBtmRight == false then
inAir = 1
elseif collisionBtmLeft == true and collisionBtmRight == false then
inAir = 0.8
elseif collisionBtmLeft == false and collisionBtmRight == true then
inAir = 0.4
elseif collisionBtmLeft == true and collisionBtmRight == true then
inAir = 0
end
--GRAVITY
if inAir == 1 then
if collisionBtmLeft == false and collisionBtmRight == false then
speedY = speedY - 0.1
end
else
speedY = 0
end
--NO-CLIPPING CHECKS
local newBtmRightAnchorPoint = script.Parent.Parent.btmRightAnchorPoint:Clone()
local newBtmLeftAnchorPoint = script.Parent.Parent.btmLeftAnchorPoint:Clone()
newBtmLeftAnchorPoint.Name = "newBtmLeftAnchorPoint"
newBtmRightAnchorPoint.Name = "newBtmRightAnchorPoint"
newBtmLeftAnchorPoint.CFrame = newBtmLeftAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
newBtmRightAnchorPoint.CFrame = newBtmRightAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
local params = RaycastParams.new()
params.FilterDescendantsInstances = {
workspace.MainElements, workspace.Baseplate
}
local raycast = workspace:Raycast(script.Parent.Parent.btmLeftAnchorPoint.Position, (newBtmLeftAnchorPoint.Position - script.Parent.Parent.btmLeftAnchorPoint.Position), params)
if raycast then
if raycast.Instance.Name == "Solid" and raycast.Instance.BrickColor == BrickColor.new("Institutional white") then
script.Parent.Parent.btmLeftAnchorPoint.Position = raycast.Position
end
else
script.Parent.Parent.btmLeftAnchorPoint.CFrame = script.Parent.Parent.btmLeftAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
end
local raycast2 = workspace:Raycast(script.Parent.Parent.btmRightAnchorPoint.Position, (newBtmRightAnchorPoint.Position - script.Parent.Parent.btmRightAnchorPoint.Position), params)
if raycast2 then
if raycast2.Instance.Name == "Solid" and raycast2.Instance.BrickColor == BrickColor.new("Institutional white") then
script.Parent.Parent.btmRightAnchorPoint.Position = raycast2.Position
end
else
script.Parent.Parent.btmRightAnchorPoint.CFrame = script.Parent.Parent.btmRightAnchorPoint.CFrame + Vector3.new(0, speedY, 0)
end
newBtmRightAnchorPoint:Destroy()
newBtmLeftAnchorPoint:Destroy()
--MOVE SONIC
if raycast then
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, script.Parent.Parent.btmLeftAnchorPoint.Position.Y + (script.Parent.Size.Y/2), 0)
else
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, speedY, 0)
end
wait(0.01)
until false
I’ve simplified the collision checking and made sure that the player’s position is adjusted consistently with the velocity (speedY). This should help prevent Sonic from clipping into the floor.
local inAir = script.Parent.Variables.inAir
local speedY = script.Parent.Variables.speedY
local collisionBtmRight = script.Parent.Variables.collisionBtmRight
local collisionBtmLeft = script.Parent.Variables.collisionBtmLeft
wait(10)
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
collisionBtmLeft = true
end
end)
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function(part)
if part.BrickColor == BrickColor.new("Institutional white") then
collisionBtmRight = true
end
end)
script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function()
collisionBtmLeft = false
end)
script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function()
collisionBtmRight = false
end)
game:GetService("RunService").Heartbeat:Connect(function()
local touchingBtmLeft = script.Parent.Parent.btmLeftAnchorPoint:GetTouchingParts()
local touchingBtmRight = script.Parent.Parent.btmRightAnchorPoint:GetTouchingParts()
local grounded = false
for i = 1, #touchingBtmLeft do
if touchingBtmLeft[i].Name == "Solid" and touchingBtmLeft[i].BrickColor == BrickColor.new("Institutional white") then
grounded = true
end
end
for i = 1, #touchingBtmRight do
if touchingBtmRight[i].Name == "Solid" and touchingBtmRight[i].BrickColor == BrickColor.new("Institutional white") then
grounded = true
end
end
if grounded then
speedY = 0
else
speedY = speedY - 0.1
end
script.Parent.CFrame = script.Parent.CFrame + Vector3.new(0, speedY, 0)
end)
everything that controls Sonic (besides the button presses which will be handled in a local script (dont worry it will fire remote events) goes in the “Main” script
He’s only supposed to move on 2 axis (Y, Z (or X I always get the 2 mixed up)) and what I’m planning on doing is having different colored parts for collision (white for solid, red for death, yellow for semisolid, etc)
local inAir = script.Parent.Variables.inAir
local speedY = script.Parent.Variables.speedY
local collisionBtmRight = script.Parent.Variables.collisionBtmRight
local collisionBtmLeft = script.Parent.Variables.collisionBtmLeft
local whiteColor = BrickColor.new("Institutional white")
local function isCollisionPartSolid(part)
return part.BrickColor == whiteColor
end
wait(10)
script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function(part)
if isCollisionPartSolid(part) then
collisionBtmLeft = true
end
end)
script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function(part)
if isCollisionPartSolid(part) then
collisionBtmRight = true
end
end)
script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function()
collisionBtmLeft = false
end)
script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function()
collisionBtmRight = false
end)
game:GetService("RunService").Heartbeat:Connect(function()
local touchingBtmLeft = script.Parent.Parent.btmLeftAnchorPoint:GetTouchingParts()
local touchingBtmRight = script.Parent.Parent.btmRightAnchorPoint:GetTouchingParts()
local grounded = false
for i = 1, #touchingBtmLeft do
if isCollisionPartSolid(touchingBtmLeft[i]) then
grounded = true
end
end
for i = 1, #touchingBtmRight do
if isCollisionPartSolid(touchingBtmRight[i]) then
grounded = true
end
end
if grounded then
speedY = 0
else
speedY = speedY - 0.1
end
-- Update your Z (or X) position here
local newPosition = script.Parent.Position + Vector3.new(0, speedY, 0) -- Modify as needed
script.Parent.Position = newPosition
end)
ve added a whiteColor variable to make it easier to check for white collision parts. Also, I’ve adjusted the code to update the position on the Y axis (Z axis in Roblox) while restricting movement on the other axis (X axis in Roblox). Be sure to modify the newPosition calculation.