Last active
March 21, 2024 14:43
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use NaughtyAttributes for some of the inspector attributes, check it out here or remove the attributes manually 😉
How to use:
GetPlayerLookMovement
&GetPlayerVelocity
methods.