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!