Sonic 1 Camera not Working

Hello. So, I’ve (somehow) fixed this problem (and this one (and this one too)) but now, of course, a new problem has risen that has been haunting me for like a week now.

Here’s the scene:

The intended behavior is when Sonic touches the Red Line (VerticalBottom), the camera goes so that the red line is at the same Y position as Sonic. Then, once Sonic’s Y position is near the Green Line (VerticalCenter), the camera instantly readjusts so that Sonic’s Y position is the same as the Green Line. And, once Sonic lands after starting the game, it works normally. It’s only once he lands after falling that it seems to wait before readjusting. Here’s a video of the intended behavior (somehow it just broke itself):
robloxapp-20240421-2141520.wmv (606.5 KB)
and here’s a video of the current behavior:

Now, here’s the camera script:

local function moveCamDown()
	repeat
		local distance = math.abs(script.Parent.Parent.Sonic.Position.Y - script.Parent.Position.Y)  -- Get the distance along the X-axis

		--if distance < 1.6 then
		if distance <= 0 then
			distance = 0.1
		end
		if script.Parent.Parent.Sonic.Variables.state == "Grounded" then
			local oldCFrame = script.Parent.CFrame
			if script.Parent.Parent.Sonic.Position.Y <= script.Parent.VerticalCenter.Position.Y then
				script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y + math.abs(script.Parent.Position.Y - script.Parent.VerticalCenter.Position.Y), script.Parent.CFrame.Z)
			elseif script.Parent.Parent.Sonic.Position.Y >= script.Parent.VerticalCenter.Position.Y then
				script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y + -math.abs(script.Parent.Position.Y - script.Parent.VerticalCenter.Position.Y), script.Parent.CFrame.Z)
			end
			return
		end
		local oldCFrame = script.Parent.CFrame
		--script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y, script.Parent.CFrame.Z)  -- Move instantly
		--if script.Parent.Position.Y - distance - math.abs(script.Parent.Position.Y - script.Parent.VerticalBottom.Position.Y) < script.Parent.Position.Y then
		script.Parent.CFrame -= Vector3.new(0, distance, 0)  -- Move Part1 along the X-axis
		--else
		--return
		--end
		--[[elseif distance == 0 then
			local direction = (script.Parent.Parent.Sonic.Position.Y - script.Parent.Position.Y) / distance  -- Get the direction along the X-axis
			local movement = direction * math.min(1.6, distance)  -- Calculate the movement

			script.Parent.CFrame -= Vector3.new(0, movement, 0)  -- Move Part1 along the X-axis
		else
			local direction = (script.Parent.Parent.Sonic.Position.Y - script.Parent.Position.Y) / distance  -- Get the direction along the X-axis
			local movement = direction * math.min(1.6, distance)  -- Calculate the movement
			script.Parent.CFrame -= Vector3.new(0, movement, 0)  -- Move Part1 along the X-axis]]
		--end
		if math.abs(script.Parent.Parent.Sonic.Position.Y - script.Parent.VerticalCenter.Position.Y) <= 1 then
			local oldCFrame = script.Parent.CFrame
			if script.Parent.Parent.Sonic.Position.Y < script.Parent.VerticalCenter.Position.Y then
				script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y + (script.Parent.Position.Y - script.Parent.VerticalCenter.Position.Y), script.Parent.CFrame.Z)
			elseif script.Parent.Parent.Sonic.Position.Y > script.Parent.VerticalCenter.Position.Y then
				script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y - (script.Parent.Position.Y - script.Parent.VerticalCenter.Position.Y), script.Parent.CFrame.Z)
			end
		end
		print("SHOTY")
		wait(0.25)
	until math.abs(script.Parent.Parent.Sonic.Position.Y - script.Parent.VerticalCenter.Position.Y) <= .8
	if math.abs(script.Parent.Parent.Sonic.Position.Y - script.Parent.VerticalCenter.Position.Y) <= .8 then
		local oldCFrame = script.Parent.CFrame
		if script.Parent.Parent.Sonic.Position.Y < script.Parent.VerticalCenter.Position.Y then
			script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y + (script.Parent.Position.Y - script.Parent.VerticalCenter.Position.Y), script.Parent.CFrame.Z)
		elseif script.Parent.Parent.Sonic.Position.Y > script.Parent.VerticalCenter.Position.Y then
			script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y - (script.Parent.Position.Y - script.Parent.VerticalCenter.Position.Y), script.Parent.CFrame.Z)
		end
	end
end
local function moveCamUp()
	repeat
		local distance = math.abs(script.Parent.Parent.Sonic.Position.Y - script.Parent.Position.Y)  -- Get the distance along the X-axis

		--if distance < 1.6 then
		local oldCFrame = script.Parent.CFrame
		--script.Parent.CFrame = oldCFrame.Rotation + Vector3.new(script.Parent.CFrame.X, script.Parent.Parent.Sonic.CFrame.Y, script.Parent.CFrame.Z)  -- Move instantly
		if script.Parent.Position.Y + distance - math.abs(script.Parent.Position.Y - script.Parent.VerticalTop.Position.Y) > script.Parent.Position.Y then
			script.Parent.CFrame += Vector3.new(0, distance - math.abs(script.Parent.Position.Y - script.Parent.VerticalTop.Position.Y), 0)  -- Move Part1 along the X-axis
		--[[end
		elseif distance == 0 then
			local direction = (script.Parent.Parent.Sonic.Position.Y - script.Parent.Position.Y) / distance  -- Get the direction along the X-axis
			local movement = direction * math.min(1.6, distance)  -- Calculate the movement

			script.Parent.CFrame -= Vector3.new(0, movement, 0)  -- Move Part1 along the X-axis
		else
			local direction = (script.Parent.Parent.Sonic.Position.Y - script.Parent.Position.Y) / distance  -- Get the direction along the X-axis
			local movement = direction * math.min(1.6, distance)  -- Calculate the movement
			script.Parent.CFrame -= Vector3.new(0, movement, 0)  -- Move Part1 along the X-axis--]]
		end
		print("SHITY")
		wait(0.25)
	until math.abs(script.Parent.Parent.Sonic.Position.Y + script.Parent.VerticalCenter.Position.Y) <= .8
end

script.Parent.Parent.Sonic.Changed:Connect(function()
	if script.Parent.Parent.Sonic.Position.Y ~= script.Parent.VerticalCenter.Position.Y then
		if tonumber(string.format("%." .. (1) .. "f", script.Parent.Parent.Sonic.Position.Y)) <= tonumber(string.format("%." .. (1) .. "f", script.Parent.VerticalBottom.Position.Y)) then
			moveCamDown()
		elseif tonumber(string.format("%." .. (1) .. "f", script.Parent.Parent.Sonic.Position.Y)) >= tonumber(string.format("%." .. (1) .. "f", script.Parent.VerticalTop.Position.Y)) then
			moveCamUp()
		end
	end
end)

and here’s Sonic’s script:

local state = script.Parent.Variables.state
local speedY = script.Parent.Variables.speedY.Value
local speedX = script.Parent.Variables.speedX
local jumpForce = script.Parent.Variables.jumpForce.Value
local groundAngle = script.Parent.Variables.groundAngle
local direction = script.Parent.Variables.direction
local collisionBtmRight = script.Parent.Variables.collisionBtmRight
local collisionBtmLeft = script.Parent.Variables.collisionBtmLeft

local sonicSizes = {
	standing = Vector3.new(0.081, 3.31, 2.571),
	standingHitbox = Vector3.new(0.162, 2.731, 1.366),
	
	jumping = Vector3.new(0.08, 2.571, 2.571),
	jumpingHitbox = Vector3.new(0.162, 1.841, 1.366),
}
local sonicPics = {
	idleRight =  "rbxassetid://15036394678",
	idleLeft =   "rbxassetid://17228640834",
	
	walkRight1 = "rbxassetid://15036394489",
	walkRight2 = "rbxassetid://15036394334",
	walkRight3 = "rbxassetid://15036394169",
	walkRight4 = "rbxassetid://15036393971",
	walkRight5 = "rbxassetid://15036393740",
	walkRight6 = "rbxassetid://15036393489",
	
	jump1 = 	 "rbxassetid://17258635607",
}

wait(10)

script.Parent.Parent.btmLeftAnchorPoint.Touched:Connect(function(part)
	if part.Name == "Solid" and part.BrickColor == BrickColor.new("Institutional white") and part.CanCollide == true then
		collisionBtmLeft.Value = true
	end
end)

script.Parent.Parent.btmRightAnchorPoint.Touched:Connect(function(part)
	if part.Name == "Solid" and part.BrickColor == BrickColor.new("Institutional white") and part.CanCollide == true then
		collisionBtmRight.Value = true
	end
end)

script.Parent.Parent.btmLeftAnchorPoint.TouchEnded:Connect(function(part)
	if part.Name == "Solid" and part.BrickColor == BrickColor.new("Institutional white") and part.CanCollide == true then
		collisionBtmLeft.Value = false
	end
end)

script.Parent.Parent.btmRightAnchorPoint.TouchEnded:Connect(function(part)
	if part.Name == "Solid" and part.BrickColor == BrickColor.new("Institutional white") and part.CanCollide == true then
		collisionBtmRight.Value = false
	end
end)

--[[local function GetOutOfGround(part, obstacle)
	-- Get references to the parts you want to move
	local partToMove = part -- Change "Part1" to the name of your part
	local obstaclePart = obstacle -- Change "Part2" to the name of the part it may be colliding with

	-- Calculate the distance to move the part
	local distanceToMove = obstaclePart.CFrame.Y + obstaclePart.Size.Y / 2 + partToMove.Size.Y / 2 - partToMove.CFrame.Y

	-- Move the part instantly
	partToMove.CFrame = partToMove.CFrame + Vector3.new(0, distanceToMove, 0)
end--]]

local function GetOutOfGround(part, obstacle)
	-- Get references to the parts you want to move
	local partToMove = part -- Change "Part1" to the name of your part
	local obstaclePart = obstacle -- Change "Part2" to the name of the part it may be colliding with

	-- Calculate the distance to move the parts
	local distanceToMove = obstaclePart.Position.Y + obstaclePart.Size.Y / 2 + partToMove.Size.Y / 2 - partToMove.Position.Y

	-- Move Sonic instantly
	partToMove.Position = partToMove.Position + Vector3.new(0, distanceToMove, 0)

	-- Move attached parts (e.g., camera, side bars) by the same amount
	for _, attachedPart in ipairs(partToMove.Parent:GetChildren()) do
		if attachedPart:IsA("BasePart") and attachedPart.Name ~= "Sonic" and attachedPart.Name ~= "CamView" and attachedPart.Name ~= "LeftBar" and attachedPart.Name ~= "RightBar" then
			attachedPart.Position = attachedPart.Position + Vector3.new(0, distanceToMove, 0)
		end
	end
	for _, attachedPart in ipairs(partToMove:GetChildren()) do
		if attachedPart:IsA("BasePart") then
			attachedPart.Position = attachedPart.Position + Vector3.new(0, distanceToMove, 0)
		end
	end
end

--CONTROLS
game.ReplicatedStorage.Remotes.SonicJump.OnServerEvent:Connect(function()
	if state.Value == "Grounded" then
		speedY += jumpForce * math.cos(groundAngle.Value)
		--print(speedY)
		--speedX.Value += jumpForce	--* math.sin(ground angle)
		script.Parent.CFrame += Vector3.new(0, 0.1, 0)
		collisionBtmRight.Value = false
		collisionBtmLeft.Value = false
		
		script.Parent.Hitbox.Size = sonicSizes.jumpingHitbox
		script.Parent.Texture.Size = sonicSizes.jumping
		
		script.Parent.Texture.Texture.Texture = sonicPics.jump1
	end
end)
game.ReplicatedStorage.Remotes.SonicCutJump.OnServerEvent:Connect(function()
	print("blud cut his jump")
	if speedY > jumpForce / 1.5 then
		speedY = jumpForce / 1.5
	end
end)

game.ReplicatedStorage.Remotes.SonicMove.OnServerEvent:Connect(function(plr, directionInput)
	if directionInput == "Left" then
		direction.Value = "Left"
		script.Parent.Size = sonicSizes.standing
		script.Parent.Texture.Texture.Texture = sonicPics.idleLeft
	elseif directionInput == "Right" then
		direction.Value = "Right"
		script.Parent.Size = sonicSizes.standing
		script.Parent.Texture.Texture.Texture = sonicPics.idleRight
	end
end)

game:GetService("RunService").Heartbeat:Connect(function()
	local touchingBtmLeft = script.Parent.Parent.btmLeftAnchorPoint:GetTouchingParts()
	local touchingBtmRight = script.Parent.Parent.btmRightAnchorPoint:GetTouchingParts()

	local grounded = false
	
	--COLLISION DETECTION
	for i = 1, #touchingBtmLeft do
		if touchingBtmLeft[i].Name == "Solid" and touchingBtmLeft[i].BrickColor == BrickColor.new("Institutional white") and touchingBtmLeft[i].CanCollide == true then
			--print("touched left")
			collisionBtmLeft.Value = true
			GetOutOfGround(script.Parent, touchingBtmLeft[i])
			
			script.Parent.Hitbox.Size = sonicSizes.standingHitbox
			script.Parent.Texture.Size = sonicSizes.standing

			if direction.Value == "Left" then
				script.Parent.Texture.Texture.Texture = sonicPics.idleLeft
			elseif direction.Value == "Right" then
				script.Parent.Texture.Texture.Texture = sonicPics.idleRight
			end
		end
	end

	for i = 1, #touchingBtmRight do
		if touchingBtmRight[i].Name == "Solid" and touchingBtmRight[i].BrickColor == BrickColor.new("Institutional white") and touchingBtmRight[i].CanCollide == true then
			--print("touched right")
			collisionBtmRight.Value = true
			GetOutOfGround(script.Parent, touchingBtmRight[i])
			
			script.Parent.Hitbox.Size = sonicSizes.standingHitbox
			script.Parent.Texture.Size = sonicSizes.standing

			if direction.Value == "Left" then
				script.Parent.Texture.Texture.Texture = sonicPics.idleLeft
			elseif direction.Value == "Right" then
				script.Parent.Texture.Texture.Texture = sonicPics.idleRight
			end
		end
	end

	--CHECK IF GROUNDED
	if collisionBtmRight.Value == true then
		grounded = true
	else
		grounded = false
	end
	if collisionBtmLeft.Value == true then
		grounded = true
	else
		grounded = false
	end

	--SPEED Y
	if grounded == true then
		speedY = 0
	elseif grounded == false then
		speedY -= 0.021875
	end
	
	--GROUND ANGLE
	if grounded == false then
		if groundAngle.Value > 0 then
			groundAngle.Value -= 2.8125
		elseif groundAngle.Value < 0 then
			groundAngle.Value += 2.8125
		end
	end
	
	--CHANGE STATE
	if grounded == true then
		state.Value = "Grounded"
	elseif grounded == false then
		if speedY > 0 then
			state.Value = "Jumping"
		elseif speedY == 0 then
			state.Value = "Grounded"
		elseif speedY < 0 then
			state.Value = "Falling"
		end
	end
	--print(grounded)

	--MOVE SPEED Y
	script.Parent.CFrame += Vector3.new(0, speedY, 0)
end)

If you need more clarification on how the camera works, you can visit https://info.sonicretro.org/SPG:Camera.
Thank you!

it worked on the 21st but after that it rebroke. have no clue why.

It seems like if Sonic falls after jumping (from a short distance) this happens. But if I set the jumpForce high, then it all works fine. Who am I talking to? I have no clue.