Skip to content

Instantly share code, notes, and snippets.

@Kellojo
Last active March 21, 2024 14:43
Show Gist options
  • Save Kellojo/fe2bd73f92d9fdab6fffc31c0a17b0e2 to your computer and use it in GitHub Desktop.
Save Kellojo/fe2bd73f92d9fdab6fffc31c0a17b0e2 to your computer and use it in GitHub Desktop.
Camera tilt/weapon sway based on player movement and look input for the Unity game engine. Can be easily slapped onto any existing character controller or gun system.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using KinematicCharacterController;
using NaughtyAttributes;
public abstract class WeaponSway : MonoBehaviour
{
[SerializeField] Transform TargetTransform;
[Header("Movement/Look Sway Settings:")]
[SerializeField, Min(0)] float SwaySpeed = 5f;
[SerializeField, Tooltip("The multiplier for the sway caused by looking around"), Min(0)] float LookSwayMultiplier = 0.26f;
[SerializeField] Vector3 MovementSwayStrength = new Vector3(5f, 1f, 1f);
[SerializeField, Space()] Vector3 MinSwayRotation = new Vector3(-15, -5, -5);
[SerializeField] Vector3 MaxSwayRotation = new Vector3(15, 5, 5);
[Header("Idle Sway Settings:")]
[SerializeField] bool EnableIdleSway = true;
[EnableIf(nameof(EnableIdleSway)), SerializeField] float IdlePositionSwayStrength = 1f;
[EnableIf(nameof(EnableIdleSway)), SerializeField] float IdlePositionSwaySpeed = 1f;
[Header("Multiplier:")]
public float CurrentMultiplier = 1f;
void Update() {
if (Time.frameCount < 10) return;
var mouse = GetPlayerLookMovement() * LookSwayMultiplier;
var movement = transform.InverseTransformDirection(GetPlayerVelocity());
movement.x *= MovementSwayStrength.x;
movement.y *= MovementSwayStrength.y;
movement.z *= MovementSwayStrength.z;
movement *= CurrentMultiplier;
var rotationX = Quaternion.AngleAxis(mouse.x, Vector3.up);
var rotationY = Quaternion.AngleAxis(-mouse.y, Vector3.right);
var rotationZ = Quaternion.AngleAxis(-movement.x, Vector3.forward);
var rotationY2 = Quaternion.AngleAxis(movement.y, Vector3.right);
var rotationY3 = Quaternion.AngleAxis(movement.z, Vector3.right);
var quatTargetRotation = rotationZ * rotationX * rotationY * rotationY2 * rotationY3;
var angles = GetSignedEulerAngles(quatTargetRotation.eulerAngles);
var targetRotation = Quaternion.Euler(
Mathf.Clamp(angles.x, MinSwayRotation.x, MaxSwayRotation.x),
Mathf.Clamp(angles.y, MinSwayRotation.y, MaxSwayRotation.y),
Mathf.Clamp(angles.z, MinSwayRotation.z, MaxSwayRotation.z)
);
TargetTransform.localRotation = Quaternion.Slerp(TargetTransform.localRotation, targetRotation, SwaySpeed * Time.deltaTime);
if (EnableIdleSway) {
var idleSwayX = Mathf.PerlinNoise(Time.time * IdlePositionSwaySpeed, Mathf.Epsilon) - 0.5f;
var idleSwayY = Mathf.PerlinNoise(Time.time * IdlePositionSwaySpeed + 0.25f, Mathf.Epsilon) - 0.5f;
var idleSway = new Vector3(idleSwayX, idleSwayY, 0) * IdlePositionSwayStrength * CurrentMultiplier;
TargetTransform.localPosition = Vector3.Lerp(TargetTransform.localPosition, idleSway, Time.deltaTime);
}
}
public Vector3 GetSignedEulerAngles(Vector3 angles) {
Vector3 signedAngles = Vector3.zero;
for (int i = 0; i < 3; i++) {
signedAngles[i] = (angles[i] + 180f) % 360f - 180f;
}
return signedAngles;
}
public abstract Vector2 GetPlayerLookMovement();
public abstract Vector3 GetPlayerVelocity();
}
@Kellojo
Copy link
Author

Kellojo commented Apr 13, 2023

I use NaughtyAttributes for some of the inspector attributes, check it out here or remove the attributes manually 😉

How to use:

  • Create a script inheriting from WeaponSway and implement the two abstract GetPlayerLookMovement & GetPlayerVelocity methods.
  • Add the script to a parent of the transform you want to apply the tilt/sway to
  • Assign the target transform in the inspector
  • Fine tune the settings to your likings

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