@quenty/camera 14.20.0 → 14.20.1
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 +11 -0
- package/package.json +17 -17
- package/src/Client/CameraStack.lua +27 -12
- package/src/Client/CameraStackService.lua +1 -1
- package/src/Client/CameraState.lua +27 -8
- package/src/Client/CameraUtils.lua +11 -6
- package/src/Client/CameraUtils.story.lua +4 -6
- package/src/Client/Controls/CameraControls.lua +3 -3
- package/src/Client/Controls/GamepadRotateModel.lua +1 -1
- package/src/Client/Effects/DefaultCamera.lua +6 -4
- package/src/Client/Effects/ImpulseCamera.lua +1 -1
- package/src/Client/Utility/CameraFrame.lua +49 -46
- package/src/Client/Utility/CameraStateTweener.lua +10 -10
- package/src/Client/Utility/FieldOfViewUtils.lua +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
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.20.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.20.0...@quenty/camera@14.20.1) (2025-04-05)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Add types to packages ([2374fb2](https://github.com/Quenty/NevermoreEngine/commit/2374fb2b043cfbe0e9b507b3316eec46a4e353a0))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [14.20.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.19.2...@quenty/camera@14.20.0) (2025-04-02)
|
|
7
18
|
|
|
8
19
|
**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.20.
|
|
3
|
+
"version": "14.20.1",
|
|
4
4
|
"description": "Quenty's camera system for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,26 +25,26 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/acceltween": "^2.5.
|
|
29
|
-
"@quenty/baseobject": "^10.8.
|
|
30
|
-
"@quenty/cframeutils": "^5.5.
|
|
31
|
-
"@quenty/cubicspline": "^10.8.
|
|
32
|
-
"@quenty/ducktype": "^5.8.
|
|
33
|
-
"@quenty/inputobjectutils": "^4.18.
|
|
34
|
-
"@quenty/loader": "^10.8.
|
|
35
|
-
"@quenty/maid": "^3.4.
|
|
36
|
-
"@quenty/math": "^2.7.
|
|
37
|
-
"@quenty/qframe": "^10.10.
|
|
38
|
-
"@quenty/servicebag": "^11.11.
|
|
39
|
-
"@quenty/spring": "^10.8.
|
|
40
|
-
"@quenty/valueobject": "^13.17.
|
|
41
|
-
"@quenty/vector3utils": "^10.8.
|
|
28
|
+
"@quenty/acceltween": "^2.5.1",
|
|
29
|
+
"@quenty/baseobject": "^10.8.1",
|
|
30
|
+
"@quenty/cframeutils": "^5.5.2",
|
|
31
|
+
"@quenty/cubicspline": "^10.8.1",
|
|
32
|
+
"@quenty/ducktype": "^5.8.2",
|
|
33
|
+
"@quenty/inputobjectutils": "^4.18.1",
|
|
34
|
+
"@quenty/loader": "^10.8.1",
|
|
35
|
+
"@quenty/maid": "^3.4.1",
|
|
36
|
+
"@quenty/math": "^2.7.2",
|
|
37
|
+
"@quenty/qframe": "^10.10.2",
|
|
38
|
+
"@quenty/servicebag": "^11.11.2",
|
|
39
|
+
"@quenty/spring": "^10.8.2",
|
|
40
|
+
"@quenty/valueobject": "^13.17.1",
|
|
41
|
+
"@quenty/vector3utils": "^10.8.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@quenty/camerastoryutils": "^10.10.
|
|
44
|
+
"@quenty/camerastoryutils": "^10.10.2"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "78c3ac0ab08dd18085b6e6e6e4f745e76ed99f68"
|
|
50
50
|
}
|
|
@@ -9,17 +9,27 @@ local HttpService = game:GetService("HttpService")
|
|
|
9
9
|
local BaseObject = require("BaseObject")
|
|
10
10
|
local CustomCameraEffect = require("CustomCameraEffect")
|
|
11
11
|
local DuckTypeUtils = require("DuckTypeUtils")
|
|
12
|
+
local _Maid = require("Maid")
|
|
12
13
|
|
|
13
14
|
local CameraStack = setmetatable({}, BaseObject)
|
|
14
15
|
CameraStack.ClassName = "CameraStack"
|
|
15
16
|
CameraStack.__index = CameraStack
|
|
16
17
|
|
|
18
|
+
export type CameraStack = typeof(setmetatable(
|
|
19
|
+
{} :: {
|
|
20
|
+
_maid: _Maid.Maid,
|
|
21
|
+
_stack: { any },
|
|
22
|
+
_disabledSet: { [string]: boolean },
|
|
23
|
+
},
|
|
24
|
+
{ __index = CameraStack }
|
|
25
|
+
))
|
|
26
|
+
|
|
17
27
|
--[=[
|
|
18
28
|
Constructs a new camera stack
|
|
19
29
|
|
|
20
30
|
@return CameraStack
|
|
21
31
|
]=]
|
|
22
|
-
function CameraStack.new()
|
|
32
|
+
function CameraStack.new(): CameraStack
|
|
23
33
|
local self = setmetatable(BaseObject.new(), CameraStack)
|
|
24
34
|
|
|
25
35
|
self._stack = {}
|
|
@@ -32,7 +42,7 @@ end
|
|
|
32
42
|
@param value any
|
|
33
43
|
@return boolean
|
|
34
44
|
]=]
|
|
35
|
-
function CameraStack.isCameraStack(value)
|
|
45
|
+
function CameraStack.isCameraStack(value: any): boolean
|
|
36
46
|
return DuckTypeUtils.isImplementation(CameraStack, value)
|
|
37
47
|
end
|
|
38
48
|
|
|
@@ -40,7 +50,7 @@ end
|
|
|
40
50
|
Pushes a disable state onto the camera stack
|
|
41
51
|
@return function -- Function to cancel disable
|
|
42
52
|
]=]
|
|
43
|
-
function CameraStack:PushDisable()
|
|
53
|
+
function CameraStack:PushDisable(): () -> ()
|
|
44
54
|
assert(self._stack, "Not initialized")
|
|
45
55
|
|
|
46
56
|
local disabledKey = HttpService:GenerateGUID(false)
|
|
@@ -54,10 +64,10 @@ end
|
|
|
54
64
|
--[=[
|
|
55
65
|
Outputs the camera stack. Intended for diagnostics.
|
|
56
66
|
]=]
|
|
57
|
-
function CameraStack:PrintCameraStack()
|
|
67
|
+
function CameraStack:PrintCameraStack(): ()
|
|
58
68
|
assert(self._stack, "Stack is not initialized yet")
|
|
59
69
|
|
|
60
|
-
for _, value in
|
|
70
|
+
for _, value in self._stack do
|
|
61
71
|
print(tostring(type(value) == "table" and value.ClassName or tostring(value)))
|
|
62
72
|
end
|
|
63
73
|
end
|
|
@@ -80,7 +90,7 @@ function CameraStack:GetTopState()
|
|
|
80
90
|
assert(self._stack, "Stack is not initialized yet")
|
|
81
91
|
|
|
82
92
|
if next(self._disabledSet) then
|
|
83
|
-
return
|
|
93
|
+
return nil
|
|
84
94
|
end
|
|
85
95
|
|
|
86
96
|
if #self._stack > 10 then
|
|
@@ -100,6 +110,8 @@ function CameraStack:GetTopState()
|
|
|
100
110
|
warn("[CameraStack] - Bad type on top of stack")
|
|
101
111
|
return nil
|
|
102
112
|
end
|
|
113
|
+
|
|
114
|
+
return nil
|
|
103
115
|
end
|
|
104
116
|
|
|
105
117
|
--[=[
|
|
@@ -116,7 +128,7 @@ function CameraStack:GetNewStateBelow()
|
|
|
116
128
|
return CustomCameraEffect.new(function()
|
|
117
129
|
local index = self:GetIndex(_stateToUse)
|
|
118
130
|
if index then
|
|
119
|
-
local below = self._stack[index-1]
|
|
131
|
+
local below = self._stack[index - 1]
|
|
120
132
|
if below then
|
|
121
133
|
return below.CameraState or below
|
|
122
134
|
else
|
|
@@ -127,9 +139,10 @@ function CameraStack:GetNewStateBelow()
|
|
|
127
139
|
warn(string.format("[CameraStack] - Could not get state from %q, returning default", tostring(_stateToUse)))
|
|
128
140
|
return self._stack[1].CameraState
|
|
129
141
|
end
|
|
130
|
-
end),
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
end),
|
|
143
|
+
function(newStateToUse)
|
|
144
|
+
_stateToUse = newStateToUse
|
|
145
|
+
end
|
|
133
146
|
end
|
|
134
147
|
|
|
135
148
|
--[=[
|
|
@@ -138,14 +151,16 @@ end
|
|
|
138
151
|
@return number? -- index
|
|
139
152
|
|
|
140
153
|
]=]
|
|
141
|
-
function CameraStack:GetIndex(state)
|
|
154
|
+
function CameraStack:GetIndex(state): number?
|
|
142
155
|
assert(self._stack, "Stack is not initialized yet")
|
|
143
156
|
|
|
144
|
-
for index, value in
|
|
157
|
+
for index, value in self._stack do
|
|
145
158
|
if value == state then
|
|
146
159
|
return index
|
|
147
160
|
end
|
|
148
161
|
end
|
|
162
|
+
|
|
163
|
+
return nil
|
|
149
164
|
end
|
|
150
165
|
|
|
151
166
|
--[=[
|
|
@@ -26,7 +26,7 @@ CameraStackService.ServiceName = "CameraStackService"
|
|
|
26
26
|
Initializes a new camera stack. Should be done via the ServiceBag.
|
|
27
27
|
@param serviceBag ServiceBag
|
|
28
28
|
]=]
|
|
29
|
-
function CameraStackService:Init(serviceBag)
|
|
29
|
+
function CameraStackService:Init(serviceBag: ServiceBag.ServiceBag)
|
|
30
30
|
assert(ServiceBag.isServiceBag(serviceBag), "Not a valid service bag")
|
|
31
31
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
32
32
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Data container for the state of a camera.
|
|
3
4
|
@class CameraState
|
|
@@ -12,24 +13,42 @@ local DuckTypeUtils = require("DuckTypeUtils")
|
|
|
12
13
|
local CameraState = {}
|
|
13
14
|
CameraState.ClassName = "CameraState"
|
|
14
15
|
|
|
16
|
+
export type CameraState = typeof(setmetatable(
|
|
17
|
+
{} :: {
|
|
18
|
+
CameraFrame: CameraFrame.CameraFrame,
|
|
19
|
+
CameraFrameDerivative: CameraFrame.CameraFrame,
|
|
20
|
+
CFrame: CFrame,
|
|
21
|
+
Position: Vector3,
|
|
22
|
+
Velocity: Vector3,
|
|
23
|
+
FieldOfView: number,
|
|
24
|
+
},
|
|
25
|
+
{ __index = CameraState }
|
|
26
|
+
))
|
|
27
|
+
|
|
15
28
|
--[=[
|
|
16
29
|
Constructs a new CameraState
|
|
17
|
-
@param cameraFrame CameraFrame | Camera
|
|
30
|
+
@param cameraFrame (CameraFrame | Camera)?
|
|
18
31
|
@param cameraFrameDerivative CameraFrame?
|
|
19
32
|
@return CameraState
|
|
20
33
|
]=]
|
|
21
|
-
function CameraState.new(
|
|
22
|
-
|
|
34
|
+
function CameraState.new(
|
|
35
|
+
cameraFrame: (CameraFrame.CameraFrame | Camera)?,
|
|
36
|
+
cameraFrameDerivative: CameraFrame.CameraFrame?
|
|
37
|
+
): CameraState
|
|
38
|
+
local self = setmetatable({} :: any, CameraState)
|
|
23
39
|
|
|
24
40
|
if typeof(cameraFrame) == "Instance" then
|
|
25
41
|
assert(cameraFrame:IsA("Camera"))
|
|
26
42
|
|
|
27
|
-
cameraFrame =
|
|
43
|
+
cameraFrame =
|
|
44
|
+
CameraFrame.new(QFrame.fromCFrameClosestTo(cameraFrame.CFrame, QFrame.new()), cameraFrame.FieldOfView)
|
|
28
45
|
end
|
|
29
46
|
|
|
30
47
|
assert(CameraFrame.isCameraFrame(cameraFrame) or type(cameraFrame) == "nil", "Bad cameraFrame")
|
|
31
|
-
assert(
|
|
32
|
-
|
|
48
|
+
assert(
|
|
49
|
+
CameraFrame.isCameraFrame(cameraFrameDerivative) or type(cameraFrameDerivative) == "nil",
|
|
50
|
+
"Bad cameraFrameDerivative"
|
|
51
|
+
)
|
|
33
52
|
|
|
34
53
|
self.CameraFrame = cameraFrame or CameraFrame.new()
|
|
35
54
|
self.CameraFrameDerivative = cameraFrameDerivative or CameraFrame.new()
|
|
@@ -42,7 +61,7 @@ end
|
|
|
42
61
|
@param value any
|
|
43
62
|
@return boolean
|
|
44
63
|
]=]
|
|
45
|
-
function CameraState.isCameraState(value)
|
|
64
|
+
function CameraState.isCameraState(value: any): boolean
|
|
46
65
|
return DuckTypeUtils.isImplementation(CameraState, value)
|
|
47
66
|
end
|
|
48
67
|
|
|
@@ -88,7 +107,7 @@ end
|
|
|
88
107
|
Set another camera state. Typically used to set Workspace.CurrentCamera's state to match this camera's state
|
|
89
108
|
@param camera Camera -- A CameraState to set, also accepts a Roblox Camera
|
|
90
109
|
]=]
|
|
91
|
-
function CameraState:Set(camera)
|
|
110
|
+
function CameraState:Set(camera: Camera)
|
|
92
111
|
camera.FieldOfView = self.FieldOfView
|
|
93
112
|
camera.CFrame = self.CFrame
|
|
94
113
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Utility methods for cameras. These are great for viewport frames.
|
|
3
4
|
|
|
@@ -28,8 +29,12 @@ local CameraUtils = {}
|
|
|
28
29
|
@param size Vector3
|
|
29
30
|
@return number
|
|
30
31
|
]=]
|
|
31
|
-
function CameraUtils.getCubeoidDiameter(size)
|
|
32
|
-
|
|
32
|
+
function CameraUtils.getCubeoidDiameter(size: Vector3): number
|
|
33
|
+
local x = size.X
|
|
34
|
+
local y = size.Y
|
|
35
|
+
local z = size.Z
|
|
36
|
+
|
|
37
|
+
return math.sqrt(x * x + y * y + z * z)
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
--[=[
|
|
@@ -41,8 +46,8 @@ end
|
|
|
41
46
|
@param aspectRatio number -- Aspect ratio of the screen
|
|
42
47
|
@return number -- Distance to move the camera back from the bounding box
|
|
43
48
|
]=]
|
|
44
|
-
function CameraUtils.fitBoundingBoxToCamera(size, fovDeg, aspectRatio)
|
|
45
|
-
local radius = CameraUtils.getCubeoidDiameter(size)/2
|
|
49
|
+
function CameraUtils.fitBoundingBoxToCamera(size: Vector3, fovDeg: number, aspectRatio: number): number
|
|
50
|
+
local radius = CameraUtils.getCubeoidDiameter(size) / 2
|
|
46
51
|
return CameraUtils.fitSphereToCamera(radius, fovDeg, aspectRatio)
|
|
47
52
|
end
|
|
48
53
|
|
|
@@ -55,7 +60,7 @@ end
|
|
|
55
60
|
@param aspectRatio number -- Aspect ratio of the screen
|
|
56
61
|
@return number -- Distance to move the camera back from the bounding box
|
|
57
62
|
]=]
|
|
58
|
-
function CameraUtils.fitSphereToCamera(radius, fovDeg, aspectRatio)
|
|
63
|
+
function CameraUtils.fitSphereToCamera(radius: number, fovDeg: number, aspectRatio: number): number
|
|
59
64
|
local halfFov = 0.5 * math.rad(fovDeg)
|
|
60
65
|
if aspectRatio < 1 then
|
|
61
66
|
halfFov = math.atan(aspectRatio * math.tan(halfFov))
|
|
@@ -71,7 +76,7 @@ end
|
|
|
71
76
|
@param position Vector3
|
|
72
77
|
@return boolean
|
|
73
78
|
]=]
|
|
74
|
-
function CameraUtils.isOnScreen(camera, position)
|
|
79
|
+
function CameraUtils.isOnScreen(camera: Camera, position: Vector3): boolean
|
|
75
80
|
local _, onScreen = camera:WorldToScreenPoint(position)
|
|
76
81
|
return onScreen
|
|
77
82
|
end
|
|
@@ -8,24 +8,22 @@ local Maid = require("Maid")
|
|
|
8
8
|
|
|
9
9
|
local CameraUtils = require("CameraUtils")
|
|
10
10
|
|
|
11
|
-
return function(target)
|
|
11
|
+
return function(target: Instance)
|
|
12
12
|
local maid = Maid.new()
|
|
13
13
|
|
|
14
|
-
local viewportFrame = Instance.new("ViewportFrame")
|
|
14
|
+
local viewportFrame = maid:Add(Instance.new("ViewportFrame"))
|
|
15
15
|
viewportFrame.BorderSizePixel = 0
|
|
16
16
|
viewportFrame.BackgroundColor3 = Color3.new(0.7, 0.7, 0.7)
|
|
17
17
|
viewportFrame.Size = UDim2.new(1, 0, 1, 0)
|
|
18
|
-
maid:GiveTask(viewportFrame)
|
|
19
18
|
|
|
20
|
-
local camera = Instance.new("Camera")
|
|
19
|
+
local camera: Camera = maid:Add(Instance.new("Camera"))
|
|
21
20
|
camera.FieldOfViewMode = Enum.FieldOfViewMode.Diagonal
|
|
22
21
|
camera.FieldOfView = 70
|
|
23
22
|
viewportFrame.CurrentCamera = camera
|
|
24
|
-
maid:GiveTask(camera)
|
|
25
23
|
|
|
26
24
|
local radius = 5
|
|
27
25
|
|
|
28
|
-
local ball = Instance.new("Part")
|
|
26
|
+
local ball: Part = maid:Add(Instance.new("Part"))
|
|
29
27
|
ball.Color = Color3.new(1, 0.5, 0.5)
|
|
30
28
|
ball.Size = Vector3.new(2*radius, 2*radius, 2*radius)
|
|
31
29
|
ball.Shape = Enum.PartType.Ball
|
|
@@ -70,17 +70,17 @@ end
|
|
|
70
70
|
Sets the gamepad rotation acceleration
|
|
71
71
|
@param acceleration number
|
|
72
72
|
]=]
|
|
73
|
-
function CameraControls:SetGamepadRotationAcceleration(acceleration)
|
|
73
|
+
function CameraControls:SetGamepadRotationAcceleration(acceleration: number)
|
|
74
74
|
assert(type(acceleration) == "number", "Bad acceleration")
|
|
75
75
|
|
|
76
76
|
self._gamepadRotateModel:SetAcceleration(acceleration)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
function CameraControls:GetKey()
|
|
79
|
+
function CameraControls:GetKey(): string
|
|
80
80
|
return self._key
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
function CameraControls:IsEnabled()
|
|
83
|
+
function CameraControls:IsEnabled(): boolean
|
|
84
84
|
return self._enabled
|
|
85
85
|
end
|
|
86
86
|
|
|
@@ -40,7 +40,7 @@ end
|
|
|
40
40
|
|
|
41
41
|
@param acceleration number
|
|
42
42
|
]=]
|
|
43
|
-
function GamepadRotateModel:SetAcceleration(acceleration)
|
|
43
|
+
function GamepadRotateModel:SetAcceleration(acceleration: number)
|
|
44
44
|
assert(type(acceleration) == "number", "Bad acceleration")
|
|
45
45
|
|
|
46
46
|
self._rampVelocityX.a = acceleration
|
|
@@ -18,6 +18,8 @@ local Maid = require("Maid")
|
|
|
18
18
|
local CFrameUtils = require("CFrameUtils")
|
|
19
19
|
local CameraFrame = require("CameraFrame")
|
|
20
20
|
local ValueObject = require("ValueObject")
|
|
21
|
+
local _Rx = require("Rx")
|
|
22
|
+
local _Observable = require("Observable")
|
|
21
23
|
|
|
22
24
|
local EPSILON = 0.001
|
|
23
25
|
|
|
@@ -73,7 +75,7 @@ DefaultCamera.OverrideCameraState = DefaultCamera.SetRobloxCameraState
|
|
|
73
75
|
|
|
74
76
|
@param cframe CFrame
|
|
75
77
|
]=]
|
|
76
|
-
function DefaultCamera:SetRobloxCFrame(cframe)
|
|
78
|
+
function DefaultCamera:SetRobloxCFrame(cframe: CFrame)
|
|
77
79
|
self._cameraState.CFrame = cframe
|
|
78
80
|
end
|
|
79
81
|
|
|
@@ -91,7 +93,7 @@ end
|
|
|
91
93
|
|
|
92
94
|
@param cameraFrame CameraState | nil
|
|
93
95
|
]=]
|
|
94
|
-
function DefaultCamera:SetLastSetCameraFrame(cameraFrame)
|
|
96
|
+
function DefaultCamera:SetLastSetCameraFrame(cameraFrame: CameraFrame.CameraFrame)
|
|
95
97
|
self._lastCameraFrame = CameraFrame.new(cameraFrame.QFrame, cameraFrame.FieldOfView)
|
|
96
98
|
end
|
|
97
99
|
|
|
@@ -107,7 +109,7 @@ end
|
|
|
107
109
|
|
|
108
110
|
@return Observable<boolean>
|
|
109
111
|
]=]
|
|
110
|
-
function DefaultCamera:ObserveIsFirstPerson()
|
|
112
|
+
function DefaultCamera:ObserveIsFirstPerson(): _Observable.Observable<boolean>
|
|
111
113
|
return self._isFirstPerson:Observe()
|
|
112
114
|
end
|
|
113
115
|
|
|
@@ -117,7 +119,7 @@ end
|
|
|
117
119
|
@param predicate ((inFirstPerson: boolean) -> boolean)?
|
|
118
120
|
@return Observable<Brio<boolean>>
|
|
119
121
|
]=]
|
|
120
|
-
function DefaultCamera:ObserveIsFirstPersonBrio(predicate)
|
|
122
|
+
function DefaultCamera:ObserveIsFirstPersonBrio(predicate: _Rx.Predicate<boolean>?)
|
|
121
123
|
return self._isFirstPerson:Observe(predicate)
|
|
122
124
|
end
|
|
123
125
|
|
|
@@ -73,7 +73,7 @@ function ImpulseCamera:_getSpring(speed, damper)
|
|
|
73
73
|
speed = speed or self._defaultSpring.Speed
|
|
74
74
|
damper = damper or self._defaultSpring.Damper
|
|
75
75
|
|
|
76
|
-
for _, spring in
|
|
76
|
+
for _, spring in self._springs do
|
|
77
77
|
if math.abs(spring.Speed - speed) <= EPSILON and math.abs(spring.Damper - damper) <= EPSILON then
|
|
78
78
|
return spring
|
|
79
79
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Represents a camera state at a certain point. Can perform math on this state.
|
|
3
4
|
@class CameraFrame
|
|
@@ -12,14 +13,43 @@ local CameraFrame = {}
|
|
|
12
13
|
CameraFrame.ClassName = "CameraFrame"
|
|
13
14
|
CameraFrame.__index = CameraFrame
|
|
14
15
|
|
|
16
|
+
export type CameraFrame = typeof(setmetatable(
|
|
17
|
+
{} :: {
|
|
18
|
+
--[=[
|
|
19
|
+
@prop CFrame CFrame
|
|
20
|
+
@within CameraFrame
|
|
21
|
+
]=]
|
|
22
|
+
CFrame: CFrame,
|
|
23
|
+
|
|
24
|
+
--[=[
|
|
25
|
+
@prop Position Vector3
|
|
26
|
+
@within CameraFrame
|
|
27
|
+
]=]
|
|
28
|
+
Position: Vector3,
|
|
29
|
+
|
|
30
|
+
--[=[
|
|
31
|
+
@prop FieldOfView number
|
|
32
|
+
@within CameraFrame
|
|
33
|
+
]=]
|
|
34
|
+
FieldOfView: number,
|
|
35
|
+
|
|
36
|
+
--[=[
|
|
37
|
+
@prop QFrame QFrame
|
|
38
|
+
@within CameraFrame
|
|
39
|
+
]=]
|
|
40
|
+
QFrame: QFrame.QFrame,
|
|
41
|
+
},
|
|
42
|
+
{ __index = CameraFrame }
|
|
43
|
+
))
|
|
44
|
+
|
|
15
45
|
--[=[
|
|
16
46
|
Constructs a new CameraFrame
|
|
17
47
|
@param qFrame QFrame
|
|
18
48
|
@param fieldOfView number
|
|
19
49
|
@return CameraFrame
|
|
20
50
|
]=]
|
|
21
|
-
function CameraFrame.new(qFrame
|
|
22
|
-
local self = setmetatable({}, CameraFrame)
|
|
51
|
+
function CameraFrame.new(qFrame: QFrame.QFrame?, fieldOfView: number?): CameraFrame
|
|
52
|
+
local self: CameraFrame = setmetatable({} :: any, CameraFrame)
|
|
23
53
|
|
|
24
54
|
self.QFrame = qFrame or QFrame.new()
|
|
25
55
|
self.FieldOfView = fieldOfView or 0
|
|
@@ -32,36 +62,11 @@ end
|
|
|
32
62
|
@param value any
|
|
33
63
|
@return boolean
|
|
34
64
|
]=]
|
|
35
|
-
function CameraFrame.isCameraFrame(value)
|
|
65
|
+
function CameraFrame.isCameraFrame(value: any): boolean
|
|
36
66
|
return DuckTypeUtils.isImplementation(CameraFrame, value)
|
|
37
67
|
end
|
|
38
68
|
|
|
39
|
-
|
|
40
|
-
@prop CFrame CFrame
|
|
41
|
-
@within CameraFrame
|
|
42
|
-
]=]
|
|
43
|
-
|
|
44
|
-
--[=[
|
|
45
|
-
@prop Position Vector3
|
|
46
|
-
@within CameraFrame
|
|
47
|
-
]=]
|
|
48
|
-
|
|
49
|
-
--[=[
|
|
50
|
-
@prop FieldOfView number
|
|
51
|
-
@within CameraFrame
|
|
52
|
-
]=]
|
|
53
|
-
|
|
54
|
-
--[=[
|
|
55
|
-
@prop QFrame QFrame
|
|
56
|
-
@within CameraFrame
|
|
57
|
-
]=]
|
|
58
|
-
|
|
59
|
-
--[=[
|
|
60
|
-
@prop QFrame QFrame
|
|
61
|
-
@within CameraFrame
|
|
62
|
-
]=]
|
|
63
|
-
|
|
64
|
-
function CameraFrame:__index(index)
|
|
69
|
+
(CameraFrame :: any).__index = function(self, index): any
|
|
65
70
|
if index == "CFrame" then
|
|
66
71
|
local result = QFrame.toCFrame(self.QFrame)
|
|
67
72
|
if not result then
|
|
@@ -95,7 +100,7 @@ function CameraFrame:__newindex(index, value)
|
|
|
95
100
|
assert(typeof(value) == "Vector3", "Bad value")
|
|
96
101
|
|
|
97
102
|
local q = self.QFrame
|
|
98
|
-
rawset(self, "QFrame", QFrame.new(value.
|
|
103
|
+
rawset(self, "QFrame", QFrame.new(value.X, value.Y, value.Z, q.W, q.X, q.Y, q.Z))
|
|
99
104
|
elseif index == "FieldOfView" or index == "QFrame" then
|
|
100
105
|
rawset(self, index, value)
|
|
101
106
|
else
|
|
@@ -109,9 +114,8 @@ end
|
|
|
109
114
|
@param b CameraFrame
|
|
110
115
|
@return CameraFrame
|
|
111
116
|
]=]
|
|
112
|
-
function CameraFrame.__add(a, b)
|
|
113
|
-
assert(CameraFrame.isCameraFrame(a) and CameraFrame.isCameraFrame(b),
|
|
114
|
-
"CameraFrame + non-CameraFrame attempted")
|
|
117
|
+
function CameraFrame.__add(a: CameraFrame, b: CameraFrame): CameraFrame
|
|
118
|
+
assert(CameraFrame.isCameraFrame(a) and CameraFrame.isCameraFrame(b), "CameraFrame + non-CameraFrame attempted")
|
|
115
119
|
|
|
116
120
|
return CameraFrame.new(a.QFrame + b.QFrame, a.FieldOfView + b.FieldOfView)
|
|
117
121
|
end
|
|
@@ -122,9 +126,8 @@ end
|
|
|
122
126
|
@param b CameraFrame
|
|
123
127
|
@return CameraFrame
|
|
124
128
|
]=]
|
|
125
|
-
function CameraFrame.__sub(a, b)
|
|
126
|
-
assert(CameraFrame.isCameraFrame(a) and CameraFrame.isCameraFrame(b),
|
|
127
|
-
"CameraFrame - non-CameraFrame attempted")
|
|
129
|
+
function CameraFrame.__sub(a: CameraFrame, b: CameraFrame): CameraFrame
|
|
130
|
+
assert(CameraFrame.isCameraFrame(a) and CameraFrame.isCameraFrame(b), "CameraFrame - non-CameraFrame attempted")
|
|
128
131
|
|
|
129
132
|
return CameraFrame.new(a.QFrame - b.QFrame, a.FieldOfView - b.FieldOfView)
|
|
130
133
|
end
|
|
@@ -134,7 +137,7 @@ end
|
|
|
134
137
|
@param a CameraFrame
|
|
135
138
|
@return CameraFrame
|
|
136
139
|
]=]
|
|
137
|
-
function CameraFrame.__unm(a)
|
|
140
|
+
function CameraFrame.__unm(a: CameraFrame): CameraFrame
|
|
138
141
|
return CameraFrame.new(-a.QFrame, -a.FieldOfView)
|
|
139
142
|
end
|
|
140
143
|
|
|
@@ -144,13 +147,13 @@ end
|
|
|
144
147
|
@param b CameraFrame | number
|
|
145
148
|
@return CameraFrame
|
|
146
149
|
]=]
|
|
147
|
-
function CameraFrame.__mul(a, b)
|
|
150
|
+
function CameraFrame.__mul(a: CameraFrame | number, b: CameraFrame | number): CameraFrame
|
|
148
151
|
if type(a) == "number" and CameraFrame.isCameraFrame(b) then
|
|
149
|
-
return CameraFrame.new(a*b.QFrame, a*b.FieldOfView)
|
|
152
|
+
return CameraFrame.new(a * (b :: CameraFrame).QFrame, a * (b :: CameraFrame).FieldOfView)
|
|
150
153
|
elseif CameraFrame.isCameraFrame(b) and type(b) == "number" then
|
|
151
|
-
return CameraFrame.new(a.QFrame*b, a.FieldOfView*b)
|
|
154
|
+
return CameraFrame.new((a :: CameraFrame).QFrame * b, (a :: CameraFrame).FieldOfView * b)
|
|
152
155
|
elseif CameraFrame.isCameraFrame(a) and CameraFrame.isCameraFrame(b) then
|
|
153
|
-
return CameraFrame.new(a.QFrame*b.QFrame, a.FieldOfView*b.FieldOfView)
|
|
156
|
+
return CameraFrame.new((a :: CameraFrame).QFrame * b.QFrame, (a :: CameraFrame).FieldOfView * b.FieldOfView)
|
|
154
157
|
else
|
|
155
158
|
error("CameraFrame * non-CameraFrame attempted")
|
|
156
159
|
end
|
|
@@ -162,9 +165,9 @@ end
|
|
|
162
165
|
@param b number
|
|
163
166
|
@return CameraFrame
|
|
164
167
|
]=]
|
|
165
|
-
function CameraFrame.__div(a, b)
|
|
168
|
+
function CameraFrame.__div(a: CameraFrame, b: CameraFrame): CameraFrame
|
|
166
169
|
if CameraFrame.isCameraFrame(a) and type(b) == "number" then
|
|
167
|
-
return CameraFrame.new(a.QFrame/b, a.FieldOfView/b)
|
|
170
|
+
return CameraFrame.new(a.QFrame / b, a.FieldOfView / b)
|
|
168
171
|
else
|
|
169
172
|
error("CameraFrame * non-CameraFrame attempted")
|
|
170
173
|
end
|
|
@@ -176,9 +179,9 @@ end
|
|
|
176
179
|
@param b number
|
|
177
180
|
@return CameraFrame
|
|
178
181
|
]=]
|
|
179
|
-
function CameraFrame.__pow(a, b)
|
|
182
|
+
function CameraFrame.__pow(a: CameraFrame, b: number): CameraFrame
|
|
180
183
|
if CameraFrame.isCameraFrame(a) and type(b) == "number" then
|
|
181
|
-
return CameraFrame.new(a.QFrame^b, a.FieldOfView^b)
|
|
184
|
+
return CameraFrame.new(a.QFrame ^ b, a.FieldOfView ^ b)
|
|
182
185
|
else
|
|
183
186
|
error("CameraFrame ^ non-CameraFrame attempted")
|
|
184
187
|
end
|
|
@@ -190,7 +193,7 @@ end
|
|
|
190
193
|
@param b CameraFrame
|
|
191
194
|
@return boolean
|
|
192
195
|
]=]
|
|
193
|
-
function CameraFrame.__eq(a, b)
|
|
196
|
+
function CameraFrame.__eq(a: CameraFrame, b: CameraFrame): boolean
|
|
194
197
|
return a.QFrame == b.QFrame and a.FieldOfView == b.FieldOfView
|
|
195
198
|
end
|
|
196
199
|
|
|
@@ -26,7 +26,7 @@ CameraStateTweener.__index = CameraStateTweener
|
|
|
26
26
|
@param speed number? -- Speed that the camera tweener tweens at. Defaults to 20
|
|
27
27
|
@return CameraStateTweener
|
|
28
28
|
]=]
|
|
29
|
-
function CameraStateTweener.new(serviceBagOrCameraStack, cameraEffect, speed)
|
|
29
|
+
function CameraStateTweener.new(serviceBagOrCameraStack, cameraEffect, speed: number?)
|
|
30
30
|
local self = setmetatable(BaseObject.new(), CameraStateTweener)
|
|
31
31
|
|
|
32
32
|
assert(cameraEffect, "No cameraEffect")
|
|
@@ -65,7 +65,7 @@ end
|
|
|
65
65
|
Returns percent visible, from 0 to 1.
|
|
66
66
|
@return number
|
|
67
67
|
]=]
|
|
68
|
-
function CameraStateTweener:GetPercentVisible()
|
|
68
|
+
function CameraStateTweener:GetPercentVisible(): number
|
|
69
69
|
return self._fadeBetween.Value
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -73,7 +73,7 @@ end
|
|
|
73
73
|
Shows the camera to fade in.
|
|
74
74
|
@param doNotAnimate? boolean -- Optional, defaults to animating
|
|
75
75
|
]=]
|
|
76
|
-
function CameraStateTweener:Show(doNotAnimate)
|
|
76
|
+
function CameraStateTweener:Show(doNotAnimate: boolean?)
|
|
77
77
|
self:SetTarget(1, doNotAnimate)
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -81,7 +81,7 @@ end
|
|
|
81
81
|
Hides the camera to fade in.
|
|
82
82
|
@param doNotAnimate? boolean -- Optional, defaults to animating
|
|
83
83
|
]=]
|
|
84
|
-
function CameraStateTweener:Hide(doNotAnimate)
|
|
84
|
+
function CameraStateTweener:Hide(doNotAnimate: boolean?)
|
|
85
85
|
self:SetTarget(0, doNotAnimate)
|
|
86
86
|
end
|
|
87
87
|
|
|
@@ -89,7 +89,7 @@ end
|
|
|
89
89
|
Returns true if we're done hiding
|
|
90
90
|
@return boolean
|
|
91
91
|
]=]
|
|
92
|
-
function CameraStateTweener:IsFinishedHiding()
|
|
92
|
+
function CameraStateTweener:IsFinishedHiding(): boolean
|
|
93
93
|
return self._fadeBetween.HasReachedTarget and self._fadeBetween.Target == 0
|
|
94
94
|
end
|
|
95
95
|
|
|
@@ -97,7 +97,7 @@ end
|
|
|
97
97
|
Returns true if we're done showing
|
|
98
98
|
@return boolean
|
|
99
99
|
]=]
|
|
100
|
-
function CameraStateTweener:IsFinishedShowing()
|
|
100
|
+
function CameraStateTweener:IsFinishedShowing(): boolean
|
|
101
101
|
return self._fadeBetween.HasReachedTarget and self._fadeBetween.Target == 1
|
|
102
102
|
end
|
|
103
103
|
|
|
@@ -107,7 +107,7 @@ end
|
|
|
107
107
|
@param doNotAnimate boolean? -- Optional, defaults to animating
|
|
108
108
|
@param callback function
|
|
109
109
|
]=]
|
|
110
|
-
function CameraStateTweener:Finish(doNotAnimate
|
|
110
|
+
function CameraStateTweener:Finish(doNotAnimate: boolean?, callback: () -> ())
|
|
111
111
|
assert(type(callback) == "function", "Bad callback")
|
|
112
112
|
|
|
113
113
|
self:Hide(doNotAnimate)
|
|
@@ -146,7 +146,7 @@ end
|
|
|
146
146
|
@param doNotAnimate boolean? -- Optional, defaults to animating
|
|
147
147
|
@return CameraStateTweener -- self
|
|
148
148
|
]=]
|
|
149
|
-
function CameraStateTweener:SetTarget(target, doNotAnimate)
|
|
149
|
+
function CameraStateTweener:SetTarget(target: number, doNotAnimate: boolean?)
|
|
150
150
|
self._fadeBetween.Target = target or error("No target")
|
|
151
151
|
if doNotAnimate then
|
|
152
152
|
self._fadeBetween.Value = self._fadeBetween.Target
|
|
@@ -160,7 +160,7 @@ end
|
|
|
160
160
|
@param speed number
|
|
161
161
|
@return CameraStateTweener -- self
|
|
162
162
|
]=]
|
|
163
|
-
function CameraStateTweener:SetSpeed(speed)
|
|
163
|
+
function CameraStateTweener:SetSpeed(speed: number)
|
|
164
164
|
assert(type(speed) == "number", "Bad speed")
|
|
165
165
|
|
|
166
166
|
self._fadeBetween.Speed = speed
|
|
@@ -173,7 +173,7 @@ end
|
|
|
173
173
|
@param isVisible boolean
|
|
174
174
|
@param doNotAnimate boolean? -- Optional, defaults to animating
|
|
175
175
|
]=]
|
|
176
|
-
function CameraStateTweener:SetVisible(isVisible, doNotAnimate)
|
|
176
|
+
function CameraStateTweener:SetVisible(isVisible: number, doNotAnimate: boolean?)
|
|
177
177
|
if isVisible then
|
|
178
178
|
self:Show(doNotAnimate)
|
|
179
179
|
else
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Utility functions involving field of view.
|
|
3
4
|
@class FieldOfViewUtils
|
|
@@ -14,8 +15,8 @@ local FieldOfViewUtils = {}
|
|
|
14
15
|
@param fov number
|
|
15
16
|
@return number
|
|
16
17
|
]=]
|
|
17
|
-
function FieldOfViewUtils.fovToHeight(fov)
|
|
18
|
-
|
|
18
|
+
function FieldOfViewUtils.fovToHeight(fov: number): number
|
|
19
|
+
return 2 * math.tan(math.rad(fov) / 2)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
--[=[
|
|
@@ -23,8 +24,8 @@ end
|
|
|
23
24
|
@param height number
|
|
24
25
|
@return number
|
|
25
26
|
]=]
|
|
26
|
-
function FieldOfViewUtils.heightToFov(height)
|
|
27
|
-
|
|
27
|
+
function FieldOfViewUtils.heightToFov(height: number): number
|
|
28
|
+
return 2 * math.deg(math.atan(height / 2))
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
--[=[
|
|
@@ -33,10 +34,10 @@ end
|
|
|
33
34
|
@param linearAt number
|
|
34
35
|
@return number
|
|
35
36
|
]=]
|
|
36
|
-
function FieldOfViewUtils.safeLog(height, linearAt)
|
|
37
|
+
function FieldOfViewUtils.safeLog(height: number, linearAt: number): number
|
|
37
38
|
if height < linearAt then
|
|
38
|
-
local slope = 1/linearAt
|
|
39
|
-
return slope*(height - linearAt) + math.log(linearAt)
|
|
39
|
+
local slope = 1 / linearAt
|
|
40
|
+
return slope * (height - linearAt) + math.log(linearAt)
|
|
40
41
|
else
|
|
41
42
|
return math.log(height)
|
|
42
43
|
end
|
|
@@ -49,11 +50,11 @@ end
|
|
|
49
50
|
@param linearAt number
|
|
50
51
|
@return number
|
|
51
52
|
]=]
|
|
52
|
-
function FieldOfViewUtils.safeExp(logHeight, linearAt)
|
|
53
|
+
function FieldOfViewUtils.safeExp(logHeight: number, linearAt: number): number
|
|
53
54
|
local transitionAt = math.log(linearAt)
|
|
54
55
|
|
|
55
56
|
if logHeight <= transitionAt then
|
|
56
|
-
return linearAt*(logHeight - transitionAt) + linearAt
|
|
57
|
+
return linearAt * (logHeight - transitionAt) + linearAt
|
|
57
58
|
else
|
|
58
59
|
return math.exp(logHeight)
|
|
59
60
|
end
|
|
@@ -66,7 +67,7 @@ end
|
|
|
66
67
|
@param percent number
|
|
67
68
|
@return number -- Fov in degrees
|
|
68
69
|
]=]
|
|
69
|
-
function FieldOfViewUtils.lerpInHeightSpace(fov0, fov1, percent)
|
|
70
|
+
function FieldOfViewUtils.lerpInHeightSpace(fov0: number, fov1: number, percent: number): number
|
|
70
71
|
local height0 = FieldOfViewUtils.fovToHeight(fov0)
|
|
71
72
|
local height1 = FieldOfViewUtils.fovToHeight(fov1)
|
|
72
73
|
|