@rbxts/vfx-forge 2.2.2-ts.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/LICENSE +82 -0
- package/README.md +39 -0
- package/out/forge-vfx/effects/beam.luau +312 -0
- package/out/forge-vfx/effects/bezier.luau +392 -0
- package/out/forge-vfx/effects/camera_shake.luau +200 -0
- package/out/forge-vfx/effects/lightning.luau +1183 -0
- package/out/forge-vfx/effects/mesh.luau +466 -0
- package/out/forge-vfx/effects/particle.luau +64 -0
- package/out/forge-vfx/effects/randomizer.luau +110 -0
- package/out/forge-vfx/effects/screen.luau +61 -0
- package/out/forge-vfx/effects/shockwave_debris.luau +277 -0
- package/out/forge-vfx/effects/shockwave_line.luau +356 -0
- package/out/forge-vfx/effects/shockwave_ring.luau +252 -0
- package/out/forge-vfx/effects/sound.luau +311 -0
- package/out/forge-vfx/effects/spin.luau +88 -0
- package/out/forge-vfx/effects/tweener.luau +122 -0
- package/out/forge-vfx/emitters.luau +387 -0
- package/out/forge-vfx/index.d.ts +356 -0
- package/out/forge-vfx/init.luau +279 -0
- package/out/forge-vfx/mod/attributes.luau +227 -0
- package/out/forge-vfx/mod/color/Oklab.luau +93 -0
- package/out/forge-vfx/mod/color/sRGB.luau +71 -0
- package/out/forge-vfx/mod/common/bezier.luau +372 -0
- package/out/forge-vfx/mod/common/flipbook.luau +102 -0
- package/out/forge-vfx/mod/lerp.luau +210 -0
- package/out/forge-vfx/mod/logger.luau +20 -0
- package/out/forge-vfx/mod/shape.luau +207 -0
- package/out/forge-vfx/mod/tween.luau +161 -0
- package/out/forge-vfx/mod/utility.luau +707 -0
- package/out/forge-vfx/obj/Bezier.luau +268 -0
- package/out/forge-vfx/obj/ObjectCache.luau +289 -0
- package/out/forge-vfx/services/caches.luau +62 -0
- package/out/forge-vfx/services/effects.luau +234 -0
- package/out/forge-vfx/services/enabled_effects.luau +120 -0
- package/out/forge-vfx/services/texture_loader.luau +174 -0
- package/out/forge-vfx/types.luau +43 -0
- package/out/index.d.ts +3 -0
- package/out/init.luau +5 -0
- package/out/shake.d.ts +2 -0
- package/out/shake.luau +6 -0
- package/out/tsconfig.tsbuildinfo +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
local TS = _G[script.Parent.Parent.Parent]
|
|
2
|
+
--!nolint LocalShadow
|
|
3
|
+
local RunService = game:GetService("RunService")
|
|
4
|
+
|
|
5
|
+
local attr = require(script.Parent.Parent.mod.attributes)
|
|
6
|
+
local tween = require(script.Parent.Parent.mod.tween)
|
|
7
|
+
local types = require(script.Parent.Parent.types)
|
|
8
|
+
local utility = require(script.Parent.Parent.mod.utility)
|
|
9
|
+
local bezier_common = require(script.Parent.Parent.mod.common.bezier)
|
|
10
|
+
|
|
11
|
+
local Bezier = require(script.Parent.Parent.obj.Bezier)
|
|
12
|
+
local ObjectCache = require(script.Parent.Parent.obj.ObjectCache)
|
|
13
|
+
|
|
14
|
+
local bezier = {}
|
|
15
|
+
|
|
16
|
+
local part_cache: ObjectCache.ObjectCache?
|
|
17
|
+
|
|
18
|
+
function bezier.init(cache)
|
|
19
|
+
part_cache = cache
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
function bezier.deinit()
|
|
23
|
+
part_cache = nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
local function readBezierAttributes(ref: Attachment)
|
|
27
|
+
return {
|
|
28
|
+
-- animation
|
|
29
|
+
facePath = attr.get(ref, "FacePath", false),
|
|
30
|
+
arcSpace = attr.get(ref, "ArcSpace", false),
|
|
31
|
+
|
|
32
|
+
-- rotation
|
|
33
|
+
rotSpeedStart = attr.getRange(ref, "RotSpeed_Start", NumberRange.new(0, 0)),
|
|
34
|
+
rotSpeedEnd = attr.getRange(ref, "RotSpeed_End", NumberRange.new(0, 0)),
|
|
35
|
+
minInitRot = attr.get(ref, "MinInitRot", vector.zero),
|
|
36
|
+
maxInitRot = attr.get(ref, "MaxInitRot", vector.zero),
|
|
37
|
+
|
|
38
|
+
-- curves
|
|
39
|
+
speedCurve = attr.get(ref, "Speed_Curve", utility.default_bezier),
|
|
40
|
+
speedDuration = attr.get(ref, "Speed_Duration", 0.1),
|
|
41
|
+
easingCurve = attr.get(ref, "Easing_Curve", utility.linear_bezier),
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
function bezier.emit(ref: Attachment, refObj: Part, scope: types.scope, mustEmit: boolean?)
|
|
46
|
+
local root = ref:FindFirstChild("Points")
|
|
47
|
+
|
|
48
|
+
if not root or not root:IsA("Attachment") or not part_cache then
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
local common = bezier_common.readCommonAttributes(ref)
|
|
53
|
+
local attrs = readBezierAttributes(ref)
|
|
54
|
+
|
|
55
|
+
local drawFunc = bezier_common.drawFuncMap[common.shapeType]
|
|
56
|
+
and bezier_common.drawFuncMap[common.shapeType][common.shapeStyle]
|
|
57
|
+
|
|
58
|
+
if not drawFunc then
|
|
59
|
+
return
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
local useDuration = common.emitDuration > 0
|
|
63
|
+
|
|
64
|
+
task.wait(common.emitDelay)
|
|
65
|
+
|
|
66
|
+
if useDuration and not mustEmit then
|
|
67
|
+
attr.trigger(ref, "Enabled", true)
|
|
68
|
+
|
|
69
|
+
if common.speedStart ~= common.speedEnd then
|
|
70
|
+
attr.setState(ref, "SpeedTweening", true)
|
|
71
|
+
|
|
72
|
+
table.insert(
|
|
73
|
+
scope,
|
|
74
|
+
tween.fromParams(
|
|
75
|
+
attrs.speedCurve,
|
|
76
|
+
attrs.speedDuration,
|
|
77
|
+
function(alpha, deltaTime)
|
|
78
|
+
attr.setState(ref, "SpeedOverride", utility.lerp(common.speedStart, common.speedEnd, alpha))
|
|
79
|
+
return deltaTime
|
|
80
|
+
end,
|
|
81
|
+
nil,
|
|
82
|
+
function()
|
|
83
|
+
attr.setState(ref, "SpeedTweening", nil)
|
|
84
|
+
end
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
task.wait(common.emitDuration)
|
|
90
|
+
|
|
91
|
+
attr.trigger(ref, "Enabled", false)
|
|
92
|
+
attr.clearState(ref)
|
|
93
|
+
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
if common.emitCount <= 0 then
|
|
98
|
+
return
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
local parent = bezier_common.validateParent(ref)
|
|
102
|
+
|
|
103
|
+
if not parent then
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
local originCFrame, originSize = utility.getTransformedOriginExtents(parent)
|
|
108
|
+
|
|
109
|
+
if not originCFrame then
|
|
110
|
+
return
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
local endPoint, endT1 = bezier_common.findEndAttachments(ref)
|
|
114
|
+
local points = utility.getBezierPoints(root)
|
|
115
|
+
|
|
116
|
+
local rng = Random.new()
|
|
117
|
+
local baseBezier = not endPoint and Bezier.new(points)
|
|
118
|
+
|
|
119
|
+
-- Hitbox params
|
|
120
|
+
local hitboxParams = bezier_common.createHitboxParams({
|
|
121
|
+
enabled = common.hitboxEnabled,
|
|
122
|
+
collisionGroup = common.hitboxCollisionGroup,
|
|
123
|
+
filterTag = common.hitboxFilterTag,
|
|
124
|
+
filterType = common.hitboxFilterType,
|
|
125
|
+
ignoreCanCollide = common.hitboxIgnoreCanCollide,
|
|
126
|
+
}, parent, root)
|
|
127
|
+
|
|
128
|
+
local promises = {}
|
|
129
|
+
|
|
130
|
+
for _ = 1, common.emitCount do
|
|
131
|
+
local rotSpeedStart = rng:NextNumber(attrs.rotSpeedStart.Min, attrs.rotSpeedStart.Max)
|
|
132
|
+
local rotSpeedEnd = rng:NextNumber(attrs.rotSpeedEnd.Min, attrs.rotSpeedEnd.Max)
|
|
133
|
+
|
|
134
|
+
local initRot = vector.create(
|
|
135
|
+
rng:NextNumber(attrs.minInitRot.x, attrs.maxInitRot.x),
|
|
136
|
+
rng:NextNumber(attrs.minInitRot.y, attrs.maxInitRot.y),
|
|
137
|
+
rng:NextNumber(attrs.minInitRot.z, attrs.maxInitRot.z)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
local duration = rng:NextNumber(common.duration.Min, common.duration.Max)
|
|
141
|
+
local lifetime = common.projectileEnabled
|
|
142
|
+
and rng:NextNumber(common.projectileLifetime.Min, common.projectileLifetime.Max)
|
|
143
|
+
|
|
144
|
+
table.insert(
|
|
145
|
+
promises,
|
|
146
|
+
TS.Promise.new(function(resolve)
|
|
147
|
+
-- Calculate emission CFrame
|
|
148
|
+
local cf = bezier_common.calculateEmissionCFrame(originCFrame, originSize, {
|
|
149
|
+
face = common.face,
|
|
150
|
+
spreadAngle = common.spreadAngle,
|
|
151
|
+
mirror = common.mirror,
|
|
152
|
+
mirrorRot = common.mirrorRot,
|
|
153
|
+
partial = common.partial,
|
|
154
|
+
emissionDirection = common.emissionDirection,
|
|
155
|
+
}, drawFunc, rng, endPoint, parent:IsA("Attachment"))
|
|
156
|
+
|
|
157
|
+
-- create bezier
|
|
158
|
+
local pathBezier = baseBezier or bezier_common.createBezierWithEndpoint(points, cf, endPoint, endT1)
|
|
159
|
+
local getPos = bezier_common.createPosGetter(pathBezier, points, cf, endPoint, attrs.arcSpace)
|
|
160
|
+
|
|
161
|
+
-- get part from cache
|
|
162
|
+
local cacheId = utility.getRandomId()
|
|
163
|
+
|
|
164
|
+
if not part_cache then
|
|
165
|
+
resolve()
|
|
166
|
+
return
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
local objAbstr = part_cache:get(cacheId)
|
|
170
|
+
objAbstr.CFrame = CFrame.new(getPos(0))
|
|
171
|
+
|
|
172
|
+
local obj = objAbstr._getReal()
|
|
173
|
+
|
|
174
|
+
utility.copyProperties(refObj, obj, utility.COPY_PART_PROPERTIES)
|
|
175
|
+
utility.copyProperties(refObj, obj, utility.COPY_EXTENDED_PART_PROPERTIES)
|
|
176
|
+
|
|
177
|
+
-- clone children from reference
|
|
178
|
+
do
|
|
179
|
+
local clone = refObj:Clone()
|
|
180
|
+
for _, child in clone:GetChildren() do
|
|
181
|
+
child.Parent = obj
|
|
182
|
+
end
|
|
183
|
+
clone:Destroy()
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
local emitOnFinish = scope.effects.prepareEmitOnFinish(obj, scope)
|
|
187
|
+
local env = scope.effects.emitNested(obj, scope.depth + 1)
|
|
188
|
+
|
|
189
|
+
table.insert(promises, env.Finished)
|
|
190
|
+
|
|
191
|
+
table.insert(scope, function()
|
|
192
|
+
if part_cache then
|
|
193
|
+
part_cache:free(cacheId)
|
|
194
|
+
end
|
|
195
|
+
end)
|
|
196
|
+
|
|
197
|
+
-- animation state
|
|
198
|
+
local lastPos = Vector3.zero
|
|
199
|
+
local lastVelocity = Vector3.zero
|
|
200
|
+
|
|
201
|
+
local didHit = false
|
|
202
|
+
local finished = false
|
|
203
|
+
|
|
204
|
+
local prevCF = CFrame.identity
|
|
205
|
+
local currentSpeed = common.speedStart
|
|
206
|
+
|
|
207
|
+
local currentRot = CFrame.fromOrientation(initRot.x, initRot.y, initRot.z)
|
|
208
|
+
local currentRotSpeed = rotSpeedStart
|
|
209
|
+
|
|
210
|
+
local function onFinish()
|
|
211
|
+
if finished then
|
|
212
|
+
return
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
if common.syncPosition then
|
|
216
|
+
local initOrigin = utility.getTransformedOriginExtents(parent)
|
|
217
|
+
local initPartPos = objAbstr.CFrame
|
|
218
|
+
|
|
219
|
+
local function updatePos()
|
|
220
|
+
objAbstr.CFrame = utility.getTransformedOriginExtents(parent) * initOrigin:ToObjectSpace(initPartPos)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
local id = utility.getRandomId()
|
|
224
|
+
|
|
225
|
+
RunService:BindToRenderStep(id, utility.RENDER_PRIORITY + scope.depth, updatePos)
|
|
226
|
+
|
|
227
|
+
table.insert(scope, function()
|
|
228
|
+
RunService:UnbindFromRenderStep(id)
|
|
229
|
+
end)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
finished = true
|
|
233
|
+
|
|
234
|
+
local finishEnv = scope.effects.emitOnFinish(emitOnFinish, obj, scope.depth + 1)
|
|
235
|
+
finishEnv.Finished:finally(function()
|
|
236
|
+
resolve()
|
|
237
|
+
end)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
local function shapecast()
|
|
241
|
+
if not common.hitboxEnabled then
|
|
242
|
+
return false
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
local result = workspace:GetPartsInPart(obj, hitboxParams)
|
|
246
|
+
return result[1] ~= nil
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
-- Speed tween
|
|
250
|
+
local speedTween
|
|
251
|
+
|
|
252
|
+
if common.speedStart ~= common.speedEnd and not attr.getState(ref, "SpeedOverride", nil) then
|
|
253
|
+
speedTween = tween.fromParams(attrs.speedCurve, attrs.speedDuration, function(alpha, deltaTime)
|
|
254
|
+
currentSpeed = utility.lerp(common.speedStart, common.speedEnd, alpha)
|
|
255
|
+
return deltaTime
|
|
256
|
+
end)
|
|
257
|
+
|
|
258
|
+
table.insert(scope, speedTween)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
local function getEffectiveSpeed()
|
|
262
|
+
return attr.getState(ref, "SpeedOverride", currentSpeed)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
local function isSpeedTweening()
|
|
266
|
+
return if speedTween then speedTween.Connected else attr.getState(ref, "SpeedTweening", false)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
-- Rotation speed tween
|
|
270
|
+
bezier_common.createPropertyTween(scope, ref, "RotSpeed", duration, rotSpeedStart, rotSpeedEnd, function(v)
|
|
271
|
+
currentRotSpeed = v
|
|
272
|
+
end, function()
|
|
273
|
+
return getEffectiveSpeed()
|
|
274
|
+
end, speedTween)
|
|
275
|
+
|
|
276
|
+
-- main animation
|
|
277
|
+
table.insert(
|
|
278
|
+
scope,
|
|
279
|
+
tween.fromParams(
|
|
280
|
+
attrs.easingCurve,
|
|
281
|
+
duration,
|
|
282
|
+
function(alpha, deltaTime, elapsed)
|
|
283
|
+
local pos1 = getPos(alpha)
|
|
284
|
+
local newCF = CFrame.new(pos1)
|
|
285
|
+
|
|
286
|
+
if attrs.facePath then
|
|
287
|
+
local pos2 = getPos(math.clamp((elapsed + (1.6666666666666665E-2)) / duration, 0, 1))
|
|
288
|
+
|
|
289
|
+
if pos1 ~= pos2 then
|
|
290
|
+
newCF = CFrame.lookAt(pos1, pos2)
|
|
291
|
+
else
|
|
292
|
+
newCF *= prevCF.Rotation
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
local add = initRot:Sign() * currentRotSpeed * utility.DEG_TO_RAD * deltaTime
|
|
297
|
+
currentRot *= CFrame.fromOrientation(add.x, add.y, add.z)
|
|
298
|
+
|
|
299
|
+
-- save current cframe before applying rotation
|
|
300
|
+
prevCF = newCF
|
|
301
|
+
newCF *= currentRot
|
|
302
|
+
|
|
303
|
+
if common.syncPosition then
|
|
304
|
+
objAbstr.CFrame = utility.getTransformedOriginExtents(parent) * originCFrame:ToObjectSpace(newCF)
|
|
305
|
+
else
|
|
306
|
+
objAbstr.CFrame = newCF
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
lastVelocity = (pos1 - lastPos) / deltaTime
|
|
310
|
+
lastPos = pos1
|
|
311
|
+
|
|
312
|
+
if shapecast() then
|
|
313
|
+
onFinish()
|
|
314
|
+
didHit = true
|
|
315
|
+
return nil
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
local speed = getEffectiveSpeed()
|
|
319
|
+
currentSpeed = speed
|
|
320
|
+
|
|
321
|
+
if speed == 0 and not isSpeedTweening() then
|
|
322
|
+
return nil
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
if (common.projectileEnabled and alpha * duration < lifetime) or not common.projectileEnabled then
|
|
326
|
+
return deltaTime * speed
|
|
327
|
+
else
|
|
328
|
+
onFinish()
|
|
329
|
+
return nil
|
|
330
|
+
end
|
|
331
|
+
end,
|
|
332
|
+
speedTween,
|
|
333
|
+
function(organic)
|
|
334
|
+
if not common.projectileEnabled or didHit then
|
|
335
|
+
if organic then
|
|
336
|
+
onFinish()
|
|
337
|
+
end
|
|
338
|
+
return
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
-- Projectile mode
|
|
342
|
+
local dir = if common.projectileMatchEnd and endPoint
|
|
343
|
+
then endPoint.WorldCFrame.LookVector
|
|
344
|
+
else lastVelocity.Unit
|
|
345
|
+
|
|
346
|
+
if dir ~= dir then
|
|
347
|
+
dir = Vector3.zero
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
lastVelocity = dir * common.projectileSpeed
|
|
351
|
+
|
|
352
|
+
local projectileOrigin = obj.Position
|
|
353
|
+
local originCFrameAtProjectileInit = utility.getTransformedOriginExtents(parent)
|
|
354
|
+
|
|
355
|
+
tween.timer(lifetime, function(deltaTime, elapsed)
|
|
356
|
+
if common.syncPosition then
|
|
357
|
+
objAbstr.CFrame = utility.getTransformedOriginExtents(parent)
|
|
358
|
+
* originCFrameAtProjectileInit:ToObjectSpace(CFrame.new(projectileOrigin + lastVelocity * elapsed))
|
|
359
|
+
else
|
|
360
|
+
objAbstr.CFrame = CFrame.new(projectileOrigin + lastVelocity * elapsed) * obj.CFrame.Rotation
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
if shapecast() then
|
|
364
|
+
onFinish()
|
|
365
|
+
didHit = true
|
|
366
|
+
return nil
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
local speed = getEffectiveSpeed()
|
|
370
|
+
currentSpeed = speed
|
|
371
|
+
|
|
372
|
+
return if speed > 0 or (elapsed > 0 and isSpeedTweening()) then deltaTime * speed else nil
|
|
373
|
+
end, speedTween, scope, utility.RENDER_PRIORITY + scope.depth)
|
|
374
|
+
|
|
375
|
+
if not didHit then
|
|
376
|
+
onFinish()
|
|
377
|
+
end
|
|
378
|
+
end,
|
|
379
|
+
true, -- start at zero, important for facepath to work on short durations
|
|
380
|
+
utility.RENDER_PRIORITY + scope.depth
|
|
381
|
+
)
|
|
382
|
+
)
|
|
383
|
+
end)
|
|
384
|
+
)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
TS.Promise.all(promises):await()
|
|
388
|
+
|
|
389
|
+
task.wait(common.destroyDelay)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
return bezier
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
local RunService = game:GetService("RunService")
|
|
2
|
+
|
|
3
|
+
local attr = require(script.Parent.Parent.mod.attributes)
|
|
4
|
+
local tween = require(script.Parent.Parent.mod.tween)
|
|
5
|
+
local types = require(script.Parent.Parent.types)
|
|
6
|
+
local utility = require(script.Parent.Parent.mod.utility)
|
|
7
|
+
|
|
8
|
+
local Shake = require(script.Parent.Parent.Parent.shake)
|
|
9
|
+
|
|
10
|
+
local activeShakes = {}
|
|
11
|
+
local totalShakeCF = CFrame.identity
|
|
12
|
+
|
|
13
|
+
local function updateCamera()
|
|
14
|
+
if #activeShakes == 0 then
|
|
15
|
+
return
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
local camera = workspace.CurrentCamera
|
|
19
|
+
|
|
20
|
+
if not RunService:IsRunning() then
|
|
21
|
+
camera.CFrame *= totalShakeCF:Inverse()
|
|
22
|
+
|
|
23
|
+
-- I <3 THE STUDIO CAMERA SYSTEM !!!! YAYAY AIHU;S H;GDFAH GSDFL
|
|
24
|
+
local cf = camera.CFrame
|
|
25
|
+
local rx, ry = cf:ToOrientation()
|
|
26
|
+
|
|
27
|
+
-- NO HAX ALLOWED!!!!!!!
|
|
28
|
+
camera.CFrame = CFrame.new(cf.Position) * CFrame.fromOrientation(rx, ry, 0)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
local totalPos = vector.zero
|
|
32
|
+
local totalRot = CFrame.identity
|
|
33
|
+
|
|
34
|
+
local stillActive = {}
|
|
35
|
+
|
|
36
|
+
for _, v in activeShakes do
|
|
37
|
+
if v.done then
|
|
38
|
+
continue
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
totalPos += v.pos
|
|
42
|
+
totalRot *= CFrame.Angles(v.rot.x, v.rot.y, v.rot.z)
|
|
43
|
+
|
|
44
|
+
table.insert(stillActive, v)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
activeShakes = stillActive
|
|
48
|
+
|
|
49
|
+
local total = CFrame.new(totalPos) * totalRot
|
|
50
|
+
|
|
51
|
+
if not RunService:IsRunning() then
|
|
52
|
+
totalShakeCF = total
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
camera.CFrame *= total
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
local camera_shake = {}
|
|
59
|
+
|
|
60
|
+
local conn
|
|
61
|
+
local lastCameraCf
|
|
62
|
+
|
|
63
|
+
function camera_shake.init()
|
|
64
|
+
if conn then
|
|
65
|
+
return
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if RunService:IsRunning() then
|
|
69
|
+
conn = RunService.Heartbeat:Connect(function()
|
|
70
|
+
if not lastCameraCf then
|
|
71
|
+
return
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
workspace.CurrentCamera.CFrame = lastCameraCf
|
|
75
|
+
end)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
RunService:BindToRenderStep("forge_updateCameraShake", Enum.RenderPriority.Last.Value + 1, updateCamera)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
function camera_shake.deinit()
|
|
82
|
+
if conn then
|
|
83
|
+
conn:Disconnect()
|
|
84
|
+
conn = nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
RunService:UnbindFromRenderStep("forge_updateCameraShake")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
function camera_shake.emit(ref: RayValue, scope: types.scope)
|
|
91
|
+
local emitDelay = attr.get(ref, "EmitDelay", 0)
|
|
92
|
+
local emitDuration = attr.get(ref, "EmitDuration", 0)
|
|
93
|
+
|
|
94
|
+
local falloff = attr.get(ref, "Falloff", 30)
|
|
95
|
+
|
|
96
|
+
local amplitude = attr.get(ref, "Amplitude", 2.5)
|
|
97
|
+
local frequency = attr.get(ref, "Frequency", 0.2)
|
|
98
|
+
|
|
99
|
+
local fadeInTime = attr.get(ref, "FadeInTime", 0.3)
|
|
100
|
+
local fadeOutTime = attr.get(ref, "FadeOutTime", 2)
|
|
101
|
+
local sustainTime = attr.get(ref, "SustainTime", 1)
|
|
102
|
+
|
|
103
|
+
local posInfluence = attr.get(ref, "PositionInfluence", vector.one)
|
|
104
|
+
local rotInfluence = attr.get(ref, "RotationInfluence", vector.one * 0.2)
|
|
105
|
+
|
|
106
|
+
local speedStart = attr.get(ref, "Speed_Start", 1)
|
|
107
|
+
local speedEnd = attr.get(ref, "Speed_End", 1)
|
|
108
|
+
|
|
109
|
+
local sustained = emitDuration > 0
|
|
110
|
+
|
|
111
|
+
local shake = Shake.new()
|
|
112
|
+
shake.Sustain = sustained
|
|
113
|
+
shake.Amplitude = amplitude
|
|
114
|
+
shake.Frequency = frequency
|
|
115
|
+
shake.FadeInTime = fadeInTime
|
|
116
|
+
shake.FadeOutTime = fadeOutTime
|
|
117
|
+
shake.SustainTime = sustainTime
|
|
118
|
+
shake.PositionInfluence = posInfluence
|
|
119
|
+
shake.RotationInfluence = rotInfluence
|
|
120
|
+
|
|
121
|
+
local currentSpeed = 1
|
|
122
|
+
|
|
123
|
+
local elapsed = 0
|
|
124
|
+
|
|
125
|
+
shake.TimeFunction = function()
|
|
126
|
+
return elapsed
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
if speedStart ~= speedEnd then
|
|
130
|
+
local speedTween = tween.fromParams(
|
|
131
|
+
attr.get(ref, "Speed_Curve", utility.default_bezier),
|
|
132
|
+
attr.get(ref, "Speed_Duration", 0.1),
|
|
133
|
+
function(alpha, deltaTime)
|
|
134
|
+
currentSpeed = utility.lerp(speedStart, speedEnd, alpha)
|
|
135
|
+
return deltaTime
|
|
136
|
+
end
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
table.insert(scope, speedTween)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
table.insert(
|
|
143
|
+
scope,
|
|
144
|
+
RunService.RenderStepped:Connect(function(deltaTime)
|
|
145
|
+
elapsed += deltaTime * currentSpeed
|
|
146
|
+
end)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
local obj = {
|
|
150
|
+
done = false,
|
|
151
|
+
pos = vector.zero,
|
|
152
|
+
rot = vector.zero,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
task.wait(emitDelay)
|
|
156
|
+
|
|
157
|
+
table.insert(activeShakes, obj)
|
|
158
|
+
|
|
159
|
+
local thread = coroutine.running()
|
|
160
|
+
|
|
161
|
+
shake:BindToRenderStep(Shake.NextRenderName(), utility.RENDER_PRIORITY + scope.depth, function(pos, rot, isDone)
|
|
162
|
+
local camera = workspace.CurrentCamera
|
|
163
|
+
|
|
164
|
+
lastCameraCf = camera.CFrame
|
|
165
|
+
|
|
166
|
+
local origin = ref:FindFirstAncestorOfClass("Attachment") or ref:FindFirstAncestorWhichIsA("BasePart")
|
|
167
|
+
|
|
168
|
+
if origin then
|
|
169
|
+
local originCFrame = utility.getTransformedOriginExtents(origin)
|
|
170
|
+
local originPosition = originCFrame and originCFrame.Position or origin.Position
|
|
171
|
+
|
|
172
|
+
local alpha = 1 - math.clamp((camera.CFrame.Position - originPosition).Magnitude / falloff, 0, 1)
|
|
173
|
+
|
|
174
|
+
pos *= alpha
|
|
175
|
+
rot *= alpha
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
obj.pos = pos
|
|
179
|
+
obj.rot = rot
|
|
180
|
+
obj.done = isDone
|
|
181
|
+
|
|
182
|
+
if isDone then
|
|
183
|
+
lastCameraCf = nil
|
|
184
|
+
task.spawn(thread)
|
|
185
|
+
end
|
|
186
|
+
end)
|
|
187
|
+
|
|
188
|
+
shake:Start()
|
|
189
|
+
|
|
190
|
+
if sustained then
|
|
191
|
+
task.wait(emitDuration)
|
|
192
|
+
shake:StopSustain()
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
if not obj.done then
|
|
196
|
+
coroutine.yield()
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
return camera_shake
|