211 lines
5.0 KiB
C#
211 lines
5.0 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
public class Player : BasePlayer, IGamePlayer
|
|
{
|
|
[Header("Movement Settings")]
|
|
[SerializeField] private float chipYOffset = 5f;
|
|
[SerializeField] private float prepareSpeed;
|
|
[SerializeField] private float moveSpeed;
|
|
|
|
// State
|
|
private PlayerState state = PlayerState.Sleep;
|
|
private Chip currentChip;
|
|
private int[] availableColumns;
|
|
private int selectedColumnIndex;
|
|
|
|
// Movement targets
|
|
private Vector2 stickedTargetPosition;
|
|
private Vector2 dropTargetPosition;
|
|
|
|
private int droppedRow, droppedColumn;
|
|
|
|
public event Action<int,int> OnChipDropped;
|
|
|
|
private int SelectedColumn => availableColumns[selectedColumnIndex];
|
|
|
|
public bool ControlsEnabled { get; set; } = true;
|
|
|
|
#region Public Methods
|
|
|
|
public void PrepareChip()
|
|
{
|
|
SetState(PlayerState.Preparing);
|
|
|
|
CacheAvailableColumns();
|
|
CreateChip();
|
|
SetInitialChipPosition();
|
|
}
|
|
|
|
public void Sleep()
|
|
{
|
|
SetState(PlayerState.Sleep);
|
|
currentChip = null;
|
|
availableColumns = null;
|
|
}
|
|
|
|
public void UpdateControls()
|
|
{
|
|
// Always update state machine regardless of ControlsEnabled
|
|
switch (state)
|
|
{
|
|
case PlayerState.Preparing:
|
|
UpdatePreparing();
|
|
break;
|
|
|
|
case PlayerState.Idle:
|
|
UpdateIdle();
|
|
break;
|
|
|
|
case PlayerState.Moving:
|
|
UpdateMoving();
|
|
break;
|
|
|
|
case PlayerState.Dropping:
|
|
UpdateDropping();
|
|
break;
|
|
|
|
case PlayerState.Sleep:
|
|
// Nothing to do
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region State Updates
|
|
|
|
private void UpdatePreparing()
|
|
{
|
|
if (currentChip.MoveToLinear(stickedTargetPosition, prepareSpeed))
|
|
{
|
|
SetState(PlayerState.Idle);
|
|
}
|
|
}
|
|
|
|
private void UpdateIdle()
|
|
{
|
|
// Only process input if controls are enabled
|
|
if (!ControlsEnabled) return;
|
|
|
|
// Try horizontal movement first
|
|
if (TryHorizontalMovement()) return;
|
|
|
|
// Then try drop
|
|
TryDrop();
|
|
}
|
|
|
|
private void UpdateMoving()
|
|
{
|
|
// Process horizontal input even while moving
|
|
if (ControlsEnabled)
|
|
{
|
|
TryHorizontalMovement();
|
|
}
|
|
|
|
// Wait for chip to reach target
|
|
if (currentChip.MoveToLinear(stickedTargetPosition, moveSpeed))
|
|
{
|
|
SetState(PlayerState.Idle);
|
|
}
|
|
}
|
|
|
|
private void UpdateDropping()
|
|
{
|
|
if (currentChip.MoveToAccelerated(dropTargetPosition))
|
|
{
|
|
if (currentChip.MoveToAccelerated(dropTargetPosition))
|
|
{
|
|
SetState(PlayerState.Sleep);
|
|
OnChipDropped?.Invoke(droppedColumn, droppedRow);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Actions
|
|
|
|
private bool TryHorizontalMovement()
|
|
{
|
|
int direction = GetHorizontalInput();
|
|
if (direction == 0) return false;
|
|
|
|
int newIndex = Mathf.Clamp(selectedColumnIndex + direction, 0, availableColumns.Length - 1);
|
|
if (newIndex == selectedColumnIndex) return false;
|
|
|
|
selectedColumnIndex = newIndex;
|
|
stickedTargetPosition = board.GetStickedPosition(SelectedColumn);
|
|
SetState(PlayerState.Moving);
|
|
|
|
return true;
|
|
}
|
|
|
|
private void TryDrop()
|
|
{
|
|
if (!IsActionPressed()) return;
|
|
|
|
dropTargetPosition = board.GetTargetPosition(SelectedColumn);
|
|
|
|
droppedColumn = SelectedColumn;
|
|
droppedRow = board.GetLowestEmptyRow(SelectedColumn);
|
|
|
|
board.DropChip(currentChip, SelectedColumn);
|
|
SetState(PlayerState.Dropping);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helpers
|
|
|
|
private void CacheAvailableColumns()
|
|
{
|
|
availableColumns = board.GetNonFullColumns();
|
|
selectedColumnIndex = availableColumns.Length / 2;
|
|
}
|
|
|
|
private void CreateChip()
|
|
{
|
|
currentChip = ChipPool.Instance.GetConfigured(chipSprite, team);
|
|
}
|
|
|
|
private void SetInitialChipPosition()
|
|
{
|
|
stickedTargetPosition = board.GetMiddleStickedPosition();
|
|
currentChip.transform.position = stickedTargetPosition + Vector2.up * chipYOffset;
|
|
}
|
|
|
|
private int GetHorizontalInput()
|
|
{
|
|
return In.GetAxis(GetJoystickSide(), InteractMode.Discrete).x;
|
|
}
|
|
|
|
private bool IsActionPressed()
|
|
{
|
|
return In.GetAction(GetJoystickSide(), InteractMode.Discrete);
|
|
}
|
|
|
|
private JoystickSide GetJoystickSide()
|
|
=> team == Team.Player1 ? JoystickSide.Left : JoystickSide.Right;
|
|
|
|
private void SetState(PlayerState newState)
|
|
{
|
|
state = newState;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested Types
|
|
|
|
private enum PlayerState
|
|
{
|
|
Sleep, // No input, chip placed on board
|
|
Preparing, // No input, chip moving to sticked position
|
|
Idle, // Input enabled, waiting for action
|
|
Moving, // Input enabled (horizontal only), chip moving horizontally
|
|
Dropping // No input, chip falling down
|
|
}
|
|
|
|
#endregion
|
|
}
|