What do you want to achieve?
Something similar to this effect games such as Enter the Gungeon uses. Noticeably, the way the camera drifts over to the cursor’s position without letting the character get out of sight.
What is the issue?
I simply don’t know what to do!
What solutions have you tried so far?
I tried looking for a few solutions already on the DevForum, but I’ve come up empty handed.
If anyone could point me into the right direction on how to do this, I’d be grateful!
The camera in this case is positioned based on the difference between the cursor position and character position. The camera is also being slid on a curve to make it smooth. You can use :Lerp() for that.
I’m not sure how to calculate the position based on the difference, and even then, I’m not sure if using Position is a good idea, since Height becomes a factor at play then.
You can remove the height component from your calculation. The difference is just literally the difference, so subtract the cursor position from the character position. Actually it looks like the position is measured from the center of the screen and not the character, which should be even easier since now those are both 2D.
I don’t believe that to be the case, since that’ll just retrieve the center between both. In Gungeon, however, you can see that isn’t the case for the camera; it’s always closer to the player.
I’ve found that simply taking the average of the average is good enough for me, but now I have no idea how to adapt it into a Camera script. No clear ideas on how to limit the distance of the camera or how to prevent it from going nuts from pointing at the sky or something similar.
I meant you can’t keep moving the camera up forever, it stops at a certain point. For the formula recommend you use game:GetService(“UserInputService”):GetMouseLocation()
What if you define the lower and upper bound of where the camera can go and then interpolate it depending on the cursor’s position from the top-left corner of the screen? From your video it looks like each axis is interpolated individually.
I think I was able to come up with something similar:
local mouse = game:GetService('Players').LocalPlayer:GetMouse()
local camera = workspace.CurrentCamera
local DUNGEON_PART = workspace:WaitForChild('DungeonPart')
local CAMERA_OFFSET = Vector3.new(0, 1000, 0) -- needs to be this high since FOV is only 1
camera.CameraType = Enum.CameraType.Scriptable
camera.FieldOfView = 1
camera.CFrame = CFrame.lookAt(DUNGEON_PART.Position + CAMERA_OFFSET, DUNGEON_PART.Position, CFrame.identity.LookVector) -- look at dungeon part from dungeon part + offset
local lowerBound = DUNGEON_PART.CFrame * CFrame.new(-DUNGEON_PART.Size / 2).Position -- if you change the / 2 part in these 2 lines, you can configure how much you want the camera to be able to move. axes are relative to the size of the part
local upperBound = DUNGEON_PART.CFrame * CFrame.new( DUNGEON_PART.Size / 2).Position
local right, up, look = camera.CFrame.XVector, camera.CFrame.YVector, camera.CFrame.ZVector
local function inverseLerp(a, b, t) -- get percent where is t between a and b
return (t - a) / (b - a)
end
local function lerp(a, b, alpha) -- get value at alpha between a and b
return a + (b - a) * alpha
end
local function getCameraCFrame()
local maxX, maxY = camera.ViewportSize.X, camera.ViewportSize.Y
local mouseX, mouseY = mouse.X, mouse.Y
local alphaX, alphaY = inverseLerp(maxX, 0, mouseX), inverseLerp(maxY, 0, mouseY) -- we need to switch max and min so the camera moves in the same direction as the cursor relative to the part
return CFrame.fromMatrix(
Vector3.new(
lerp(lowerBound.X, upperBound.X, alphaX),
DUNGEON_PART.Position.Y + CAMERA_OFFSET.Y,
lerp(lowerBound.Z, upperBound.Z, alphaY)
), right, up, look -- since right up and look vectors should remain constant, we don't need to recalculate them w/ CFrame.lookAt
)
end
game:GetService('RunService').RenderStepped:Connect(function(delta)
camera.CFrame = getCameraCFrame()
end)
Sorry for the late reply, but I don’t think this goes well with what I’m trying to do. Having room limits isn’t feasible, and even if it were, I think this system would be limited to small rooms.
I managed to get a system working out! However, I still have an issue, shown in the video below.
This is without a doubt caused by the fact I’m using the Mouse’s Position in this equation… Does anyone know a work-around or an alternative? Other than, you know, huge invisible walls…
Here’s my code:
-- yea, i picked this up from roblox guide. too lazy to rewrite it entirely
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local mouse = player:GetMouse()
local CAMERA_DEPTH = 24
local HEIGHT_OFFSET = 2
local function updateCamera()
local character = player.Character
if character then
local root = character:FindFirstChild("HumanoidRootPart")
if root then
local mousePos = mouse.Hit.Position
local rootPos = root.Position + Vector3.new(0, HEIGHT_OFFSET, 0)
local camPos = (((rootPos + mousePos) / 2) + rootPos) / 2
local cameraPosition = Vector3.new(camPos.X, camPos.Y, rootPos.Z+CAMERA_DEPTH)
camera.CFrame = CFrame.new(cameraPosition)
end
end
end
RunService:BindToRenderStep("SidescrollingCamera", Enum.RenderPriority.Camera.Value + 1, updateCamera)