Слежение 2д персонажа за курсором мыши
Я пытаюсь реализовать слежение 2Dперсонажа за курсором мыши, анимации переключаю с помощью паттерна State Machine в самом коде. Когда персонаж стоит, все работает исправно, но при движении возникает точка, в которой анимации меняются без перерыва. (Например, анимация вверх и влево(-0.7, 0.7))
Проблема возникает именно при движении персонажа, когда за ним следует камера.
У меня есть четыре направления анимаций:
- (1, 0) - вверх
- (-1, 0) - вниз
- (0, 1) - вправо
- (0, -1) - влево
Анимацию я меняю на ту, которая ближе к точке ((Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition) - _rigidbody.position).normalized
Движение персонажа происходит через _rigidbody.MovePosition()
Код:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerAnimationController : MonoBehaviour
{
[SerializeField] private List<InfoAboutAnimation> _idleAnimations;
[SerializeField] private List<InfoAboutAnimation> _walkAnimations;
[SerializeField] private Animator _animator;
private Rigidbody2D _rigidbody;
private List<(Vector2 vector, Direction direction)> _directionCircle;
private StateMachine _heroAnimationController;
private IState _idleHeroState;
private IState _walkHeroState;
private void BuildDirectionCircle()
{
_directionCircle.Add((new Vector2(0, 1), Direction.Up));
_directionCircle.Add((new Vector2(0, -1), Direction.Down));
_directionCircle.Add((new Vector2(-1, 0), Direction.Left));
_directionCircle.Add((new Vector2(1, 0), Direction.Right));
}
private void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
_heroAnimationController = new StateMachine();
_idleHeroState = new Idle(_animator);
_walkHeroState = new Walk(_animator);
_directionCircle = new List<(Vector2 vector, Direction direction)>();
foreach (var e in _idleAnimations)
{
_idleHeroState = _idleHeroState.AddDirection(e.direction, e.clip);
}
foreach (var e in _walkAnimations)
{
_walkHeroState = _walkHeroState.AddDirection(e.direction, e.clip);
}
BuildDirectionCircle();
}
private Direction FindNearestDirection(Vector2 vec)
{
(Vector2 vector, Direction direction) ans = _directionCircle[0];
foreach ((Vector2 vector, Direction direction) e in _directionCircle)
{
if (Vector2.Distance(vec, e.vector) < Vector2.Distance(vec, ans.vector))
ans = e;
}
return ans.direction;
}
private void Update()
{
Vector2 movement = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
Vector2 direction = ((Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition) - _rigidbody.position).normalized;
Debug.Log(direction);
Direction viewDirection = FindNearestDirection(direction);
Direction moveDirection = FindNearestDirection(movement);
_walkHeroState.SetNormalDirection();
if (movement != Vector2.zero)
{
//if (IsOppositeDirections(viewDirection, moveDirection))
//{
// _walkHeroState.SetReverseDirection();
//}
//else
//{
// _walkHeroState.SetNormalDirection();
//}
_heroAnimationController.Initialize(_walkHeroState, viewDirection);
}
else
{
_heroAnimationController.Initialize(_idleHeroState, viewDirection);
}
}
private bool IsOppositeDirections(Direction a, Direction b)
{
return (a == Direction.Left && b == Direction.Right) ||
(a == Direction.Right && b == Direction.Left) ||
(a == Direction.Up && b == Direction.Down) ||
(a == Direction.Down && b == Direction.Up);
}
}
Видео с проблемой: https://drive.google.com/file/d/1PIKdfMWFNYT2e0MzmPmKLIC1xLADyWaC/view?usp=sharing
Ответы (1 шт):
Если у вас есть вектор направления от объекта на мышь (вероятно, direction), то отнормируйте его, разделив на его же длину (в unity наверняка есть функция вроде normalized). Затем посчитайте скалярные произведения этого вектора и единичных векторов направлений (в юнити Vector2.Dot). Наибольший результат - наиболее близкое совпадение направления