Skip to content

Instantly share code, notes, and snippets.

@kurtdekker
Created June 11, 2022 21:59
Show Gist options
  • Save kurtdekker/be2a15216a41bef5ad39b609ff1625ef to your computer and use it in GitHub Desktop.
Save kurtdekker/be2a15216a41bef5ad39b609ff1625ef to your computer and use it in GitHub Desktop.
Unity screen-space auto-aim helper (aimbot)
using UnityEngine;
public class AimhelperTarget : MonoBehaviour
{
// @kurtdekker - nothing to see here; just put this
// on target GameObjects you want to assist-aim to.
//
// All the magic happen over in BasicAimHelper.cs
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// @kurtdekker
//
// FPS Aim helper, super-generic screenspace aimbot helper.
//
// This only needs is to be called with your actual proposed
// mouse inputs and to know which way it is facing.
//
// Add GameObject children with the AimhelperTarget script (just an empty marker)
// on every piece of your enemy you want "attraction" to work on (head, chest, etc.)
//
// You can try it out alongside the BasicFPCC script from Alucard, located here:
//
// https://forum.unity.com/threads/a-basic-first-person-character-controller-for-prototyping.1169491/
//
// You will need the BasicFPCC.cs script above. Set it up fully as instructions explain.
//
// Add this script onto that same Player's Camera (must be on camera for alignment!)
//
// Modify the BasicFPCC script, immediately after the
// mouse look is read in ProcessInputs(), as follows:
//
// // code to insert in BasicFPCC.cs (or in your own mouse look script
// if (BasicAimHelper.I)
// {
// BasicAimHelper.I.AllowForAutoAim( ref inputLookX, ref inputLookY);
// }
//
// NOTE: the BasicFPCC script is hosted as a gist and may change,
// making these patches invalid or even breaking this script.
//
public class BasicAimHelper : MonoBehaviour
{
[Header( "@kurtdekker")]
[Header( "Radius to act within (percent of minimum screen axis)")]
public float ActiveScreenFractionRadius = 0.15f;
[Header( "Choose this to be adequate but still let you break lock.")]
public float AimingAssistanceStrength = 10.0f;
[Header( "At what range does attraction max out?")]
public float MinimumActiveLinearRange = 20.0f;
[Header( "How rapidly does the effect fall off on distant enemies?")]
public float MaximumActiveLinearRange = 40.0f;
[Header( "How far can the effectiveness fall based on range?")]
public float FloorAttractionAtMaxRange = 0.25f;
public static BasicAimHelper I { get; private set; }
void OnEnable()
{
I = this;
}
void OnDisable()
{
I = null;
}
static float ScreenMinimumAxis { get { return Mathf.Min( Screen.width, Screen.height); } }
// returns true if the mouse was adjusted
public bool AllowForAutoAim( ref float mouseX, ref float mouseY)
{
bool adjusted = false;
// TODO: expects to be ON the GameObject with the Camera!
var cam = GetComponent<Camera>();
// TODO: assumes crosshairs are middle of the screen precisely
Vector2 screenCrosshairs = new Vector2( Screen.width, Screen.height) / 2;
// TODO: get these once in a far more efficient way. This is for demo only!
var targets = FindObjectsOfType<AimhelperTarget>();
float activeRadius = ScreenMinimumAxis * ActiveScreenFractionRadius;
// used to only consider the drive from the closest target, not a mix of all nearby
float closestRadius = activeRadius;
// will ultimately end up being the closest to our aimpoint only.
Vector2 mouseAssistanceDrive = Vector2.zero;
foreach( var target in targets)
{
Vector3 worldDelta = target.transform.position - transform.position;
// only lock onto stuff in front of us
if (Vector3.Dot( transform.forward, worldDelta) > 0)
{
float targetWorldDistanceRange = worldDelta.magnitude;
if (targetWorldDistanceRange < MaximumActiveLinearRange)
{
Vector2 screenTargetPos = cam.WorldToScreenPoint( target.transform.position);
Vector2 screenDelta = screenTargetPos - screenCrosshairs;
float screenDistance = screenDelta.magnitude;
// any attraction at all?
if (screenDistance < activeRadius)
{
if (screenDistance < closestRadius)
{
closestRadius = screenDistance;
// linear from 0 at radius to 1 at dead-on (0 distance)
float effectiveness = Mathf.InverseLerp( activeRadius, 0, screenDistance);
// TODO: you could look this up in a non-linear curve, such
// as by using a public AnimationCurve and setting it up.
// TODO: you could square or square-root this to change the "feel"
// After all the above, we have a value from 0 to 1 that
// tells us how much we want to drive the mouse.
// scale down by screen pixels
effectiveness /= ScreenMinimumAxis;
// master scaling amount
effectiveness *= AimingAssistanceStrength;
// how much is effectiveness reduced as you get far away?
float rangeEffectivenessAttenuation = Mathf.InverseLerp(
MaximumActiveLinearRange,
MinimumActiveLinearRange,
targetWorldDistanceRange);
// TODO: you might want range falloff to be non-linear, as above
// Re-lerp it to the floor attraction
rangeEffectivenessAttenuation = Mathf.Lerp( FloorAttractionAtMaxRange, 1.0f, rangeEffectivenessAttenuation);
// apply range attraction attenuation
effectiveness *= rangeEffectivenessAttenuation;
mouseAssistanceDrive = screenDelta * effectiveness;
adjusted = true;
}
}
}
}
}
if (adjusted)
{
mouseX += mouseAssistanceDrive.x;
mouseY += mouseAssistanceDrive.y;
}
return adjusted;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment