M5-M7: сцены, лобби, экран игры и цикл матча
Обе сцены собраны через Code Mode, не руками. - loader: поднимает модули, прогревает арт карт, уходит в lobby - lobby: обе UI-ветки в одной сцене (по ARCHITECTURE.md), матч — это смена видимого корня, а не загрузка сцены - GameScreen рисует текущее состояние и доводит узлы твинами, а не проигрывает поток событий: узел карты живёт вместе со своей картой, поэтому "шестёрка ушла из руки на стол" не требует отдельного случая - один тап = ход целиком; логика вынесена в core/rules/intent.ts и покрыта тестами, в том числе проверкой, что она никогда не предложит ход, который правила отвергнут - арт карт переехал в assets/resources: .pac — это инструкция упаковки на сборке, а не рантайм-ассет, и без ссылок на кадры в сборку не попадало ничего. Теперь все 37 спрайтов в одной текстуре 2048x2048 - клики кнопок подписываются в коде, а не через clickEvents сцены - строки интерфейса собраны в одном файле Сборка web-mobile проходит чисто, все ссылки в сцене проверены. Вживую не запускалось: браузер в этом окружении не поднимает главный цикл движка. Подробности — в docs/TECHNICAL.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@@ -0,0 +1,171 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"__type__": "cc.Prefab",
|
||||||
|
"_name": "card",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_native": "",
|
||||||
|
"data": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"optimizationPolicy": 0,
|
||||||
|
"persistent": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "card",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": null,
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": {
|
||||||
|
"__id__": 8
|
||||||
|
},
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 3
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 220,
|
||||||
|
"height": 320
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "5332t7MZRMZ7fwhsKNiE8i"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Sprite",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 5
|
||||||
|
},
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 255,
|
||||||
|
"b": 255,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_spriteFrame": {
|
||||||
|
"__uuid__": "610347f5-8934-4a68-8e68-70269c912a7a@f9941",
|
||||||
|
"__expectedType__": "cc.SpriteFrame"
|
||||||
|
},
|
||||||
|
"_type": 0,
|
||||||
|
"_fillType": 0,
|
||||||
|
"_sizeMode": 0,
|
||||||
|
"_fillCenter": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"_fillStart": 0,
|
||||||
|
"_fillRange": 0,
|
||||||
|
"_isTrimmedMode": true,
|
||||||
|
"_useGrayscale": false,
|
||||||
|
"_atlas": null,
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "9bawLq5CJJCLV+Gk6r0mbF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "da016ez+jBIsZXjka0QzaXY",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 7
|
||||||
|
},
|
||||||
|
"sprite": {
|
||||||
|
"__id__": 4
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "85phkdNBxMuaolENti1wG5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.PrefabInfo",
|
||||||
|
"root": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"asset": {
|
||||||
|
"__id__": 0
|
||||||
|
},
|
||||||
|
"fileId": "f4cMBOjypJJZjyWxfFGIq6",
|
||||||
|
"instance": null,
|
||||||
|
"targetOverrides": null
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.50",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "1ad36ebe-345c-4936-be65-c838f51b4eb4",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "card"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "a300e972-9887-4462-8c4d-47fe8ce9c106",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"isBundle": true,
|
||||||
|
"bundleConfigID": "default",
|
||||||
|
"bundleName": "resources",
|
||||||
|
"priority": 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@@ -3,7 +3,9 @@
|
|||||||
"importer": "auto-atlas",
|
"importer": "auto-atlas",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "914afa5f-3f77-4d7d-835e-530e298c6816",
|
"uuid": "914afa5f-3f77-4d7d-835e-530e298c6816",
|
||||||
"files": [],
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
"subMetas": {},
|
"subMetas": {},
|
||||||
"userData": {
|
"userData": {
|
||||||
"maxWidth": 2048,
|
"maxWidth": 2048,
|
||||||
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,881 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"__type__": "cc.SceneAsset",
|
||||||
|
"_name": "loader",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_native": "",
|
||||||
|
"scene": {
|
||||||
|
"__id__": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Scene",
|
||||||
|
"_name": "loader",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": null,
|
||||||
|
"_children": [
|
||||||
|
{
|
||||||
|
"__id__": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [],
|
||||||
|
"_prefab": null,
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"autoReleaseAssets": false,
|
||||||
|
"_globals": {
|
||||||
|
"__id__": 19
|
||||||
|
},
|
||||||
|
"_id": "1aee5910-40c3-4b99-bc8d-e477cf0e25ed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "Canvas",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_children": [
|
||||||
|
{
|
||||||
|
"__id__": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 13
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 18
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 640,
|
||||||
|
"y": 360,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": "b1zlEjeP1PhKkvGqJs9BIU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "Camera",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 1000
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": "2a7WNH7jhEM6VozsNzw40D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 3
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 100,
|
||||||
|
"height": 100
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": "eazUhZVnFKVo+ewS5T/BhE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Camera",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 3
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_projection": 0,
|
||||||
|
"_priority": 1073741824,
|
||||||
|
"_fov": 45,
|
||||||
|
"_fovAxis": 0,
|
||||||
|
"_orthoHeight": 440.25052192066806,
|
||||||
|
"_near": 1,
|
||||||
|
"_far": 2000,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 8,
|
||||||
|
"g": 44,
|
||||||
|
"b": 26,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_depth": 1,
|
||||||
|
"_stencil": 0,
|
||||||
|
"_clearFlags": 7,
|
||||||
|
"_rect": {
|
||||||
|
"__type__": "cc.Rect",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"width": 1,
|
||||||
|
"height": 1
|
||||||
|
},
|
||||||
|
"_aperture": 19,
|
||||||
|
"_shutter": 7,
|
||||||
|
"_iso": 0,
|
||||||
|
"_screenScale": 1,
|
||||||
|
"_visibility": 33554432,
|
||||||
|
"_targetTexture": null,
|
||||||
|
"_postProcess": null,
|
||||||
|
"_usePostProcess": false,
|
||||||
|
"_cameraType": -1,
|
||||||
|
"_trackingType": 0,
|
||||||
|
"_id": "8b1/mYGuxP9KcC4z0D4cNh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "Background",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": "71vPMl7sZIb5K5fhEuSsMZ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 6
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 1280,
|
||||||
|
"height": 720
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": "b13TjyVF1EFoHFL0w6g3gL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Sprite",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 6
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 255,
|
||||||
|
"b": 255,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_spriteFrame": {
|
||||||
|
"__uuid__": "d5553c08-e820-46af-a832-40d807724dfb@f9941",
|
||||||
|
"__expectedType__": "cc.SpriteFrame"
|
||||||
|
},
|
||||||
|
"_type": 0,
|
||||||
|
"_fillType": 0,
|
||||||
|
"_sizeMode": 0,
|
||||||
|
"_fillCenter": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"_fillStart": 0,
|
||||||
|
"_fillRange": 0,
|
||||||
|
"_isTrimmedMode": true,
|
||||||
|
"_useGrayscale": false,
|
||||||
|
"_atlas": null,
|
||||||
|
"_id": "1eZC1dDqZKBKdiIGlCVQdh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Widget",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 6
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_alignFlags": 45,
|
||||||
|
"_target": null,
|
||||||
|
"_left": 0,
|
||||||
|
"_right": 0,
|
||||||
|
"_top": 0,
|
||||||
|
"_bottom": 0,
|
||||||
|
"_horizontalCenter": 0,
|
||||||
|
"_verticalCenter": 0,
|
||||||
|
"_isAbsLeft": true,
|
||||||
|
"_isAbsRight": true,
|
||||||
|
"_isAbsTop": true,
|
||||||
|
"_isAbsBottom": true,
|
||||||
|
"_isAbsHorizontalCenter": true,
|
||||||
|
"_isAbsVerticalCenter": true,
|
||||||
|
"_originalWidth": 540,
|
||||||
|
"_originalHeight": 960,
|
||||||
|
"_alignMode": 1,
|
||||||
|
"_lockFlags": 0,
|
||||||
|
"_id": "6fkN296q1Ef5voPy2qYK6X"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "Title",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 12
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 60,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": "e2HX8VID5CHqTyzON7WJb5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 10
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 900,
|
||||||
|
"height": 160
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": "d2e/FNyWJMm4yQCG2+A4LP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 10
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 244,
|
||||||
|
"g": 194,
|
||||||
|
"b": 69,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_string": "Fool",
|
||||||
|
"_horizontalAlign": 1,
|
||||||
|
"_verticalAlign": 1,
|
||||||
|
"_actualFontSize": 127,
|
||||||
|
"_fontSize": 130,
|
||||||
|
"_fontFamily": "Arial",
|
||||||
|
"_lineHeight": 163,
|
||||||
|
"_overflow": 2,
|
||||||
|
"_enableWrapText": false,
|
||||||
|
"_font": null,
|
||||||
|
"_isSystemFontUsed": true,
|
||||||
|
"_spacingX": 0,
|
||||||
|
"_isItalic": false,
|
||||||
|
"_isBold": true,
|
||||||
|
"_isUnderline": false,
|
||||||
|
"_underlineHeight": 2,
|
||||||
|
"_cacheMode": 0,
|
||||||
|
"_enableOutline": false,
|
||||||
|
"_outlineColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_outlineWidth": 2,
|
||||||
|
"_enableShadow": false,
|
||||||
|
"_shadowColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_shadowOffset": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 2,
|
||||||
|
"y": 2
|
||||||
|
},
|
||||||
|
"_shadowBlur": 2,
|
||||||
|
"_id": "93TKfIU91MsYoPl+MbLJLU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "Hint",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": -60,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": "edGCK/J5pJMo3QjOFjHMU8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 13
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 900,
|
||||||
|
"height": 60
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": "0amqxP4mdHTJm3HJPkzYdS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 13
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 174,
|
||||||
|
"g": 196,
|
||||||
|
"b": 182,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_string": "loading",
|
||||||
|
"_horizontalAlign": 1,
|
||||||
|
"_verticalAlign": 1,
|
||||||
|
"_actualFontSize": 36,
|
||||||
|
"_fontSize": 36,
|
||||||
|
"_fontFamily": "Arial",
|
||||||
|
"_lineHeight": 45,
|
||||||
|
"_overflow": 2,
|
||||||
|
"_enableWrapText": false,
|
||||||
|
"_font": null,
|
||||||
|
"_isSystemFontUsed": true,
|
||||||
|
"_spacingX": 0,
|
||||||
|
"_isItalic": false,
|
||||||
|
"_isBold": false,
|
||||||
|
"_isUnderline": false,
|
||||||
|
"_underlineHeight": 2,
|
||||||
|
"_cacheMode": 0,
|
||||||
|
"_enableOutline": false,
|
||||||
|
"_outlineColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_outlineWidth": 2,
|
||||||
|
"_enableShadow": false,
|
||||||
|
"_shadowColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_shadowOffset": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 2,
|
||||||
|
"y": 2
|
||||||
|
},
|
||||||
|
"_shadowBlur": 2,
|
||||||
|
"_id": "be14O3yOdDardPtTt2bDrD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 1280,
|
||||||
|
"height": 720
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": "9429lRu9BL6rByObLUXHia"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Canvas",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"_cameraComponent": {
|
||||||
|
"__id__": 5
|
||||||
|
},
|
||||||
|
"_alignCanvasWithScreen": true,
|
||||||
|
"_id": "7crolsyK9Cs5GFmQZmc9QW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "c91ddke4YBE9JjRtYzU2wFp",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": null,
|
||||||
|
"nextScene": "lobby",
|
||||||
|
"_id": "dcSHYP80NEeZirk4SzzDBT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.SceneGlobals",
|
||||||
|
"ambient": {
|
||||||
|
"__id__": 20
|
||||||
|
},
|
||||||
|
"shadows": {
|
||||||
|
"__id__": 21
|
||||||
|
},
|
||||||
|
"_skybox": {
|
||||||
|
"__id__": 22
|
||||||
|
},
|
||||||
|
"fog": {
|
||||||
|
"__id__": 23
|
||||||
|
},
|
||||||
|
"octree": {
|
||||||
|
"__id__": 24
|
||||||
|
},
|
||||||
|
"skin": {
|
||||||
|
"__id__": 25
|
||||||
|
},
|
||||||
|
"lightProbeInfo": {
|
||||||
|
"__id__": 26
|
||||||
|
},
|
||||||
|
"postSettings": {
|
||||||
|
"__id__": 27
|
||||||
|
},
|
||||||
|
"bakedWithStationaryMainLight": false,
|
||||||
|
"bakedWithHighpLightmap": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.AmbientInfo",
|
||||||
|
"_skyColorHDR": {
|
||||||
|
"__type__": "cc.Vec4",
|
||||||
|
"x": 0.2,
|
||||||
|
"y": 0.5,
|
||||||
|
"z": 0.8,
|
||||||
|
"w": 0.520833125
|
||||||
|
},
|
||||||
|
"_skyColor": {
|
||||||
|
"__type__": "cc.Vec4",
|
||||||
|
"x": 0.2,
|
||||||
|
"y": 0.5,
|
||||||
|
"z": 0.8,
|
||||||
|
"w": 0.520833125
|
||||||
|
},
|
||||||
|
"_skyIllumHDR": 20000,
|
||||||
|
"_skyIllum": 20000,
|
||||||
|
"_groundAlbedoHDR": {
|
||||||
|
"__type__": "cc.Vec4",
|
||||||
|
"x": 0.2,
|
||||||
|
"y": 0.2,
|
||||||
|
"z": 0.2,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_groundAlbedo": {
|
||||||
|
"__type__": "cc.Vec4",
|
||||||
|
"x": 0.2,
|
||||||
|
"y": 0.2,
|
||||||
|
"z": 0.2,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_skyColorLDR": {
|
||||||
|
"__type__": "cc.Vec4",
|
||||||
|
"x": 0.452588,
|
||||||
|
"y": 0.607642,
|
||||||
|
"z": 0.755699,
|
||||||
|
"w": 0
|
||||||
|
},
|
||||||
|
"_skyIllumLDR": 0.8,
|
||||||
|
"_groundAlbedoLDR": {
|
||||||
|
"__type__": "cc.Vec4",
|
||||||
|
"x": 0.618555,
|
||||||
|
"y": 0.577848,
|
||||||
|
"z": 0.544564,
|
||||||
|
"w": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.ShadowsInfo",
|
||||||
|
"_enabled": false,
|
||||||
|
"_type": 0,
|
||||||
|
"_normal": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 1,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_distance": 0,
|
||||||
|
"_planeBias": 1,
|
||||||
|
"_shadowColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 76,
|
||||||
|
"g": 76,
|
||||||
|
"b": 76,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_maxReceived": 4,
|
||||||
|
"_size": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 1024,
|
||||||
|
"y": 1024
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.SkyboxInfo",
|
||||||
|
"_envLightingType": 0,
|
||||||
|
"_envmapHDR": {
|
||||||
|
"__uuid__": "d032ac98-05e1-4090-88bb-eb640dcb5fc1@b47c0",
|
||||||
|
"__expectedType__": "cc.TextureCube"
|
||||||
|
},
|
||||||
|
"_envmap": {
|
||||||
|
"__uuid__": "d032ac98-05e1-4090-88bb-eb640dcb5fc1@b47c0",
|
||||||
|
"__expectedType__": "cc.TextureCube"
|
||||||
|
},
|
||||||
|
"_envmapLDR": {
|
||||||
|
"__uuid__": "6f01cf7f-81bf-4a7e-bd5d-0afc19696480@b47c0",
|
||||||
|
"__expectedType__": "cc.TextureCube"
|
||||||
|
},
|
||||||
|
"_diffuseMapHDR": null,
|
||||||
|
"_diffuseMapLDR": null,
|
||||||
|
"_enabled": false,
|
||||||
|
"_useHDR": true,
|
||||||
|
"_editableMaterial": null,
|
||||||
|
"_reflectionHDR": null,
|
||||||
|
"_reflectionLDR": null,
|
||||||
|
"_rotationAngle": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.FogInfo",
|
||||||
|
"_type": 0,
|
||||||
|
"_fogColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 200,
|
||||||
|
"g": 200,
|
||||||
|
"b": 200,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_enabled": false,
|
||||||
|
"_fogDensity": 0.3,
|
||||||
|
"_fogStart": 0.5,
|
||||||
|
"_fogEnd": 300,
|
||||||
|
"_fogAtten": 5,
|
||||||
|
"_fogTop": 1.5,
|
||||||
|
"_fogRange": 1.2,
|
||||||
|
"_accurate": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.OctreeInfo",
|
||||||
|
"_enabled": false,
|
||||||
|
"_minPos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": -1024,
|
||||||
|
"y": -1024,
|
||||||
|
"z": -1024
|
||||||
|
},
|
||||||
|
"_maxPos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1024,
|
||||||
|
"y": 1024,
|
||||||
|
"z": 1024
|
||||||
|
},
|
||||||
|
"_depth": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.SkinInfo",
|
||||||
|
"_enabled": true,
|
||||||
|
"_blurRadius": 0.01,
|
||||||
|
"_sssIntensity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.LightProbeInfo",
|
||||||
|
"_giScale": 1,
|
||||||
|
"_giSamples": 1024,
|
||||||
|
"_bounces": 2,
|
||||||
|
"_reduceRinging": 0,
|
||||||
|
"_showProbe": true,
|
||||||
|
"_showWireframe": true,
|
||||||
|
"_showConvex": false,
|
||||||
|
"_data": null,
|
||||||
|
"_lightProbeSphereVolume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.PostSettingsInfo",
|
||||||
|
"_toneMappingType": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"ver":"1.1.50","importer":"scene","imported":true,"uuid":"1aee5910-40c3-4b99-bc8d-e477cf0e25ed","files":[".json"],"subMetas":{},"userData":{}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"ver":"1.1.50","importer":"scene","imported":true,"uuid":"220f80f8-6216-4ec2-b63b-72365bcbfde9","files":[".json"],"subMetas":{},"userData":{}}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { CocosStorage } from '../modules/save/CocosStorage';
|
||||||
|
import { SaveManager } from '../modules/save/SaveManager';
|
||||||
|
import { StatsSection } from '../modules/save/StatsSection';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's services, created once by the loader scene.
|
||||||
|
*
|
||||||
|
* Cocos components are built by the engine, so there is nowhere to inject
|
||||||
|
* dependencies through a constructor; a small explicit locator is the honest
|
||||||
|
* alternative to every component reaching for its own singleton. Everything it
|
||||||
|
* holds is engine-independent apart from the storage adapter, so a test can
|
||||||
|
* build one over `MemoryStorage` and drive the whole thing headlessly.
|
||||||
|
*/
|
||||||
|
export class App {
|
||||||
|
private static _instance: App | null = null;
|
||||||
|
|
||||||
|
readonly save: SaveManager;
|
||||||
|
readonly stats: StatsSection;
|
||||||
|
|
||||||
|
private constructor(save: SaveManager, stats: StatsSection) {
|
||||||
|
this.save = save;
|
||||||
|
this.stats = stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the services and loads saved progress. Called once, from `Bootstrap`. */
|
||||||
|
static create(): App {
|
||||||
|
if (App._instance) {
|
||||||
|
return App._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stats = new StatsSection();
|
||||||
|
const save = new SaveManager(new CocosStorage());
|
||||||
|
save.register(stats);
|
||||||
|
save.load();
|
||||||
|
|
||||||
|
App._instance = new App(save, stats);
|
||||||
|
return App._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get instance(): App {
|
||||||
|
if (!App._instance) {
|
||||||
|
throw new Error('App.create() has not run — is the loader scene the start scene?');
|
||||||
|
}
|
||||||
|
return App._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get exists(): boolean {
|
||||||
|
return App._instance !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Records the result of a match and writes it out immediately. */
|
||||||
|
recordMatch(outcome: 'win' | 'loss' | 'draw'): void {
|
||||||
|
this.stats.recordResult(outcome);
|
||||||
|
this.save.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "982035ad-66a6-428b-bba3-4fe31ed7a095",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { _decorator, Component, director, game, resources, SpriteFrame } from 'cc';
|
||||||
|
import { App } from './App';
|
||||||
|
import { CARDS_DIR } from '../ui/game/CardLibrary';
|
||||||
|
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The loader scene, per ARCHITECTURE.md: bring the modules up, then hand over
|
||||||
|
* to the lobby. Everything that must exist before any gameplay runs belongs
|
||||||
|
* here, and nowhere else.
|
||||||
|
*/
|
||||||
|
@ccclass('Bootstrap')
|
||||||
|
export class Bootstrap extends Component {
|
||||||
|
@property({ tooltip: 'Scene to open once the modules are ready.' })
|
||||||
|
nextScene = 'lobby';
|
||||||
|
|
||||||
|
start(): void {
|
||||||
|
// A phone that throttles to 30 fps makes the card animations stutter;
|
||||||
|
// asking for 60 up front is cheap and the engine falls back on its own.
|
||||||
|
game.frameRate = 60;
|
||||||
|
|
||||||
|
App.create();
|
||||||
|
|
||||||
|
// Warm the card art here rather than on the first deal: thirty-seven
|
||||||
|
// sprites are the only sizeable load in the game, and a loader scene is
|
||||||
|
// exactly where a player expects to wait for it.
|
||||||
|
resources.loadDir(CARDS_DIR, SpriteFrame, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error('[bootstrap] could not preload the card art', error);
|
||||||
|
}
|
||||||
|
this._openLobby();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _openLobby(): void {
|
||||||
|
director.loadScene(this.nextScene, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(`[bootstrap] could not open '${this.nextScene}'`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "c91dd91e-e180-44f4-98d1-b58cd4db0169",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Card } from '../cards/Card';
|
||||||
|
import { Action, Actions } from './Action';
|
||||||
|
import { GameState, Phase, PlayerId } from './GameState';
|
||||||
|
import { beats, currentActor, legalActions, unbeatenSlots } from './DurakRules';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What tapping a card means for a player right now, or null if that card cannot
|
||||||
|
* be played.
|
||||||
|
*
|
||||||
|
* This lives in the core rather than in the game screen so it can be tested
|
||||||
|
* without the engine: it is the one piece of interface logic that can silently
|
||||||
|
* turn a legal move into a rejected tap, and it is far too easy to get wrong by
|
||||||
|
* eye. The screen just calls it and submits whatever comes back.
|
||||||
|
*
|
||||||
|
* One tap is the whole interaction. When defending, the attack to beat is worked
|
||||||
|
* out here instead of being chosen separately — the serialised rules leave only
|
||||||
|
* one unanswered attack at a time, and where several somehow exist the lowest
|
||||||
|
* slot this card can beat is taken.
|
||||||
|
*/
|
||||||
|
export function intentFor(state: GameState, player: PlayerId, card: Card): Action | null {
|
||||||
|
if (currentActor(state) !== player) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.phase === Phase.Defence) {
|
||||||
|
const slot = unbeatenSlots(state)
|
||||||
|
.find((i) => beats(card, state.table[i].attack, state.trumpSuit));
|
||||||
|
return slot === undefined ? null : Actions.defend(player, card, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wanted = Actions.attack(player, card);
|
||||||
|
const legal = legalActions(state, player)
|
||||||
|
.some((a) => a.type === wanted.type && (a as { card?: Card }).card === card);
|
||||||
|
return legal ? wanted : null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "b1aa773a-2d2c-43f5-980a-d6e2ffb829fd",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { _decorator, Component, Node } from 'cc';
|
||||||
|
import { App } from '../app/App';
|
||||||
|
import { LobbyScreen } from './lobby/LobbyScreen';
|
||||||
|
import { GameScreen, MatchOutcome } from './game/GameScreen';
|
||||||
|
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Owns the two screens the lobby scene contains and moves between them.
|
||||||
|
*
|
||||||
|
* ARCHITECTURE.md puts the main game UI in the lobby scene, so a match is a
|
||||||
|
* change of visible screen rather than a scene load: no reload cost between
|
||||||
|
* games, and no way for a half-finished match to leak into a new one as long
|
||||||
|
* as `GameScreen.teardown` is honest about clearing up.
|
||||||
|
*/
|
||||||
|
@ccclass('MainFlow')
|
||||||
|
export class MainFlow extends Component {
|
||||||
|
@property(LobbyScreen)
|
||||||
|
lobby: LobbyScreen | null = null;
|
||||||
|
|
||||||
|
@property(GameScreen)
|
||||||
|
game: GameScreen | null = null;
|
||||||
|
|
||||||
|
@property(Node)
|
||||||
|
lobbyRoot: Node | null = null;
|
||||||
|
|
||||||
|
@property(Node)
|
||||||
|
gameRoot: Node | null = null;
|
||||||
|
|
||||||
|
start(): void {
|
||||||
|
if (this.lobby) {
|
||||||
|
this.lobby.onStartRequested = () => this.startMatch();
|
||||||
|
}
|
||||||
|
if (this.game) {
|
||||||
|
this.game.onFinished = (outcome) => this.finishMatch(outcome);
|
||||||
|
this.game.onQuitRequested = () => this.abandonMatch();
|
||||||
|
}
|
||||||
|
this.showLobby();
|
||||||
|
}
|
||||||
|
|
||||||
|
private showLobby(): void {
|
||||||
|
setActive(this.gameRoot, false);
|
||||||
|
setActive(this.lobbyRoot, true);
|
||||||
|
this.lobby?.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private startMatch(): void {
|
||||||
|
setActive(this.lobbyRoot, false);
|
||||||
|
setActive(this.gameRoot, true);
|
||||||
|
this.game?.startNewMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private finishMatch(outcome: MatchOutcome): void {
|
||||||
|
if (App.exists) {
|
||||||
|
App.instance.recordMatch(outcome);
|
||||||
|
}
|
||||||
|
this.game?.teardown();
|
||||||
|
this.showLobby();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Leaving early still ends the match — and it counts as a loss. */
|
||||||
|
private abandonMatch(): void {
|
||||||
|
this.finishMatch('loss');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActive(node: Node | null, active: boolean): void {
|
||||||
|
if (node) {
|
||||||
|
node.active = active;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "0b757fc9-4bb2-4007-9b13-b618d0655b6e",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Every piece of text the player reads, in one place.
|
||||||
|
*
|
||||||
|
* Localisation is out of scope for iteration 1 (see docs/PLAN.md), but keeping
|
||||||
|
* the strings together means adding a language later is a change to this file
|
||||||
|
* and nothing else — rather than a hunt through scenes and components.
|
||||||
|
*/
|
||||||
|
export const Strings = {
|
||||||
|
appTitle: 'Fool',
|
||||||
|
appSubtitle: 'a game of durak',
|
||||||
|
|
||||||
|
newGame: 'New Game',
|
||||||
|
quit: 'Leave',
|
||||||
|
playAgain: 'Play Again',
|
||||||
|
backToLobby: 'Back',
|
||||||
|
|
||||||
|
statsTitle: 'Your record',
|
||||||
|
statsPlayed: 'Played',
|
||||||
|
statsWon: 'Won',
|
||||||
|
statsLost: 'Lost',
|
||||||
|
statsStreak: 'Streak',
|
||||||
|
|
||||||
|
take: 'Take',
|
||||||
|
done: 'Done',
|
||||||
|
|
||||||
|
yourMove: 'Your move',
|
||||||
|
yourDefence: 'Beat it, or take',
|
||||||
|
addMore: 'Add cards, or say done',
|
||||||
|
opponentThinking: 'Opponent is thinking',
|
||||||
|
opponentTook: 'Opponent takes the cards',
|
||||||
|
youTook: 'You take the cards',
|
||||||
|
|
||||||
|
trumpIs: 'Trump',
|
||||||
|
deckLeft: 'Deck',
|
||||||
|
opponentHand: 'Opponent',
|
||||||
|
|
||||||
|
wonTitle: 'You win',
|
||||||
|
lostTitle: 'You are the fool',
|
||||||
|
drawTitle: 'A draw',
|
||||||
|
wonBody: 'Your opponent was left holding the cards.',
|
||||||
|
lostBody: 'You were left holding the cards.',
|
||||||
|
drawBody: 'You both ran out at the same time.',
|
||||||
|
|
||||||
|
cannotPlayThat: 'You cannot play that card',
|
||||||
|
} as const;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "672ddd76-ded7-498e-97b1-df2d7d30f662",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { Color } from 'cc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared visual constants. Anything a layout or a colour is tuned by lives here
|
||||||
|
* rather than being typed into each scene, so a change lands everywhere at once
|
||||||
|
* and the scene files stay free of magic numbers.
|
||||||
|
*
|
||||||
|
* Lengths are in design units — the screen is always exactly 1080 wide, see
|
||||||
|
* docs/DECISIONS.md.
|
||||||
|
*/
|
||||||
|
export const Layout = {
|
||||||
|
designWidth: 1080,
|
||||||
|
designHeight: 1920,
|
||||||
|
|
||||||
|
/** Card sprite size, matching what scripts/build-art.mjs produces. */
|
||||||
|
cardWidth: 220,
|
||||||
|
cardHeight: 320,
|
||||||
|
|
||||||
|
/** Cards on the table are drawn smaller so six pairs fit comfortably. */
|
||||||
|
tableCardScale: 0.62,
|
||||||
|
/** The opponent's hand is smaller again — it is only ever card backs. */
|
||||||
|
opponentCardScale: 0.5,
|
||||||
|
|
||||||
|
/** Horizontal step between neighbouring cards in the player's hand. */
|
||||||
|
handStep: 128,
|
||||||
|
/** Never let a hand grow wider than this; the step shrinks instead. */
|
||||||
|
handMaxWidth: 940,
|
||||||
|
/** How far the tapped card lifts out of the hand. */
|
||||||
|
handLift: 48,
|
||||||
|
|
||||||
|
/** Offset of a beating card from the card it beats. */
|
||||||
|
beatOffset: { x: 26, y: -34 },
|
||||||
|
|
||||||
|
/** Comfortable minimum for anything tappable, per docs/UI.md. */
|
||||||
|
minTapSize: 120,
|
||||||
|
|
||||||
|
screenMargin: 40,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where things sit on the table, in canvas coordinates (origin at the
|
||||||
|
* centre, y up). Vertical positions stay well inside the 1080×1920 design
|
||||||
|
* area so that a 4:3 screen — which crops the top and bottom — still shows
|
||||||
|
* every one of them. See docs/DECISIONS.md.
|
||||||
|
*/
|
||||||
|
region: {
|
||||||
|
opponentHandY: 600,
|
||||||
|
opponentLabelY: 770,
|
||||||
|
deck: { x: -390, y: 150 },
|
||||||
|
trump: { x: -300, y: 120 },
|
||||||
|
discard: { x: 430, y: 150 },
|
||||||
|
/** Centre of the first table row; the second row sits a row-height below. */
|
||||||
|
tableTopY: -20,
|
||||||
|
tableRowStep: 235,
|
||||||
|
tableColumnStep: 180,
|
||||||
|
messageY: 330,
|
||||||
|
actionBarY: -430,
|
||||||
|
playerHandY: -700,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const Palette = {
|
||||||
|
gold: new Color(244, 194, 69, 255),
|
||||||
|
cream: new Color(247, 240, 222, 255),
|
||||||
|
dim: new Color(174, 196, 182, 255),
|
||||||
|
good: new Color(126, 217, 140, 255),
|
||||||
|
bad: new Color(232, 116, 104, 255),
|
||||||
|
shade: new Color(0, 0, 0, 170),
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
/** How long the standard card movements take, in seconds. */
|
||||||
|
export const Timing = {
|
||||||
|
deal: 0.28,
|
||||||
|
dealStagger: 0.06,
|
||||||
|
play: 0.22,
|
||||||
|
collect: 0.3,
|
||||||
|
flip: 0.16,
|
||||||
|
/** Pause before the bot acts, so its moves can be followed. */
|
||||||
|
botThinking: 0.55,
|
||||||
|
/** Pause after a turn resolves, before the next one starts. */
|
||||||
|
turnBreak: 0.4,
|
||||||
|
} as const;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "3ba498f9-9dcb-48dc-bb1d-1de46602c43a",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { _decorator, Component, resources, SpriteFrame } from 'cc';
|
||||||
|
import { Card } from '../../core/cards/Card';
|
||||||
|
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/** Folder under `assets/resources` holding the 36 faces and the back. */
|
||||||
|
export const CARDS_DIR = 'cards';
|
||||||
|
const BACK_NAME = 'card_back';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns a `Card` into the sprite frame that draws it.
|
||||||
|
*
|
||||||
|
* The frames are loaded as a folder out of the `resources` bundle rather than
|
||||||
|
* being referenced one by one in the scene: thirty-seven inspector slots would
|
||||||
|
* be miserable to maintain, and an auto-atlas (`.pac`) is only a build-time
|
||||||
|
* packing instruction — it is not something that can be loaded and asked for a
|
||||||
|
* frame by name at runtime. The `.pac` beside the images still does its job,
|
||||||
|
* packing all thirty-seven into one texture so the table costs one draw call.
|
||||||
|
*
|
||||||
|
* The only contract between the rules and the art is `Card.assetName`.
|
||||||
|
*/
|
||||||
|
@ccclass('CardLibrary')
|
||||||
|
export class CardLibrary extends Component {
|
||||||
|
@property({ tooltip: 'Folder under assets/resources holding the card sprites.' })
|
||||||
|
directory = CARDS_DIR;
|
||||||
|
|
||||||
|
private readonly _frames = new Map<string, SpriteFrame>();
|
||||||
|
private readonly _missingReported = new Set<string>();
|
||||||
|
private _ready = false;
|
||||||
|
private _waiting: (() => void)[] = [];
|
||||||
|
|
||||||
|
onLoad(): void {
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
get ready(): boolean {
|
||||||
|
return this._ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the folder. Bootstrap preloads the same folder before the lobby
|
||||||
|
* opens, so in practice this resolves from cache within a frame.
|
||||||
|
*/
|
||||||
|
load(): void {
|
||||||
|
if (this._ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resources.loadDir(this.directory, SpriteFrame, (error, frames) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(`[cards] could not load '${this.directory}'`, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const frame of frames) {
|
||||||
|
this._frames.set(frame.name, frame);
|
||||||
|
}
|
||||||
|
this._ready = true;
|
||||||
|
const waiting = this._waiting;
|
||||||
|
this._waiting = [];
|
||||||
|
for (const resolve of waiting) resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Runs `done` once the frames are available — immediately if they already are. */
|
||||||
|
whenReady(done: () => void): void {
|
||||||
|
if (this._ready) {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
this._waiting.push(done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frameFor(card: Card): SpriteFrame | null {
|
||||||
|
return this._frame(card.assetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get backFrame(): SpriteFrame | null {
|
||||||
|
return this._frame(BACK_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _frame(name: string): SpriteFrame | null {
|
||||||
|
const frame = this._frames.get(name) ?? null;
|
||||||
|
if (!frame && this._ready && !this._missingReported.has(name)) {
|
||||||
|
this._missingReported.add(name);
|
||||||
|
console.error(`[cards] '${name}' is missing — run 'npm run build:art'`);
|
||||||
|
}
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "4e2c42cf-866c-4ba0-aa4f-78c256d28a0f",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||