Isometric Camera Inconsistencies

i’ve modified the isometric camera from roblox’s code samples to include support for camera shaking and rotating your character toward your mouse. however, what really stumps me is that sometimes, for no reason at all, it will inexplicably just… break? it angles the camera downwards, but still acts like the default camera and lets me move the camera around slightly before snapping it back?

this is what is supposed to happen.

this is what happens sometimes. it’s very inconsistent and somewhat buggy.

here is what the script looks like.

local services = {
	Players = game:GetService("Players");
	ReplicatedStorage = game:GetService("ReplicatedStorage");
	RunService = game:GetService("RunService");
	SoundService = game:GetService("SoundService");
}

local player = services.Players.LocalPlayer
local camera = workspace.CurrentCamera
local module_folder = services.ReplicatedStorage:WaitForChild("modules")

local explosion_distance = 65
local camera_depth = 64
local height_offset = 2
local field_of_view = 20

local function kaboom(explosion)
	local camera_shaker = require(module_folder:WaitForChild("CameraShaker"))
	local cam_shake = camera_shaker.new(Enum.RenderPriority.Camera.Value, function(shake_cframe)
		if camera then
			camera.CFrame = camera.CFrame * shake_cframe
		end
	end)

	if explosion:IsA("Explosion") then
		local distance = (player.Character.Head.Position - explosion.Position).magnitude
		local intensity = distance / (explosion.BlastRadius / 6)
		if intensity < explosion_distance then
			if cam_shake then
				cam_shake:Start()
				cam_shake:ShakeOnce(explosion.BlastRadius / 2, 12, 0.15, 1.4)
			end
		end
	end
end


local function update_camera()
	local character = player.Character

	if character then
		local root_part = character:FindFirstChild("HumanoidRootPart")
		local head = character:FindFirstChild("Head")
		
		if root_part and head then
			services.SoundService:SetListener(Enum.ListenerType.CFrame, head.CFrame)
			
			local player_position = root_part.Position + Vector3.yAxis * height_offset
			local camera_position = player_position + Vector3.one * camera_depth
			camera.CFrame = CFrame.lookAt(camera_position, player_position)
			
			local obscuring_parts = camera:GetPartsObscuringTarget({root_part.Position}, character:GetChildren())
			if #obscuring_parts > 0 then
				local highlight = character:FindFirstChildWhichIsA("Highlight")
				if not highlight then
					local highlight = Instance.new("Highlight")
					highlight.Parent = character
					highlight.OutlineTransparency = 0.45
					highlight.FillColor = Color3.fromRGB(59, 58, 67)
					highlight.FillTransparency = 0.86
				end
			else
				local highlight = character:FindFirstChildWhichIsA("Highlight")
				if highlight then highlight:Destroy() end
			end
		end
	end
end

local function handle_mouse()
	local character = player.Character
	local mouse = player:GetMouse()
	
	if character then
		local root_part = character:FindFirstChild("HumanoidRootPart")
		
		if root_part then
			local obscuring_parts = camera:GetPartsObscuringTarget({root_part.Position}, character:GetChildren())
			local highlight = character:FindFirstChildWhichIsA("Highlight")

			if #obscuring_parts > 0 then
				if not highlight then
					highlight = Instance.new("Highlight")
					highlight.Parent = character
					highlight.OutlineTransparency = 0.45
					highlight.FillColor = Color3.fromRGB(59, 58, 67)
					highlight.FillTransparency = 0.86
				end
			else
				if highlight then
					highlight:Destroy()
				end
			end

			local function ray_plane(plane_point, plane_normal, origin, direction)
				return -((origin - plane_point):Dot(plane_normal)) / (direction:Dot(plane_normal))
			end

			local function create_body_gyro(parent)
				local body_gyro = Instance.new("BodyGyro")
				body_gyro.Parent = parent
				body_gyro.D = 55
				body_gyro.P = 5000
				body_gyro.MaxTorque = Vector3.new(4000000, 4000000, 4000000)
				print("gyro created, delicious!")
				return body_gyro
			end

			local function update_body_gyro(body_gyro, target_cframe)
				if body_gyro then
					body_gyro.CFrame = body_gyro.CFrame:lerp(target_cframe, 0.09)
				end
			end

			local ray = camera:ScreenPointToRay(mouse.X, mouse.Y)
			local t = ray_plane(character.Head.Position, Vector3.new(0, 1, 0), ray.Origin, ray.Direction)
			local head = character:WaitForChild("Head")

			local body_gyro = head:FindFirstChildOfClass("BodyGyro") or create_body_gyro(head)
			local plane_intersection_point = (ray.Direction * t) + ray.Origin
			local target_cframe = CFrame.lookAt(head.Position, plane_intersection_point)
			update_body_gyro(body_gyro, target_cframe)
		end
	end
end

camera.FieldOfView = field_of_view
camera.CameraType = Enum.CameraType.Scriptable
workspace.DescendantAdded:Connect(kaboom)

services.RunService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value, update_camera)
services.RunService:BindToRenderStep("Mouse", Enum.RenderPriority.Last.Value, handle_mouse)
3 Likes

Does it only break when you launch your game? I had a similar issue when messing with the camera where I would initialize my camera code, specifically setting CameraType to Enum.CameraType.Scriptable and afterwards the Roblox default camera module would load in and reset the CameraType. This resulted in the player having the default camera behavior instead of my custom behavior. The same thing might be happening here.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.