Confused about this spring module script

5, 50, 4, 4 are the default values if no arguments are passed when creating a new spring object, i.e spring.new(). And I get this result when using the default spring values

But then when I do spring.new(5, 50, 4, 4), which is just the default values passed as arguments, I get a wildly different result. Whats going on?

-- Constants

local ITERATIONS	= 8

-- Module

local SPRING	= {}

-- Functions 

function SPRING.new(self, mass, force, damping, speed)

	local spring	= {
		Target		= Vector3.new();
		Position	= Vector3.new();
		Velocity	= Vector3.new();

		Mass		= mass or 5;
		Force		= force or 50;
		Damping		= damping or 4;
		Speed		= speed  or 4;
	}

	function spring.shove(self, force)
		local x, y, z	= force.X, force.Y, force.Z
		if x ~= x or x == math.huge or x == -math.huge then
			x	= 0
		end
		if y ~= y or y == math.huge or y == -math.huge then
			y	= 0
		end
		if z ~= z or z == math.huge or z == -math.huge then
			z	= 0
		end
		self.Velocity	= self.Velocity + Vector3.new(x, y, z)
	end

	function spring.update(self, dt)
		local scaledDeltaTime = math.min(dt,1) * self.Speed / ITERATIONS

		for i = 1, ITERATIONS do
			local iterationForce= self.Target - self.Position
			local acceleration	= (iterationForce * self.Force) / self.Mass

			acceleration		= acceleration - self.Velocity * self.Damping

			self.Velocity	= self.Velocity + acceleration * scaledDeltaTime
			self.Position	= self.Position + self.Velocity * scaledDeltaTime
		end

		return self.Position
	end

	return spring
end

-- Return

return SPRING
1 Like

Match up the parameters.

the module include self which means it expects spring:new() instead spring.new().
Also the spring uses semi-implicit euler integration. Therefore expect errors at large timesteps.

Quentys spring module is better as it uses an exact solution.

comparing to wikipedia we can see why it uses math.exp a lot.

1 Like

If GenerateRecoil() gets called too many times within a short period of time, the recoil gets progressively larger and larger, I’m guessing this is because spring velocity is stacking every time the function is called.

How can I solve this problem? I’ve tried setting the spring’s velocity back to 0 after every time fireShot() is called, but this doesn’t work.

EDIT: I modified the time and duration variables as well as the spring speed and damper. After some trial and error I managed to find values that got the springs to work correctly.

	-- Local function to handle a single shot
	local function fireShot()
		-- Prevent firing until animation ends
		canFire = false

		-- Play animations and sounds
		fireVMTrack:Play()
		fireSound:Play()
		GenerateRecoil()

		task.wait(0.1)
		canFire = true
	end


function GenerateRecoil()
	time = duration -- Reset the recoil timer
	
	local X = settingsModule.getRecoilPattern(index)[1]
	local Y = settingsModule.getRecoilPattern(index)[2]

	local recoil = Vector3.new(X, Y, 0)
	recoilSpring:Impulse((recoil) * deltaTime * 60)
	
	index += 1
end

function Update(dt)
	deltaTime = dt
	local recoilCam = recoilSpring.Position
	
	
	-- apply recoil
	if time > 0 then
		camera.CFrame *= CFrame.Angles(math.rad(recoilCam.X), math.rad(recoilCam.Y),0)
		time -= dt
	end
end

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.