# Making barrage arms go in an arc motion?

So this might be a bit confusing. I’m working on a Jojo game and I want to replicate this effect from yba, where the arms in the barrage go in an arc motion. Does anyone have an idea of how I could do this?

https://gyazo.com/f4b4a38d7b1923403275b14d3b2f57c0

I’m thinking that it’d be something to do with moving the frame using some kind of math expression.

7 Likes

That’s pretty easy to do, review about bezier curves then use for loop then some trails then you’re pretty much done.

4 Likes

Yes, exactly what @EnigmaticDevil said.

I was wondering how to make an effect similar, but not entirely what you were trying to achieve awhile ago, so I did so. I can share the formula I used to make your life a little bit easier.

Now, usually, Bézier curves take in any amount of points, but for the sake of ease, I just let this quadratic Bézier take in 3 points. A start, curve (how far it should bend, essentially), and an end.

Best of luck in the future!

``````function Bezier_Module:QuadraticBezier(Time,Point0,Point1,Point2)
return (1-Time)^2*Point0+2*(1-Time)*Time*Point1+t^2*Point2; --This'll give you that curve you were looking for :)
end;
``````

Here’s how it looks real-time being tweened to its goal, following this quadratic Bézier path:

2 Likes

Btw how is this any different from the original?

Btw how is this any different from the original?

What do you mean?

I never said it was any different. I’m just saying, it takes in 3 points only, despite Bezier curves being known for taking more than 3 points.

I listed this specifically just in case he wanted to know, these are what bezier curves are known for.

yea i didn’t see lmao mb

Thanks a lot for your response! I’m sorry if I’m being a bit stupid right now but how could I tween my object along the path?

You would notice that there’s a Time argument in the function.
Just put the function in a loop-until-duration code ( I believe the function returns a Vector3)

``````local duration = 1
local timeElapsed = 0
while timeElapsed < duration do
local pointAtTimeElapsed = Bezier_Module:QuadraticBezier(timeElapsed, startPoint, curvePoint, endPoint)
timeElapsed += runService.Heartbeat:Wait()
end
``````

If you want a smoother movement, put this in Client and create a tween for each pointAtTimeElapsed.

Here’s how I would go about tweening this personally:

``````for t = 0,1,Speed.Value do
local TargetPosition = QuadraticBezier(t , Position_Start, (CFrame.new(Midpoint)*Random_Offset).p, Position_End);
local Goal = {
Position = TargetPosition;
};
local Tween = TweenService:Create(Part_To_Tween, TweeningInfo, Goal);
Tween:Play();
end
``````

I hope this helped, if you have any more questions, feel free to ask away.
Though, the solution above is probably less memory-consuming, and probably more effcient, honestly.
This was my implementation (as practice), though not the best obviously, for the time I was learning about Bezier curves, however.

1 Like

Thank you! I managed to make it work however now I am faced with a different problem. It’s not that major but it kind of ruins the effect.

The arms seem to be turning around again when reaching the end.

Here’s my code for reference. The code is in a local script that activates by a remote from the server. (keep in mind I just used whatever worked so it might be inefficient.)

``````spawn(function()
local duration = 1-(arm.Size.Z/10)
local timeElapsed = 0

local rnd = Random.new()
local rndCF = CFrame.new(rnd:NextInteger(-1,1),rnd:NextNumber(-1.5,1.5),rnd:NextNumber(-1,-5.5))

local speed = 0.05

while timeElapsed < duration do
local pointAtTimeElapsed = Bezier_Module:QuadraticBezier(timeElapsed,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p)
local lookAt = Bezier_Module:QuadraticBezier(timeElapsed+speed,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p)

if timeElapsed == 0 then
arm.CFrame = CFrame.new(pointAtTimeElapsed,Bezier_Module:QuadraticBezier(timeElapsed+.01,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p)) -- Makes the arm face the right way
elseif timeElapsed == speed then
local tween = TweenService:Create(arm,TweenInfo.new(.4),{Transparency = 0}):Play()
end

timeElapsed += speed
local tween = TweenService:Create(arm,TweenInfo.new(speed),{CFrame = CFrame.new(pointAtTimeElapsed,lookAt)}):Play()
wait(speed)
end

arm:Destroy()
end)``````

Ok so, first of all,
In the example I made there’s a mistake ( I think) :

the time value for quadratic curve is supposed to be 0 <= t <= 1
To convert timeElapsed to time for curve, you do

``````local t = timeElapsed/duration
local pointAtTimeElapsed = bezier(t, start, mid, endPos)
``````

Your speed variable isn’t exactly speed; it’s the delay between tweens
Here’s how you can implement speed

``````local speed = script.Parent:GetAttribute("speed") -- insert your value (I use between  1-2)
local duration = (armStartCf.p - pivotCFrame.Position).Magnitude / speed
``````

You might notice there’s a armStartCf variable; that’s the solution to your problem.
Here lies the problem:

``````local pointAtTimeElapsed = Bezier_Module:QuadraticBezier(timeElapsed,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p)
local lookAt = Bezier_Module:QuadraticBezier(timeElapsed+speed,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p)
arm.CFrame = CFrame.new(pointAtTimeElapsed,Bezier_Module:QuadraticBezier(timeElapsed+.01,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p))
``````

Your start and middle position is not constant, the curve tries to get to the turning point, but it never reaches it since it is always behind resulting in a spiral.

Just change
` arm.Position`
into `armStartCf.p`

and
`arm.CFrame * rndCf`
into `armStartCf * rndCf`

where armStartCf is the starting CFrame of the arm // spawn cframe of the arm

Here’s the code that I used

``````local TweenService = game:GetService("TweenService")
local arm = nil
local pivotCFrame = CFrame.new(script.Parent.Attachment.WorldPosition)
local Bezier_Module = {}
script.Parent:SetAttribute("speed", 2)
return (1-Time)^2*Point0+2*(1-Time)*Time*Point1+Time^2*Point2; --This'll give you that curve you were looking for :)
end;

local function TweenArm(arm)
spawn(function()
local armStartCf = arm.CFrame
local timeElapsed = 0

local rnd = Random.new()
local rndCF = CFrame.new(rnd:NextInteger(-1,1),rnd:NextNumber(-2.5,2.5),rnd:NextNumber(-5,-5.5))

local speed = script.Parent:GetAttribute("speed")
local duration = (armStartCf.p - pivotCFrame.Position).Magnitude / speed
local tweenDelay = 0.1
local new  = Instance.new("Part")
new.CFrame = arm.CFrame * rndCF
new.Size = Vector3.new(1,1,1)
new.Anchored = true
new.CanCollide = false
new.Material = Enum.Material.Neon
new.Parent = script.Parent

print(duration)
--while timeElapsed < duration do
--	local pointAtTimeElapsed = Bezier_Module:QuadraticBezier(timeElapsed,armStartCf,(arm.CFrame * rndCF).p, pivotCFrame.p)
--	local new  = Instance.new("Part")
--	new.Position = pointAtTimeElapsed
--	new.Size = Vector3.new(.2,.2,.2)
--	new.Anchored = true
--	new.CanCollide = false
--	new.Material = Enum.Material.Neon
--	new.Parent = script.Parent
----	arm.CFrame = CFrame.new(pointAtTimeElapsed,Bezier_Module:QuadraticBezier(timeElapsed+.001,arm.Position,(arm.CFrame * rndCF).p, pivotCFrame.p)) -- Makes the arm face the right way
--	timeElapsed += 0.01
--end
timeElapsed = 0
while timeElapsed < duration do
local progress = timeElapsed / duration
local pointAtTimeElapsed = Bezier_Module:QuadraticBezier(progress,armStartCf.p,(armStartCf * rndCF).p, pivotCFrame.p)
local lookAt = Bezier_Module:QuadraticBezier(progress+0.01,armStartCf.p,(armStartCf * rndCF).p, pivotCFrame.p)

if timeElapsed == 0 then
arm.CFrame = CFrame.new(pointAtTimeElapsed,Bezier_Module:QuadraticBezier(progress+.01,armStartCf.p,(armStartCf * rndCF).p, pivotCFrame.p)) -- Makes the arm face the right way
elseif timeElapsed == speed then
local tween = TweenService:Create(arm,TweenInfo.new(.4),{Transparency = 0}):Play()
end

timeElapsed += speed
local tween = TweenService:Create(arm,TweenInfo.new(tweenDelay),{CFrame = CFrame.new(pointAtTimeElapsed,lookAt)})
tween:Play()
wait(tweenDelay)
end

arm:Destroy()
end)
end

while true do
local arm = script.Parent.Arm:Clone()
arm.Position = script.Parent.Position
arm.Parent = script.Parent
pivotCFrame = CFrame.new(script.Parent.Attachment.WorldPosition)
TweenArm(arm)
wait(0.5)
end
``````

Also, you may want to increase the rndCf’s range to get a wider curve. (Like about half the maximum height of the curve you want)
(Think of the curve tool in MS Paint to get an idea how your curve would look like; set 2 points and drag the line to curve it)

9 Likes

I was able to make it work! Thank you so much.

2 Likes

Sorry for the late reply, I stumbled upon your post while trying to make my own barrage, and I can’t help but notice the bezier_module, do you mind sharing it with me so i can use it as well?

1 Like

Bezier_module is

``````function Bezier_Module:QuadraticBezier(Time,Point0,Point1,Point2)
return (1-Time)^2*Point0+2*(1-Time)*Time*Point1+Time^2*Point2
end;`````````

Whenever I Plug it in the red underlines just appear dispite it being the exact same idk

do
local Bezier_Module = {}
– the bezier function below here

1 Like

ty I ended up getting it after I sent the message lol

1 Like