You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RizzeProjectile/Assets/Scripts/Projectiles/ProjectileUtility.cs

118 lines
3.9 KiB
C#

using Fusion;
using System.Collections.Generic;
using Fusion.LagCompensation;
using UnityEngine;
namespace Projectiles
{
/// <summary>
/// This utility unifies handling of lag compensated casts across the project.
/// </summary>
public static class ProjectileUtility
{
public static bool ProjectileCast(NetworkRunner runner, PlayerRef owner, Vector3 firePosition, Vector3 direction, float distance, LayerMask hitMask, out LagCompensatedHit hit, bool ignoreInputAuthority = true)
{
var hitOptions = HitOptions.IncludePhysX | HitOptions.SubtickAccuracy;
if (ignoreInputAuthority == true)
{
hitOptions |= HitOptions.IgnoreInputAuthority;
}
return runner.LagCompensation.Raycast(firePosition, direction, distance, owner, out hit, hitMask, hitOptions);
}
public static bool ProjectileCastAll(NetworkRunner runner, PlayerRef owner, int ownerObjectInstanceID, Vector3 firePosition, Vector3 direction, float distance, LayerMask hitMask, List<LagCompensatedHit> validHits)
{
return ProjectileCastAll(runner, owner, ownerObjectInstanceID, firePosition, direction, 0f, distance, hitMask, validHits);
}
public static bool ProjectileCastAll(NetworkRunner runner, PlayerRef owner, int ownerObjectInstanceID, Vector3 firePosition, Vector3 direction, float distanceToTarget, float raycastDistance, LayerMask hitMask, List<LagCompensatedHit> validHits)
{
validHits.Clear();
var hits = ListPool.Get<LagCompensatedHit>(16);
var hitOptions = HitOptions.IncludePhysX | HitOptions.SubtickAccuracy | HitOptions.IgnoreInputAuthority;
int hitCount = runner.LagCompensation.RaycastAll(firePosition, direction, raycastDistance, owner, hits, hitMask, true, hitOptions);
if (hitCount <= 0)
{
ListPool.Return(hits);
return false;
}
var hitRoots = ListPool.Get<int>(16);
float ignoreDistanceMin = 3f;
float ignoreDistanceMax = Mathf.Max(distanceToTarget - 1f, ignoreDistanceMin);
hits.SortDistance();
for (int i = 0; i < hits.Count; i++)
{
var hit = hits[i];
if (distanceToTarget > 0f)
{
// For 3rd person cast it is possible that we want to shoot through environment objects a little bit if we already know the destination point
// => ray from camera is different than ray from 3rd person character
if (hit.Distance >= ignoreDistanceMin && hit.Distance < ignoreDistanceMax && hit.GameObject != null && ObjectLayerMask.Environment.value.IsBitSet(hit.GameObject.layer))
continue;
}
int hitRootID = hit.Hitbox != null ? hit.Hitbox.Root.gameObject.GetInstanceID() : 0;
if (hitRootID != 0)
{
if (hitRootID == ownerObjectInstanceID)
continue; // Owner was hit
if (hitRoots.Contains(hitRootID) == true)
continue; // Same object was hit multiple times
hitRoots.Add(hitRootID);
}
validHits.Add(hits[i]);
}
ListPool.Return(hitRoots);
ListPool.Return(hits);
return validHits.Count > 0;
}
public static bool CircleCast(NetworkRunner runner, PlayerRef owner, Vector3 firePosition, Vector3 direction, float distance, float radius, int numberOfRays, LayerMask hitMask, out LagCompensatedHit hit)
{
hit = default;
float angleStep = numberOfRays > 2 ? (2f * Mathf.PI) / (numberOfRays - 1) : 0f;
Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.LookRotation(direction));
for (int i = 0; i < numberOfRays; i++)
{
Vector3 position = firePosition;
// First ray is always directly in the center
if (i > 0)
{
float angle = angleStep * (i - 1);
var offset = new Vector3(radius * Mathf.Cos(angle), radius * Mathf.Sin(angle), 0f);
position += rotationMatrix.MultiplyPoint3x4(offset);
}
if (ProjectileCast(runner, owner, position, direction, distance, hitMask, out LagCompensatedHit currentHit) == true)
{
if (hit.Type == HitType.None || currentHit.Distance < hit.Distance)
{
hit = currentHit;
}
}
}
return hit.Type != HitType.None;
}
}
}