Angled projectile

Hey everyone

I have been trying to create an Artillery model, for that I was browsing the devforum to see if there was any code/resource on projectile motion.

I found the following:

local i = 0

local x0 = launch.Position
local g = Vector3.new(0, -game.Workspace.Gravity, 0)

local v0 = (enemy.Position - x0 - 0.5*g*t*t)/t

game:GetService("RunService").Heartbeat:Connect(function(step)
    
    
    if not (i >= 1) then
        i = i + step
        projectile.CFrame = CFrame.new(0.5*g*i*i + v0*i + x0)
     end
  
end)

This is what it does currently

It works well and all, but the projectile isn’t launched at angle; which is what I have been trying to solve.
Are there any physics/maths related resources you guys can recommend for me to learn from?

5 Likes

The reason it’s not angling is that you’re initializing the projectile’s CFrame as just one vector 3, i.e only a position, so it just sets the rotation to 0,0,0.

There’s a bunch of different ways to set up CFrames’ rotations, and frankly some of them are fairly complicated, and I can’t explain them.

Your best bet would be to check the wiki page. Scroll down to the part about “look vectors”, more specifically “Finding a LookAt Vector”.

Usually i’d suggest the (now deprecated?) method of initializing a CFrame with CFrame.new(<part position vector 3>, <part target vector 3 position>) but AFAIK that method tends to not work well at high angles (towards the sky), which is precisely where your artillery operates.

This is a bit of a handful to learn, 3d transformations (i.e movement + rotation) are pretty complicated and confusing to learn, so don’t feel bad if it seems alien to you.

I actually initialised the projectile with the CFrame of the launch site and the video is what it resulted in

local launch     = workspace.Artillery.ShootFromHere
projectile.CFrame     = launch.CFrame

So I’m guessing I’ll have to adjust the formula to take account the initial angle

Well if ShootFromHere is a part, then indeed the projectile should have identical orientation to said part.

If that’s not the case, you’ve coded something incorrect, we’d be seeing a whole lot more weird behaviour across many games if the CFrame equivalence broke.

In the code you sent at the start, you, in your “for” loop, kept setting the CFrame to a NEW cframe. If you want to “move” a CFrame you want to either add the new CFrame to the old CFrame, or multiply the two.

NEW CFrames have no rotation/orientation data unless you explicitly set it with one of the many constructor methods.

Note that:
CFrame1 + CFrame2 = move the CFrame in the world coordinates,

CFrame1 * CFrame 2 = move the CFrame “CFrame2” units with relation to CFrame 1, i.e

CFrame1 * CFrame.new(0,0,-5) —> move CFrame1 five units forward, with respect to it’s own direction (rather than the global Z axis)

I figured it out after alot of trial and error. If anyone wants to launch a projectile from an Angle then use the following code.

Also make sure to define “launch” and “enemy”, in my case both were parts. launch’s FrontFace should face the enemy target, and it’s X orientation should be adjusted if you need to launch it at a higher/lower angle.

local speed = (launch.Position - enemy.Position).Magnitude / (90 - launch.Orientation.X)
local t = 1 * speed
local i = 0

local x0 = launch.Position + launch.CFrame.LookVector 
local g = Vector3.new(0, -workspace.Gravity,0)

local v0 = (enemy.Position - x0 - 0.5*g*t*t)/t

game:GetService("RunService").Heartbeat:Connect(function(step)
    
    
    if not (i >= t) then
    
        i = i + step
        projectile.CFrame = CFrame.new(0.5*g*i*i + v0*i + x0)
       
     end
  
end)

Here is the place file if anyone needs it
artierlly test.rbxl (19.3 KB)