How would I go about using Inverse Kinematics in my Gun System?

So I am currently attempting to make a gun system. This is my first time doing so and seems like it will be a very tough task as it is.

However, I would love to inflict pain upon myself and incorporate inverse kinematics in the said gun system. It will be used when the player holds the gun to simulate accurate collisions with the environment. Sort of like in this clip Watch Deadline Gun IK | Streamable (Deadline).

So far, this is what I have but it feels completely incorrect Watch Gun IK Progress | Streamable. If someone can help me out and tell me the process I would need to execute to successfully make inverse kinematics for my gun, that would be amazing.

Also does anyone know any good gun tutorials?

2 Likes

i don’t think they’re using inverse kinematics for this. i’ve seen this ‘realistic anti-wall clipping’ approach used in an ACS mod that i was tinkering with a few months ago. what they most likely did was raycast from the barrel of the viewmodel’s gun, and if it hit something, (like a wall) move the viewmodel backwards, and if you’re close enough to a wall, then hold the gun upwards (or have it be held close to the player’s chest) and make u unable to shoot until u back up

1 Like

Interesting. That seems about right as using IK would be very buggy and CPU intensive for running it every frame for every frame. But how would they position the arm viewmodels when the gun moves back?

to position the view models effectively, u can determine a target position that is slightly behind the current position of the model. once u have this target position, use linear interpolation to smoothly transition the view model from its current position to the new target position.

1 Like

Thank you. But how would I position the arms dynamically so that it’s holding the gun, but still having realistic joint simulation, instead of the arms clipping through the player?

this is the limit of my knowledge. unfortunately, i’ve only implemented anti-clipping measures for the viewmodel, not for the player’s character itself.

1 Like

That’s alright. Thank you so much for your help. Is it possible for you to send a video of your implementation? Do you just move the arms back?

i don’t have footage of that specific implementation, but i can recreate the anti-clipping and provide new footage.

1 Like

That would be awesome if you can. I would really appreciate it. Thanks.

i apologize for the delayed response, but here’s the footage (this is just a viewmodel with the arm movement i described, no animations):

1 Like

No problem thanks a lot man. thats sick. you helped me a ton. hell i would’ve been stuck tryna use inverse kinematics on the characters arms, then figuring out how to get the gun to not clip, then i would have to make the arms visible in fp, and then replicate all of this to the other clients… i probably wouldve just given up ngl. but you saved me :grin:. thanks dude

1 Like

wait can you send me the code for that?

be warned, the code is atrocious
viewmodel.rbxl (88.2 KB)

1 Like

ima be honest - i dont understand any of it :sob:
i am NOT gonna be able to script an fps system
however…
i must try

we all start somewhere!
anyway, which parts are the most confusing? i could try to explain what they do

1 Like

what distance buffer do and why do you need the averages?

local distance = result.Distance

-- smooth the distance using a buffer
table.insert(distanceBuffer, distance)
if #distanceBuffer > bufferSize then
	table.remove(distanceBuffer, 1) -- remove oldest entry
end

-- calculate the average distance from the buffer
local averageDistance = 0
for _, d in ipairs(distanceBuffer) do
	averageDistance = averageDistance + d
end
averageDistance = averageDistance / #distanceBuffer

if previousDistance == 0 then
	previousDistance = averageDistance
else
	previousDistance = previousDistance * 0.8 + averageDistance * 0.2
end

and what does

previousDistance = previousDistance * 0.8 + averageDistance * 0.2

do?

what are the target offset and current offset calculations?

				local maxOffset = 5
				local minDistance = 1 -- minimum distance to start increasing offset (to avoid division by zero)
				local scale = 1

				if previousDistance < minDistance then
					targetOffset = maxOffset
				else
					targetOffset = math.clamp(maxOffset - (scale / previousDistance), 0, maxOffset)
				end
			end

			-- use lerping on the current offset towards the target offset using deltaTime for smoother movement
			local lerpFactor = 0.05 -- adjust for smoothing (between 0 and 1)
			currentOffset = currentOffset + (targetOffset - currentOffset) * lerpFactor

o i see now you’re not moving the gun and then the arms to the gun, you’re moving it all as a whole

1 Like

pls help

char limit char limit

ok, let’s break it down:

i’m using a “distance buffer” to track of several distance values over time. it helps smooth out fluctuations in the distance measurement, so sudden changes don’t cause jittery behavior. i add the latest distance to the buffer, and if the buffer exceeds a specified size (bufferSize), i remove the oldest distance. this keeps the buffer at a manageable length and makes sure it only contains recent measurements.

i calculate the average of the distances stored in the buffer. this average smooths out any extreme values and provides a more stable distance for further use.

the line previousDistance = previousDistance * 0.8 + averageDistance * 0.2 means:

  • i’m taking 80% of the previous smoothed distance and adding 20% of the new average distance.
  • this helps to gradually adjust previousDistance towards the new average without jumping too abruptly. the result is a smoother transition and less jitter when the distance changes.

then i calculate a targetOffset based on the previousDistance. if the previousDistance is less than minDistance, i set the targetOffset to maxOffset, which sets a maximum amount of movement.

now, if the previousDistance is greater than or equal to minDistance, i decrease the offset as the distance increases, ensuring the offset does not go below zero (thanks to math.clamp).

finally, for the lerping. lerpFactor is a small value used for interpolation (smoothing).
i update currentOffset by gradually moving it toward the targetOffset. this is done by taking the difference between targetOffset and currentOffset, multiplying by lerpFactor, and adding it to currentOffset.

tl;dr:

  • distance “buffering” helps smooth out fluctuations in distance measurements,
  • averages provide a stable reference to avoid sudden changes,
  • previous distance calculation uses exponential smoothing to make transitions gradual,
  • target offset calculation adjusts movement based on distance, making it feel more responsive,
  • and lerping smooths the movement of offsets over time for a more polished effect
1 Like

tysm that helped tons. now i understand. thats actually really cool. how did you even come up with this??? phenomenal. its genius.