197 lines
6.4 KiB
C#
197 lines
6.4 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using CharacterSystem;
|
||
using UnityEngine;
|
||
using UnityEngine.Serialization;
|
||
|
||
public class DualAvatarController : MonoBehaviour
|
||
{
|
||
[SerializeField, FormerlySerializedAs("characterPrefabs")] private List<GameObject> _characterPrefabs;
|
||
[SerializeField, FormerlySerializedAs("AvatarsParent")] private Transform _avatarsParent;
|
||
[SerializeField, FormerlySerializedAs("baseHiddenLocalPosition")] private Vector2 _player1HiddenLocalPosition;
|
||
[SerializeField, FormerlySerializedAs("baseShownLocalPosition")] private Vector2 _player1ShownLocalPosition;
|
||
[SerializeField] private Vector2 _player2HiddenLocalPosition = new(27f, -5.86f);
|
||
[SerializeField] private Vector2 _player2ShownLocalPosition = new(11.4f, -5.86f);
|
||
[SerializeField] private float _characterScale = 10f;
|
||
[SerializeField, FormerlySerializedAs("CharacterMovementSpeed")] private float _characterMovementSpeed = 15f;
|
||
|
||
private const string AppearTrigger = "Appear";
|
||
private const string SleepTrigger = "Sleep";
|
||
private const string WinTrigger = "Win";
|
||
private readonly Dictionary<Team, PvpCharacter> _characters = new();
|
||
private Coroutine _player1Movement;
|
||
private Coroutine _player2Movement;
|
||
private bool _isShowing;
|
||
private bool _isVisible;
|
||
|
||
public static DualAvatarController Instance { get; private set; }
|
||
|
||
public void Initialize()
|
||
{
|
||
Instance = this;
|
||
|
||
if (_characters.Count > 0)
|
||
return;
|
||
|
||
if (_characterPrefabs == null || _characterPrefabs.Count < 2 ||
|
||
_characterPrefabs[0] == null || _characterPrefabs[1] == null)
|
||
{
|
||
Debug.LogError("Для PvP не назначены персонажи 6 и 7.", this);
|
||
return;
|
||
}
|
||
|
||
_characters[Team.Player1] = CreateCharacter(_characterPrefabs[0], Team.Player1);
|
||
_characters[Team.Player2] = CreateCharacter(_characterPrefabs[1], Team.Player2);
|
||
}
|
||
|
||
public void ShowCharacters()
|
||
{
|
||
if (_characters.Count < 2 || _isVisible || _isShowing)
|
||
return;
|
||
|
||
StopMovement();
|
||
_isShowing = true;
|
||
|
||
PrepareForAppearance(_characters[Team.Player1]);
|
||
PrepareForAppearance(_characters[Team.Player2]);
|
||
|
||
int appearedCharacters = 0;
|
||
Action onAppeared = () =>
|
||
{
|
||
appearedCharacters++;
|
||
if (appearedCharacters < 2)
|
||
return;
|
||
|
||
_isShowing = false;
|
||
_isVisible = true;
|
||
};
|
||
|
||
_player1Movement = StartCoroutine(MoveLocal(
|
||
_characters[Team.Player1],
|
||
GetShownPosition(Team.Player1),
|
||
true,
|
||
onAppeared));
|
||
_player2Movement = StartCoroutine(MoveLocal(
|
||
_characters[Team.Player2],
|
||
GetShownPosition(Team.Player2),
|
||
true,
|
||
onAppeared));
|
||
}
|
||
|
||
public void PlayWin(Team winner)
|
||
{
|
||
if (!_characters.TryGetValue(winner, out PvpCharacter character) || !character.Animator.enabled)
|
||
return;
|
||
|
||
character.Animator.ResetTrigger(WinTrigger);
|
||
character.Animator.SetTrigger(WinTrigger);
|
||
}
|
||
|
||
public void HideCharacters()
|
||
{
|
||
if (_characters.Count < 2)
|
||
return;
|
||
|
||
StopMovement();
|
||
_isShowing = false;
|
||
_isVisible = false;
|
||
|
||
_player1Movement = StartCoroutine(MoveLocal(
|
||
_characters[Team.Player1],
|
||
GetHiddenPosition(Team.Player1),
|
||
false,
|
||
null));
|
||
_player2Movement = StartCoroutine(MoveLocal(
|
||
_characters[Team.Player2],
|
||
GetHiddenPosition(Team.Player2),
|
||
false,
|
||
null));
|
||
}
|
||
|
||
private PvpCharacter CreateCharacter(GameObject prefab, Team team)
|
||
{
|
||
GameObject characterObject = Instantiate(prefab, _avatarsParent);
|
||
Animator animator = characterObject.GetComponentInChildren<Animator>(true);
|
||
|
||
if (animator == null)
|
||
throw new InvalidOperationException($"У PvP-персонажа {prefab.name} отсутствует Animator.");
|
||
|
||
MessageBox messageBox = characterObject.GetComponentInChildren<MessageBox>(true);
|
||
if (messageBox != null)
|
||
messageBox.gameObject.SetActive(false);
|
||
|
||
characterObject.transform.localScale = new Vector3(_characterScale, _characterScale, 1f);
|
||
characterObject.transform.localPosition = GetHiddenPosition(team);
|
||
animator.enabled = false;
|
||
return new PvpCharacter(characterObject.transform, animator);
|
||
}
|
||
|
||
private void PrepareForAppearance(PvpCharacter character)
|
||
{
|
||
character.Animator.enabled = true;
|
||
character.Animator.ResetTrigger(AppearTrigger);
|
||
character.Animator.ResetTrigger(WinTrigger);
|
||
character.Animator.ResetTrigger(SleepTrigger);
|
||
character.Animator.SetTrigger(SleepTrigger);
|
||
}
|
||
|
||
private void StopMovement()
|
||
{
|
||
if (_player1Movement != null)
|
||
StopCoroutine(_player1Movement);
|
||
|
||
if (_player2Movement != null)
|
||
StopCoroutine(_player2Movement);
|
||
|
||
_player1Movement = null;
|
||
_player2Movement = null;
|
||
}
|
||
|
||
private Vector3 GetHiddenPosition(Team team)
|
||
=> team == Team.Player1 ? _player1HiddenLocalPosition : _player2HiddenLocalPosition;
|
||
|
||
private Vector3 GetShownPosition(Team team)
|
||
=> team == Team.Player1 ? _player1ShownLocalPosition : _player2ShownLocalPosition;
|
||
|
||
private IEnumerator MoveLocal(
|
||
PvpCharacter character,
|
||
Vector3 targetLocalPosition,
|
||
bool playAppear,
|
||
Action onComplete)
|
||
{
|
||
while (character.Transform.localPosition != targetLocalPosition)
|
||
{
|
||
character.Transform.localPosition = Vector3.MoveTowards(
|
||
character.Transform.localPosition,
|
||
targetLocalPosition,
|
||
_characterMovementSpeed * Time.deltaTime);
|
||
yield return null;
|
||
}
|
||
|
||
if (playAppear)
|
||
{
|
||
character.Animator.ResetTrigger(AppearTrigger);
|
||
character.Animator.SetTrigger(AppearTrigger);
|
||
}
|
||
else
|
||
{
|
||
character.Animator.enabled = false;
|
||
}
|
||
|
||
onComplete?.Invoke();
|
||
}
|
||
|
||
private sealed class PvpCharacter
|
||
{
|
||
public PvpCharacter(Transform transform, Animator animator)
|
||
{
|
||
Transform = transform;
|
||
Animator = animator;
|
||
}
|
||
|
||
public Transform Transform { get; }
|
||
public Animator Animator { get; }
|
||
}
|
||
}
|