Provide an overview of:
- What does the code do and what are you not satisfied with?
- The module controls a camera that orbits a golf ball object.
- What potential improvements have you considered?
- I have been considering making this module not object oriented, since I doubt I will ever have a use for having multiple camera objects.
- How (specifically) do you want to improve the code?
- The code is long, and certain parts feel repetitive/unintuitive. I am still relatively new to scripting, and would like to start getting into the habit of making readable and expandable code.
For context, the GolfCam.new(ball)
function takes a ball object with an instance
note: for some odd reason, this only works with events deffered
local GolfCam = {}
GolfCam.__index = GolfCam
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Maid = require(ReplicatedStorage:WaitForChild("Maid"))
function GolfCam.new(ball)
local self = setmetatable({}, GolfCam)
self.camera = workspace.CurrentCamera
self.yAngle = 90
self.xAngle = -30
self.yOffset = 2
self.xOffset = 0
self.distance = 15
self.desiredDistance = 15
self.distanceLerp = 12
self.controllerSpeed = 2
self.controllerSpeedSlow = 0.15
self.mouseSpeed = 1
self.clampMax = 0
self.clampMin = -90
self.minDistance = 5
self.maxDistance = 50
self.zoomSpeed = 5
self._controllerCamRotY = 0
self._controllerCamRotX = 0
self._maid = Maid.new()
self.focus = ball.instance
--set camera raycast filter
self.filter = {}
table.insert(self.filter, self.focus)
--loops through players and adds their character to the filter
for _, plr in ipairs(Players:GetChildren()) do
if plr.Character then
table.insert(self.filter, plr.Character)
end
end
--filters golf balls
for _, v in ipairs(CollectionService:GetTagged("golfball")) do
table.insert(self.filter, v)
end
for _, v in ipairs(CollectionService:GetTagged("pointer")) do
table.insert(self.filter, v)
end
workspace.ChildAdded:Connect(function(child)
self:_updateRaycastFilter(child)
end)
self:enable()
return self
end
function GolfCam:_clampXAngle()
if self.xAngle > self.clampMax then
self.xAngle = self.clampMax
elseif self.xAngle < self.clampMin then
self.xAngle = self.clampMin
end
end
--switches to the golfcam and creates connections
function GolfCam:enable()
self.camera.CameraType = Enum.CameraType.Scriptable
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
--Sets the camera's final rotation
local function stepped(delta)
if not self.focus or not self.focus:IsDescendantOf(game) then
self.focus = nil
return
end
self:_processInput()
--makes the camera smoothly zoom when zooming with scroll wheel
self.distance += (self.desiredDistance - self.distance) * self.distanceLerp * math.min(delta, 1)
local controllerSens = self.controllerSpeed
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then
controllerSens = self.controllerSpeed * self.controllerSpeedSlow
end
self.yAngle += self._controllerCamRotY * controllerSens
self.xAngle += self._controllerCamRotX * controllerSens
self:_clampXAngle()
local focuspos = self.focus.Position + Vector3.new(self.xOffset, self.yOffset, 0)
self.camera.CFrame = CFrame.new(focuspos)
* CFrame.Angles(0, math.rad(self.yAngle), 0)
* CFrame.Angles(math.rad(self.xAngle), 0, 0)
* CFrame.new(self.xOffset, 0, self.distance)
--Moves the camera to a new location if it's obstructed
--raycastParams.FilterDescendantsInstances = self.filter
--local raycastResult = workspace:Raycast(
-- focuspos,
-- -(focuspos - self.camera.CFrame.Position).Unit * self.distance,
-- raycastParams
--)
--if raycastResult then
-- self.camera.CFrame = CFrame.LookAt(raycastResult.Position, focuspos)
--end
end
RunService:BindToRenderStep("cam", Enum.RenderPriority.Camera.Value, stepped)
--Camera rotation
self._maid:GiveTask(UserInputService.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
local delta = UserInputService:GetMouseDelta()
self.yAngle = self.yAngle - delta.x * self.mouseSpeed
self.xAngle = self.xAngle - delta.y * self.mouseSpeed
self:_clampXAngle()
end
if input.UserInputType == Enum.UserInputType.MouseWheel then
if (self.desiredDistance >= self.minDistance and input.Position.Z > 0)
or (input.Position.Z < 0 and self.desiredDistance <= self.maxDistance) then
self.desiredDistance -= input.Position.Z * self.zoomSpeed
end
end
end))
self._maid:GiveTask(UserInputService.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
end
end))
self._maid:GiveTask(UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
end))
end
function GolfCam:disable()
self._maid:DoCleaning()
RunService:UnbindFromRenderStep("cam")
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
function GolfCam:destroy()
self:disable()
self = nil
end
function GolfCam:_processInput()
self._controllerCamRotX = 0
self._controllerCamRotY = 0
local function key(...)
return UserInputService:IsKeyDown(...)
end
if key(Enum.KeyCode.Left) or key(Enum.KeyCode.A) then
self._controllerCamRotY += 1
end
if key(Enum.KeyCode.Right) or key(Enum.KeyCode.D) then
self._controllerCamRotY -= 1
end
if key(Enum.KeyCode.Up) or key(Enum.KeyCode.W) then
self._controllerCamRotX += 1
end
if key(Enum.KeyCode.Down) or key(Enum.KeyCode.S) then
self._controllerCamRotX -= 1
end
end
function GolfCam:_updateRaycastFilter(child)
if not child then
return
end
if Players:GetPlayerFromCharacter(child) then
table.insert(self.filter, child)
elseif CollectionService:HasTag(child, "pointer") then
table.insert(self.filter, child)
elseif CollectionService:HasTag(child, "golfball") then
table.insert(self.filter, child)
end
end
return GolfCam
Currently it’s around 190 lines long and I feel like a lot of what’s happening is inefficient.
cam.rbxl (31.7 KB)