How to make a "softer" tween?

This is kind of an extension of the other post I made on how to make smoother recoil.

Anyways, I changed from lerping to tweening and it’s smoother, but it looks extremely harsh. The problem is, I have no idea what’s making it that way. I have noticed that changing the amount of time it takes the tween to happen changes how harsh it is, but not by much.

Here’s my code:

function RecoilShove()
	local Recoil = 0.17
	
	local recoilUpdate = CFrame.Angles(Recoil,0,0)
	local recoilUpdateDown = CFrame.Angles(-Recoil,0,0)
	
	local RecoilInfoUp = TweenInfo.new(0.08, Enum.EasingStyle.Quad, Enum.EasingDirection.In, 0, true, 0)
	local RecoilInfoDown = TweenInfo.new(0.08, Enum.EasingStyle.Quad, Enum.EasingDirection.In, 0, true, 0)
	
	
	local RecoilGoalUp = {CFrame = camera.CFrame * recoilUpdate}
	local RecoilGoalDown = {CFrame = camera.CFrame * recoilUpdateDown}
	
	local PlayUp = TweenServ:Create(camera, RecoilInfoUp, RecoilGoalUp)
	
	PlayUp:Play()
	
	spawn(function()
		wait(0.08)
		local PlayDown = TweenServ:Create(camera, RecoilInfoUp, RecoilGoalDown)
		PlayDown:Play()
	end)
end

YouTube Demonstration: https://www.youtube.com/watch?v=tnDucS1QCs0

Any help would be great! :grinning: :

3 Likes

First off, nice name.

I don’t think using tweens would be the best route to recoil implementation. Most of the time springs or lerping(careful with lerping fps) is used for this type of stuff. I found a few threads that go over the implementation and math that hopefully you’ll find helpful.

Recoil Example (lerping)
Gun framework (springs)
Camera recoil (springs)

5 Likes

Wow! Thanks a lot! I have tried using springs, but someone else told me it was too complicated and I should we tween instead. Also, you have a pretty cool user too!

Although, I do use springs for my weapon sway

Looks like I’m a bit late to the party. Someone already suggested springs. I do have some additional insights and a few pointers, though.

The math behind springs is a bit daunting at first, but it’s not super complicated once you start to understand the physics behind them. I actually wrote about this exact topic a while ago, if you’re interested in the maths behind spring-based recoil animations:

https://projects.anna.gg/SpringSimulation/

(If you’re looking for spring code to use, scroll to the bottom of the page. The first one has issues which I explain on the page itself).

When you use springs and lerps based on a simple exponential equation, you can get some incredibly smooth animations. I tested around with this a bit a while ago:

https://www.roblox.com/games/4963396572/Gun-Test

(I still have to code the bullets, please don’t kill - well, you can’t, there’s no bullets :wink:)

In my case, I used 5 different springs; 2 for the camera (pitch and yaw) and 3 for the gun’s viewport model (pitch, yaw and backwards movement):

Camera Pivots

image

Gun Movement

image

The idea is that you keep track of the view angles and add the positions of those springs to the angle the actual camera is at. That way, the recoil can heavily throw off the camera but will always return to the direction the player was originally facing.

You want to give the camera a decent upward kick, as well as some sideways kick. For the gun, you give it a decent backwards kick, as well as some upwards rotation and a very small bit of sideways rotation. All of these springs should be relatively stiff and have high damping - in my example, all springs have a spring constant of 20 and a damping coefficient of 10. Lower values on either of these result in a longer time to target, higher values result in a quicker time to target.

With my example code in the first link, you can give the springs a kick using the Spring:addVelocity(dV) method and get the velocity of the spring at any point in time using the Spring:step(dT) method. The idea is that you call Spring:step(dT) every time RenderStepped fires.

For the ADS/hipfire view, I have two separate “target” CFrames relative to the camera, and I change the start and target positions whenever the mouse input changes. As the lerp “factor”, I use the following equation:

factor = 1 - math.exp(-timeSinceChange * speed)

This gives it a sharp response initially, but it slows down when it approaches the target value and feels a lot more natural.

Hopefully you find this helpful! ^^

4 Likes

Wow dude! THANKS A TON!!!

1 Like