I just need someone to tell me how I could script a Popper like the one roblox uses.
These are accessible by running the game and looking inside StarterPlayer
- you will see that PlayerModule
and CameraModule
gets added.
Otherwise you can view the source online:
The general idea is that for each frame:
-
Cast 1 or more rays - learn about raycasting here - from
CameraSubject
to the desired position of the camera, or use the in builtCamera::GetPartsObscuringTarget()
found here - ignore any intersections that belong to the player or have some other condition -
Use the intersection point as the new camera position such that:
- if the new camera position is less than some desired distance you could force the player into first person here
- otherwise, you should interpolate from the last camera position to the new position over a few frames so there isn’t a big jump visible to the player
-
Repeat
After fixing many bugs that my script has, i’ve come up with this:
local Poppercam = {}
local camera = workspace.CurrentCamera
local character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local rootPart = character:WaitForChild("HumanoidRootPart")
local CameraVariable = require(script.Parent.CameraVariables)
local function RotateVector2(vector, angle)
local x = vector.X * math.cos(angle) - vector.Y * math.sin(angle)
local y = vector.X * math.sin(angle) + vector.Y * math.cos(angle)
return Vector2.new(x, y)
end
local function RaycastFromCamera(direction)
local viewportSize = camera.ViewportSize
local screenCenter = Vector2.new(viewportSize.X / 2, viewportSize.Y / 2)
local ray = camera:ScreenPointToRay(screenCenter.X, screenCenter.Y)
local rotatedDirection = RotateVector2(Vector2.new(ray.Direction.X, ray.Direction.Z), direction)
local rotatedRay = Ray.new(ray.Origin, Vector3.new(rotatedDirection.X, ray.Direction.Y, rotatedDirection.Y))
local hitPart, hitPosition, hitNormal = workspace:FindPartOnRay(rotatedRay)
return rotatedRay, hitPart, hitPosition, hitNormal
end
function Poppercam.Raycast()
local numRays = 8
local maxDistance = 1000
local closestDistance = math.huge
local closestRay = nil
for i = 1, numRays do
local angle = math.pi * 2 * (i - 1) / numRays
local ray, hitPart, hitPosition, hitNormal = RaycastFromCamera(angle)
if hitPart then
local distance = (hitPosition - camera.CFrame.Position).Magnitude
if distance < closestDistance then
closestDistance = distance
closestRay = ray
end
end
end
if closestRay then
local newCameraPosition = closestRay.Origin + closestRay.Direction * (closestDistance - 1)
local cameraFocus = newCameraPosition + camera.CFrame.LookVector * 100
camera.CFrame = CFrame.lookAt(newCameraPosition, cameraFocus)
end
end
return Poppercam
The problem is that it for some reason still lets the camera pass through the wall
force to zoom in if the focus (workspace.currentcamera.Focus) position cant find the camera.CFrame.p like a raycast from the head to the camera, if theres something on the way then you zoom (forced), you can use the magnitude between each other for length
but idk how to also help with this since u prob need it instant
I can probably use my custom zoom to achieve this
alr but it still would cause the bug, the camera still would noclip unless idk you mess up with the zoom distance, like if the wall is 4 stud long from the character and u put ur camera on it, it’ll offset idk -4 ???
(im not good at this lol)
im not good at this either, im still trying to figure out the math to actually do this xD
idk how to implement the thing you said, but I found out that when the camera clips the wall the rays just stop detecting the wall, so that might be the issue
I’m not sure if I’m able to understand your code fully, but are you casting the ray from the camera to the focus, or from in front of the camera to the camera? If it’s the former, the ray won’t collide with some objects, since it’s being casted from inside the object.