@quenty/camera 14.20.3 → 14.20.4-canary.11a5dcf.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 +16 -0
- package/package.json +17 -17
- package/src/Client/CameraStack.lua +27 -20
- package/src/Client/CameraStackService.lua +53 -35
- package/src/Client/CameraState.lua +8 -8
- package/src/Client/CameraUtils.lua +1 -1
- package/src/Client/CameraUtils.story.lua +5 -4
- package/src/Client/Controls/CameraControls.lua +107 -60
- package/src/Client/Controls/CameraGamepadInputUtils.lua +36 -21
- package/src/Client/Controls/GamepadRotateModel.lua +22 -12
- package/src/Client/Effects/CameraEffectUtils.lua +10 -1
- package/src/Client/Effects/CustomCameraEffect.lua +21 -5
- package/src/Client/Effects/DefaultCamera.lua +50 -32
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera.lua +7 -7
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera2.lua +11 -11
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera3.lua +57 -21
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera4.lua +17 -9
- package/src/Client/Effects/FadingCamera.lua +21 -5
- package/src/Client/Effects/HeartbeatCamera.lua +22 -9
- package/src/Client/Effects/ImpulseCamera.lua +44 -28
- package/src/Client/Effects/ImpulseCamera.story.lua +6 -6
- package/src/Client/Effects/InverseFader.lua +22 -6
- package/src/Client/Effects/LagPointCamera.lua +27 -8
- package/src/Client/Effects/OverrideDefaultCameraToo.lua +26 -4
- package/src/Client/Effects/PointCamera.lua +22 -6
- package/src/Client/Effects/PushCamera.lua +35 -14
- package/src/Client/Effects/RotatedCamera.lua +23 -9
- package/src/Client/Effects/SmoothPositionCamera.lua +22 -10
- package/src/Client/Effects/SmoothRotatedCamera.lua +52 -24
- package/src/Client/Effects/SmoothZoomedCamera.lua +31 -12
- package/src/Client/Effects/SummedCamera.lua +38 -16
- package/src/Client/Effects/TrackCamera.lua +24 -11
- package/src/Client/Effects/XZPlaneLockCamera.lua +21 -8
- package/src/Client/Effects/ZoomedCamera.lua +24 -7
- package/src/Client/Input/CameraInputUtils.lua +49 -13
- package/src/Client/Input/CameraTouchInputUtils.lua +17 -16
- package/src/Client/Utility/CameraFrame.lua +2 -2
- package/src/Client/Utility/CameraFrame.story.lua +21 -12
- package/src/Client/Utility/CameraStateTweener.lua +39 -19
- package/src/Client/Utility/FieldOfViewUtils.lua +1 -1
- package/test/scripts/Client/ClientMain.client.lua +1 -1
- package/test/scripts/Server/ServerMain.server.lua +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Interface between user input and camera controls
|
|
3
4
|
@class CameraControls
|
|
@@ -9,16 +10,19 @@ local ContextActionService = game:GetService("ContextActionService")
|
|
|
9
10
|
local RunService = game:GetService("RunService")
|
|
10
11
|
local UserInputService = game:GetService("UserInputService")
|
|
11
12
|
|
|
12
|
-
local Maid = require("Maid")
|
|
13
13
|
local GamepadRotateModel = require("GamepadRotateModel")
|
|
14
14
|
local InputObjectUtils = require("InputObjectUtils")
|
|
15
|
+
local Maid = require("Maid")
|
|
16
|
+
local PushCamera = require("PushCamera")
|
|
17
|
+
local SmoothRotatedCamera = require("SmoothRotatedCamera")
|
|
18
|
+
local SmoothZoomedCamera = require("SmoothZoomedCamera")
|
|
15
19
|
|
|
16
20
|
-- Stolen directly from ROBLOX's core scripts.
|
|
17
21
|
-- Looks like a simple integrator.
|
|
18
22
|
-- Called (zoom, zoomScale, 1) returns zoom
|
|
19
|
-
local function rk4Integrator(position, velocity, t)
|
|
23
|
+
local function rk4Integrator(position: number, velocity: number, t: number): (number, number)
|
|
20
24
|
local direction = velocity < 0 and -1 or 1
|
|
21
|
-
local function acceleration(p, _)
|
|
25
|
+
local function acceleration(p: number, _: number): number
|
|
22
26
|
local accel = direction * math.max(1, (p / 3.3) + 0.5)
|
|
23
27
|
return accel
|
|
24
28
|
end
|
|
@@ -44,11 +48,31 @@ end
|
|
|
44
48
|
local CameraControls = {}
|
|
45
49
|
CameraControls.__index = CameraControls
|
|
46
50
|
CameraControls.ClassName = "CameraControls"
|
|
47
|
-
CameraControls.MOUSE_SENSITIVITY = Vector2.new(math.pi*4, math.pi*1.9)
|
|
51
|
+
CameraControls.MOUSE_SENSITIVITY = Vector2.new(math.pi * 4, math.pi * 1.9)
|
|
48
52
|
CameraControls._dragBeginTypes = { Enum.UserInputType.MouseButton2, Enum.UserInputType.Touch }
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
export type CameraControls = typeof(setmetatable(
|
|
55
|
+
{} :: {
|
|
56
|
+
_enabled: boolean,
|
|
57
|
+
_key: string,
|
|
58
|
+
_maid: Maid.Maid?,
|
|
59
|
+
_strength: number,
|
|
60
|
+
_zoomedCamera: SmoothZoomedCamera.SmoothZoomedCamera?,
|
|
61
|
+
_rotatedCamera: SmoothRotatedCamera.SmoothRotatedCamera?,
|
|
62
|
+
_gamepadRotateModel: GamepadRotateModel.GamepadRotateModel,
|
|
63
|
+
_rotVelocityTracker: any?,
|
|
64
|
+
_lastMousePosition: Vector3?,
|
|
65
|
+
_startZoomScale: number,
|
|
66
|
+
_dragMaid: Maid.Maid?,
|
|
67
|
+
},
|
|
68
|
+
{} :: typeof({ __index = CameraControls })
|
|
69
|
+
))
|
|
70
|
+
|
|
71
|
+
function CameraControls.new(
|
|
72
|
+
zoomedCamera: SmoothZoomedCamera.SmoothZoomedCamera?,
|
|
73
|
+
rotatedCamera: SmoothRotatedCamera.SmoothRotatedCamera?
|
|
74
|
+
): CameraControls
|
|
75
|
+
local self: CameraControls = setmetatable({} :: any, CameraControls)
|
|
52
76
|
|
|
53
77
|
self._enabled = false
|
|
54
78
|
self._key = tostring(self) .. "CameraControls"
|
|
@@ -56,8 +80,8 @@ function CameraControls.new(zoomCamera, rotatedCamera)
|
|
|
56
80
|
-- Destroyed below
|
|
57
81
|
self._gamepadRotateModel = GamepadRotateModel.new()
|
|
58
82
|
|
|
59
|
-
if
|
|
60
|
-
self:SetZoomedCamera(
|
|
83
|
+
if zoomedCamera then
|
|
84
|
+
self:SetZoomedCamera(zoomedCamera)
|
|
61
85
|
end
|
|
62
86
|
if rotatedCamera then
|
|
63
87
|
self:SetRotatedCamera(rotatedCamera)
|
|
@@ -70,24 +94,24 @@ end
|
|
|
70
94
|
Sets the gamepad rotation acceleration
|
|
71
95
|
@param acceleration number
|
|
72
96
|
]=]
|
|
73
|
-
function CameraControls
|
|
97
|
+
function CameraControls.SetGamepadRotationAcceleration(self: CameraControls, acceleration: number)
|
|
74
98
|
assert(type(acceleration) == "number", "Bad acceleration")
|
|
75
99
|
|
|
76
100
|
self._gamepadRotateModel:SetAcceleration(acceleration)
|
|
77
101
|
end
|
|
78
102
|
|
|
79
|
-
function CameraControls
|
|
103
|
+
function CameraControls.GetKey(self: CameraControls): string
|
|
80
104
|
return self._key
|
|
81
105
|
end
|
|
82
106
|
|
|
83
|
-
function CameraControls
|
|
107
|
+
function CameraControls.IsEnabled(self: CameraControls): boolean
|
|
84
108
|
return self._enabled
|
|
85
109
|
end
|
|
86
110
|
|
|
87
111
|
--[=[
|
|
88
112
|
Enables the control.
|
|
89
113
|
]=]
|
|
90
|
-
function CameraControls
|
|
114
|
+
function CameraControls.Enable(self: CameraControls)
|
|
91
115
|
if self._enabled then
|
|
92
116
|
return
|
|
93
117
|
end
|
|
@@ -95,9 +119,10 @@ function CameraControls:Enable()
|
|
|
95
119
|
assert(not self._maid, "Maid already defined")
|
|
96
120
|
self._enabled = true
|
|
97
121
|
|
|
98
|
-
|
|
122
|
+
local maid = Maid.new()
|
|
123
|
+
self._maid = maid
|
|
99
124
|
|
|
100
|
-
|
|
125
|
+
maid:GiveTask(self._gamepadRotateModel.IsRotating.Changed:Connect(function()
|
|
101
126
|
if self._gamepadRotateModel.IsRotating.Value then
|
|
102
127
|
self:_handleGamepadRotateStart()
|
|
103
128
|
else
|
|
@@ -121,11 +146,11 @@ function CameraControls:Enable()
|
|
|
121
146
|
self:_handleThumbstickInput(inputObject)
|
|
122
147
|
end, false, Enum.KeyCode.Thumbstick2)
|
|
123
148
|
|
|
124
|
-
|
|
149
|
+
maid:GiveTask(UserInputService.TouchPinch:Connect(function(_, scale, velocity, userInputState)
|
|
125
150
|
self:_handleTouchPinch(scale, velocity, userInputState)
|
|
126
151
|
end))
|
|
127
152
|
|
|
128
|
-
|
|
153
|
+
maid:GiveTask(function()
|
|
129
154
|
ContextActionService:UnbindAction(self._key)
|
|
130
155
|
ContextActionService:UnbindAction(self._key .. "Drag")
|
|
131
156
|
ContextActionService:UnbindAction(self._key .. "Rotate")
|
|
@@ -135,11 +160,12 @@ end
|
|
|
135
160
|
--[=[
|
|
136
161
|
Disables the control.
|
|
137
162
|
]=]
|
|
138
|
-
function CameraControls
|
|
163
|
+
function CameraControls.Disable(self: CameraControls)
|
|
139
164
|
if not self._enabled then
|
|
140
165
|
return
|
|
141
166
|
end
|
|
142
167
|
|
|
168
|
+
assert(self._maid, "Must be enabled")
|
|
143
169
|
self._enabled = false
|
|
144
170
|
|
|
145
171
|
self._maid:DoCleaning()
|
|
@@ -148,7 +174,9 @@ function CameraControls:Disable()
|
|
|
148
174
|
self._lastMousePosition = nil
|
|
149
175
|
end
|
|
150
176
|
|
|
151
|
-
function CameraControls
|
|
177
|
+
function CameraControls.BeginDrag(self: CameraControls, beginInputObject)
|
|
178
|
+
assert(self._maid, "Must be enabled")
|
|
179
|
+
|
|
152
180
|
if not self._rotatedCamera then
|
|
153
181
|
self._maid._dragMaid = nil
|
|
154
182
|
return
|
|
@@ -181,45 +209,58 @@ function CameraControls:BeginDrag(beginInputObject)
|
|
|
181
209
|
self._maid._dragMaid = maid
|
|
182
210
|
end
|
|
183
211
|
|
|
184
|
-
function CameraControls
|
|
212
|
+
function CameraControls.SetZoomedCamera(
|
|
213
|
+
self: CameraControls,
|
|
214
|
+
zoomedCamera: SmoothZoomedCamera.SmoothZoomedCamera
|
|
215
|
+
): CameraControls
|
|
185
216
|
self._zoomedCamera = assert(zoomedCamera, "Bad zoomedCamera")
|
|
186
|
-
self._startZoomScale =
|
|
217
|
+
self._startZoomScale = zoomedCamera.Zoom
|
|
187
218
|
|
|
188
219
|
return self
|
|
189
220
|
end
|
|
190
221
|
|
|
191
|
-
function CameraControls
|
|
222
|
+
function CameraControls.SetRotatedCamera(
|
|
223
|
+
self: CameraControls,
|
|
224
|
+
rotatedCamera: SmoothRotatedCamera.SmoothRotatedCamera
|
|
225
|
+
): CameraControls
|
|
192
226
|
self._rotatedCamera = assert(rotatedCamera, "Bad rotatedCamera")
|
|
193
227
|
return self
|
|
194
228
|
end
|
|
195
229
|
|
|
196
230
|
-- This code was the same algorithm used by Roblox. It makes it so you can zoom easier at further distances.
|
|
197
|
-
function CameraControls
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
local
|
|
231
|
+
function CameraControls._handleMouseWheel(self: CameraControls, inputObject: InputObject): ()
|
|
232
|
+
local zoomedCamera = self._zoomedCamera
|
|
233
|
+
if zoomedCamera then
|
|
234
|
+
local delta = math.clamp(-inputObject.Position.Z, -1, 1) * 1.4
|
|
235
|
+
local zoom = rk4Integrator(zoomedCamera.TargetZoom, delta, 1)
|
|
201
236
|
|
|
202
|
-
|
|
237
|
+
zoomedCamera.TargetZoom = zoom
|
|
203
238
|
end
|
|
204
239
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
240
|
+
local rotatedCamera = self._rotatedCamera
|
|
241
|
+
if rotatedCamera then
|
|
242
|
+
if rotatedCamera.ClassName == "PushCamera" then
|
|
243
|
+
((rotatedCamera :: any) :: PushCamera.PushCamera):StopRotateBack()
|
|
208
244
|
end
|
|
209
245
|
end
|
|
210
246
|
end
|
|
211
247
|
|
|
212
|
-
function CameraControls
|
|
248
|
+
function CameraControls._handleTouchPinch(
|
|
249
|
+
self: CameraControls,
|
|
250
|
+
scale: number,
|
|
251
|
+
velocity: number,
|
|
252
|
+
userInputState: Enum.UserInputState
|
|
253
|
+
)
|
|
213
254
|
if self._zoomedCamera then
|
|
214
255
|
if userInputState == Enum.UserInputState.Begin then
|
|
215
256
|
self._startZoomScale = self._zoomedCamera.Zoom
|
|
216
|
-
self._zoomedCamera.Zoom = self._startZoomScale*1/scale
|
|
257
|
+
self._zoomedCamera.Zoom = self._startZoomScale * 1 / scale
|
|
217
258
|
elseif userInputState == Enum.UserInputState.End then
|
|
218
|
-
self._zoomedCamera.Zoom = self._startZoomScale*1/scale
|
|
219
|
-
self._zoomedCamera.TargetZoom = self._zoomedCamera.Zoom + -velocity/5
|
|
259
|
+
self._zoomedCamera.Zoom = self._startZoomScale * 1 / scale
|
|
260
|
+
self._zoomedCamera.TargetZoom = self._zoomedCamera.Zoom + -velocity / 5
|
|
220
261
|
elseif userInputState == Enum.UserInputState.Change then
|
|
221
262
|
if self._startZoomScale then
|
|
222
|
-
self._zoomedCamera.TargetZoom = self._startZoomScale*1/scale
|
|
263
|
+
self._zoomedCamera.TargetZoom = self._startZoomScale * 1 / scale
|
|
223
264
|
self._zoomedCamera.Zoom = self._zoomedCamera.TargetZoom
|
|
224
265
|
else
|
|
225
266
|
warn("[CameraControls._handleTouchPinch] - No self._startZoomScale")
|
|
@@ -229,40 +270,40 @@ function CameraControls:_handleTouchPinch(scale, velocity, userInputState)
|
|
|
229
270
|
end
|
|
230
271
|
|
|
231
272
|
-- This is also a Roblox algorithm. Not sure why screen resolution is locked like it is.
|
|
232
|
-
function CameraControls
|
|
233
|
-
local xTheta = (translationVector.
|
|
234
|
-
local yTheta = (translationVector.
|
|
273
|
+
function CameraControls._mouseTranslationToAngle(_self: CameraControls, translationVector: Vector3): Vector2
|
|
274
|
+
local xTheta = (translationVector.X / 1920)
|
|
275
|
+
local yTheta = (translationVector.Y / 1200)
|
|
235
276
|
return Vector2.new(xTheta, yTheta)
|
|
236
277
|
end
|
|
237
278
|
|
|
238
|
-
function CameraControls
|
|
279
|
+
function CameraControls.SetVelocityStrength(self: CameraControls, strength: number): ()
|
|
239
280
|
self._strength = strength
|
|
240
281
|
end
|
|
241
282
|
|
|
242
|
-
function CameraControls
|
|
243
|
-
strength =
|
|
283
|
+
function CameraControls._getVelocityTracker(_self: CameraControls, initialStrength: number?, startVelocity: Vector2)
|
|
284
|
+
local strength = initialStrength or 1
|
|
244
285
|
|
|
245
|
-
local lastUpdate =
|
|
246
|
-
local velocity = startVelocity
|
|
286
|
+
local lastUpdate = os.clock()
|
|
287
|
+
local velocity: Vector2 = startVelocity
|
|
247
288
|
|
|
248
289
|
return {
|
|
249
|
-
Update = function(
|
|
250
|
-
local elapsed =
|
|
251
|
-
lastUpdate =
|
|
252
|
-
velocity = velocity / (2^(elapsed/strength)) + (delta / (0.0001 + elapsed)) * strength
|
|
253
|
-
end
|
|
290
|
+
Update = function(_this, delta: Vector2)
|
|
291
|
+
local elapsed = os.clock() - lastUpdate
|
|
292
|
+
lastUpdate = os.clock()
|
|
293
|
+
velocity = velocity / (2 ^ (elapsed / strength)) + (delta / (0.0001 + elapsed)) * strength
|
|
294
|
+
end,
|
|
254
295
|
GetVelocity = function(this)
|
|
255
|
-
this:Update(startVelocity*0)
|
|
296
|
+
this:Update(startVelocity * 0)
|
|
256
297
|
return velocity
|
|
257
|
-
end
|
|
298
|
+
end,
|
|
258
299
|
}
|
|
259
300
|
end
|
|
260
301
|
|
|
261
|
-
function CameraControls
|
|
302
|
+
function CameraControls._handleMouseMovement(self: CameraControls, inputObject: InputObject)
|
|
262
303
|
if self._lastMousePosition then
|
|
263
304
|
if self._rotatedCamera then
|
|
264
305
|
-- This calculation may seem weird, but either .Position updates (if it's locked), or .Delta updates (if it's not).
|
|
265
|
-
local delta
|
|
306
|
+
local delta: Vector3
|
|
266
307
|
if InputObjectUtils.isMouseUserInputType(inputObject.UserInputType) then
|
|
267
308
|
delta = -inputObject.Delta + self._lastMousePosition - inputObject.Position
|
|
268
309
|
else
|
|
@@ -281,11 +322,11 @@ function CameraControls:_handleMouseMovement(inputObject)
|
|
|
281
322
|
end
|
|
282
323
|
end
|
|
283
324
|
|
|
284
|
-
function CameraControls
|
|
325
|
+
function CameraControls._handleThumbstickInput(self: CameraControls, inputObject: InputObject)
|
|
285
326
|
self._gamepadRotateModel:HandleThumbstickInput(inputObject)
|
|
286
327
|
end
|
|
287
328
|
|
|
288
|
-
function CameraControls
|
|
329
|
+
function CameraControls._applyRotVelocityTracker(self: CameraControls, rotVelocityTracker)
|
|
289
330
|
if self._rotatedCamera then
|
|
290
331
|
local position = self._rotatedCamera.AngleXZ
|
|
291
332
|
local velocity = rotVelocityTracker:GetVelocity().X
|
|
@@ -300,7 +341,9 @@ function CameraControls:_applyRotVelocityTracker(rotVelocityTracker)
|
|
|
300
341
|
end
|
|
301
342
|
end
|
|
302
343
|
|
|
303
|
-
function CameraControls
|
|
344
|
+
function CameraControls._endDrag(self: CameraControls): ()
|
|
345
|
+
assert(self._maid, "Must be enabled")
|
|
346
|
+
|
|
304
347
|
if self._rotVelocityTracker then
|
|
305
348
|
self:_applyRotVelocityTracker(self._rotVelocityTracker)
|
|
306
349
|
self._rotVelocityTracker = nil
|
|
@@ -312,7 +355,9 @@ function CameraControls:_endDrag()
|
|
|
312
355
|
self._maid._dragMaid = nil
|
|
313
356
|
end
|
|
314
357
|
|
|
315
|
-
function CameraControls
|
|
358
|
+
function CameraControls._handleGamepadRotateStop(self: CameraControls): ()
|
|
359
|
+
assert(self._maid, "Must be enabled")
|
|
360
|
+
|
|
316
361
|
if self._rotVelocityTracker then
|
|
317
362
|
self:_applyRotVelocityTracker(self._rotVelocityTracker)
|
|
318
363
|
self._rotVelocityTracker = nil
|
|
@@ -321,7 +366,9 @@ function CameraControls:_handleGamepadRotateStop()
|
|
|
321
366
|
self._maid._dragMaid = nil
|
|
322
367
|
end
|
|
323
368
|
|
|
324
|
-
function CameraControls
|
|
369
|
+
function CameraControls._handleGamepadRotateStart(self: CameraControls): ()
|
|
370
|
+
assert(self._maid, "Must be enabled")
|
|
371
|
+
|
|
325
372
|
if not self._rotatedCamera then
|
|
326
373
|
self._maid._dragMaid = nil
|
|
327
374
|
return
|
|
@@ -334,7 +381,7 @@ function CameraControls:_handleGamepadRotateStart()
|
|
|
334
381
|
end
|
|
335
382
|
|
|
336
383
|
maid:GiveTask(RunService.Stepped:Connect(function()
|
|
337
|
-
local deltaAngle = 0.1*self._gamepadRotateModel:GetThumbstickDeltaAngle()
|
|
384
|
+
local deltaAngle: Vector2 = 0.1 * self._gamepadRotateModel:GetThumbstickDeltaAngle()
|
|
338
385
|
|
|
339
386
|
if self._rotatedCamera then
|
|
340
387
|
self._rotatedCamera:RotateXY(deltaAngle)
|
|
@@ -348,10 +395,10 @@ function CameraControls:_handleGamepadRotateStart()
|
|
|
348
395
|
self._maid._dragMaid = maid
|
|
349
396
|
end
|
|
350
397
|
|
|
351
|
-
function CameraControls
|
|
398
|
+
function CameraControls.Destroy(self: CameraControls)
|
|
352
399
|
self:Disable()
|
|
353
400
|
self._gamepadRotateModel:Destroy()
|
|
354
|
-
setmetatable(self, nil)
|
|
401
|
+
setmetatable(self :: any, nil)
|
|
355
402
|
end
|
|
356
403
|
|
|
357
|
-
return CameraControls
|
|
404
|
+
return CameraControls
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
3
|
+
Utility classes to work with gamepad thumbsticks
|
|
2
4
|
@class CameraGamepadInputUtils
|
|
3
5
|
]=]
|
|
4
6
|
|
|
@@ -8,40 +10,53 @@ local CameraGamepadInputUtils = {}
|
|
|
8
10
|
-- the larger K is the more straight/linear the curve gets
|
|
9
11
|
local k = 0.35
|
|
10
12
|
local lowerK = 0.8
|
|
11
|
-
local function SCurveTranform(t)
|
|
13
|
+
local function SCurveTranform(t: number): number
|
|
12
14
|
t = math.clamp(t, -1, 1)
|
|
13
15
|
if t >= 0 then
|
|
14
|
-
return (k*t) / (k - t + 1)
|
|
16
|
+
return (k * t) / (k - t + 1)
|
|
15
17
|
end
|
|
16
|
-
return -((lowerK
|
|
18
|
+
return -((lowerK * -t) / (lowerK + t + 1))
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
local DEADZONE = 0.1
|
|
20
|
-
local function toSCurveSpace(t)
|
|
21
|
-
return (1 + DEADZONE) * (2*math.abs(t) - 1) - DEADZONE
|
|
22
|
+
local function toSCurveSpace(t: number): number
|
|
23
|
+
return (1 + DEADZONE) * (2 * math.abs(t) - 1) - DEADZONE
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
local function fromSCurveSpace(t)
|
|
25
|
-
return t/2 + 0.5
|
|
26
|
+
local function fromSCurveSpace(t: number): number
|
|
27
|
+
return t / 2 + 0.5
|
|
26
28
|
end
|
|
27
29
|
|
|
28
|
-
function
|
|
30
|
+
local function onAxis(axisValue: number): number
|
|
31
|
+
local sign = 1
|
|
32
|
+
if axisValue < 0 then
|
|
33
|
+
sign = -1
|
|
34
|
+
end
|
|
35
|
+
local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math.abs(axisValue))))
|
|
36
|
+
point = point * sign
|
|
37
|
+
return math.clamp(point, -1, 1)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
--[=[
|
|
41
|
+
Returns true if the input is outside the deadzone.
|
|
42
|
+
|
|
43
|
+
@param inputObject InputObject
|
|
44
|
+
@return boolean
|
|
45
|
+
]=]
|
|
46
|
+
function CameraGamepadInputUtils.outOfDeadZone(inputObject: InputObject): boolean
|
|
29
47
|
local stickOffset = inputObject.Position
|
|
30
48
|
return stickOffset.Magnitude >= DEADZONE
|
|
31
49
|
end
|
|
32
50
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
local sign = 1
|
|
36
|
-
if axisValue < 0 then
|
|
37
|
-
sign = -1
|
|
38
|
-
end
|
|
39
|
-
local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math.abs(axisValue))))
|
|
40
|
-
point = point * sign
|
|
41
|
-
return math.clamp(point, -1, 1)
|
|
42
|
-
end
|
|
43
|
-
return Vector2.new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y))
|
|
44
|
-
end
|
|
51
|
+
--[=[
|
|
52
|
+
Converts a thumbstick position to a curve space.
|
|
45
53
|
|
|
54
|
+
@within CameraGamepadInputUtils
|
|
55
|
+
@param thumbstickPosition Vector2
|
|
56
|
+
@return Vector2
|
|
57
|
+
]=]
|
|
58
|
+
function CameraGamepadInputUtils.gamepadLinearToCurve(thumbstickPosition: Vector2): Vector2
|
|
59
|
+
return Vector2.new(onAxis(thumbstickPosition.X), onAxis(thumbstickPosition.Y))
|
|
60
|
+
end
|
|
46
61
|
|
|
47
|
-
return CameraGamepadInputUtils
|
|
62
|
+
return CameraGamepadInputUtils
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Rotation model for gamepad controls that uses Roblox's curve smoothing and other components.
|
|
3
4
|
|
|
@@ -15,12 +16,22 @@ local GamepadRotateModel = setmetatable({}, BaseObject)
|
|
|
15
16
|
GamepadRotateModel.__index = GamepadRotateModel
|
|
16
17
|
GamepadRotateModel.ClassName = "GamepadRotateModel"
|
|
17
18
|
|
|
19
|
+
export type GamepadRotateModel = typeof(setmetatable(
|
|
20
|
+
{} :: {
|
|
21
|
+
_lastInputObject: InputObject?,
|
|
22
|
+
_rampVelocityX: AccelTween.AccelTween,
|
|
23
|
+
_rampVelocityY: AccelTween.AccelTween,
|
|
24
|
+
IsRotating: ValueObject.ValueObject<boolean>,
|
|
25
|
+
},
|
|
26
|
+
{} :: typeof({ __index = GamepadRotateModel })
|
|
27
|
+
)) & BaseObject.BaseObject
|
|
28
|
+
|
|
18
29
|
--[=[
|
|
19
30
|
Constructs a new GamepadRotateModel.
|
|
20
31
|
@return GamepadRotateModel
|
|
21
32
|
]=]
|
|
22
|
-
function GamepadRotateModel.new()
|
|
23
|
-
local self = setmetatable(BaseObject.new(), GamepadRotateModel)
|
|
33
|
+
function GamepadRotateModel.new(): GamepadRotateModel
|
|
34
|
+
local self: GamepadRotateModel = setmetatable(BaseObject.new() :: any, GamepadRotateModel)
|
|
24
35
|
|
|
25
36
|
self._rampVelocityX = AccelTween.new(25)
|
|
26
37
|
self._rampVelocityY = AccelTween.new(25)
|
|
@@ -40,7 +51,7 @@ end
|
|
|
40
51
|
|
|
41
52
|
@param acceleration number
|
|
42
53
|
]=]
|
|
43
|
-
function GamepadRotateModel
|
|
54
|
+
function GamepadRotateModel.SetAcceleration(self: GamepadRotateModel, acceleration: number): ()
|
|
44
55
|
assert(type(acceleration) == "number", "Bad acceleration")
|
|
45
56
|
|
|
46
57
|
self._rampVelocityX.a = acceleration
|
|
@@ -51,7 +62,7 @@ end
|
|
|
51
62
|
Gets the delta for the thumbstick
|
|
52
63
|
@return Vector2
|
|
53
64
|
]=]
|
|
54
|
-
function GamepadRotateModel
|
|
65
|
+
function GamepadRotateModel.GetThumbstickDeltaAngle(self: GamepadRotateModel): Vector2
|
|
55
66
|
if not self._lastInputObject then
|
|
56
67
|
return Vector2.zero
|
|
57
68
|
end
|
|
@@ -62,7 +73,7 @@ end
|
|
|
62
73
|
--[=[
|
|
63
74
|
Stops rotation
|
|
64
75
|
]=]
|
|
65
|
-
function GamepadRotateModel
|
|
76
|
+
function GamepadRotateModel.StopRotate(self: GamepadRotateModel): ()
|
|
66
77
|
self._lastInputObject = nil
|
|
67
78
|
self._rampVelocityX.t = 0
|
|
68
79
|
self._rampVelocityX.p = self._rampVelocityX.t
|
|
@@ -79,16 +90,15 @@ end
|
|
|
79
90
|
|
|
80
91
|
@param inputObject InputObject
|
|
81
92
|
]=]
|
|
82
|
-
function GamepadRotateModel
|
|
93
|
+
function GamepadRotateModel.HandleThumbstickInput(self: GamepadRotateModel, inputObject: InputObject): ()
|
|
83
94
|
if CameraGamepadInputUtils.outOfDeadZone(inputObject) then
|
|
84
95
|
self._lastInputObject = inputObject
|
|
85
96
|
|
|
86
|
-
local stickOffset =
|
|
87
|
-
stickOffset = Vector2.new(-stickOffset.x, stickOffset.y) -- Invert axis!
|
|
88
|
-
|
|
97
|
+
local stickOffset = Vector2.new(-inputObject.Position.X, inputObject.Position.Y) -- Invert axis!
|
|
89
98
|
local adjustedStickOffset = CameraGamepadInputUtils.gamepadLinearToCurve(stickOffset)
|
|
90
|
-
|
|
91
|
-
self.
|
|
99
|
+
|
|
100
|
+
self._rampVelocityX.t = adjustedStickOffset.X
|
|
101
|
+
self._rampVelocityY.t = adjustedStickOffset.Y
|
|
92
102
|
|
|
93
103
|
self.IsRotating.Value = true
|
|
94
104
|
else
|
|
@@ -96,4 +106,4 @@ function GamepadRotateModel:HandleThumbstickInput(inputObject)
|
|
|
96
106
|
end
|
|
97
107
|
end
|
|
98
108
|
|
|
99
|
-
return GamepadRotateModel
|
|
109
|
+
return GamepadRotateModel
|
|
@@ -1,19 +1,28 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
A CameraEffect is something that can be resolved into a CameraState providing source
|
|
3
4
|
@class CameraEffectUtils
|
|
4
5
|
]=]
|
|
5
6
|
|
|
7
|
+
local require = require(script.Parent.loader).load(script)
|
|
8
|
+
|
|
9
|
+
local CameraState = require("CameraState")
|
|
10
|
+
|
|
6
11
|
--[=[
|
|
7
12
|
Represents an effect that can be used in combination with other effects.
|
|
8
13
|
@interface CameraEffect
|
|
9
14
|
.CameraState CameraState
|
|
10
15
|
@within CameraEffectUtils
|
|
11
16
|
]=]
|
|
17
|
+
export type CameraEffect = {
|
|
18
|
+
CameraState: CameraState.CameraState,
|
|
19
|
+
}
|
|
12
20
|
|
|
13
21
|
--[=[
|
|
14
22
|
Something that is like a camera
|
|
15
23
|
@type CameraLike CameraEffect | CameraState
|
|
16
24
|
@within CameraEffectUtils
|
|
17
25
|
]=]
|
|
26
|
+
export type CameraLike = CameraEffect | CameraState.CameraState
|
|
18
27
|
|
|
19
|
-
return {}
|
|
28
|
+
return {}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
For effects that can be easily bound in scope
|
|
3
4
|
@class CustomCameraEffect
|
|
@@ -5,25 +6,40 @@
|
|
|
5
6
|
|
|
6
7
|
local require = require(script.Parent.loader).load(script)
|
|
7
8
|
|
|
9
|
+
local CameraEffectUtils = require("CameraEffectUtils")
|
|
10
|
+
local CameraState = require("CameraState")
|
|
8
11
|
local SummedCamera = require("SummedCamera")
|
|
9
12
|
|
|
10
13
|
local CustomCameraEffect = {}
|
|
11
14
|
CustomCameraEffect.ClassName = "CustomCameraEffect"
|
|
12
15
|
|
|
16
|
+
export type ComputeCameraState = () -> CameraState.CameraState
|
|
17
|
+
|
|
18
|
+
export type CustomCameraEffect = typeof(setmetatable(
|
|
19
|
+
{} :: {
|
|
20
|
+
CameraState: CameraState.CameraState,
|
|
21
|
+
_getCurrentStateFunc: ComputeCameraState,
|
|
22
|
+
},
|
|
23
|
+
{} :: typeof({ __index = CustomCameraEffect })
|
|
24
|
+
)) & CameraEffectUtils.CameraEffect
|
|
25
|
+
|
|
13
26
|
--[=[
|
|
14
27
|
Constructs a new custom camera effect
|
|
15
28
|
@param getCurrentStateFunc () -> CameraState -- Custom effect generator
|
|
16
29
|
@return CustomCameraEffect
|
|
17
30
|
]=]
|
|
18
|
-
function CustomCameraEffect.new(getCurrentStateFunc)
|
|
19
|
-
local self = setmetatable({}, CustomCameraEffect)
|
|
31
|
+
function CustomCameraEffect.new(getCurrentStateFunc: ComputeCameraState): CustomCameraEffect
|
|
32
|
+
local self: CustomCameraEffect = setmetatable({} :: any, CustomCameraEffect)
|
|
20
33
|
|
|
21
34
|
self._getCurrentStateFunc = getCurrentStateFunc or error("getCurrentStateFunc is required")
|
|
22
35
|
|
|
23
36
|
return self
|
|
24
37
|
end
|
|
25
38
|
|
|
26
|
-
function CustomCameraEffect
|
|
39
|
+
function CustomCameraEffect.__add(
|
|
40
|
+
self: CustomCameraEffect,
|
|
41
|
+
other: CameraEffectUtils.CameraEffect
|
|
42
|
+
): SummedCamera.SummedCamera
|
|
27
43
|
return SummedCamera.new(self, other)
|
|
28
44
|
end
|
|
29
45
|
|
|
@@ -33,7 +49,7 @@ end
|
|
|
33
49
|
@prop CameraState CameraState
|
|
34
50
|
@within CustomCameraEffect
|
|
35
51
|
]=]
|
|
36
|
-
function CustomCameraEffect
|
|
52
|
+
function CustomCameraEffect.__index(self: CustomCameraEffect, index)
|
|
37
53
|
if index == "CameraState" then
|
|
38
54
|
return self._getCurrentStateFunc()
|
|
39
55
|
else
|
|
@@ -41,4 +57,4 @@ function CustomCameraEffect:__index(index)
|
|
|
41
57
|
end
|
|
42
58
|
end
|
|
43
59
|
|
|
44
|
-
return CustomCameraEffect
|
|
60
|
+
return CustomCameraEffect
|