Targeter.cs
using System.Collections.Generic;
using Cinemachine;
using UnityEngine;
public class Targeter : MonoBehaviour
{
[SerializeField] CinemachineTargetGroup cineTargetGroup;
Camera mainCamera;
List<Target> targets = new List<Target>();
public Target CurrentTarget { get; private set; }
void start()
{
mainCamera = Camera.main;
}
void OnTriggerEnter(Collider other)
{
if (!other.TryGetComponent<Target>(out Target target)) { return; }
targets.Add(target);
target.OnDestroyed += RemoveTarget;
}
void OnTriggerExit(Collider other)
{
if (!other.TryGetComponent<Target>(out Target target)) { return; }
RemoveTarget(target);
}
public bool SelectTarget()
{
if (targets.Count == 0) { return false; }
Target closestTarget = null;
float closestTargetDistance = Mathf.Infinity;
foreach (Target target in targets)
{
Vector2 viewPos = mainCamera.WorldToViewportPoint(target.transform.position);
if (viewPos.x < 0 || viewPos.x > 1 || viewPos.y < 0 || viewPos.y > 1)
{
continue;
}
Vector2 toCenter = viewPos - new Vector2(0.5f, 0.5f);
if (toCenter.sqrMagnitude < closestTargetDistance)
{
closestTarget = target;
closestTargetDistance = toCenter.sqrMagnitude;
}
}
if (closestTarget == null) { return false; }
CurrentTarget = closestTarget;
cineTargetGroup.AddMember(CurrentTarget.transform, 1f, 2f);
return true;
}
public void Cancel()
{
if (CurrentTarget == null) { return; }
cineTargetGroup.RemoveMember(CurrentTarget.transform);
CurrentTarget = null;
}
void RemoveTarget(Target target)
{
if (CurrentTarget == target)
{
cineTargetGroup.RemoveMember(CurrentTarget.transform);
CurrentTarget = null;
}
target.OnDestroyed -= RemoveTarget;
targets.Remove(target);
}
}
PlayerFreeLookState.cs
using UnityEngine;
public class PlayerFreeLookState : PlayerBaseState
{
readonly int FreeLookSpeedHash = Animator.StringToHash("FreeLookSpeed");
readonly int FreeLookBlendTreeHash = Animator.StringToHash("FreeLookBlendTree");
const float AnimatorDampTime = 0.1f;
public PlayerFreeLookState(PlayerStateMachine stateMachine) : base(stateMachine)
{
}
public override void Enter()
{
stateMachine.InputReader.TargetEvent += OnTarget;
stateMachine.Animator.Play(FreeLookBlendTreeHash);
}
public override void Tick(float deltaTime)
{
Vector3 movement = CalculateMovement();
Move(movement * stateMachine.FreeLookMovementSpeed, deltaTime);
if (stateMachine.InputReader.MovementValue == Vector2.zero)
{
stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0, AnimatorDampTime, deltaTime);
return;
}
stateMachine.Animator.SetFloat(FreeLookSpeedHash, 1, AnimatorDampTime, deltaTime);
FaceMovementDirection(movement, deltaTime);
}
public override void Exit()
{
stateMachine.InputReader.TargetEvent -= OnTarget;
}
void OnTarget()
{
if (!stateMachine.Targeter.SelectTarget()) { return; }
stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
}
Vector3 CalculateMovement()
{
Vector3 forward = stateMachine.MainCameraTransform.forward;
Vector3 right = stateMachine.MainCameraTransform.right;
forward.y = 0f;
right.y = 0f;
forward.Normalize();
right.Normalize();
return forward * stateMachine.InputReader.MovementValue.y +
right * stateMachine.InputReader.MovementValue.x;
}
void FaceMovementDirection(Vector3 movement, float deltaTime)
{
stateMachine.transform.rotation = Quaternion.Lerp(stateMachine.transform.rotation,
Quaternion.LookRotation(movement),
deltaTime * stateMachine.RotationDamping);
}
}
Player prefab