How can I find if the camera collides with a part?

Okay so my question is, with a free roam camera (custom made), how would you be able to do camera collisions since with scriptable cameras I think there are no default collisions like the other camera modes have. So how would I be able to detect collisions with other parts using a scriptable camera system? Thank you.

9 Likes

You could do it with raycasts, but you would require alot of rays to make sure camera isn’t colliding with anything (I had a system with 1 raycast before just checking direction camera is moving in, and there were few ways to break it and go through the ground). The way I did it in the end is having a sphere, moving it with AlignPosition to the new camera position and then moving the camera to the spheres position. I didn’t spend much time on this system though and as this just worked fine, I left it at that. You can definitely make it better by just moving the sphere and attaching the camera to it.

2 Likes

Could you give me some code samples of that working? I’ve heard of that strategy before but I don’t fully understand it. Thanks for answering.

2 Likes

It all depends on how your freecam works. I’m using roblox’s FreeCam for this and it calculates the position where camera should move, then move the camera to that position, I instead move the sphere to that position and then move the camera to the spheres new position (as the sphere collides it wont go through objects).

cameraCFrame = --calculate the position where camera should move
sphere.AlignPosition.Position = cameraCFrame.p --move the sphere to that position
cameraCFrame = cameraCFrame - cameraCFrame.p + sphere.CFrame.p --replace with new position
Camera.CFrame = cameraCFrame --move the camera to the new position
2 Likes

Here’s a different way: have a tiny invisible and collisionless part follow the camera. On every frame, run a spatial query (workspace:GetPartsInPart()) on that part to detect for anything that’s colliding with it.

P.S., you should set the .MaxParts property of the OverlapParams to just 1 to save on performance

3 Likes

How do I create the sphere? Could you give me the code that also shows how the sphere is generated? Thanks for the help.

Could you give me some code so I can see it in action? I would really appreciate that. Thank you for your answer.

You don’t need to generate the sphere with code, just create a sphere that isn’t anchored, is massless, has AlignPosition within it, parent it to the script and clone it when you start the freecam.

2 Likes

Okay, so just a few questions:

  1. What size should the sphere be?
  2. How can I get Roblox’s freecam?
  3. Where do I put the clone under which parent?

My freecam currently is one I got from someone on devforum but I would very much like to use the official one if there is one. Thank you for your help. I appreciate it.

The sphere can be as big as you want it to be away from obstacles (if its too big it might not be able to go between 2 parts that are close to each other), I’ve made them 1.5 studs.

Honestly being the official one doesnt mean much, as it has many imperfections within its code. Its also quite old at this point, so creating your own freecam or getting it from someone on devforum might even be a better option, as the roblox one has quite alot of things you might not need. Another thing to note is that it was made for creating cinematics for your game and getting screenshots. That being said, if you still want to try it out just enter a game, and in your PlayerGui you should find Freecam gui, the script is located within it.

When you clone the sphere, you should put it into workspace so it can interact with the world.

1 Like

Okay I tried it but for some reason the camera just gets stuck in the baseplate. Do you know what I did wrong? Thanks.

1 Like

Id recommend playing around with AlignPosition, to see how it interacts with the part. You should put the current spheres position into the AlignPosition, so when it gets cloned it doesn’t just go to (0,0,0).

I’m still having problems. I made the AlignPosition one attachment and put into its position the sphere’s position but I am still stuck in the baseplate. :confused: Do you know what’s wrong? Thanks.

EDIT: Like I can move the camera around, just that i’m stuck in the baseplate.

Thats weird, as even if you somehow spawn inside of the baseplate, you should be able to go out of it. Did you try just running the game with the sphere just suspended in air and changing the AlignPosition’s Position? If that works fine then its probably something with the freecam code.

EDIT: NVM I will try to do it myself but I need help. I just need to get out of the baseplate, do you know how I can do this? Is it because of the sphere? Thanks.

As I said before, if you can move the sphere normally by just changing AlignPosition, then its probably something with the code. When it comes to moving it with the code, instead of changing camera’s position, you have to change AlignPosition, then move the camera to the spheres position. It could be that currently something is moving it into the baseplate, as if you are stuck inside of it, you should just be able to fly out as you shouldn’t be colliding with it from inside of it.

This is the code I have so far- can you tell me what i’m doing wrong? This is including the free roam script and yours at the bottom. Thank you!

function doFunction(dt)

local move = Vector3.zero
for _, v in pairs(activeDirections) do
move += v
end

if move ~= Vector3.zero then
	speedBonus += 0.1
	else
	speedBonus = 0
end

local speed = if shiftPressed then SHIFT_SPEED else MOVE_SPEED + speedBonus

local char = player.Character
local head = char.Head

position += angle * (move * speed * dt)
local cameraCFrame = angle + position
	
--- Do collisions here
	
local sphere = script.Sphere:Clone()
	
--cameraCFrame = --calculate the position where camera should move
sphere.AlignPosition.Position = cameraCFrame.p --move the sphere to that position
cameraCFrame = cameraCFrame - cameraCFrame.p + sphere.CFrame.p --replace with new position
camera.CFrame = cameraCFrame --move the camera to the new position
		
end
1 Like

The sphere should be cloned only once when the freecam is started and not every time it updates its position, you also need to move it to workspace. The example I gave you works if you are changing camera’s CFrame in the first place, as that is not the full code I don’t know how you are getting the position where you want your camera to move. If you are changing its CFrame then you simply have to get the position from that CFrame and feed it to AlignPosition.
This is a simple example of moving the sphere correctly, but it doesnt include going where you are looking:

local camera = game.Workspace.CurrentCamera
local uis = game:GetService("UserInputService")

local sphere = script:WaitForChild("Part"):Clone()
sphere.Parent = workspace

local direction = Vector3.new(0,0,0)

local directions = {
	["W"] = Vector3.new(1,0,0),
	["A"] = Vector3.new(0,0,-1),
	["S"] = Vector3.new(-1,0,0),
	["D"] = Vector3.new(0,0,1),
	["E"] = Vector3.new(0,1,0),
	["Q"] = Vector3.new(0,-1,0)
}

task.wait(2)

camera.CameraSubject = sphere

game:GetService("RunService").RenderStepped:Connect(function()
	sphere.AlignPosition.Position = sphere.Position + direction
end)

uis.InputBegan:Connect(function(input,processed)
	if processed then return end
	if directions[input.KeyCode.Name] then
		direction += directions[input.KeyCode.Name]
	end
end)

uis.InputEnded:Connect(function(input,processed)
	if processed then return end
	if directions[input.KeyCode.Name] then
		direction -= directions[input.KeyCode.Name]
	end
end)

Keep in mind this is just an example of how to move the sphere in all 6 directions, to implement it into the freecam code, you instead have to get the CFrame of where you are moving the camera, take only the position and move the AlignPosition there, then replace that same position from the CFrame with the new position of the sphere and apply that CFrame to the camera.

1 Like

I still don’t understand, sorry. I did get the position of the camera’s CFrame and put it into AlignPosition.

sphere.AlignPosition.Position = cameraCFrame.p --move the sphere to that position

Also here is the freecam code (the code that goes before the text I gave you):

local KEY_DIRECTIONS = table.freeze({
	[Enum.KeyCode.A] = Vector3.new(-1, 0, 0),
	[Enum.KeyCode.D] = Vector3.new(1, 0, 0),
	[Enum.KeyCode.S] = Vector3.new(0, 0, 1),
	[Enum.KeyCode.W] = Vector3.new(0, 0, -1),
	[Enum.KeyCode.Q] = Vector3.new(0, -1, 0),
	[Enum.KeyCode.E] = Vector3.new(0, 1, 0)
})

local TURN_SPEED = 1/90 -- in radians/pixel
local SHIFT_SPEED = 6 -- in studs/second
local MOVE_SPEED = 60 -- in studs/second

local shiftPressed = false

local activeDirections = {}

local x = 0
local y = 0
local angle = CFrame.Angles(0, x, 0) * CFrame.Angles(y, 0, 0)
local position = Vector3.new(0, 0, 0)

UserInputService.InputBegan:Connect(function(input)
	if KEY_DIRECTIONS[input.KeyCode] then
		activeDirections[input.KeyCode] = KEY_DIRECTIONS[input.KeyCode]
	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
	elseif input.KeyCode == Enum.KeyCode.LeftShift then
		shiftPressed = true
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if KEY_DIRECTIONS[input.KeyCode] then
		activeDirections[input.KeyCode] = nil
	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	elseif input.KeyCode == Enum.KeyCode.LeftShift then
		shiftPressed = false
	end
end)

UserInputService.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement then
		x = (x - input.Delta.X * TURN_SPEED)%(2*math.pi)
		y = math.clamp(y - input.Delta.Y * TURN_SPEED, math.rad(-89), math.rad(89))
		angle = CFrame.Angles(0, x, 0) * CFrame.Angles(y, 0, 0)
	elseif input.UserInputType == Enum.UserInputType.MouseWheel then
		position += angle * Vector3.new(0, 0, 5*input.Position.Z)
	end
end)

local speedBonus = 0

That code should work fine. All you have to do is move the cloning of the sphere outside of the function that runs every frame, and parent the sphere to workspace after you clone it:

local sphere = script.Sphere:Clone()
sphere.Parent = workspace

And in the function when you calculate the position instead of position += angle * (move * speed * dt)
you should do:

position += sphere.Position - position + angle * (move * speed * dt)

This is because you have to track current sphere position to make sure it collided with something, otherwise it would just stand still but when you try to move in opposite direction it will take few seconds before it actually starts moving.