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.
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.
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.
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
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
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.
Okay, so just a few questions:
- What size should the sphere be?
- How can I get Roblox’s freecam?
- 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.
Okay I tried it but for some reason the camera just gets stuck in the baseplate. Do you know what I did wrong? Thanks.
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. 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
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.
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.