Introduction
Hello everyone! My name is HeIIoISteaIUsernames. I’ve been working on my game for almost a week now, and one of its main functions is the Camera/Room system (you’ll see why it’s called that below.)
About the Camera/Room System (I need a better name tbh)
Essentially what it does is that if a Player is inside a room (via the floor, which is a part), it will activate camera to focus on the player through these two parts:
The camera perspective is top-down, as you can see here:
If you need another visual of how the system works, here ya go:
“How did you do this?” you ask? With the power of Raycasting!!
Here’s what the script (local script) does:
- Creates a function called checkForRoom() and sets up these 5 variables:
local isInRoom, roomName, cam1, cam2, floorType
- Creates a ray with an ignore list inside the HumanoidRootPart, pointing downwards
- Checks if the ray has hit a specific part and if the part’s name is “Floor” or “Floor2”. If the part exists then we set isInRoom to true
- Checks if the cameraParts (cameraMain and cameraStatic) exist if isInRoom == true. If both those parts exist, and if the cameraStatic’s Active value is set to true or false, then we set cam1 to cameraMain, and cam2 to cameraStatic.
- We then return those five variables from earlier through a table for further use
- Later on in the script, we set up a RenderStepped event, accessed the returned table from the checkForRoom() function, and did some magical awesome stuff! YAY!!
Source Code
--room system using raycasting
local function checkForRoom()
local ray = Ray.new(Character:WaitForChild('HumanoidRootPart').Position, Vector3.new(0, -2, 0)* 5)
local room, roomStuff
local isInRoom, roomName, cam1, cam2, floorType
local hit, pos = workspace:FindPartOnRayWithIgnoreList(ray, {Character, game.Workspace:WaitForChild("World").Props, game.Workspace:WaitForChild("World").Interactables})
if hit then
--checking for ground
if hit.Name == "Floor" then --bottomFloor for advanced camera manipulation
floorType = hit.Name
room = hit
if room:WaitForChild("RoomNecessities") then
roomStuff = room:WaitForChild("RoomNecessities")
if roomStuff.IsARoom.Value == true then
--we found a floor!
isInRoom = true
roomName = roomStuff.RoomName.Value
else
isInRoom = false
roomName = nil
end
end
-- checking for camera
if isInRoom == true and roomName ~= nil then
local b = hit.Parent
local camera = b:WaitForChild('Camera')
local camMain, camStatic = camera:WaitForChild('cameraMain'), camera:WaitForChild('cameraStatic')
if camMain then
--camera1 exists, we got our camera!
cam1 = camMain
end
if camStatic then
if camStatic:WaitForChild('Active').Value == true then
cam2 = camStatic
else
cam2 = camStatic
end
end
end
elseif hit.Name == 'Floor2' then --topFloor for advanced camera manipulation
room = hit
floorType = hit.Name
if room:WaitForChild("RoomNecessities") then
roomStuff = room:WaitForChild("RoomNecessities")
if roomStuff.IsARoom.Value == true then
--we found a floor!
isInRoom = true
roomName = roomStuff.RoomName.Value
else
isInRoom = false
roomName = nil
end
end
-- checking for camera
if isInRoom == true and roomName ~= nil then
local b = hit.Parent
local camera = b:WaitForChild('Camera')
local camMain, camStatic = camera:WaitForChild('cameraMain'), camera:WaitForChild('cameraStatic')
if camMain then
--camera1 exists
cam1 = camMain
end
if camStatic then
if camStatic:WaitForChild('Active').Value == true then
cam2 = camStatic
else
cam2 = camStatic
end
end
end
else
isInRoom = false
roomName = nil
cam1 = nil
cam2 = nil
floorType = nil
end
end
if isInRoom and cam1 then
if cam2 ~= nil then
if cam2:WaitForChild('Active').Value == true then
return {
RoomStatusType = 'Enter';
IsInRoom = isInRoom;
RoomName = roomName;
CameraMain = cam1;
CameraStatic = cam2;
FloorType = floorType
}
else
return {
RoomStatusType = 'Enter';
IsInRoom = isInRoom;
RoomName = roomName;
CameraMain = cam1;
CameraStatic = cam2;
FloorType = floorType
}
end
else
return {
RoomStatusType = 'Enter';
IsInRoom = isInRoom;
RoomName = roomName;
CameraMain = cam1;
CameraStatic = cam2;
FloorType = floorType
}
end
else
return {
RoomStatusType = 'Exit';
IsInRoom = isInRoom;
RoomName = roomName;
CameraMain = cam1;
CameraStatic = cam2;
FloorType = floorType
}
end
end
RunService.RenderStepped:Connect(function()
Camera.CameraType = Enum.CameraType.Scriptable
--coroutine.wrap(function()
local b = checkForRoom()
local type1, isInRoom, roomName, roomCameraM, roomCameraS, floorType = b['RoomStatusType'], b['IsInRoom'], b['RoomName'], b['CameraMain'], b['CameraStatic'], b['FloorType']
if type1 == "Enter" and isInRoom == true then
if roomCameraM and roomCameraS then
if floorType == 'Floor2' then
Camera.FieldOfView = Settings.CameraFOV.Value
wait(.2)
Camera.CFrame = Camera.CFrame:Lerp(roomCameraS.CFrame, .2)
RunService.RenderStepped:Wait()
elseif floorType == 'Floor' then
Camera.FieldOfView = Settings.CameraFOV.Value
wait(.2)
Camera.CFrame = Camera.CFrame:Lerp(roomCameraM.CFrame, .2)
RunService.RenderStepped:Wait()
end
end
end
if type1 == "Exit" and isInRoom == false then
Camera.FieldOfView = Settings.CameraFOV.Value
local humanoidRootPart = Character:FindFirstChild('HumanoidRootPart')
wait(.2)
Camera.CFrame = Camera.CFrame:Lerp(CFrame.new(humanoidRootPart.Position + Vector3.new(0, 20, 2)) * CFrame.Angles(math.rad(-90), 0, 0),.2)
RunService.RenderStepped:Wait()
end
--end)()
end)
Now you might be asking, “Well, what’s wrong with this?”
Well, here are the problems (performance-wise):
- FPS DROPS (The longer you stay in-game, the FPS will decrease)
- LAG SPIKES (the same situation as the FPS drops problem)
- INSANELY HIGH PING (I don’t know if I should worry about this or not.)
Proof (the ping when the picture below was uploaded was around 200 ms):
Ending
To me, I feel like the Camera/Room System script is working nicely, but the performance in-game feels laggy and poorly optimized. I’m trying to improve the code so it works wonders at 60FPS, but I’m stuck on what to do. I’ve considered using Region3 on the server to check if a player is inside a certain part, and then send the data through RemoteEvent/RemoteFunction and have the camera focus on the player, but I don’t know if this could be efficient.
Questions:
- How can I improve the script so that it runs smoothly?
- Is there a way I can do this efficiently without putting stress on the client?
- Did I overlook some parts in the code?
Thank you for reading all of this! Must’ve been a nightmare, huh?