Рефакторниг позиционирования и сброса фишки

This commit is contained in:
Сергей Бондарь 2026-07-17 10:16:32 +03:00
parent 99ccb2e8ae
commit c86aef53f1
13 changed files with 351 additions and 524 deletions

View File

@ -6680,6 +6680,7 @@ MonoBehaviour:
SettingsPointer: {fileID: 334401357}
timerManager: {fileID: 259182288}
rulesController: {fileID: 454272343}
chipPointer: {fileID: 1615046714}
gameMode: 0
coinPanel: {fileID: 1407544274}
board: {fileID: 1551328425}
@ -6699,7 +6700,6 @@ MonoBehaviour:
player2Chip: {fileID: 4478126490810938235, guid: 376ff57f7b90bd845a887cfd6ba95427, type: 3}
botChip: {fileID: 4478126490810938235, guid: afe8782fb49b2254cbdae76f1a9f22a8, type: 3}
currentChip: {fileID: 0}
chipPointer: {fileID: 21300000, guid: 3b962dad9ec02724b892bfa03441cb4f, type: 3}
selectedPanel: {fileID: 1304898661, guid: bff7731f029e97345b55849f0e330c32, type: 3}
deselectedPanel: {fileID: 1744797893, guid: 93e5f9833bed0474cb1481410d00191c, type: 3}
EngamePanel: {fileID: 347852021}
@ -55211,6 +55211,113 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1614501702}
m_CullTransparentMesh: 1
--- !u!1 &1615046713
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1615046716}
- component: {fileID: 1615046715}
- component: {fileID: 1615046714}
m_Layer: 0
m_Name: ChipPointer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1615046714
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1615046713}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 787d4a706011d6f4e9797e869d6e24df, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::ChipPointer
spriteRenderer: {fileID: 1615046715}
player1Color: {r: 1, g: 0.5, b: 0, a: 1}
player2Color: {r: 0, g: 0.3, b: 1, a: 1}
--- !u!212 &1615046715
SpriteRenderer:
serializedVersion: 2
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1615046713}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: -5330059
m_SortingLayer: 2
m_SortingOrder: 0
m_MaskInteraction: 0
m_Sprite: {fileID: 21300000, guid: 3b962dad9ec02724b892bfa03441cb4f, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_SpriteSortPoint: 0
--- !u!4 &1615046716
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1615046713}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -1.36, y: -10.3, z: 0}
m_LocalScale: {x: 1.15, y: 1.15, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1617932514
GameObject:
m_ObjectHideFlags: 0
@ -80475,3 +80582,4 @@ SceneRoots:
- {fileID: 592995719}
- {fileID: 1984502422}
- {fileID: 172285186}
- {fileID: 1615046716}

View File

@ -0,0 +1,28 @@
using UnityEngine;
public class ChipPointer : MonoBehaviour
{
[SerializeField] SpriteRenderer spriteRenderer;
[SerializeField] Color player1Color = new Color(1, 0.5f, 0, 1);
[SerializeField] Color player2Color = new Color(0, .3f, 1, 1);
public void Show() => spriteRenderer.enabled = true;
public void Hide() => spriteRenderer.enabled = false;
public void SetPosition(Vector2 position) => transform.position = position;
public void SetColorByPlayer(CellState player) => spriteRenderer.color = player == CellState.Player1 ? player1Color : player2Color;
public void SinAlphaAnimation()
{
Color color = spriteRenderer.color;
color.a = 0.8f + Mathf.Sin(Time.time * 7) * 0.2f;
spriteRenderer.color = color;
}
private void Update()
{
if(spriteRenderer.enabled)
SinAlphaAnimation();
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 787d4a706011d6f4e9797e869d6e24df

View File

@ -83,8 +83,6 @@ public class BotThinkingState : IState
{
if (!animationStarted)
{
//нужно запустить анимацию подброса и дождаться ее окончания
//Debug.Log("Throw из botthink");
animator.SetTrigger("Throw");
startAnimTime = Time.time;
animationStarted = true;
@ -96,35 +94,27 @@ public class BotThinkingState : IState
{
//ставим фишку в расчитанную колонку (подготовка к следующему состоянию)
GameManager.instance.currentColumnIndex = calculatedColumn;
float targetY = GameManager.instance.startY + 5;
float targetY = GameManager.instance.startY;
float targetX = GameManager.instance.slotLeftTop.position.x +
GameManager.instance.currentColumnIndex *
GameManager.instance.stepX;
GameManager.instance.currentChip.transform.position = new Vector2(targetX, targetY);
//GameManager.instance.currentChip.SetActive(true);
GameManager.instance.stateMachine.ChangeState(new ChipFallingState(0));
Vector2 targetPosition = new Vector2(targetX, targetY);
GameManager.instance.currentChip.transform.position = new Vector2(targetX, targetY + 5);
GameManager.instance.stateMachine.ChangeState(new ChipFallingState(0, calculatedColumn));
}
}
}
void calc()
{
//calculatedColumn = Solver.FindBestMove(GameManager.fieldModel.fieldArr, GameManager.instance.currentPlayer);
GameManager gm = GameManager.instance;
//Судя по счету мы находимся на последнем боте.
bool OnBossByScore = gm.vsBotScore == gm.botsAmount - 1;
bool IsHardCommonDifficulty = SettingsManager.GetString("Difficulty", "Средняя") == "Сложная";
bool IsUpperCashDifficulty = SettingsManager.GetString("BaseBotDifficulty", "Повышенная") == "Повышенная";
bool NeedSuperPreset = OnBossByScore && (IsHardCommonDifficulty || IsUpperCashDifficulty);
//NeedSuperPreset = true;
//Debug.Log($"Использовать суперсложность: {NeedSuperPreset}\nСейчас босс: {OnBossByScore}\nСложная сложность: {IsHardCommonDifficulty}\nВключен режим заработка: {IsUpperCashDifficulty}\n");
if (NeedSuperPreset)
{
calculatedColumn = SolverV2.FindBestMove(GameManager.fieldModel.FieldArray, GameManager.instance.currentPlayer);

View File

@ -2,58 +2,49 @@
using UnityEngine;
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;
bool USE_BOUNCE = false;
int rowIndex;
int colIndex;
int targetColumn;
float angularSpeed;
float velocityY = 0;
Vector2 targetPosition;
Transform chipTransform;
bool firstTouchCompleted = false;
float startDelay = 0;
bool delayCompleted = false;
private GameManager gm;
public ChipFallingState(float startDelay)
public ChipFallingState(float startDelay, int col)
{
gm = GameManager.instance;
this.startDelay = startDelay;
targetColumn = col;
rowIndex = GameManager.fieldModel.GetColumnHeight(targetColumn);
}
private Vector2 CalculateTargetPosition()
{
float targetX = gm.slotLeftTop.position.x + targetColumn * gm.stepX;
float targetY = gm.slotLeftTop.transform.position.y - GameManager.instance.stepY * rowIndex;
return new Vector2(targetX, targetY);
}
public void enter()
{
targetPosition = CalculateTargetPosition();
GameManager.instance.StartCoroutine(DelayedEnter(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;
@ -62,77 +53,33 @@ public class ChipFallingState : IState
if (chipTransform.position.y == targetPosition.y)
{
//обработка первого касания
if (!firstTouchCompleted)
{
firstTouchCompleted = true;
chipTransform.GetComponent<TrailRenderer>().emitting = false;
//Можно попробовать некоторый звук подходящий в это место
//SoundManager.instance.playExplosion();
}
if (USE_BOUNCE)
BounceBehaviour();
else
NoBounceBehaviour();
chipTransform.GetComponent<TrailRenderer>().emitting = false;
SoundManager.instance.playChipBounce();
CompleteChipLanding();
}
}
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);
velocityY += GameManager.instance.chipAcceleration * Time.deltaTime;
float delta = velocityY * Time.deltaTime;
chipTransform.position = Vector2.MoveTowards(chipTransform.position, targetPosition, delta);
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.FieldArray[rowIndex, colIndex] = GameManager.instance.currentPlayer;
GameManager.instance.setChipTransformToArray(rowIndex, colIndex, chipTransform);
//GameManager.instance.stateMachine.ChangeState(new CheckState());
//EndOfTurnHandler.EvaluateTurnEnding();
GameManager.fieldModel.FieldArray[rowIndex, targetColumn] = GameManager.instance.currentPlayer;
GameManager.instance.setChipTransformToArray(rowIndex, targetColumn, chipTransform);
StateRouter.RouteAfterTurn();
}
#endregion
#region EXIT_METHODS
public void exit() => AnnouncePlayerTurn();
public void exit()
{
velocityY = 0;
AnnouncePlayerTurn();
}
private void AnnouncePlayerTurn()
{
if (GameManager.instance.currentPlayer == CellState.Player1)
@ -140,8 +87,6 @@ public class ChipFallingState : IState
CharacterEventBus.Instance.OnPlayerTurn?.Invoke();
}
}
#endregion
IEnumerator DelayedEnter(float startDelay)
{
@ -153,4 +98,4 @@ public class ChipFallingState : IState
delayCompleted = true;
}
}
}

View File

@ -1,17 +1,14 @@
using System.Collections.Generic;
using System.Collections;
using UnityEngine;
public class PositioningState : IState
{
GameManager gm;
GameObject chip;
Transform chipPointer;
SpriteRenderer pointerRend;
int index;
int position;
bool canMove;
bool chipOnPosition;
const int DEFAULT_SPEED = 50;
@ -19,64 +16,148 @@ public class PositioningState : IState
public void enter()
{
//DebugWindow.Message("Позиционирование");
gm = GameManager.instance;
CollectValidPositions();
canMove = true;
//получаем ссылку на фишку
chip = gm.currentChip;
chipOnPosition = true;
validPositions = GameManager.fieldModel.CollectNonFullCols();
int centralIndex = validPositions.Count / 2;
index = centralIndex;
position = validPositions[centralIndex];
gm.currentColumnIndex = validPositions[centralIndex];
//ставим фишку на стартовую точку
//float offsety = 5;
float offsety = gm.startY;
if (gm.gameMode == GameMode.pvp) offsety = gm.startY + 5;//повыше
float x = gm.slotLeftTop.position.x + validPositions[index] * gm.stepX;
float y = gm.startY + offsety;
chip.transform.position = new Vector3(x, y, 0);
chip.SetActive(true);
gm.chipYSpeed = 0;
//настройка указателя куда упадет фишка
chipPointer = new GameObject("Pointer").transform;
chipPointer.position = new Vector3(100, 100);
chipPointer.localScale = new Vector2(1.15f, 1.15f);
chipPointer.gameObject.SetActive(false);
pointerRend = chipPointer.gameObject.AddComponent<SpriteRenderer>();
pointerRend.enabled = false;
pointerRend.sprite = gm.chipPointer;
pointerRend.color = gm.currentPlayer == CellState.Player1 ? new Color(1, .5f, 0, 1) : new Color(0, .3f, 1, 1);
pointerRend.sortingLayerName = "Middle";
pointerRend.enabled = true;
//НАДО POINTER ЯРЧЕ!
chipPointer.gameObject.SetActive(true);
gm.chipPointer.Show();
gm.chipPointer.SetColorByPlayer(gm.currentPlayer);
}
public void exit()
{
gm.pvpPointer.SetVisibility(false);
gm.StartCoroutine(DestroyPointer());
gm.chipPointer.Hide();
}
public void update()
{
#region Получение инпутов
// вычисление ввода в зависимости от игрового режима
var input = GetInputs();
if (gm.gameMode == GameMode.pve) gm.vsBotThinkTime += Time.deltaTime;
HandleChipMovement(input.direction);
Vector2 stickedPosition = GetStickedPosition();
Vector2 targetPosition = GetTargetPosition();
gm.chipPointer.SetPosition(targetPosition);
if (gm.gameMode == GameMode.pvp)
{
gm.pvpPointer.SetColor(gm.currentPlayer);
gm.pvpPointer.SetVisibility(true);
gm.pvpPointer.MoveTo(stickedPosition);
stickedPosition += Vector2.up * 5;//повыше
}
chip.transform.position = Vector2.MoveTowards(chip.transform.position, stickedPosition, DEFAULT_SPEED * Time.deltaTime);
if ((Vector2)chip.transform.position == stickedPosition)
chipOnPosition = true;
else
chipOnPosition = false;
if (HandleDrop(input.action)) return;
if (HandleExitToMenu()) return;
}
private void HandleChipMovement(int direction)
{
if (!chipOnPosition) return;
index = Mathf.Clamp(index + direction, 0, validPositions.Count - 1);
int prevPos = position;
position = validPositions[index];
int dist = Mathf.Abs(position - prevPos);
gm.chipXSpeed = dist * DEFAULT_SPEED;//скорость зануляется
gm.currentColumnIndex = position;
SoundManager.instance.playSwitch();
}
private bool HandleExitToMenu()
{
bool exitPressed = In.GetButtonDown(ButtonPinMapping.startOnePlayer) || In.GetButtonDown(ButtonPinMapping.startTwoPlayers);
if (exitPressed && !gm.moveMade)
{
FieldCleaner.Clear();
PaymentSystem.ReturnCredits(gm.gameMode);
GameManager.instance.timerManager.StopAllTimers();
GameManager.instance.stateMachine.ChangeState(new MenuState());
return true;
}
return false;
}
private bool HandleDrop(bool action)
{
if (!action) return false;
//todo: посмотреть нахуя currentColumnIndex зарыто в gm. разрыть.
bool canDropInCurrentColumn = GameManager.fieldModel.GetColumnHeight(gm.currentColumnIndex) != -1;
if (!(chipOnPosition && canDropInCurrentColumn))
{
SoundManager.instance.playWrong();
return false;
}
float delayBeforeStartFalling = 0;
if (gm.gameMode == GameMode.pve) gm.vsBotMoves += 1;
if (gm.gameMode == GameMode.pvp)
{
AvatarEventBus.Instance.OnTurnEnd?.Invoke(gm.currentPlayer);
delayBeforeStartFalling = DualAvatarController.Instance.CurrentAvatar.ChipSpawnTime;
}
gm.moveMade = true;
Vector2 targetPosition = GetTargetPosition();
gm.stateMachine.ChangeState(new ChipFallingState(startDelay: delayBeforeStartFalling, gm.currentColumnIndex));
return true;
}
private Vector2 GetStickedPosition()
{
float targetX = gm.slotLeftTop.position.x +
gm.currentColumnIndex *
gm.stepX;
float targetY = gm.startY;
return new Vector2(targetX, targetY);
}
private Vector2 GetTargetPosition()
{
float targetX = gm.slotLeftTop.position.x +
gm.currentColumnIndex *
gm.stepX;
float targetY = GameManager.instance.slotLeftTop.transform.position.y - GameManager.instance.stepY * GameManager.fieldModel.GetColumnHeight(gm.currentColumnIndex);
return new Vector2(targetX, targetY);
}
private (int direction, bool action) GetInputs()
{
bool left = false,
right = false,
action = false;
if (gm.gameMode == GameMode.pvp)
{
left = In.GetButtonDownCurrentPlayer(PlayerAction.left);
@ -88,136 +169,12 @@ public class PositioningState : IState
left = In.GetButtonDownAnyPlayer(PlayerAction.left);
right = In.GetButtonDownAnyPlayer(PlayerAction.right);
action = In.GetButtonDownAnyPlayer(PlayerAction.down);
gm.vsBotThinkTime += Time.deltaTime;
}
#endregion
#region Обработка left|right
if (canMove)
{
//вычисляем куда двигаться
int direction = 0;
if (left && right)
direction = 0;
else if (left)
direction = -1;
else if (right)
direction = 1;
//если двигаемся
if (direction != 0)
{
index = Mathf.Clamp(index + direction, 0, validPositions.Count - 1);
int prevPos = position;
position = validPositions[index];
int dist = Mathf.Abs(position - prevPos);
gm.chipXSpeed = dist * DEFAULT_SPEED;//скорость зануляется
gm.currentColumnIndex = position;
SoundManager.instance.playSwitch();
}
}
#endregion
float targetX = gm.slotLeftTop.position.x +
gm.currentColumnIndex *
gm.stepX;
float targetY = gm.startY;
Vector2 targetPosition = new Vector2(targetX, targetY);
float speed = DEFAULT_SPEED;
//УКАЗАТЕЛЬ
float pointerY = gm.slotLeftTop.transform.position.y - gm.stepY * GameManager.fieldModel.getHeight(position);
chipPointer.position = new Vector2(targetX, pointerY);
Color color = pointerRend.color;
color.a = 0.8f + Mathf.Sin(Time.time * 7) * 0.2f;
pointerRend.color = color;
if (gm.gameMode == GameMode.pvp)
{
gm.pvpPointer.SetColor(gm.currentPlayer);
gm.pvpPointer.SetVisibility(true);
gm.pvpPointer.MoveTo(targetPosition);
targetPosition += Vector2.up * 5;//повыше
}
chip.transform.position = Vector2.MoveTowards(chip.transform.position, targetPosition, speed * Time.deltaTime);
int direction = 0;
if (left) direction -= 1;
if (right) direction += 1;
if ((Vector2)chip.transform.position == targetPosition)
canMove = true;
else
canMove = false;
if (action)
{
if (canMove && GameManager.fieldModel.getHeight(gm.currentColumnIndex) != -1)
{
float delayBeforeStartFalling = 0;
if (gm.gameMode == GameMode.pve)
{
gm.vsBotMoves += 1;
}
if (gm.gameMode == GameMode.pvp)
{
AvatarEventBus.Instance.OnTurnEnd?.Invoke(gm.currentPlayer);
delayBeforeStartFalling = DualAvatarController.Instance.CurrentAvatar.ChipSpawnTime;
}
gm.moveMade = true;
gm.stateMachine.ChangeState(new ChipFallingState(startDelay: delayBeforeStartFalling));
}
else
{
SoundManager.instance.playWrong();
}
}
//ВЫХОД ДО ПЕРВОГО ХОДА
bool exitPressed = In.GetButtonDown(ButtonPinMapping.startOnePlayer) || In.GetButtonDown(ButtonPinMapping.startTwoPlayers);
if (exitPressed && !gm.moveMade)
{
FieldCleaner.Clear();
PaymentSystem.ReturnCredits(gm.gameMode);
GameManager.instance.timerManager.StopAllTimers();
//GameManager.instance.stateMachine.ChangeState(new MenuState(fromGameplay: true));
GameManager.instance.stateMachine.ChangeState(new MenuState());
}
return (direction, action);
}
void CollectValidPositions()
{
validPositions = new List<int>();
for (int i = 0; i < gm.Cols; i++)
{
if (GameManager.fieldModel.getHeight(i) != -1)
{
validPositions.Add(i);
}
}
}
IEnumerator DestroyPointer()
{
Color color = pointerRend.color;
float t = 1;
while (t > 0)
{
t -= Time.deltaTime * 3;
color.a = t;
pointerRend.color = color;
yield return null;
}
Object.Destroy(chipPointer.gameObject);
}
}
}

View File

@ -8,33 +8,30 @@ public enum GameMode { pve, pvp }
public class GameManager : MonoBehaviour
{
private const int DEFAULT_FRAME_RATE = 60;
public int Rows = 7, Cols = 7;
public PlayerStatsService StatsService;
public int botsAmount = 5;
public int boardVersion = 1;
[Header("General")]
public GameStateMachine stateMachine;
public Transform slotLeftTop;
public static FieldModel fieldModel;
public static GameManager instance;
public GameObject AdminPanel, NumberPanel, SettingsPointer;
public GameObject AdminPanel, NumberPanel;
public TimerManager timerManager;
public RulesController rulesController;
public ChipPointer chipPointer;
[Header("Menu")]
public GameMode gameMode;
public Transform
coinPanel,
board,
noPrizeLabel;
public GameObject mainMenu;
public UiManager menuUi;
public TMP_FontAsset russo_font;
[Header("Scores")]
public int player1score = 0, player2score = 0, vsBotScore = 0;
@ -53,9 +50,8 @@ public class GameManager : MonoBehaviour
public GameObject player2Chip;
public GameObject botChip;
[HideInInspector] public GameObject currentChip;
public Sprite chipPointer, selectedPanel, deselectedPanel;
public RectTransform EngamePanel, TimerImage;
public RectTransform EngamePanel;
public RectTransform smallPrizesOut;
public Image ReplayButton, MenuButton;
public DrawVisual DrawVisual;
@ -76,7 +72,6 @@ public class GameManager : MonoBehaviour
public bool moveMade = false;
public float chipXSpeed = 10,
chipYSpeed = 0,
chipAcceleration = 20;
public Transform[,] chipTransforms;
@ -85,7 +80,6 @@ public class GameManager : MonoBehaviour
[Header("Панели ввода")]
public TextInput nameInput;
public TextInput ValutaNameInput;
public TextInput specialPrizeInput;
public TextInput NumberTech;
public NumberInput pricePveInput;
public NumberInput pricePvpInput;
@ -96,8 +90,6 @@ public class GameManager : MonoBehaviour
public Leaderboard leaderboard;
public GameObject CharactersConfigurator;
public GameObject fastCheckCounters;
public GameObject checkQrPanel;
public DualAvatarController avatarController;
public PvpPointer pvpPointer;
@ -111,7 +103,6 @@ public class GameManager : MonoBehaviour
public VitrinaPanel vitrinaPanel;
public QrPanel qrPanel;
private Logger logger;
public VitrinaCatcher vitrinaCatcher;
public TakeOrRiskPanel takeOrRiskPanel;
@ -138,11 +129,6 @@ public class GameManager : MonoBehaviour
InitializePrefs();
SettingsManager.Initialize();
GetComponent<Logger>().Initialize();
//Тестируем пока что. Не прод(ну ладно прод.)
logger = GetComponent<Logger>();
InitializeDevices();
@ -189,7 +175,7 @@ public class GameManager : MonoBehaviour
{
sb.Append($"{device.Key} : {device.Value}");
}
logger.Log(sb.ToString());
Debug.Log(sb.ToString());
bool controllerFound = false;
@ -201,40 +187,39 @@ public class GameManager : MonoBehaviour
if (device.Value == ComPortScanner.DeviceType.PrizeShowcase)
{
vitrinaPort = device.Key;
logger.Log($"нашел витрину на порту, {vitrinaPort}");
Debug.Log($"нашел витрину на порту, {vitrinaPort}");
}
else if (device.Value == ComPortScanner.DeviceType.ControllerV1)
{
if (!controllerFound)
{
logger.Log("Нашел периферийник1 открываю.");
Debug.Log("Нашел периферийник1 открываю.");
ComWrapper.Initialize(device.Key, boardVersion: 1);
controllerFound = true;
}
}
else if (device.Value == ComPortScanner.DeviceType.ControllerV2)
{
if (!controllerFound)
{
logger.Log("Нашел периферийник2 открываю.");
Debug.Log("Нашел периферийник2 открываю.");
ComWrapper.Initialize(device.Key, boardVersion: 2);
controllerFound = true;
}
}
else
{
logger.Log($"неизвестный тип {device.Key}:{device.Value}");
Debug.Log($"неизвестный тип {device.Key}:{device.Value}");
}
}
if (vitrinaPort != null)
{
logger.Log($"Витрину открываем (порт {vitrinaPort}");
Debug.Log($"Витрину открываем (порт {vitrinaPort}");
int h = ComNativeWrapper.Serial_Open(vitrinaPort, 115200, 8, 0, 1, 4, 10);
if (h > 0) logger.Log("Открыл");
else logger.Log("Не Открыл");
PrizeStandController.Initialize(h, 5, logger);
if (h > 0) Debug.Log("Открыл");
else Debug.Log("Не Открыл");
PrizeStandController.Initialize(h, 5);
}
}
@ -245,7 +230,7 @@ public class GameManager : MonoBehaviour
private void PrizeStandController_InitializationComplete(bool arg1, string arg2)
{
logger.Log($"Инициализация витрины: {arg1} : {arg2}");
Debug.Log($"Инициализация витрины: {arg1} : {arg2}");
}
private static void InitializePrefs()
@ -332,7 +317,6 @@ public class GameManager : MonoBehaviour
Player1Scale.SetSlotsCount(5);
Player2Scale.SetSlotsCount(5);
Player1Scale.ResetScale();
Player2Scale.ResetScale();
break;
@ -458,7 +442,6 @@ public class GameManager : MonoBehaviour
}
}
public void ResetGameSession()
{
vsBotThinkTime = 0;

View File

@ -330,9 +330,9 @@ public class COMinput : InputSource
if (prizeSensorPin < input.Length && input[prizeSensorPin] == sensorPositive)
{
Logger.Instance.Log($"Считано положительное значени датчика приза ({sensorPositive}). Устанавливаю значение 1 в буфер");
Debug.Log($"Считано положительное значени датчика приза ({sensorPositive}). Устанавливаю значение 1 в буфер");
PlayerPrefs.SetInt("PrizeGivenBuffer", 1);
Logger.Instance.Log($"Установлено значение буфера {PlayerPrefs.GetInt("PrizeGivenBuffer")}");
Debug.Log($"Установлено значение буфера {PlayerPrefs.GetInt("PrizeGivenBuffer")}");
}
}

View File

@ -1,177 +0,0 @@
using System;
using System.IO;
using UnityEngine;
public class Logger : MonoBehaviour, ILogger
{
private static Logger instance;
private string logFilePath;
private StreamWriter writer;
public static Logger Instance
{
get
{
return instance;
}
}
public ILogHandler logHandler { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool logEnabled { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public LogType filterLogType { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
/// <summary>
/// Инициализирует логгер и создает файл лога
/// </summary>
public void Initialize()
{
try
{
instance = this;
// Получаем путь к папке PersistentDataPath
string persistentPath = Application.persistentDataPath;
// Создаем имя файла с датой и временем
string fileName = $"comlog_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt";
logFilePath = Path.Combine(persistentPath,"LOGS", fileName);
// Создаем директорию если не существует
string directory = Path.GetDirectoryName(logFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// Создаем файл и записываем начальное сообщение
writer = new StreamWriter(logFilePath, true);
string startMessage = $"Начало логгирования {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
writer.WriteLine(startMessage);
writer.Flush();
//Debug.Log($"Логгер инициализирован. Файл: {logFilePath}");
}
catch (Exception e)
{
Debug.LogError($"Ошибка инициализации логгера: {e.Message}");
}
}
/// <summary>
/// Записывает сообщение в лог
/// </summary>
/// <param name="message">Сообщение для записи</param>
public void Log(object message)
{
if (writer == null)
{
Debug.LogWarning("Логгер не инициализирован. Сначала вызовите Initialize().");
return;
}
try
{
string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}";
writer.WriteLine(logEntry);
writer.Flush(); // Принудительно записываем в файл
}
catch (Exception e)
{
Debug.LogError($"Ошибка записи в лог: {e.Message}");
}
}
/// <summary>
/// Закрывает логгер и освобождает ресурсы
/// </summary>
public void Close()
{
if (writer != null)
{
try
{
string endMessage = $"Конец логгирования {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
writer.WriteLine(endMessage);
writer.Flush();
writer.Close();
writer = null;
}
catch (Exception e)
{
Debug.LogError($"Ошибка закрытия логгера: {e.Message}");
}
}
}
void OnApplicationQuit()
{
Close();
}
void OnDestroy()
{
Close();
}
public bool IsLogTypeAllowed(LogType logType)
{
return false;
}
public void Log(LogType logType, object message)
{
}
public void Log(LogType logType, object message, UnityEngine.Object context)
{
}
public void Log(LogType logType, string tag, object message)
{
}
public void Log(LogType logType, string tag, object message, UnityEngine.Object context)
{
}
public void Log(string tag, object message)
{
}
public void Log(string tag, object message, UnityEngine.Object context)
{
}
public void LogWarning(string tag, object message)
{
}
public void LogWarning(string tag, object message, UnityEngine.Object context)
{
}
public void LogError(string tag, object message)
{
}
public void LogError(string tag, object message, UnityEngine.Object context)
{
}
public void LogFormat(LogType logType, string format, params object[] args)
{
}
public void LogException(Exception exception)
{
}
public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
{
}
public void LogException(Exception exception, UnityEngine.Object context)
{
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 1331a40789493ab488ebc7f5b640537e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -113,7 +113,7 @@ namespace PrizeSystem
#region Приватные методы
//private string StartHopperCommand => ComWrapper.BoardVersion switch { 1 => "303", 2 => "301", _ => "303" };
//private string StopHopperCommand => ComWrapper.BoardVersion switch { 1 => "302", 2 => "300", _ => "302" };
private string StartHopperCommand => "303";
private string StartHopperCommand => "303";
private string StopHopperCommand => "302";
private IEnumerator PrizingProcess(int amount, CountablePrizeType Type)
{
@ -124,7 +124,7 @@ namespace PrizeSystem
}
prizing = true;
Logger.Instance.Log($"Выдача приза {Type}. Количество: {amount}");
Debug.Log($"Выдача приза {Type}. Количество: {amount}");
bool atLeastOnePrize = false;
for (int i = 0; i < amount; i++)
@ -133,11 +133,11 @@ namespace PrizeSystem
bool errorRegistred = PlayerPrefs.GetInt(PrefsKeyVault.PRIZING_ERROR_REGISTRED, 0) == 1;
if (errorRegistred && noPrizWhenError) yield break;
Logger.Instance.Log($"Включаю мотор хоппера: {StartHopperCommand}");
Debug.Log($"Включаю мотор хоппера: {StartHopperCommand}");
ComWrapper.Send(StartHopperCommand);//включаем мотор
PlayerPrefs.SetInt("PrizeGivenBuffer", 0);//подготовка буфера
Logger.Instance.Log($"Буфер подготовлен. Значение: {PlayerPrefs.GetInt("PrizeGivenBuffer")}");
Debug.Log($"Буфер подготовлен. Значение: {PlayerPrefs.GetInt("PrizeGivenBuffer")}");
float startTime = Time.time;
bool success = false;
@ -146,7 +146,7 @@ namespace PrizeSystem
{
if (PlayerPrefs.GetInt("PrizeGivenBuffer", 0) == 1)
{
Logger.Instance.Log($"Считан приз. Значение буфера {PlayerPrefs.GetInt("PrizeGivenBuffer")}");
Debug.Log($"Считан приз. Значение буфера {PlayerPrefs.GetInt("PrizeGivenBuffer")}");
success = true;
break;
}

View File

@ -36,8 +36,6 @@ public static class PrizeStandController
public static int BoxesCount { get; private set; }
private static readonly SemaphoreSlim _lock = new(1, 1);
private static ILogger _logger;
#region PUBLIC API
/// <summary>
/// Инициализировать модуль витрины.
@ -45,7 +43,7 @@ public static class PrizeStandController
/// <param name="handleId">Id хэндла полученное после ComNativeWrapper.Serial_Open</param>
/// <param name="countOfBoxes">Количество физических коробок витрины</param>
/// <param name="logger">(опционально) Логгер</param>
public static void Initialize(int handleId, int countOfBoxes, ILogger logger)
public static void Initialize(int handleId, int countOfBoxes)
{
bool hasError = false;
StringBuilder sb = new StringBuilder();
@ -66,11 +64,6 @@ public static class PrizeStandController
}
else BoxesCount = countOfBoxes;
//Установка логгера
_logger = logger;
if (_logger == null)
sb.AppendLine($"[Модуль витрины] Получен логгер NULL. Если нужно логгирование, передайте дествующий логгер.");
//Завершение
if (hasError)
{
@ -133,13 +126,13 @@ public static class PrizeStandController
}
else
{
_logger?.Log($"[Модуль витрины] Ошибка при открытии ячейки {boxNumber}");
Log($"[Модуль витрины] Ошибка при открытии ячейки {boxNumber}");
OpeningFinished?.Invoke(true, $"Ошибка при открытии ячейки {boxNumber}");
}
}
catch (Exception ex)
{
_logger?.Log($"[Модуль витрины] Ошибка при открытии ячейки {boxNumber}: {ex.Message}");
Log($"[Модуль витрины] Ошибка при открытии ячейки {boxNumber}: {ex.Message}");
OpeningFinished?.Invoke(false, ex.Message);
}
finally
@ -233,7 +226,7 @@ public static class PrizeStandController
}
else if (entryLength < 0) //ошибка
{
_logger?.Log($"Ошибка при считывании статуса ячеек={entryLength} :: {ComNativeWrapper.GetLastError()}");
Log($"Ошибка при считывании статуса ячеек={entryLength} :: {ComNativeWrapper.GetLastError()}");
continue;
}
@ -249,7 +242,7 @@ public static class PrizeStandController
if(ParseResult.BoxNumber == -1)
{
_logger?.Log($"[Модуль витрины. Ошибка получения статуса ячейки]\n{ParseResult.Message}");
Log($"[Модуль витрины. Ошибка получения статуса ячейки]\n{ParseResult.Message}");
}
else
{
@ -263,7 +256,7 @@ public static class PrizeStandController
if (sw.Elapsed.TotalSeconds >= timeout) UnityEngine.Debug.Log("Вышли по таймауту");
if (status == BoxStatus.NotFound)
_logger?.Log($"[Модуль витрины. Не дождался ответа по статусу ячейки]\n" +
Log($"[Модуль витрины. Не дождался ответа по статусу ячейки]\n" +
$"Ожидаемый номер: {expectedBoxNumber}\n" +
$"Получено статусов ячеек: {boxesRecieved}/{expectedEntriesCount}");
return status;
@ -303,7 +296,7 @@ public static class PrizeStandController
}
else if (entryLength < 0) //ошибка
{
_logger?.Log($"Ошибка при считывании статуса ячеек={entryLength} :: {ComNativeWrapper.GetLastError()}");
Log($"Ошибка при считывании статуса ячеек={entryLength} :: {ComNativeWrapper.GetLastError()}");
continue;
}
@ -319,7 +312,7 @@ public static class PrizeStandController
if (ParseResult.BoxNumber == -1)
{
_logger?.Log($"[Модуль витрины. Ошибка получения статуса ячейки]\n{ParseResult.Message}");
Log($"[Модуль витрины. Ошибка получения статуса ячейки]\n{ParseResult.Message}");
}
else
{
@ -404,13 +397,13 @@ public static class PrizeStandController
.Select(kvp => kvp.Key)
.ToArray();
_logger?.Log($"[Модуль витрины] Найдено готовых к выдаче ячеек: {readyBoxes.Length}");
Log($"[Модуль витрины] Найдено готовых к выдаче ячеек: {readyBoxes.Length}");
return readyBoxes;
}
catch (Exception ex)
{
_logger?.Log($"[Модуль витрины] Ошибка при получении списка готовых ячеек: {ex.Message}");
Log($"[Модуль витрины] Ошибка при получении списка готовых ячеек: {ex.Message}");
return Array.Empty<int>();
}
}
@ -431,18 +424,18 @@ public static class PrizeStandController
}
else
{
_logger?.Log($"[Модуль витрины] Таймаут при получении списка готовых ячеек");
Log($"[Модуль витрины] Таймаут при получении списка готовых ячеек");
return Array.Empty<int>();
}
}
catch (Exception ex)
{
_logger?.Log($"[Модуль витрины] Ошибка при получении списка готовых ячеек: {ex.Message}");
Log($"[Модуль витрины] Ошибка при получении списка готовых ячеек: {ex.Message}");
return Array.Empty<int>();
}
}
private static void Log(string message) => UnityEngine.Debug.Log(message);
}
public enum BoxStatus

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
public enum CellState
@ -7,7 +7,7 @@ public enum CellState
}
public class FieldModel
{
//двумерный массив для поля
//двумерный массив для поля
public CellState[,] FieldArray;
public int Height;
public int Width;
@ -15,7 +15,7 @@ public class FieldModel
public FieldModel(int width, int height)
{
//0 индекс для строк, 1 индекс для столбцов
//0 индекс для строк, 1 индекс для столбцов
Width = width;
Height = height;
makeEmptyField(width, height);
@ -73,9 +73,9 @@ public class FieldModel
{
int start = -1;
for (int col = 0; col <= Width; col++) // теперь проходим до Width включительно
for (int col = 0; col <= Width; col++) // теперь проходим до Width включительно
{
// Проверяем, не вышли ли за границы массива
// Проверяем, не вышли ли за границы массива
bool isMatch = col < Width && FieldArray[row, col] == targetCellState;
if (isMatch && start == -1)
@ -131,7 +131,7 @@ public class FieldModel
{
var winningCells = new HashSet<(int row, int col)>();
// Проверка главных диагоналей
// Проверка главных диагоналей
for (int row = 0; row < Height; row++)
{
CheckDiagonalStartingAt(row, 0, 1, 1, targetCellState, winningCells);
@ -141,7 +141,7 @@ public class FieldModel
CheckDiagonalStartingAt(0, col, 1, 1, targetCellState, winningCells);
}
// Проверка побочных диагоналей
// Проверка побочных диагоналей
for (int row = 0; row < Height; row++)
{
CheckDiagonalStartingAt(row, Width - 1, 1, -1, targetCellState, winningCells);
@ -176,7 +176,7 @@ public class FieldModel
if (sequenceLength >= TargetLineLength)
{
// Добавляем ВСЕ ячейки из текущей последовательности
// Добавляем ВСЕ ячейки из текущей последовательности
for (int i = 0; i < sequenceLength; i++)
{
int r = sequenceStartRow + i * rowStep;
@ -196,7 +196,7 @@ public class FieldModel
currentCol += colStep;
}
}
public int getHeight(int colIndex)
public int GetColumnHeight(int colIndex)
{
for (int row = Height - 1; row >= 0; row--)
{
@ -205,17 +205,26 @@ public class FieldModel
return row;
}
}
return -1;//если не нашли, то больше добавить нельзя
return -1;//если не нашли, то больше добавить нельзя
}
public bool checkDraw()
{
for (int col = 0; col < Width; col++)
{
if (getHeight(col) != -1) return false;
if (GetColumnHeight(col) != -1) return false;
}
return true;
}
public List<int> CollectNonFullCols()
{
var positions = new List<int>();
for (int i = 0; i < Width; i++)
if (GetColumnHeight(i) != -1)
positions.Add(i);
return positions;
}
}