Skip to content

Instantly share code, notes, and snippets.

@Donnotron666
Last active April 3, 2017 22:34
Show Gist options
  • Save Donnotron666/e1742aa595618b20166eb04a42321339 to your computer and use it in GitHub Desktop.
Save Donnotron666/e1742aa595618b20166eb04a42321339 to your computer and use it in GitHub Desktop.
Filtering analog aim input into something more usable in Unity3d. This is pulled from my game, so ignore the obvious engine code.
using System;
using Client.Game.Attributes;
using Client.Game.Abilities.Payloads;
using UnityEngine;
using Client.Game.Actors;
using System.Collections.Generic;
using Client.Utils;
using Client.Game.Utils;
namespace Client.Game.Abilities.Scripts.Buffs
{
public class ControllerAimFilter : BuffBase
{
public ControllerAimFilter ()
{
}
bool DebugRays = false;
private float distance;
public override void Start ()
{
distance = this.Attributes[ActorAttributes.Distance];
context.source.Attributes[ActorAttributes.ControllerAimAssist] += this.Attributes[ActorAttributes.ControllerAimAssist];
}
public override bool OnPayloadSend (Payload payload)
{
var wpnPayload = payload as WeaponFirePayload;
if(wpnPayload != null) {
Adjust(payload.Context);
}
return false;
}
void Adjust (AbilityContext firingContext)
{
var start = VectorUtils.Vector2(context.source.HalfHeight);
var matches = new List<ScoredMatch>();
var tolerance = context.source.Attributes[ActorAttributes.ControllerAimAssist];
var direction2D = VectorUtils.Vector2(firingContext.targetDirection);
//a wide cast feels better than a cone-cast, cone rejection is handled by angle scoring later on.
var hits = Physics2D.CircleCastAll(start, 10f, direction2D, distance);
ScoredMatch match = null;
foreach( var hit in hits ) {
if(TryScore(start, tolerance, direction2D, hit, out match)) {
matches.Add(match);
}
}
if(matches.Count > 0) {
matches.Sort(MatchComparer);
if(DebugRays) {
Debug.Log("HIT ACTOR: " + matches[0].Actor.ActorType);
Debug.DrawRay(start, matches[0].Direction*20f, Color.green, 2f);
}
firingContext.targetDirection = matches[0].Direction;
}
}
bool TryScore (Vector2 start, float tolerance, Vector2 targetDirection, RaycastHit2D hit, out ScoredMatch match)
{
if(DebugRays) {
Debug.DrawRay(start, targetDirection* distance, Color.red, 2f);
}
Actor actor = null;
//try to convert the hit info to an Actor instance
if (ActorUtils.TryHitToActor(hit, out actor)) {
//enemies only, could be replaced with a team check, but not really necessary for BF88
if (actor.ActorType == Data.ActorType.Enemy) {
var resultDirection = (actor.HalfHeight2D - start).normalized;
var angle = Mathf.Abs(Vector2.Angle(resultDirection, targetDirection));
//a heuristic for sorting many results, balancing things that are close -vs- extreme corrections
var score = angle + (hit.distance * .1f);
if (DebugRays) {
Debug.DrawLine(start, hit.point, Color.gray, 2f);
}
if (angle <= tolerance) {
if (DebugRays) {
Debug.DrawLine(start, hit.point, Color.cyan, 2f);
}
match = new ScoredMatch();
match.Direction = resultDirection;
match.Score = score;
match.Actor = actor;
return true;
}
}
}
match = null;
return false;
}
private class ScoredMatch {
public float Score;
public Actor Actor;
public Vector2 Direction;
}
private static MatchComparator MatchComparer = new MatchComparator();
private class MatchComparator: IComparer<ScoredMatch> {
public int Compare (ScoredMatch x, ScoredMatch y)
{
return x.Score.CompareTo(y.Score);
}
}
public override void End ()
{
context.source.Attributes[ActorAttributes.ControllerAimAssist] -= this.Attributes[ActorAttributes.ControllerAimAssist];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment