@quenty/camera 14.22.1 → 14.22.2-canary.675e877.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
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
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.22.2-canary.675e877.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.22.1...@quenty/camera@14.22.2-canary.675e877.0) (2025-08-07)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Fix formatting ([41ceadb](https://github.com/Quenty/NevermoreEngine/commit/41ceadbc674b7860d8593019b5dc5d4cbe539deb))
|
|
12
|
+
* Setting RobloxCFrame also assigns the override CFrame ([1014f69](https://github.com/Quenty/NevermoreEngine/commit/1014f69cce67eda8cde99f7cb7b4243a83ec9fba))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Add CameraSubjectUtils ([5e32c47](https://github.com/Quenty/NevermoreEngine/commit/5e32c47a1cec33ca903c9f558463fffbc8f2daf4))
|
|
18
|
+
* Add epsilon ([9f61ef3](https://github.com/Quenty/NevermoreEngine/commit/9f61ef3c7fdfc8b7ffc65c592873fd960a5ef126))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
## [14.22.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.22.0...@quenty/camera@14.22.1) (2025-07-14)
|
|
7
25
|
|
|
8
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/camera",
|
|
3
|
-
"version": "14.22.
|
|
3
|
+
"version": "14.22.2-canary.675e877.0",
|
|
4
4
|
"description": "Quenty's camera system for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,27 +25,27 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/acceltween": "
|
|
29
|
-
"@quenty/baseobject": "
|
|
30
|
-
"@quenty/cframeutils": "
|
|
31
|
-
"@quenty/cubicspline": "
|
|
32
|
-
"@quenty/ducktype": "
|
|
33
|
-
"@quenty/inputobjectutils": "
|
|
34
|
-
"@quenty/loader": "
|
|
35
|
-
"@quenty/maid": "
|
|
36
|
-
"@quenty/math": "
|
|
37
|
-
"@quenty/qframe": "
|
|
38
|
-
"@quenty/rx": "
|
|
39
|
-
"@quenty/servicebag": "
|
|
40
|
-
"@quenty/spring": "
|
|
41
|
-
"@quenty/valueobject": "
|
|
42
|
-
"@quenty/vector3utils": "
|
|
28
|
+
"@quenty/acceltween": "2.5.3",
|
|
29
|
+
"@quenty/baseobject": "10.9.0",
|
|
30
|
+
"@quenty/cframeutils": "5.5.3",
|
|
31
|
+
"@quenty/cubicspline": "10.9.0",
|
|
32
|
+
"@quenty/ducktype": "5.9.0",
|
|
33
|
+
"@quenty/inputobjectutils": "4.19.0",
|
|
34
|
+
"@quenty/loader": "10.9.0",
|
|
35
|
+
"@quenty/maid": "3.5.0",
|
|
36
|
+
"@quenty/math": "2.7.3",
|
|
37
|
+
"@quenty/qframe": "10.11.0",
|
|
38
|
+
"@quenty/rx": "13.18.0",
|
|
39
|
+
"@quenty/servicebag": "11.13.0",
|
|
40
|
+
"@quenty/spring": "10.9.0",
|
|
41
|
+
"@quenty/valueobject": "13.18.0",
|
|
42
|
+
"@quenty/vector3utils": "10.9.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@quenty/camerastoryutils": "
|
|
45
|
+
"@quenty/camerastoryutils": "10.11.0"
|
|
46
46
|
},
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "675e87759fbcf0f346c264580e679725819353e3"
|
|
51
51
|
}
|
|
@@ -91,6 +91,10 @@ DefaultCamera.OverrideCameraState = DefaultCamera.SetRobloxCameraState
|
|
|
91
91
|
]=]
|
|
92
92
|
function DefaultCamera.SetRobloxCFrame(self: DefaultCamera, cframe: CFrame)
|
|
93
93
|
self._cameraState.CFrame = cframe
|
|
94
|
+
|
|
95
|
+
if self._lastCameraFrame then
|
|
96
|
+
self._lastCameraFrame.CFrame = cframe
|
|
97
|
+
end
|
|
94
98
|
end
|
|
95
99
|
|
|
96
100
|
--[=[
|
|
@@ -30,6 +30,7 @@ export type FadeBetweenCamera3 = typeof(setmetatable(
|
|
|
30
30
|
Speed: number,
|
|
31
31
|
Velocity: number,
|
|
32
32
|
Target: number,
|
|
33
|
+
Epsilon: number?,
|
|
33
34
|
},
|
|
34
35
|
{} :: typeof({ __index = FadeBetweenCamera3 })
|
|
35
36
|
)) & CameraEffectUtils.CameraEffect
|
|
@@ -73,7 +74,7 @@ function FadeBetweenCamera3:__newindex(index, value)
|
|
|
73
74
|
self._spring.Target = value
|
|
74
75
|
elseif index == "Velocity" then
|
|
75
76
|
self._spring.Velocity = value
|
|
76
|
-
elseif index == "CameraA" or index == "CameraB" then
|
|
77
|
+
elseif index == "CameraA" or index == "CameraB" or index == "Epsilon" then
|
|
77
78
|
rawset(self, index, value)
|
|
78
79
|
else
|
|
79
80
|
error(string.format("%q is not a valid member of FadeBetweenCamera3", tostring(index)))
|
|
@@ -88,7 +89,7 @@ end
|
|
|
88
89
|
]=]
|
|
89
90
|
function FadeBetweenCamera3:__index(index)
|
|
90
91
|
if index == "CameraState" then
|
|
91
|
-
local _, t = SpringUtils.animating(self._spring)
|
|
92
|
+
local _, t = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
|
|
92
93
|
if t == 0 then
|
|
93
94
|
return self.CameraStateA
|
|
94
95
|
elseif t == 1 then
|
|
@@ -146,24 +147,26 @@ function FadeBetweenCamera3:__index(index)
|
|
|
146
147
|
elseif index == "Damper" then
|
|
147
148
|
return self._spring.Damper
|
|
148
149
|
elseif index == "Value" then
|
|
149
|
-
local _, t = SpringUtils.animating(self._spring)
|
|
150
|
+
local _, t = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
|
|
150
151
|
return t
|
|
151
152
|
elseif index == "Speed" then
|
|
152
153
|
return self._spring.Speed
|
|
153
154
|
elseif index == "Target" then
|
|
154
155
|
return self._spring.Target
|
|
155
156
|
elseif index == "Velocity" then
|
|
156
|
-
local animating = SpringUtils.animating(self._spring)
|
|
157
|
+
local animating = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
|
|
157
158
|
if animating then
|
|
158
159
|
return self._spring.Velocity
|
|
159
160
|
else
|
|
160
161
|
return 0
|
|
161
162
|
end
|
|
162
163
|
elseif index == "HasReachedTarget" then
|
|
163
|
-
local animating = SpringUtils.animating(self._spring)
|
|
164
|
+
local animating = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
|
|
164
165
|
return not animating
|
|
165
166
|
elseif index == "Spring" then
|
|
166
167
|
return self._spring
|
|
168
|
+
elseif index == "Epsilon" then
|
|
169
|
+
return rawget(self, "Epsilon")
|
|
167
170
|
elseif FadeBetweenCamera3[index] then
|
|
168
171
|
return FadeBetweenCamera3[index]
|
|
169
172
|
else
|
|
@@ -156,6 +156,10 @@ function CameraStateTweener.GetCameraBelow(self: CameraStateTweener): CameraEffe
|
|
|
156
156
|
return self._cameraBelow
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
+
function CameraStateTweener:SetEpsilon(epsilon: number?)
|
|
160
|
+
self._fadeBetween.Epsilon = epsilon
|
|
161
|
+
end
|
|
162
|
+
|
|
159
163
|
--[=[
|
|
160
164
|
Sets the percent visible target
|
|
161
165
|
@param target number
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
@class CameraSubjectUtils
|
|
3
|
+
]=]
|
|
4
|
+
|
|
5
|
+
local CameraSubjectUtils = {}
|
|
6
|
+
|
|
7
|
+
local HEAD_OFFSET = Vector3.new(0, 1.5, 0)
|
|
8
|
+
local R15_HEAD_OFFSET = Vector3.new(0, 1.5, 0)
|
|
9
|
+
local R15_HEAD_OFFSET_NO_SCALING = Vector3.new(0, 2, 0)
|
|
10
|
+
local HUMANOID_ROOT_PART_SIZE = Vector3.new(2, 2, 1)
|
|
11
|
+
|
|
12
|
+
--[=[
|
|
13
|
+
Follows the same logic as Roblox's default camera
|
|
14
|
+
]=]
|
|
15
|
+
function CameraSubjectUtils.getRobloxCameraSubjectCFrame(cameraSubject: Instance): CFrame?
|
|
16
|
+
if cameraSubject:IsA("Humanoid") then
|
|
17
|
+
local humanoid = cameraSubject
|
|
18
|
+
local humanoidIsDead = humanoid:GetState() == Enum.HumanoidStateType.Dead
|
|
19
|
+
|
|
20
|
+
local cameraOffset = humanoid.CameraOffset
|
|
21
|
+
local bodyPartToFollow: BasePart? = humanoid.RootPart
|
|
22
|
+
|
|
23
|
+
-- If the humanoid is dead, prefer their head part as a follow target, if it exists
|
|
24
|
+
if humanoidIsDead then
|
|
25
|
+
if humanoid.Parent and humanoid.Parent:IsA("Model") then
|
|
26
|
+
bodyPartToFollow = (humanoid.Parent:FindFirstChild("Head") :: BasePart) or bodyPartToFollow
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if bodyPartToFollow and bodyPartToFollow:IsA("BasePart") then
|
|
31
|
+
local heightOffset
|
|
32
|
+
if humanoid.RigType == Enum.HumanoidRigType.R15 then
|
|
33
|
+
if humanoid.AutomaticScalingEnabled then
|
|
34
|
+
heightOffset = R15_HEAD_OFFSET
|
|
35
|
+
|
|
36
|
+
local rootPart = humanoid.RootPart
|
|
37
|
+
if bodyPartToFollow == rootPart then
|
|
38
|
+
local rootPartSizeOffset = (rootPart.Size.Y - HUMANOID_ROOT_PART_SIZE.Y) / 2
|
|
39
|
+
heightOffset = heightOffset + Vector3.new(0, rootPartSizeOffset, 0)
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
heightOffset = R15_HEAD_OFFSET_NO_SCALING
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
heightOffset = HEAD_OFFSET
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if humanoidIsDead then
|
|
49
|
+
heightOffset = Vector3.zero
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
return bodyPartToFollow.CFrame * CFrame.new(heightOffset + cameraOffset)
|
|
53
|
+
end
|
|
54
|
+
elseif cameraSubject:IsA("BasePart") then
|
|
55
|
+
return cameraSubject.CFrame
|
|
56
|
+
elseif cameraSubject:IsA("Model") then
|
|
57
|
+
-- Model subjects are expected to have a PrimaryPart to determine orientation
|
|
58
|
+
if cameraSubject.PrimaryPart then
|
|
59
|
+
return (cameraSubject :: any):GetPrimaryPartCFrame()
|
|
60
|
+
else
|
|
61
|
+
return nil
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
return CameraSubjectUtils
|