├── scene heirarchy.png ├── LICENSE ├── Recoil.gd └── README.md /scene heirarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AceSpectre/GodotProceduralRecoil/HEAD/scene heirarchy.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 AceSpectre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Recoil.gd: -------------------------------------------------------------------------------- 1 | extends Node3D 2 | 3 | # Rotations 4 | var currentRotation : Vector3 5 | var targetRotation : Vector3 6 | 7 | # Recoil vectors 8 | @export var recoil : Vector3 9 | @export var aimRecoil : Vector3 10 | 11 | # Settings 12 | @export var snappiness : float 13 | @export var returnSpeed : float 14 | 15 | func _process(delta): 16 | # Lerp target rotation to (0,0,0) and lerp current rotation to target rotation 17 | targetRotation = lerp(targetRotation, Vector3.ZERO, returnSpeed * delta) 18 | currentRotation = lerp(currentRotation, targetRotation, snappiness * delta) 19 | 20 | # Set rotation 21 | rotation = currentRotation 22 | 23 | # Camera z axis tilt fix, ignored if tilt intentional 24 | # I have no idea why it tilts if recoil.z is set to 0 25 | if recoil.z == 0 and aimRecoil.z == 0: 26 | global_rotation.z = 0 27 | 28 | func recoilFire(isAiming : bool = false): 29 | if isAiming: 30 | targetRotation += Vector3(aimRecoil.x, randf_range(-aimRecoil.y, aimRecoil.y), randf_range(-aimRecoil.z, aimRecoil.z)) 31 | else: 32 | targetRotation += Vector3(recoil.x, randf_range(-recoil.y, recoil.y), randf_range(-recoil.z, recoil.z)) 33 | 34 | func setRecoil(newRecoil : Vector3): 35 | recoil = newRecoil 36 | 37 | func setAimRecoil(newRecoil : Vector3): 38 | aimRecoil = newRecoil 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GodotProceduralRecoil 2 | Godot port of Gilbert's procedural recoil system for Unity 3 | 4 | Credit to Gilbert for the original system, [here's his YouTube tutorial for it.](https://www.youtube.com/watch?v=geieixA4Mqc) The only major difference between the Unity implementation and this one, is that Godot doesn't (as far as I'm aware) have an `slerp` function, so a `lerp` function is used instead. To make this version as smooth as the original, an alternative to Godot's `lerp` would need to be used. 5 | 6 | ## Installation 7 | Download `recoil.gd` and import it into your Godot Project. 8 | 9 | This script is designed to be used on the parent of the Camera3D node, and the child of the node that is rotated by the mouse input. 10 | 11 | ![Scene Hierarchy of the player](https://github.com/AceSpectre/GodotProceduralRecoil/blob/main/scene%20heirarchy.png) 12 | 13 | In the screenshot above, the `Head` node is rotated by mouse input and `recoil.gd` is attached to the `CameraRecoil` node. 14 | 15 | ## Usage 16 | 17 | ### Procdural Recoil Parameters 18 | `Recoil`: Rotation vector added to the target rotation whenever `recoilFire()` is called 19 | 20 | `Aim Recoil`: Rotation vector added to the target rotation whenever `recoilFire(true)` is called 21 | 22 | `Snappiness`: Rate at which the current rotation lerps to the target rotation 23 | 24 | `Return Speed`: Rate at which the target rotation returns to `(0, 0, 0)` 25 | 26 | ### Functions 27 | 28 | `recoilFire(isAiming : bool = false)` 29 | 30 | - Adds rotation vector to the target rotation, which vector is added is determined by `isAiming` 31 | 32 | `setRecoil(newRecoil : Vector3)` 33 | 34 | - Sets the recoil vector to `newRecoil` 35 | 36 | `setAimRecoil(newRecoil : Vector3)` 37 | 38 | - Sets the aim recoil vector to `newRecoil` 39 | 40 | ## Current Issues 41 | 42 | Extremely small z-axis rotations are applied to the rotation, even when the z-axis value of the recoil vector is set to 0. The fix for this issue is to manually set `global_rotation.z` of the node to 0 every frame. 43 | 44 | Make sure to change this if you don't want this rotation to be overridden. 45 | --------------------------------------------------------------------------------