Add controller support for prize selection and configuration

This commit is contained in:
Сергей Бондарь 2026-08-25 10:47:56 +03:00
parent dd1e8edcda
commit 90da97d220
11 changed files with 227 additions and 306 deletions

23
AGENTS.md Normal file
View File

@ -0,0 +1,23 @@
# Обязательные инструкции проекта
## Язык общения
- Все ответы пользователю в чате необходимо писать только на русском языке.
- Английский язык допустим только внутри кода, имён API, идентификаторов, путей, команд и дословных технических терминов, когда перевод ухудшает точность.
## Работа с Unity
- При любой работе с Unity обязательно использовать MCP-сервер `unityMCP`.
- Это правило распространяется в том числе на UI, сцены, префабы, GameObject, компоненты, ассеты, материалы, камеры, настройки проекта, консоль, компиляцию, тесты и визуальную проверку результата.
- Перед изменениями читать через `unityMCP` релевантные ресурсы и состояние Unity Editor. После изменений проверять результат через `unityMCP`, включая состояние компиляции, консоль, тесты и снимки экрана, когда это применимо.
- Не считать работу с Unity завершённой без проверки через `unityMCP`. Если сервер недоступен, явно сообщить об этом пользователю и не подменять обязательную Unity-проверку неподтверждёнными предположениями.
## Память и контекст проекта
- В любой задаче без исключений обязательно использовать MCP-сервер `agentmemory` для получения и сохранения контекста проекта.
- В начале каждой задачи запрашивать из `agentmemory` релевантную информацию до принятия архитектурных и реализационных решений.
- Использовать `agentmemory` как постоянное хранилище сведений об архитектуре, структуре папок и файлов, кодовой базе, документации, принятых решениях, соглашениях, зависимостях, известных проблемах и результатах работы.
- По мере исследования и выполнения задачи сохранять или обновлять в `agentmemory` новую существенную информацию, чтобы она была доступна в следующих задачах.
- При создании контекста решения обязательно объединять актуальное состояние репозитория и Unity Editor с информацией из `agentmemory`; не полагаться только на текущий чат.
- Перед завершением задачи фиксировать в `agentmemory` важные изменения, решения и результаты проверки.
- Если `agentmemory` недоступен, явно сообщить об этом пользователю. Попытка обратиться к `agentmemory` всё равно обязательна; задача не должна молча обходить это требование.

View File

@ -9,22 +9,58 @@ public class AvailablePrizesTable : MonoBehaviour
public PrizeButton _prizeButtonPrefab;
[SerializeField] RectTransform _buttonsRoot;
public List<PrizeButton> prizeButtons;
public CountablePrizeConfigurator countablePrizeConfigurator;
public QrPrizeConfigurator qrPrizeConfigurator;
public VitrinaPrizeConfigurator vitrinaPrizeConfigurator;
public PrizeSet cachedSet;
public RectTransform root;
public PrizesSelector selector;
public void Refresh(PrizeSet set)
{
ClearButtons();
cachedSet = set;
ClearButtons();
prizeButtons = new();
foreach (var type in GetMissingPrizeTypes(set.Prizes))
{
var button = Instantiate(_prizeButtonPrefab, _buttonsRoot);
button.Configure(type);
button.OnPrize += OnPrizeTypeSelected;
prizeButtons.Add(button);
}
}
private void OnPrizeTypeSelected(PrizeType type)
{
//открыть окошко по типу, подписаться на него
print($"Выбран приз {type}");
BasePrizeConfigurator window = type switch
{
PrizeType.Hopper => countablePrizeConfigurator,
PrizeType.Marbles => countablePrizeConfigurator,
PrizeType.Ticket => countablePrizeConfigurator,
PrizeType.VitrinaBox => vitrinaPrizeConfigurator,
PrizeType.Qr => qrPrizeConfigurator
};
var configurator = Instantiate(window, root);
configurator.Configure(type);
configurator.OnPrizeConfigured += Configurator_OnPrizeConfigured;
ControlsPerformer.Instance.SetControlable(configurator);
}
private void Configurator_OnPrizeConfigured(Prize prize)
{
cachedSet.Prizes.Add(prize);
Refresh(cachedSet);
selector.skipFrame = true;
}
private void ClearButtons()

View File

@ -305,7 +305,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::CountablePrizeConfigurator
icon: {fileID: 6195150281388987687}
numberInput: {fileID: 0}
numberInput: {fileID: 5533544630844077496}
--- !u!1001 &1512082769719754990
PrefabInstance:
m_ObjectHideFlags: 0
@ -468,3 +468,14 @@ RectTransform:
m_CorrespondingSourceObject: {fileID: 1981593229059902703, guid: ced775cf87d3b2c4b9c58d53e5af7f72, type: 3}
m_PrefabInstance: {fileID: 1512082769719754990}
m_PrefabAsset: {fileID: 0}
--- !u!114 &5533544630844077496 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 6354832797770298710, guid: ced775cf87d3b2c4b9c58d53e5af7f72, type: 3}
m_PrefabInstance: {fileID: 1512082769719754990}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2b998a08d01f1c74da6995359c69e8a0, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::MNumberStepper

View File

@ -25,7 +25,7 @@ public class CountablePrizeConfigurator : BasePrizeConfigurator, IControlable
{
numberInput.SetDirection(In.GetAxis(Axis.Horizontal, JoystickSide.Both, InteractMode.Continious));
if (In.GetButtonDownAnyPlayer(PlayerAction.action))
if (In.GetButtonAnyPlayer(PlayerAction.action))
{
Prize prize = PrizeUtils.CreatePrize(CountablePrizeType.Hopper, numberInput.Value);
Complete(prize);

View File

@ -1291,7 +1291,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &4296811095572388652
RectTransform:
m_ObjectHideFlags: 0
@ -1310,6 +1310,7 @@ RectTransform:
- {fileID: 4388752671798834034}
- {fileID: 6755101644642404136}
- {fileID: 6087319970201647579}
- {fileID: 2717940143288701108}
m_Father: {fileID: 4098477273951441249}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
@ -1370,6 +1371,8 @@ MonoBehaviour:
_addedPrizesTable: {fileID: 6087319970201647579}
_prizeViewPrefab: {fileID: 1203032466002125781, guid: f8172e74629723c4e993e8ac2f322bdf, type: 3}
_availablePrizesTable: {fileID: 978156554344200501}
skipFrame: 0
pointer: {fileID: 2717940143288701108}
--- !u!1 &8288873238761209220
GameObject:
m_ObjectHideFlags: 0
@ -1461,6 +1464,12 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::AvailablePrizesTable
_prizeButtonPrefab: {fileID: 942699711437869465, guid: f4d8e373cd4ebc948abb9692f14709e6, type: 3}
_buttonsRoot: {fileID: 4388752671798834034}
prizeButtons: []
countablePrizeConfigurator: {fileID: 5680088572919083885, guid: 8b123b0e9e795b842948d07b6e135d84, type: 3}
qrPrizeConfigurator: {fileID: 8201104754896611310, guid: 419ede247f441324681aeb7eeacf4ea0, type: 3}
vitrinaPrizeConfigurator: {fileID: 2013129107579668837, guid: fa4e8b6466206ac4cb113d8b98d3a8e5, type: 3}
root: {fileID: 4098477273951441249}
selector: {fileID: 2866604199148495954}
--- !u!114 &2520044121805980792
MonoBehaviour:
m_ObjectHideFlags: 0
@ -1487,6 +1496,81 @@ MonoBehaviour:
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!1 &9222883903295952007
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2717940143288701108}
- component: {fileID: 8407250239058543666}
- component: {fileID: 7042360804196379557}
m_Layer: 5
m_Name: pointer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2717940143288701108
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9222883903295952007}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4296811095572388652}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8407250239058543666
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9222883903295952007}
m_CullTransparentMesh: 1
--- !u!114 &7042360804196379557
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9222883903295952007}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1001 &675856799151252063
PrefabInstance:
m_ObjectHideFlags: 0

View File

@ -8,9 +8,15 @@ public class PrizesSelector : MonoBehaviour
[SerializeField] PrizeView _prizeViewPrefab;
[SerializeField] AvailablePrizesTable _availablePrizesTable;
int index = 0;
private PrizeSet set;
public bool skipFrame = false;
[SerializeField] Transform pointer;
public void Open(Character character)
{
print($"открыто с персонажем {character.CharacterIndex}");
@ -18,10 +24,8 @@ public class PrizesSelector : MonoBehaviour
set = PrizeSystemManager.PrizeContainer.Sets[character.CharacterIndex];
UpdateView();
}
private void UpdateView()
{
ClearTable();
@ -29,7 +33,31 @@ public class PrizesSelector : MonoBehaviour
_availablePrizesTable.Refresh(set);
}
private void Update()
{
if (skipFrame)
{
if(In.AnyButton() == false)
skipFrame = false;
return;
}
if (_availablePrizesTable.prizeButtons == null) return;
if (_availablePrizesTable.prizeButtons.Count == 0) return;
index = index - In.GetAxis(Axis.Vertical, JoystickSide.Both);
index = Mathf.Clamp(index, 0, _availablePrizesTable.prizeButtons.Count);
pointer.position = _availablePrizesTable.prizeButtons[index].transform.position;
if (In.GetButtonAnyPlayer(PlayerAction.action))
{
_availablePrizesTable.prizeButtons[index].ClickAnimation();
}
}
private void ClearTable()
{
for (int i = _addedPrizesTable.childCount - 1; i >= 0; i--)
@ -47,4 +75,4 @@ public class PrizesSelector : MonoBehaviour
view.SetPrize(item);
}
}
}
}

View File

@ -648,7 +648,6 @@ GameObject:
- component: {fileID: 36301026}
- component: {fileID: 36301029}
- component: {fileID: 36301028}
- component: {fileID: 36301027}
m_Layer: 5
m_Name: Prize.1
m_TagString: Untagged
@ -675,25 +674,6 @@ RectTransform:
m_AnchoredPosition: {x: 50, y: -250.8}
m_SizeDelta: {x: 603.2, y: 49.76}
m_Pivot: {x: 0, y: 0.5}
--- !u!114 &36301027
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 36301025}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5793ef5705258b41b327430fe3c351e, type: 3}
m_Name:
m_EditorClassIdentifier:
material: {fileID: 0}
speed: 0.6
min: 1
max: 1
scaleSpeed: 0
rotateSpeed: 0
angularAmpliude: 0
--- !u!114 &36301028
MonoBehaviour:
m_ObjectHideFlags: 0
@ -863,7 +843,6 @@ GameObject:
- component: {fileID: 52771949}
- component: {fileID: 52771948}
- component: {fileID: 52771947}
- component: {fileID: 52771950}
m_Layer: 0
m_Name: Text (TMP)
m_TagString: Untagged
@ -1010,20 +989,6 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 52771945}
m_CullTransparentMesh: 1
--- !u!114 &52771950
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 52771945}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5ba96e91114b0544ba59501932dd77c, type: 3}
m_Name:
m_EditorClassIdentifier:
label: {fileID: 52771948}
speed: 0.3
--- !u!1 &61619036
GameObject:
m_ObjectHideFlags: 0
@ -2729,7 +2694,6 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
botsAmount: 5
stateMachine: {fileID: 259182281}
AdminPanel: {fileID: 0}
NumberPanel: {fileID: 0}
timerManager: {fileID: 259182288}
@ -2749,14 +2713,6 @@ MonoBehaviour:
currentChip: {fileID: 0}
canReturnToMenu: 0
nameInput: {fileID: 0}
ValutaNameInput: {fileID: 0}
NumberTech: {fileID: 0}
pricePveInput: {fileID: 0}
pricePvpInput: {fileID: 0}
pricePveRevengeInput: {fileID: 0}
prizesAvailableInput: {fileID: 0}
pulsesToResetDifficultyInput: {fileID: 0}
valutaPerPulseInput: {fileID: 0}
leaderboard: {fileID: 0}
CharactersConfigurator: {fileID: 141381088}
menuGameplayTransit: {fileID: 29868612}
@ -18161,7 +18117,6 @@ GameObject:
- component: {fileID: 1921927567}
- component: {fileID: 1921927570}
- component: {fileID: 1921927569}
- component: {fileID: 1921927568}
m_Layer: 5
m_Name: Status
m_TagString: Untagged
@ -18188,20 +18143,6 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 287}
m_SizeDelta: {x: 1300, y: 115.350006}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &1921927568
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1921927566}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5ba96e91114b0544ba59501932dd77c, type: 3}
m_Name:
m_EditorClassIdentifier:
label: {fileID: 1921927569}
speed: 0.3
--- !u!114 &1921927569
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@ -2,5 +2,5 @@
{
public const string DIGITS = "0123456789";
public const string RUS_AND_DIGITS = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя0123456789";
public const string RUS_AND_DIGITS = " АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя0123456789";
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,6 @@
{
"dependencies": {
"com.coplaydev.unity-mcp": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main",
"com.github-glitchenzo.nugetforunity": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity",
"com.unity.2d.sprite": "1.0.0",
"com.unity.ide.visualstudio": "2.0.27",

View File

@ -1,5 +1,22 @@
{
"dependencies": {
"com.coplaydev.unity-mcp": {
"version": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main",
"depth": 0,
"source": "git",
"dependencies": {
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.nuget.newtonsoft-json": "3.0.2",
"com.unity.test-framework": "1.1.31"
},
"hash": "4ce7dd3cc54e37e2ed6dc59cb5a047f3dccb3f50"
},
"com.github-glitchenzo.nugetforunity": {
"version": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity",
"depth": 0,
@ -64,6 +81,13 @@
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.nuget.newtonsoft-json": {
"version": "3.2.2",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.render-pipelines.core": {
"version": "17.4.0",
"depth": 1,