Skip to content

Instantly share code, notes, and snippets.

@HajiyevEl
Forked from pppoe252110/WeaponSway.cs
Created March 15, 2025 08:03
Show Gist options
  • Save HajiyevEl/a090270841ce1b931b91f813b434dbf1 to your computer and use it in GitHub Desktop.
Save HajiyevEl/a090270841ce1b931b91f813b434dbf1 to your computer and use it in GitHub Desktop.
Correct Weapon Sway implementation which does not depend on fps
using UnityEngine;
public class WeaponSway : MonoBehaviour
{
[SerializeField] private Transform weaponTransform;
[Header("Sway Properties")]
[SerializeField] private float swaySmooth = 8f;
[SerializeField] private float swayDamp = 2f;
[SerializeField] private float posToRotAmount = 1f;
[SerializeField] private float rotToPosAmount = .1f;
[Header("Rotation Sway")]
[SerializeField] private float rotationSwayMultiplier = -.2f;
[SerializeField] private float maxRotSwayAmount = 5f;
[Header("Position Sway")]
[SerializeField] private float movementSwayMultiplier = -0.05f;
[SerializeField] private float maxPosSwayAmount = 0.01f;
private Vector3 _initialPosition;
private Quaternion _initialRotation;
private Vector2 _rotSway;
private Vector3 _posSway;
private Quaternion _lastRotation;
private Vector3 _lastPosition;
private void Start()
{
if (!weaponTransform)
weaponTransform = transform.GetChild(0);
CacheInitialTransforms();
}
private void CacheInitialTransforms()
{
_lastRotation = transform.localRotation;
_lastPosition = transform.position;
_initialPosition = weaponTransform.localPosition;
_initialRotation = weaponTransform.localRotation;
}
private void LateUpdate()
{
CalculateSway();
ApplySway();
}
private void CalculateSway()
{
CalculateRotationalSway();
CalculatePositionalSway();
ClampSwayValues();
}
private void CalculateRotationalSway()
{
Quaternion angularVelocity = Quaternion.Inverse(_lastRotation) * transform.rotation;
_lastRotation = transform.rotation;
float mouseX = FixAngle(angularVelocity.eulerAngles.y) * rotationSwayMultiplier;
float mouseY = -FixAngle(angularVelocity.eulerAngles.x) * rotationSwayMultiplier;
_rotSway += new Vector2(mouseX, mouseY);
}
private void CalculatePositionalSway()
{
Vector3 positionDelta = transform.position - _lastPosition;
_lastPosition = transform.position;
positionDelta = weaponTransform.InverseTransformDirection(positionDelta) * movementSwayMultiplier;
_posSway += positionDelta;
}
private void ClampSwayValues()
{
_rotSway = Vector2.ClampMagnitude(_rotSway, maxRotSwayAmount);
_posSway = Vector3.ClampMagnitude(_posSway, maxPosSwayAmount);
}
private void ApplySway()
{
float sway = swaySmooth * Time.deltaTime;
ApplyRotationSway(sway);
ApplyPositionSway(sway);
ReduceSwayOverTime(sway * swayDamp, sway * swayDamp);
}
private void ApplyRotationSway(float deltaRot)
{
Quaternion targetRotation = _initialRotation * Quaternion.Euler(new Vector3(-_rotSway.y - _posSway.y * posToRotAmount * Mathf.Rad2Deg, _rotSway.x + _posSway.x * posToRotAmount * Mathf.Rad2Deg, 0));
weaponTransform.localRotation = Quaternion.Lerp(weaponTransform.localRotation, targetRotation, deltaRot * swaySmooth);
}
private void ApplyPositionSway(float deltaPos)
{
Vector3 targetPosition = _initialPosition + _posSway + new Vector3(rotToPosAmount * _rotSway.x * Mathf.Deg2Rad, rotToPosAmount * _rotSway.y * Mathf.Deg2Rad);
weaponTransform.localPosition = Vector3.Lerp(weaponTransform.localPosition, targetPosition, deltaPos * swaySmooth );
}
private void ReduceSwayOverTime(float deltaRot, float deltaPos)
{
_rotSway = Vector2.Lerp(_rotSway, Vector2.zero, deltaRot);
_posSway = Vector3.Lerp(_posSway, Vector3.zero, deltaPos);
}
private float FixAngle(float angle)
{
// Normalize the angle to be within -180 to 180 degrees
return Mathf.Repeat(angle + 180f, 360f) - 180f;
}
}
@pppoe252110
Copy link

good job

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment