Magic Spell Projectile Physics

In this video, you can see an example of two different spells being fired. I was wondering how you can achieve an effect like that while not compromising insane amounts of accuracy (the spell landing far off target). Is it truly random or is there an algorithm?

The method I’m using rn is a simple straight projectile that uses rays to check a hit

If it’s a physical projectile, you can give it different forces at different points, based on whatever you want. If you’re strictly using data, you can use a node system for a pre-calculated path (it will still have to calculate live with the projectile in case something moves in the way).

There are many ways to do the second option, but you basically have control over time and offset, and can use that in your algorithm. A spiral, for example, would simply be having a straight line of nodes that get rotated by time and offset outward by some amount, either static or also multiplied by time (if you want the spiral to grow the longer it lasts). These nodes don’t have to be generated all at once, you can generate them throughout the lifetime of the projectile, to maximize how dynamic it is.

1 Like

rotate the angle theta continuously

the x and y offset (relative to lookvector of the projectile) is x=cos(theta) and y=sin(theta), and then for randomness you just add some noise so x += math.noise(t) and y += math.noise(t+offset)

i think both use the same formula, but the first one moves slower because you just make the angle and time change slower

1 Like

Thank you! Can you guide me on how I might be able to do this? If I’m being honest, I’m quite stuck on this

i think precalculating points is worse than just calculating a dynamic offset but you would do something like

local function generateNodes(distance : number, start : Vector3, velocity : Vector3) : {Vector3}
	
	local NODE_DISTANCE = 2 -- one node every two studs
	local ROTATION_SPEED = 2 -- how fast the spiral rotates
	local SPIRAL_MAGNITUDE = 5 -- how big the spiral is
	
	local NOISE_VOLATILITY = 0.1 -- how volatile the noise (random movement) Is
	local NOISE_MAGNITUDE = 1 -- how strong the noise is
	
	local nodes : {Vector3} = {}
	local nodeCount = distance / NODE_DISTANCE
	
	for i = 1, nodeCount do
		
		local currentPosition = start + (velocity * i)
		local angle = i * ROTATION_SPEED
		
		local offsetX = math.cos(angle) * SPIRAL_MAGNITUDE
		local offsetY = math.sin(angle) * SPIRAL_MAGNITUDE
		
		local noiseX = math.noise(i*NOISE_VOLATILITY) * NOISE_MAGNITUDE
		local noiseY = math.noise(i*NOISE_VOLATILITY) * NOISE_MAGNITUDE
		
		nodes[i] = currentPosition + Vector3.new(offsetX, offsetY, 0) + Vector3.new(noiseX, noiseY, 0)
		
	end
	
	return nodes
	
end

and then the position of the projectile at any given point is the linear interpolated vector3 of nodes[i+1] and nodes[i]

edit: lerp would be like a zigzag line, so you could use something like bezier curve or just dynamic offset would be the best

2 Likes