chip-game/Assets/Scripts/GameFSM/ChipFallingState.cs
2026-01-12 09:36:17 +03:00

157 lines
4.4 KiB
C#

//Refactored 24.11.2025
using System.Collections;
using UnityEngine;
using UnityEngine.UIElements;
public class ChipFallingState : IState
{
const float ROTATION_SPEED_FACTOR = -0.5f;
const float BOUNCE_SPEEDY_LOSS_FACTOR = 0.5f;
const float BOUNCE_SPEEDY_TRESHOLD = 5;
const float MAX_ANGULAR_SPEED = 500;
const bool USE_BOUNCE = false;
int rowIndex;
int colIndex;
float angularSpeed;
Vector2 targetPosition;
Transform chipTransform;
bool firstTouchCompleted = false;
float startDelay = 0;
bool delayCompleted = false;
public ChipFallingState(float startDelay)
{
this.startDelay = startDelay;
}
#region ENTER_METHODS
public void enter() => GameManager.instance.StartCoroutine(DelayedEnter(startDelay));
private void CacheFields()
{
chipTransform = GameManager.instance.currentChip.transform;
colIndex = GameManager.instance.currentColumnIndex;
rowIndex = GameManager.fieldModel.getHeight(colIndex);
targetPosition = CalculateTargetPosition();
angularSpeed = Random.Range(-MAX_ANGULAR_SPEED, MAX_ANGULAR_SPEED);
}
private void PrepareForFalling()
{
chipTransform.GetComponent<TrailRenderer>().enabled = true;
GameManager.instance.chipYSpeed = 0;
}
private void InitialSound() => SoundManager.instance.playDropDown();
private Vector2 CalculateTargetPosition()
{
float targetX = chipTransform.position.x;
float targetY = GameManager.instance.slotLeftTop.transform.position.y - GameManager.instance.stepY * rowIndex;
return new Vector2(targetX, targetY);
}
#endregion
#region UPDATE_METHODS
public void update()
{
if (!delayCompleted) return;
ChipFallProcess();
if (chipTransform.position.y == targetPosition.y)
{
//обработка первого касания
if (!firstTouchCompleted)
{
firstTouchCompleted = true;
chipTransform.GetComponent<TrailRenderer>().emitting = false;
//Можно попробовать некоторый звук подходящий в это место
//SoundManager.instance.playExplosion();
}
if (USE_BOUNCE)
BounceBehaviour();
else
NoBounceBehaviour();
}
}
private void ChipFallProcess()
{
GameManager.instance.chipYSpeed += GameManager.instance.chipAcceleration * Time.deltaTime;
float speed = GameManager.instance.chipYSpeed;
float offsetY = speed * Time.deltaTime;
if (chipTransform.position.y - offsetY < targetPosition.y)
offsetY = -targetPosition.y + chipTransform.position.y;
chipTransform.transform.Translate(Vector2.down * offsetY, Space.World);
chipTransform.transform.Rotate(0, 0, angularSpeed * Time.deltaTime);
}
private void BounceBehaviour()
{
if (GameManager.instance.chipYSpeed > BOUNCE_SPEEDY_TRESHOLD)
{
Bounce();
}
else
{
CompleteChipLanding();
}
}
private void NoBounceBehaviour()
{
SoundManager.instance.playChipBounce();
CompleteChipLanding();
}
private void Bounce()
{
angularSpeed *= ROTATION_SPEED_FACTOR;
SoundManager.instance.playChipBounce();
GameManager.instance.chipYSpeed = -GameManager.instance.chipYSpeed * BOUNCE_SPEEDY_LOSS_FACTOR;
}
private void CompleteChipLanding()
{
chipTransform.position = targetPosition;
GameManager.fieldModel.fieldArr[rowIndex, colIndex] = GameManager.instance.currentPlayer;
GameManager.instance.setChipTransformToArray(rowIndex, colIndex, chipTransform);
GameManager.instance.stateMachine.ChangeState(new CheckState(rowIndex, colIndex));
}
#endregion
#region EXIT_METHODS
public void exit() => AnnouncePlayerTurn();
private void AnnouncePlayerTurn()
{
if (GameManager.instance.currentPlayer == CellState.Player1)
{
CharacterEventBus.Instance.OnPlayerTurn?.Invoke();
}
}
#endregion
IEnumerator DelayedEnter(float startDelay)
{
yield return new WaitForSeconds(startDelay);
CacheFields();
PrepareForFalling();
InitialSound();
delayCompleted = true;
}
}