@quenty/camera 14.40.0 → 14.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/package.json +10 -10
- package/src/Client/CameraStack.lua +1 -1
- package/src/Client/CameraStackService.lua +2 -2
- package/src/Client/Controls/ConstrainedLookControls.lua +220 -0
- package/src/Client/Effects/ConstrainedLookCamera.lua +143 -0
- package/src/Client/Effects/DefaultCamera.lua +1 -1
- package/src/Client/Effects/ZoomedCamera.lua +2 -2
- package/src/Client/Utility/CameraStateTweener.lua +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [14.41.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.40.1...@quenty/camera@14.41.0) (2026-06-03)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- ConstrainedLookCamera ([8247ba8](https://github.com/Quenty/NevermoreEngine/commit/8247ba88b84c8f209bd1f72b7a384b907f735338))
|
|
11
|
+
|
|
12
|
+
## [14.40.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.40.0...@quenty/camera@14.40.1) (2026-05-30)
|
|
13
|
+
|
|
14
|
+
**Note:** Version bump only for package @quenty/camera
|
|
15
|
+
|
|
6
16
|
# [14.40.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.39.0...@quenty/camera@14.40.0) (2026-05-29)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @quenty/camera
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/camera",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.41.0",
|
|
4
4
|
"description": "Quenty's camera system for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -31,27 +31,27 @@
|
|
|
31
31
|
"@quenty/acceltween": "2.7.0",
|
|
32
32
|
"@quenty/baseobject": "10.13.0",
|
|
33
33
|
"@quenty/cframeutils": "5.5.6",
|
|
34
|
-
"@quenty/cubicspline": "10.12.
|
|
35
|
-
"@quenty/draw": "7.14.
|
|
34
|
+
"@quenty/cubicspline": "10.12.1",
|
|
35
|
+
"@quenty/draw": "7.14.1",
|
|
36
36
|
"@quenty/ducktype": "5.11.0",
|
|
37
|
-
"@quenty/inputobjectutils": "4.30.
|
|
37
|
+
"@quenty/inputobjectutils": "4.30.1",
|
|
38
38
|
"@quenty/loader": "10.11.0",
|
|
39
39
|
"@quenty/maid": "3.9.0",
|
|
40
40
|
"@quenty/math": "2.7.5",
|
|
41
41
|
"@quenty/nevermore-test-runner": "1.4.0",
|
|
42
|
-
"@quenty/qframe": "10.22.
|
|
43
|
-
"@quenty/rx": "13.28.
|
|
44
|
-
"@quenty/servicebag": "11.18.
|
|
42
|
+
"@quenty/qframe": "10.22.1",
|
|
43
|
+
"@quenty/rx": "13.28.3",
|
|
44
|
+
"@quenty/servicebag": "11.18.1",
|
|
45
45
|
"@quenty/spring": "10.12.0",
|
|
46
|
-
"@quenty/valueobject": "13.31.
|
|
46
|
+
"@quenty/valueobject": "13.31.1",
|
|
47
47
|
"@quenty/vector3utils": "10.11.0",
|
|
48
48
|
"@quentystudios/jest-lua": "3.10.0-quenty.2"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@quenty/camerastoryutils": "10.21.
|
|
51
|
+
"@quenty/camerastoryutils": "10.21.1"
|
|
52
52
|
},
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "75291c76133c2b87b71c620125800dd3d72b7fe1"
|
|
57
57
|
}
|
|
@@ -76,7 +76,7 @@ function CameraStack.PrintCameraStack(self: CameraStack): ()
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
--[=[
|
|
79
|
-
Gets the camera
|
|
79
|
+
Gets the camera currently on the top of the stack
|
|
80
80
|
@return CameraEffect
|
|
81
81
|
]=]
|
|
82
82
|
function CameraStack.GetTopCamera(self: CameraStack): CameraEffectUtils.CameraLike
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--!nonstrict
|
|
2
2
|
--[=[
|
|
3
3
|
Holds camera states and allows for the last camera state to be retrieved. Also
|
|
4
|
-
initializes an impulse and default camera
|
|
4
|
+
initializes an impulse and default camera at the bottom of the stack. Is a singleton.
|
|
5
5
|
|
|
6
6
|
@class CameraStackService
|
|
7
7
|
]=]
|
|
@@ -173,7 +173,7 @@ function CameraStackService.GetRawDefaultCamera(self: CameraStackService): Defau
|
|
|
173
173
|
end
|
|
174
174
|
|
|
175
175
|
--[=[
|
|
176
|
-
Gets the camera
|
|
176
|
+
Gets the camera currently on the top of the stack
|
|
177
177
|
@return CameraEffect
|
|
178
178
|
]=]
|
|
179
179
|
function CameraStackService.GetTopCamera(self: CameraStackService): CameraEffectUtils.CameraLike
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
Input handler that drives a [ConstrainedLookCamera]. Reacts to right-click
|
|
4
|
+
drag on mouse, drag on touchscreen, and right thumbstick on gamepad.
|
|
5
|
+
|
|
6
|
+
@class ConstrainedLookControls
|
|
7
|
+
]=]
|
|
8
|
+
|
|
9
|
+
local require = require(script.Parent.loader).load(script)
|
|
10
|
+
|
|
11
|
+
local ContextActionService = game:GetService("ContextActionService")
|
|
12
|
+
local RunService = game:GetService("RunService")
|
|
13
|
+
local UserInputService = game:GetService("UserInputService")
|
|
14
|
+
|
|
15
|
+
local ConstrainedLookCamera = require("ConstrainedLookCamera")
|
|
16
|
+
local GamepadRotateModel = require("GamepadRotateModel")
|
|
17
|
+
local InputObjectUtils = require("InputObjectUtils")
|
|
18
|
+
local Maid = require("Maid")
|
|
19
|
+
|
|
20
|
+
local ConstrainedLookControls = {}
|
|
21
|
+
ConstrainedLookControls.__index = ConstrainedLookControls
|
|
22
|
+
ConstrainedLookControls.ClassName = "ConstrainedLookControls"
|
|
23
|
+
|
|
24
|
+
ConstrainedLookControls.MOUSE_SENSITIVITY = Vector2.new(math.pi * 4, math.pi * 1.9)
|
|
25
|
+
ConstrainedLookControls.GAMEPAD_SENSITIVITY = 0.1
|
|
26
|
+
ConstrainedLookControls._dragBeginTypes = { Enum.UserInputType.MouseButton2, Enum.UserInputType.Touch }
|
|
27
|
+
|
|
28
|
+
export type ConstrainedLookControls = typeof(setmetatable(
|
|
29
|
+
{} :: {
|
|
30
|
+
_camera: ConstrainedLookCamera.ConstrainedLookCamera,
|
|
31
|
+
_enabled: boolean,
|
|
32
|
+
_key: string,
|
|
33
|
+
_maid: Maid.Maid?,
|
|
34
|
+
_gamepadRotateModel: GamepadRotateModel.GamepadRotateModel,
|
|
35
|
+
_lastMousePosition: Vector3?,
|
|
36
|
+
_mouseSensitivity: Vector2,
|
|
37
|
+
_gamepadSensitivity: number,
|
|
38
|
+
},
|
|
39
|
+
{} :: typeof({ __index = ConstrainedLookControls })
|
|
40
|
+
))
|
|
41
|
+
|
|
42
|
+
--[=[
|
|
43
|
+
Constructs a new ConstrainedLookControls bound to the given camera.
|
|
44
|
+
]=]
|
|
45
|
+
function ConstrainedLookControls.new(camera: ConstrainedLookCamera.ConstrainedLookCamera): ConstrainedLookControls
|
|
46
|
+
local self: ConstrainedLookControls = setmetatable({} :: any, ConstrainedLookControls)
|
|
47
|
+
|
|
48
|
+
self._camera = assert(camera, "Bad camera")
|
|
49
|
+
self._enabled = false
|
|
50
|
+
self._key = tostring(self) .. "ConstrainedLookControls"
|
|
51
|
+
self._mouseSensitivity = ConstrainedLookControls.MOUSE_SENSITIVITY
|
|
52
|
+
self._gamepadSensitivity = ConstrainedLookControls.GAMEPAD_SENSITIVITY
|
|
53
|
+
self._gamepadRotateModel = GamepadRotateModel.new()
|
|
54
|
+
|
|
55
|
+
return self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
--[=[
|
|
59
|
+
Sets mouse sensitivity.
|
|
60
|
+
]=]
|
|
61
|
+
function ConstrainedLookControls.SetMouseSensitivity(self: ConstrainedLookControls, sensitivity: Vector2)
|
|
62
|
+
self._mouseSensitivity = sensitivity
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
--[=[
|
|
66
|
+
Sets gamepad sensitivity.
|
|
67
|
+
]=]
|
|
68
|
+
function ConstrainedLookControls.SetGamepadSensitivity(self: ConstrainedLookControls, sensitivity: number)
|
|
69
|
+
self._gamepadSensitivity = sensitivity
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
--[=[
|
|
73
|
+
Returns whether controls are enabled.
|
|
74
|
+
]=]
|
|
75
|
+
function ConstrainedLookControls.IsEnabled(self: ConstrainedLookControls): boolean
|
|
76
|
+
return self._enabled
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
--[=[
|
|
80
|
+
Enables input. Binds drag (MouseButton2 / Touch) and gamepad Thumbstick2.
|
|
81
|
+
]=]
|
|
82
|
+
function ConstrainedLookControls.Enable(self: ConstrainedLookControls)
|
|
83
|
+
if self._enabled then
|
|
84
|
+
return
|
|
85
|
+
end
|
|
86
|
+
assert(not self._maid, "Maid already defined")
|
|
87
|
+
self._enabled = true
|
|
88
|
+
|
|
89
|
+
local maid = Maid.new()
|
|
90
|
+
self._maid = maid
|
|
91
|
+
|
|
92
|
+
maid:GiveTask(self._gamepadRotateModel.IsRotating.Changed:Connect(function()
|
|
93
|
+
if self._gamepadRotateModel.IsRotating.Value then
|
|
94
|
+
self:_handleGamepadRotateStart()
|
|
95
|
+
else
|
|
96
|
+
self:_handleGamepadRotateStop()
|
|
97
|
+
end
|
|
98
|
+
end))
|
|
99
|
+
|
|
100
|
+
ContextActionService:BindAction(self._key .. "Drag", function(_, userInputState, inputObject)
|
|
101
|
+
if userInputState == Enum.UserInputState.Begin then
|
|
102
|
+
self:_beginDrag(inputObject)
|
|
103
|
+
end
|
|
104
|
+
end, false, unpack(self._dragBeginTypes))
|
|
105
|
+
|
|
106
|
+
ContextActionService:BindAction(self._key .. "Rotate", function(_, _, inputObject)
|
|
107
|
+
self._gamepadRotateModel:HandleThumbstickInput(inputObject)
|
|
108
|
+
end, false, Enum.KeyCode.Thumbstick2)
|
|
109
|
+
|
|
110
|
+
maid:GiveTask(function()
|
|
111
|
+
ContextActionService:UnbindAction(self._key .. "Drag")
|
|
112
|
+
ContextActionService:UnbindAction(self._key .. "Rotate")
|
|
113
|
+
end)
|
|
114
|
+
|
|
115
|
+
maid:GiveTask(function()
|
|
116
|
+
self._camera:Release()
|
|
117
|
+
end)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
--[=[
|
|
121
|
+
Disables input and releases the camera.
|
|
122
|
+
]=]
|
|
123
|
+
function ConstrainedLookControls.Disable(self: ConstrainedLookControls)
|
|
124
|
+
if not self._enabled then
|
|
125
|
+
return
|
|
126
|
+
end
|
|
127
|
+
assert(self._maid, "Must be enabled")
|
|
128
|
+
self._enabled = false
|
|
129
|
+
|
|
130
|
+
self._maid:DoCleaning()
|
|
131
|
+
self._maid = nil
|
|
132
|
+
self._lastMousePosition = nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
function ConstrainedLookControls._beginDrag(self: ConstrainedLookControls, beginInputObject: InputObject)
|
|
136
|
+
assert(self._maid, "Must be enabled")
|
|
137
|
+
|
|
138
|
+
local maid = Maid.new()
|
|
139
|
+
self._lastMousePosition = beginInputObject.Position
|
|
140
|
+
|
|
141
|
+
local isMouse = InputObjectUtils.isMouseUserInputType(beginInputObject.UserInputType)
|
|
142
|
+
if isMouse then
|
|
143
|
+
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
|
|
144
|
+
maid:GiveTask(function()
|
|
145
|
+
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
|
|
146
|
+
end)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
maid:GiveTask(UserInputService.InputEnded:Connect(function(inputObject: InputObject)
|
|
150
|
+
if inputObject == beginInputObject then
|
|
151
|
+
self:_endDrag()
|
|
152
|
+
end
|
|
153
|
+
end))
|
|
154
|
+
|
|
155
|
+
maid:GiveTask(UserInputService.InputChanged:Connect(function(inputObject: InputObject)
|
|
156
|
+
if InputObjectUtils.isMouseUserInputType(inputObject.UserInputType) or inputObject == beginInputObject then
|
|
157
|
+
self:_handleDragMovement(inputObject)
|
|
158
|
+
end
|
|
159
|
+
end))
|
|
160
|
+
|
|
161
|
+
maid:GiveTask(function()
|
|
162
|
+
self._lastMousePosition = nil
|
|
163
|
+
self._camera:Release()
|
|
164
|
+
end)
|
|
165
|
+
|
|
166
|
+
self._maid._dragMaid = maid
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
function ConstrainedLookControls._endDrag(self: ConstrainedLookControls)
|
|
170
|
+
assert(self._maid, "Must be enabled")
|
|
171
|
+
self._maid._dragMaid = nil
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
function ConstrainedLookControls._handleDragMovement(self: ConstrainedLookControls, inputObject: InputObject)
|
|
175
|
+
if not self._lastMousePosition then
|
|
176
|
+
return
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
local delta = -inputObject.Delta
|
|
180
|
+
if InputObjectUtils.isMouseUserInputType(inputObject.UserInputType) then
|
|
181
|
+
delta += self._lastMousePosition - inputObject.Position
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
local xTheta = delta.X / 1920
|
|
185
|
+
local yTheta = delta.Y / 1200
|
|
186
|
+
local deltaAngle = Vector2.new(xTheta, yTheta) * self._mouseSensitivity
|
|
187
|
+
self._camera:RotateXY(deltaAngle)
|
|
188
|
+
|
|
189
|
+
self._lastMousePosition = inputObject.Position
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
function ConstrainedLookControls._handleGamepadRotateStart(self: ConstrainedLookControls)
|
|
193
|
+
assert(self._maid, "Must be enabled")
|
|
194
|
+
|
|
195
|
+
local maid = Maid.new()
|
|
196
|
+
|
|
197
|
+
maid:GiveTask(RunService.Stepped:Connect(function()
|
|
198
|
+
local deltaAngle = self._gamepadSensitivity * self._gamepadRotateModel:GetThumbstickDeltaAngle()
|
|
199
|
+
self._camera:RotateXY(deltaAngle)
|
|
200
|
+
end))
|
|
201
|
+
|
|
202
|
+
maid:GiveTask(function()
|
|
203
|
+
self._camera:Release()
|
|
204
|
+
end)
|
|
205
|
+
|
|
206
|
+
self._maid._dragMaid = maid
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
function ConstrainedLookControls._handleGamepadRotateStop(self: ConstrainedLookControls)
|
|
210
|
+
assert(self._maid, "Must be enabled")
|
|
211
|
+
self._maid._dragMaid = nil
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
function ConstrainedLookControls.Destroy(self: ConstrainedLookControls)
|
|
215
|
+
self:Disable()
|
|
216
|
+
self._gamepadRotateModel:Destroy()
|
|
217
|
+
setmetatable(self :: any, nil)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
return ConstrainedLookControls
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
Constrains pitch and yaw within a cone.
|
|
4
|
+
|
|
5
|
+
@class ConstrainedLookCamera
|
|
6
|
+
]=]
|
|
7
|
+
|
|
8
|
+
local require = require(script.Parent.loader).load(script)
|
|
9
|
+
|
|
10
|
+
local CameraEffectUtils = require("CameraEffectUtils")
|
|
11
|
+
local CameraState = require("CameraState")
|
|
12
|
+
local Spring = require("Spring")
|
|
13
|
+
local SummedCamera = require("SummedCamera")
|
|
14
|
+
|
|
15
|
+
local ConstrainedLookCamera = {}
|
|
16
|
+
ConstrainedLookCamera.ClassName = "ConstrainedLookCamera"
|
|
17
|
+
|
|
18
|
+
export type ConstrainedLookCamera =
|
|
19
|
+
typeof(setmetatable(
|
|
20
|
+
{} :: {
|
|
21
|
+
CameraState: CameraState.CameraState,
|
|
22
|
+
CFrame: CFrame,
|
|
23
|
+
AngleYaw: number,
|
|
24
|
+
AnglePitch: number,
|
|
25
|
+
TargetAngleYaw: number,
|
|
26
|
+
TargetAnglePitch: number,
|
|
27
|
+
MaxYawOffset: number,
|
|
28
|
+
MaxPitchOffset: number,
|
|
29
|
+
Speed: number,
|
|
30
|
+
SpeedYaw: number,
|
|
31
|
+
SpeedPitch: number,
|
|
32
|
+
Damper: number,
|
|
33
|
+
SpringYaw: Spring.Spring<number>,
|
|
34
|
+
SpringPitch: Spring.Spring<number>,
|
|
35
|
+
},
|
|
36
|
+
{} :: typeof({ __index = ConstrainedLookCamera })
|
|
37
|
+
))
|
|
38
|
+
& CameraEffectUtils.CameraEffect
|
|
39
|
+
|
|
40
|
+
ConstrainedLookCamera._maxYawOffset = math.rad(20)
|
|
41
|
+
ConstrainedLookCamera._maxPitchOffset = math.rad(15)
|
|
42
|
+
|
|
43
|
+
--[=[
|
|
44
|
+
Constructs a new ConstrainedLookCamera.
|
|
45
|
+
]=]
|
|
46
|
+
function ConstrainedLookCamera.new(): ConstrainedLookCamera
|
|
47
|
+
local self: ConstrainedLookCamera = setmetatable({} :: any, ConstrainedLookCamera)
|
|
48
|
+
|
|
49
|
+
self.SpringYaw = Spring.new(0)
|
|
50
|
+
self.SpringPitch = Spring.new(0)
|
|
51
|
+
self.Speed = 15
|
|
52
|
+
self.Damper = 1
|
|
53
|
+
|
|
54
|
+
return self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
function ConstrainedLookCamera.__add(self: ConstrainedLookCamera, other: CameraEffectUtils.CameraEffect)
|
|
58
|
+
return SummedCamera.new(self, other)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
--[=[
|
|
62
|
+
Rotates the target yaw (X) and pitch (Y) by the given delta, clamped within the max offsets.
|
|
63
|
+
]=]
|
|
64
|
+
function ConstrainedLookCamera.RotateXY(self: ConstrainedLookCamera, delta: Vector2)
|
|
65
|
+
self.TargetAngleYaw += delta.X
|
|
66
|
+
self.TargetAnglePitch += delta.Y
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
--[=[
|
|
70
|
+
Releases input, sending spring targets back to the origin.
|
|
71
|
+
]=]
|
|
72
|
+
function ConstrainedLookCamera.Release(self: ConstrainedLookCamera)
|
|
73
|
+
self.TargetAngleYaw = 0
|
|
74
|
+
self.TargetAnglePitch = 0
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
--[=[
|
|
78
|
+
Snaps springs to the origin without animating.
|
|
79
|
+
]=]
|
|
80
|
+
function ConstrainedLookCamera.SnapToOrigin(self: ConstrainedLookCamera)
|
|
81
|
+
self.SpringYaw:SetTarget(0, true)
|
|
82
|
+
self.SpringPitch:SetTarget(0, true)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
function ConstrainedLookCamera.__newindex(self: ConstrainedLookCamera, index, value)
|
|
86
|
+
if index == "AngleYaw" then
|
|
87
|
+
self.SpringYaw.Position = math.clamp(value, -self.MaxYawOffset, self.MaxYawOffset)
|
|
88
|
+
elseif index == "AnglePitch" then
|
|
89
|
+
self.SpringPitch.Position = math.clamp(value, -self.MaxPitchOffset, self.MaxPitchOffset)
|
|
90
|
+
elseif index == "TargetAngleYaw" then
|
|
91
|
+
self.SpringYaw.Target = math.clamp(value, -self.MaxYawOffset, self.MaxYawOffset)
|
|
92
|
+
elseif index == "TargetAnglePitch" then
|
|
93
|
+
self.SpringPitch.Target = math.clamp(value, -self.MaxPitchOffset, self.MaxPitchOffset)
|
|
94
|
+
elseif index == "MaxYawOffset" then
|
|
95
|
+
assert(value >= 0, "MaxYawOffset must be non-negative")
|
|
96
|
+
self._maxYawOffset = value
|
|
97
|
+
self.TargetAngleYaw = self.SpringYaw.Target
|
|
98
|
+
elseif index == "MaxPitchOffset" then
|
|
99
|
+
assert(value >= 0, "MaxPitchOffset must be non-negative")
|
|
100
|
+
self._maxPitchOffset = value
|
|
101
|
+
self.TargetAnglePitch = self.SpringPitch.Target
|
|
102
|
+
elseif index == "SpeedYaw" then
|
|
103
|
+
self.SpringYaw.Speed = value
|
|
104
|
+
elseif index == "SpeedPitch" then
|
|
105
|
+
self.SpringPitch.Speed = value
|
|
106
|
+
elseif index == "Speed" then
|
|
107
|
+
self.SpringYaw.Speed = value
|
|
108
|
+
self.SpringPitch.Speed = value
|
|
109
|
+
elseif index == "Damper" then
|
|
110
|
+
self.SpringYaw.Damper = value
|
|
111
|
+
self.SpringPitch.Damper = value
|
|
112
|
+
elseif ConstrainedLookCamera[index] ~= nil or index == "SpringYaw" or index == "SpringPitch" then
|
|
113
|
+
rawset(self, index, value)
|
|
114
|
+
else
|
|
115
|
+
error(`{tostring(index)} is not a valid member of ConstrainedLookCamera`)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
function ConstrainedLookCamera.__index(self: ConstrainedLookCamera, index)
|
|
120
|
+
if index == "CameraState" then
|
|
121
|
+
local state = CameraState.new()
|
|
122
|
+
state.CFrame = self.CFrame
|
|
123
|
+
return state
|
|
124
|
+
elseif index == "CFrame" then
|
|
125
|
+
return CFrame.Angles(0, self.AngleYaw, 0) * CFrame.Angles(self.AnglePitch, 0, 0)
|
|
126
|
+
elseif index == "AngleYaw" then
|
|
127
|
+
return self.SpringYaw.Position
|
|
128
|
+
elseif index == "AnglePitch" then
|
|
129
|
+
return self.SpringPitch.Position
|
|
130
|
+
elseif index == "TargetAngleYaw" then
|
|
131
|
+
return self.SpringYaw.Target
|
|
132
|
+
elseif index == "TargetAnglePitch" then
|
|
133
|
+
return self.SpringPitch.Target
|
|
134
|
+
elseif index == "MaxYawOffset" then
|
|
135
|
+
return self._maxYawOffset
|
|
136
|
+
elseif index == "MaxPitchOffset" then
|
|
137
|
+
return self._maxPitchOffset
|
|
138
|
+
else
|
|
139
|
+
return ConstrainedLookCamera[index]
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
return ConstrainedLookCamera
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--[=[
|
|
3
|
-
Hack to maintain default camera control by binding before and after the camera update cycle
|
|
3
|
+
Hack to maintain default camera control by binding before and after the camera update cycle.
|
|
4
4
|
This allows other cameras to build off of the "default" camera while maintaining the same Roblox control scheme.
|
|
5
5
|
|
|
6
6
|
This camera is automatically setup by the [CameraStackService](/api/CameraStackService).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--[=[
|
|
3
3
|
Allow freedom of movement around a current place, much like the classic script works now.
|
|
4
|
-
Not intended to be
|
|
5
|
-
Intended to be used with a SummedCamera, relative.
|
|
4
|
+
Not intended to be used with the current character script.
|
|
5
|
+
Intended to be used with a [SummedCamera], relative.
|
|
6
6
|
|
|
7
7
|
```lua
|
|
8
8
|
local zoom = ZoomedCamera.new()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--[=[
|
|
3
3
|
Makes transitions between states easier. Uses the `CameraStackService` to tween in and
|
|
4
|
-
out a new camera state Call `:Show()` and `:Hide()` to do so, and make sure to
|
|
5
|
-
call `:Destroy()` after usage
|
|
4
|
+
out a new camera state. Call `:Show()` and `:Hide()` to do so, and make sure to
|
|
5
|
+
call `:Destroy()` after usage.
|
|
6
6
|
|
|
7
7
|
@class CameraStateTweener
|
|
8
8
|
]=]
|
|
@@ -89,7 +89,7 @@ end
|
|
|
89
89
|
|
|
90
90
|
--[=[
|
|
91
91
|
Shows the camera to fade in.
|
|
92
|
-
@param doNotAnimate
|
|
92
|
+
@param doNotAnimate boolean? -- Optional, defaults to animating
|
|
93
93
|
]=]
|
|
94
94
|
function CameraStateTweener.Show(self: CameraStateTweener, doNotAnimate: boolean?)
|
|
95
95
|
self:SetTarget(1, doNotAnimate)
|
|
@@ -97,7 +97,7 @@ end
|
|
|
97
97
|
|
|
98
98
|
--[=[
|
|
99
99
|
Hides the camera to fade in.
|
|
100
|
-
@param doNotAnimate
|
|
100
|
+
@param doNotAnimate boolean? -- Optional, defaults to animating
|
|
101
101
|
]=]
|
|
102
102
|
function CameraStateTweener.Hide(self: CameraStateTweener, doNotAnimate: boolean?)
|
|
103
103
|
self:SetTarget(0, doNotAnimate)
|
|
@@ -158,6 +158,10 @@ function CameraStateTweener.GetCameraBelow(self: CameraStateTweener): CameraEffe
|
|
|
158
158
|
return self._cameraBelow
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
+
--[=[
|
|
162
|
+
Sets the epsilon to stop animating
|
|
163
|
+
@param epsilon number?
|
|
164
|
+
]=]
|
|
161
165
|
function CameraStateTweener:SetEpsilon(epsilon: number?)
|
|
162
166
|
self._fadeBetween.Epsilon = epsilon
|
|
163
167
|
end
|