diff --git a/assets/prefabs/card.prefab b/assets/prefabs/card.prefab new file mode 100644 index 0000000..05daf08 --- /dev/null +++ b/assets/prefabs/card.prefab @@ -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 + } +] \ No newline at end of file diff --git a/assets/prefabs/card.prefab.meta b/assets/prefabs/card.prefab.meta new file mode 100644 index 0000000..f1b141b --- /dev/null +++ b/assets/prefabs/card.prefab.meta @@ -0,0 +1,13 @@ +{ + "ver": "1.1.50", + "importer": "prefab", + "imported": true, + "uuid": "1ad36ebe-345c-4936-be65-c838f51b4eb4", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": { + "syncNodeName": "card" + } +} diff --git a/assets/resources.meta b/assets/resources.meta new file mode 100644 index 0000000..603547c --- /dev/null +++ b/assets/resources.meta @@ -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 + } +} diff --git a/assets/art/cards.meta b/assets/resources/cards.meta similarity index 100% rename from assets/art/cards.meta rename to assets/resources/cards.meta diff --git a/assets/art/cards/10_of_clubs.png b/assets/resources/cards/10_of_clubs.png similarity index 100% rename from assets/art/cards/10_of_clubs.png rename to assets/resources/cards/10_of_clubs.png diff --git a/assets/art/cards/10_of_clubs.png.meta b/assets/resources/cards/10_of_clubs.png.meta similarity index 100% rename from assets/art/cards/10_of_clubs.png.meta rename to assets/resources/cards/10_of_clubs.png.meta diff --git a/assets/art/cards/10_of_diamonds.png b/assets/resources/cards/10_of_diamonds.png similarity index 100% rename from assets/art/cards/10_of_diamonds.png rename to assets/resources/cards/10_of_diamonds.png diff --git a/assets/art/cards/10_of_diamonds.png.meta b/assets/resources/cards/10_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/10_of_diamonds.png.meta rename to assets/resources/cards/10_of_diamonds.png.meta diff --git a/assets/art/cards/10_of_hearts.png b/assets/resources/cards/10_of_hearts.png similarity index 100% rename from assets/art/cards/10_of_hearts.png rename to assets/resources/cards/10_of_hearts.png diff --git a/assets/art/cards/10_of_hearts.png.meta b/assets/resources/cards/10_of_hearts.png.meta similarity index 100% rename from assets/art/cards/10_of_hearts.png.meta rename to assets/resources/cards/10_of_hearts.png.meta diff --git a/assets/art/cards/10_of_spades.png b/assets/resources/cards/10_of_spades.png similarity index 100% rename from assets/art/cards/10_of_spades.png rename to assets/resources/cards/10_of_spades.png diff --git a/assets/art/cards/10_of_spades.png.meta b/assets/resources/cards/10_of_spades.png.meta similarity index 100% rename from assets/art/cards/10_of_spades.png.meta rename to assets/resources/cards/10_of_spades.png.meta diff --git a/assets/art/cards/6_of_clubs.png b/assets/resources/cards/6_of_clubs.png similarity index 100% rename from assets/art/cards/6_of_clubs.png rename to assets/resources/cards/6_of_clubs.png diff --git a/assets/art/cards/6_of_clubs.png.meta b/assets/resources/cards/6_of_clubs.png.meta similarity index 100% rename from assets/art/cards/6_of_clubs.png.meta rename to assets/resources/cards/6_of_clubs.png.meta diff --git a/assets/art/cards/6_of_diamonds.png b/assets/resources/cards/6_of_diamonds.png similarity index 100% rename from assets/art/cards/6_of_diamonds.png rename to assets/resources/cards/6_of_diamonds.png diff --git a/assets/art/cards/6_of_diamonds.png.meta b/assets/resources/cards/6_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/6_of_diamonds.png.meta rename to assets/resources/cards/6_of_diamonds.png.meta diff --git a/assets/art/cards/6_of_hearts.png b/assets/resources/cards/6_of_hearts.png similarity index 100% rename from assets/art/cards/6_of_hearts.png rename to assets/resources/cards/6_of_hearts.png diff --git a/assets/art/cards/6_of_hearts.png.meta b/assets/resources/cards/6_of_hearts.png.meta similarity index 100% rename from assets/art/cards/6_of_hearts.png.meta rename to assets/resources/cards/6_of_hearts.png.meta diff --git a/assets/art/cards/6_of_spades.png b/assets/resources/cards/6_of_spades.png similarity index 100% rename from assets/art/cards/6_of_spades.png rename to assets/resources/cards/6_of_spades.png diff --git a/assets/art/cards/6_of_spades.png.meta b/assets/resources/cards/6_of_spades.png.meta similarity index 100% rename from assets/art/cards/6_of_spades.png.meta rename to assets/resources/cards/6_of_spades.png.meta diff --git a/assets/art/cards/7_of_clubs.png b/assets/resources/cards/7_of_clubs.png similarity index 100% rename from assets/art/cards/7_of_clubs.png rename to assets/resources/cards/7_of_clubs.png diff --git a/assets/art/cards/7_of_clubs.png.meta b/assets/resources/cards/7_of_clubs.png.meta similarity index 100% rename from assets/art/cards/7_of_clubs.png.meta rename to assets/resources/cards/7_of_clubs.png.meta diff --git a/assets/art/cards/7_of_diamonds.png b/assets/resources/cards/7_of_diamonds.png similarity index 100% rename from assets/art/cards/7_of_diamonds.png rename to assets/resources/cards/7_of_diamonds.png diff --git a/assets/art/cards/7_of_diamonds.png.meta b/assets/resources/cards/7_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/7_of_diamonds.png.meta rename to assets/resources/cards/7_of_diamonds.png.meta diff --git a/assets/art/cards/7_of_hearts.png b/assets/resources/cards/7_of_hearts.png similarity index 100% rename from assets/art/cards/7_of_hearts.png rename to assets/resources/cards/7_of_hearts.png diff --git a/assets/art/cards/7_of_hearts.png.meta b/assets/resources/cards/7_of_hearts.png.meta similarity index 100% rename from assets/art/cards/7_of_hearts.png.meta rename to assets/resources/cards/7_of_hearts.png.meta diff --git a/assets/art/cards/7_of_spades.png b/assets/resources/cards/7_of_spades.png similarity index 100% rename from assets/art/cards/7_of_spades.png rename to assets/resources/cards/7_of_spades.png diff --git a/assets/art/cards/7_of_spades.png.meta b/assets/resources/cards/7_of_spades.png.meta similarity index 100% rename from assets/art/cards/7_of_spades.png.meta rename to assets/resources/cards/7_of_spades.png.meta diff --git a/assets/art/cards/8_of_clubs.png b/assets/resources/cards/8_of_clubs.png similarity index 100% rename from assets/art/cards/8_of_clubs.png rename to assets/resources/cards/8_of_clubs.png diff --git a/assets/art/cards/8_of_clubs.png.meta b/assets/resources/cards/8_of_clubs.png.meta similarity index 100% rename from assets/art/cards/8_of_clubs.png.meta rename to assets/resources/cards/8_of_clubs.png.meta diff --git a/assets/art/cards/8_of_diamonds.png b/assets/resources/cards/8_of_diamonds.png similarity index 100% rename from assets/art/cards/8_of_diamonds.png rename to assets/resources/cards/8_of_diamonds.png diff --git a/assets/art/cards/8_of_diamonds.png.meta b/assets/resources/cards/8_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/8_of_diamonds.png.meta rename to assets/resources/cards/8_of_diamonds.png.meta diff --git a/assets/art/cards/8_of_hearts.png b/assets/resources/cards/8_of_hearts.png similarity index 100% rename from assets/art/cards/8_of_hearts.png rename to assets/resources/cards/8_of_hearts.png diff --git a/assets/art/cards/8_of_hearts.png.meta b/assets/resources/cards/8_of_hearts.png.meta similarity index 100% rename from assets/art/cards/8_of_hearts.png.meta rename to assets/resources/cards/8_of_hearts.png.meta diff --git a/assets/art/cards/8_of_spades.png b/assets/resources/cards/8_of_spades.png similarity index 100% rename from assets/art/cards/8_of_spades.png rename to assets/resources/cards/8_of_spades.png diff --git a/assets/art/cards/8_of_spades.png.meta b/assets/resources/cards/8_of_spades.png.meta similarity index 100% rename from assets/art/cards/8_of_spades.png.meta rename to assets/resources/cards/8_of_spades.png.meta diff --git a/assets/art/cards/9_of_clubs.png b/assets/resources/cards/9_of_clubs.png similarity index 100% rename from assets/art/cards/9_of_clubs.png rename to assets/resources/cards/9_of_clubs.png diff --git a/assets/art/cards/9_of_clubs.png.meta b/assets/resources/cards/9_of_clubs.png.meta similarity index 100% rename from assets/art/cards/9_of_clubs.png.meta rename to assets/resources/cards/9_of_clubs.png.meta diff --git a/assets/art/cards/9_of_diamonds.png b/assets/resources/cards/9_of_diamonds.png similarity index 100% rename from assets/art/cards/9_of_diamonds.png rename to assets/resources/cards/9_of_diamonds.png diff --git a/assets/art/cards/9_of_diamonds.png.meta b/assets/resources/cards/9_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/9_of_diamonds.png.meta rename to assets/resources/cards/9_of_diamonds.png.meta diff --git a/assets/art/cards/9_of_hearts.png b/assets/resources/cards/9_of_hearts.png similarity index 100% rename from assets/art/cards/9_of_hearts.png rename to assets/resources/cards/9_of_hearts.png diff --git a/assets/art/cards/9_of_hearts.png.meta b/assets/resources/cards/9_of_hearts.png.meta similarity index 100% rename from assets/art/cards/9_of_hearts.png.meta rename to assets/resources/cards/9_of_hearts.png.meta diff --git a/assets/art/cards/9_of_spades.png b/assets/resources/cards/9_of_spades.png similarity index 100% rename from assets/art/cards/9_of_spades.png rename to assets/resources/cards/9_of_spades.png diff --git a/assets/art/cards/9_of_spades.png.meta b/assets/resources/cards/9_of_spades.png.meta similarity index 100% rename from assets/art/cards/9_of_spades.png.meta rename to assets/resources/cards/9_of_spades.png.meta diff --git a/assets/art/cards/ATTRIBUTION.md b/assets/resources/cards/ATTRIBUTION.md similarity index 100% rename from assets/art/cards/ATTRIBUTION.md rename to assets/resources/cards/ATTRIBUTION.md diff --git a/assets/art/cards/ATTRIBUTION.md.meta b/assets/resources/cards/ATTRIBUTION.md.meta similarity index 100% rename from assets/art/cards/ATTRIBUTION.md.meta rename to assets/resources/cards/ATTRIBUTION.md.meta diff --git a/assets/art/cards/ace_of_clubs.png b/assets/resources/cards/ace_of_clubs.png similarity index 100% rename from assets/art/cards/ace_of_clubs.png rename to assets/resources/cards/ace_of_clubs.png diff --git a/assets/art/cards/ace_of_clubs.png.meta b/assets/resources/cards/ace_of_clubs.png.meta similarity index 100% rename from assets/art/cards/ace_of_clubs.png.meta rename to assets/resources/cards/ace_of_clubs.png.meta diff --git a/assets/art/cards/ace_of_diamonds.png b/assets/resources/cards/ace_of_diamonds.png similarity index 100% rename from assets/art/cards/ace_of_diamonds.png rename to assets/resources/cards/ace_of_diamonds.png diff --git a/assets/art/cards/ace_of_diamonds.png.meta b/assets/resources/cards/ace_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/ace_of_diamonds.png.meta rename to assets/resources/cards/ace_of_diamonds.png.meta diff --git a/assets/art/cards/ace_of_hearts.png b/assets/resources/cards/ace_of_hearts.png similarity index 100% rename from assets/art/cards/ace_of_hearts.png rename to assets/resources/cards/ace_of_hearts.png diff --git a/assets/art/cards/ace_of_hearts.png.meta b/assets/resources/cards/ace_of_hearts.png.meta similarity index 100% rename from assets/art/cards/ace_of_hearts.png.meta rename to assets/resources/cards/ace_of_hearts.png.meta diff --git a/assets/art/cards/ace_of_spades.png b/assets/resources/cards/ace_of_spades.png similarity index 100% rename from assets/art/cards/ace_of_spades.png rename to assets/resources/cards/ace_of_spades.png diff --git a/assets/art/cards/ace_of_spades.png.meta b/assets/resources/cards/ace_of_spades.png.meta similarity index 100% rename from assets/art/cards/ace_of_spades.png.meta rename to assets/resources/cards/ace_of_spades.png.meta diff --git a/assets/art/cards/card_back.png b/assets/resources/cards/card_back.png similarity index 100% rename from assets/art/cards/card_back.png rename to assets/resources/cards/card_back.png diff --git a/assets/art/cards/card_back.png.meta b/assets/resources/cards/card_back.png.meta similarity index 100% rename from assets/art/cards/card_back.png.meta rename to assets/resources/cards/card_back.png.meta diff --git a/assets/art/cards/cards.pac b/assets/resources/cards/cards.pac similarity index 100% rename from assets/art/cards/cards.pac rename to assets/resources/cards/cards.pac diff --git a/assets/art/cards/cards.pac.meta b/assets/resources/cards/cards.pac.meta similarity index 96% rename from assets/art/cards/cards.pac.meta rename to assets/resources/cards/cards.pac.meta index fbf62b7..9cee9f2 100644 --- a/assets/art/cards/cards.pac.meta +++ b/assets/resources/cards/cards.pac.meta @@ -3,7 +3,9 @@ "importer": "auto-atlas", "imported": true, "uuid": "914afa5f-3f77-4d7d-835e-530e298c6816", - "files": [], + "files": [ + ".json" + ], "subMetas": {}, "userData": { "maxWidth": 2048, diff --git a/assets/art/cards/jack_of_clubs.png b/assets/resources/cards/jack_of_clubs.png similarity index 100% rename from assets/art/cards/jack_of_clubs.png rename to assets/resources/cards/jack_of_clubs.png diff --git a/assets/art/cards/jack_of_clubs.png.meta b/assets/resources/cards/jack_of_clubs.png.meta similarity index 100% rename from assets/art/cards/jack_of_clubs.png.meta rename to assets/resources/cards/jack_of_clubs.png.meta diff --git a/assets/art/cards/jack_of_diamonds.png b/assets/resources/cards/jack_of_diamonds.png similarity index 100% rename from assets/art/cards/jack_of_diamonds.png rename to assets/resources/cards/jack_of_diamonds.png diff --git a/assets/art/cards/jack_of_diamonds.png.meta b/assets/resources/cards/jack_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/jack_of_diamonds.png.meta rename to assets/resources/cards/jack_of_diamonds.png.meta diff --git a/assets/art/cards/jack_of_hearts.png b/assets/resources/cards/jack_of_hearts.png similarity index 100% rename from assets/art/cards/jack_of_hearts.png rename to assets/resources/cards/jack_of_hearts.png diff --git a/assets/art/cards/jack_of_hearts.png.meta b/assets/resources/cards/jack_of_hearts.png.meta similarity index 100% rename from assets/art/cards/jack_of_hearts.png.meta rename to assets/resources/cards/jack_of_hearts.png.meta diff --git a/assets/art/cards/jack_of_spades.png b/assets/resources/cards/jack_of_spades.png similarity index 100% rename from assets/art/cards/jack_of_spades.png rename to assets/resources/cards/jack_of_spades.png diff --git a/assets/art/cards/jack_of_spades.png.meta b/assets/resources/cards/jack_of_spades.png.meta similarity index 100% rename from assets/art/cards/jack_of_spades.png.meta rename to assets/resources/cards/jack_of_spades.png.meta diff --git a/assets/art/cards/king_of_clubs.png b/assets/resources/cards/king_of_clubs.png similarity index 100% rename from assets/art/cards/king_of_clubs.png rename to assets/resources/cards/king_of_clubs.png diff --git a/assets/art/cards/king_of_clubs.png.meta b/assets/resources/cards/king_of_clubs.png.meta similarity index 100% rename from assets/art/cards/king_of_clubs.png.meta rename to assets/resources/cards/king_of_clubs.png.meta diff --git a/assets/art/cards/king_of_diamonds.png b/assets/resources/cards/king_of_diamonds.png similarity index 100% rename from assets/art/cards/king_of_diamonds.png rename to assets/resources/cards/king_of_diamonds.png diff --git a/assets/art/cards/king_of_diamonds.png.meta b/assets/resources/cards/king_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/king_of_diamonds.png.meta rename to assets/resources/cards/king_of_diamonds.png.meta diff --git a/assets/art/cards/king_of_hearts.png b/assets/resources/cards/king_of_hearts.png similarity index 100% rename from assets/art/cards/king_of_hearts.png rename to assets/resources/cards/king_of_hearts.png diff --git a/assets/art/cards/king_of_hearts.png.meta b/assets/resources/cards/king_of_hearts.png.meta similarity index 100% rename from assets/art/cards/king_of_hearts.png.meta rename to assets/resources/cards/king_of_hearts.png.meta diff --git a/assets/art/cards/king_of_spades.png b/assets/resources/cards/king_of_spades.png similarity index 100% rename from assets/art/cards/king_of_spades.png rename to assets/resources/cards/king_of_spades.png diff --git a/assets/art/cards/king_of_spades.png.meta b/assets/resources/cards/king_of_spades.png.meta similarity index 100% rename from assets/art/cards/king_of_spades.png.meta rename to assets/resources/cards/king_of_spades.png.meta diff --git a/assets/art/cards/queen_of_clubs.png b/assets/resources/cards/queen_of_clubs.png similarity index 100% rename from assets/art/cards/queen_of_clubs.png rename to assets/resources/cards/queen_of_clubs.png diff --git a/assets/art/cards/queen_of_clubs.png.meta b/assets/resources/cards/queen_of_clubs.png.meta similarity index 100% rename from assets/art/cards/queen_of_clubs.png.meta rename to assets/resources/cards/queen_of_clubs.png.meta diff --git a/assets/art/cards/queen_of_diamonds.png b/assets/resources/cards/queen_of_diamonds.png similarity index 100% rename from assets/art/cards/queen_of_diamonds.png rename to assets/resources/cards/queen_of_diamonds.png diff --git a/assets/art/cards/queen_of_diamonds.png.meta b/assets/resources/cards/queen_of_diamonds.png.meta similarity index 100% rename from assets/art/cards/queen_of_diamonds.png.meta rename to assets/resources/cards/queen_of_diamonds.png.meta diff --git a/assets/art/cards/queen_of_hearts.png b/assets/resources/cards/queen_of_hearts.png similarity index 100% rename from assets/art/cards/queen_of_hearts.png rename to assets/resources/cards/queen_of_hearts.png diff --git a/assets/art/cards/queen_of_hearts.png.meta b/assets/resources/cards/queen_of_hearts.png.meta similarity index 100% rename from assets/art/cards/queen_of_hearts.png.meta rename to assets/resources/cards/queen_of_hearts.png.meta diff --git a/assets/art/cards/queen_of_spades.png b/assets/resources/cards/queen_of_spades.png similarity index 100% rename from assets/art/cards/queen_of_spades.png rename to assets/resources/cards/queen_of_spades.png diff --git a/assets/art/cards/queen_of_spades.png.meta b/assets/resources/cards/queen_of_spades.png.meta similarity index 100% rename from assets/art/cards/queen_of_spades.png.meta rename to assets/resources/cards/queen_of_spades.png.meta diff --git a/assets/scenes/loader.scene b/assets/scenes/loader.scene new file mode 100644 index 0000000..a133320 --- /dev/null +++ b/assets/scenes/loader.scene @@ -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 + } +] \ No newline at end of file diff --git a/assets/scenes/loader.scene.meta b/assets/scenes/loader.scene.meta new file mode 100644 index 0000000..0b6cdb3 --- /dev/null +++ b/assets/scenes/loader.scene.meta @@ -0,0 +1 @@ +{"ver":"1.1.50","importer":"scene","imported":true,"uuid":"1aee5910-40c3-4b99-bc8d-e477cf0e25ed","files":[".json"],"subMetas":{},"userData":{}} diff --git a/assets/scenes/lobby.scene b/assets/scenes/lobby.scene new file mode 100644 index 0000000..da07db5 --- /dev/null +++ b/assets/scenes/lobby.scene @@ -0,0 +1,5555 @@ +[ + { + "__type__": "cc.SceneAsset", + "_name": "lobby", + "_objFlags": 0, + "__editorExtras__": {}, + "_native": "", + "scene": { + "__id__": 1 + } + }, + { + "__type__": "cc.Scene", + "_name": "lobby", + "_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__": 130 + }, + "_id": "220f80f8-6216-4ec2-b63b-72365bcbfde9" + }, + { + "__type__": "cc.Node", + "_name": "Canvas", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [ + { + "__id__": 3 + }, + { + "__id__": 6 + }, + { + "__id__": 10 + } + ], + "_active": true, + "_components": [ + { + "__id__": 127 + }, + { + "__id__": 128 + }, + { + "__id__": 129 + } + ], + "_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": "7emmXvhnlPuJK6l6gVCv9H" + }, + { + "__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": "9fSZarkqBO04vpquLB6lRA" + }, + { + "__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": "b9TWHkNCVNhIy4HXZ0oIuw" + }, + { + "__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": "46TvnomDZNuZmLgmOrd7EJ" + }, + { + "__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": "e9G2pMRFJCk5BTDYdamROB" + }, + { + "__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": "e968iUlOpC1a0/6xHCy3/W" + }, + { + "__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": "9dBayqRP9GX6fEFCM2WU/1" + }, + { + "__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": "864q2Xz2RKOYLrAaQYWN65" + }, + { + "__type__": "cc.Node", + "_name": "Safe", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 2 + }, + "_children": [ + { + "__id__": 11 + }, + { + "__id__": 58 + } + ], + "_active": true, + "_components": [ + { + "__id__": 124 + }, + { + "__id__": 125 + }, + { + "__id__": 126 + } + ], + "_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": "a6waWjco5J144U+0knU1Xa" + }, + { + "__type__": "cc.Node", + "_name": "LobbyRoot", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 10 + }, + "_children": [ + { + "__id__": 12 + }, + { + "__id__": 15 + }, + { + "__id__": 18 + }, + { + "__id__": 48 + } + ], + "_active": true, + "_components": [ + { + "__id__": 55 + }, + { + "__id__": 56 + }, + { + "__id__": 57 + } + ], + "_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": "43OLs2LKxJHZLQLr1Ix3e6" + }, + { + "__type__": "cc.Node", + "_name": "Title", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 11 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 13 + }, + { + "__id__": 14 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 600, + "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": "03ZojlCshMWbGQDDZyoTsz" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 12 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 900, + "height": 160 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "11i1OFXVtOnbCoVDeLDCJL" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 12 + }, + "_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": "78XHuex+tNlJksCcMev+55" + }, + { + "__type__": "cc.Node", + "_name": "Subtitle", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 11 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 16 + }, + { + "__id__": 17 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 480, + "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": "e9zmseGPxLZJhC9cWV0OrZ" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 15 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 900, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "0aSQUDb75L5bAgARhC4TkI" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 15 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 174, + "g": 196, + "b": 182, + "a": 255 + }, + "_string": "a game of durak", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 42, + "_fontSize": 42, + "_fontFamily": "Arial", + "_lineHeight": 53, + "_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": "21IkUEeqlATZOV7bBCQ9DM" + }, + { + "__type__": "cc.Node", + "_name": "StatsPanel", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 11 + }, + "_children": [ + { + "__id__": 19 + }, + { + "__id__": 22 + }, + { + "__id__": 25 + }, + { + "__id__": 28 + }, + { + "__id__": 31 + }, + { + "__id__": 34 + }, + { + "__id__": 37 + }, + { + "__id__": 40 + }, + { + "__id__": 43 + } + ], + "_active": true, + "_components": [ + { + "__id__": 46 + }, + { + "__id__": 47 + } + ], + "_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": "708jg1DR5LU5HMh+sTX/3R" + }, + { + "__type__": "cc.Node", + "_name": "StatsTitle", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 20 + }, + { + "__id__": 21 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 145, + "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": "29zagRQzZCU6//ChtTgJqJ" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 19 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 620, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "d9Jn9fg9xNj5YVtB+NU0zY" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 19 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 244, + "g": 194, + "b": 69, + "a": 255 + }, + "_string": "Your record", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_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": "58CvNRaYRIEaUlLuAcSo0f" + }, + { + "__type__": "cc.Node", + "_name": "PlayedName", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 23 + }, + { + "__id__": 24 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -150, + "y": 55, + "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": "87t/oZuyBHuZ0dYP7hRJlv" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 22 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "37teNkBbNHe69WUZsoeDqx" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 22 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 174, + "g": 196, + "b": 182, + "a": 255 + }, + "_string": "Played", + "_horizontalAlign": 0, + "_verticalAlign": 1, + "_actualFontSize": 38, + "_fontSize": 38, + "_fontFamily": "Arial", + "_lineHeight": 48, + "_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": "3b5kLpXJRLI7xcNU8gQJuw" + }, + { + "__type__": "cc.Node", + "_name": "PlayedValue", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 26 + }, + { + "__id__": 27 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 160, + "y": 55, + "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": "11/lJNPOVAc5oFc2ekFB6C" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 25 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 260, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "7a0xeTFUVLIbIp0GOHl2lS" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 25 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "0", + "_horizontalAlign": 2, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_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": "aer71f2a5CsIwtIXyiQHvs" + }, + { + "__type__": "cc.Node", + "_name": "WonName", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 29 + }, + { + "__id__": 30 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -150, + "y": -21, + "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": "6f/COqnt1JKYmPVrrZ9FlB" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 28 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "9fj+UI0MVCELviG6om6EXl" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 28 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 174, + "g": 196, + "b": 182, + "a": 255 + }, + "_string": "Won", + "_horizontalAlign": 0, + "_verticalAlign": 1, + "_actualFontSize": 38, + "_fontSize": 38, + "_fontFamily": "Arial", + "_lineHeight": 48, + "_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": "2ewySN/p1IAIYjNUH2kDmH" + }, + { + "__type__": "cc.Node", + "_name": "WonValue", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 32 + }, + { + "__id__": 33 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 160, + "y": -21, + "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": "9bqiCRkmJN05ko+EHyHEn9" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 31 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 260, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "1d0dSVOhRBqr9tzrE3iUYH" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 31 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "0", + "_horizontalAlign": 2, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_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": "20AgFcor1HW7FKemGOKiL2" + }, + { + "__type__": "cc.Node", + "_name": "LostName", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 35 + }, + { + "__id__": 36 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -150, + "y": -97, + "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": "abpdX/LCJDeK4oMMPANS/j" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 34 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "2bsqat+c5JOpkuJE1zhbXC" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 34 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 174, + "g": 196, + "b": 182, + "a": 255 + }, + "_string": "Lost", + "_horizontalAlign": 0, + "_verticalAlign": 1, + "_actualFontSize": 38, + "_fontSize": 38, + "_fontFamily": "Arial", + "_lineHeight": 48, + "_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": "d8re8wLO5G/4kU6yWWj3c8" + }, + { + "__type__": "cc.Node", + "_name": "LostValue", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 38 + }, + { + "__id__": 39 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 160, + "y": -97, + "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": "30IKIGKVhNSJdEgFBt91yF" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 37 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 260, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "47ilG/xUlEe5wkdxJsjdYd" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 37 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "0", + "_horizontalAlign": 2, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_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": "f0v13TYNdI0oqa3ramFBHO" + }, + { + "__type__": "cc.Node", + "_name": "StreakName", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 41 + }, + { + "__id__": 42 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -150, + "y": -173, + "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": "94eN9PQ8pNko9xYZ4hl/VW" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 40 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "01ohkkvNRCkbKdd2JYQgbx" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 40 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 174, + "g": 196, + "b": 182, + "a": 255 + }, + "_string": "Streak", + "_horizontalAlign": 0, + "_verticalAlign": 1, + "_actualFontSize": 38, + "_fontSize": 38, + "_fontFamily": "Arial", + "_lineHeight": 48, + "_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": "e262ZTAqJFvab+BRWnlBpZ" + }, + { + "__type__": "cc.Node", + "_name": "StreakValue", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 18 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 44 + }, + { + "__id__": 45 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 160, + "y": -173, + "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": "4a9qCPBkZC8LAyvpwXHiSf" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 43 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 260, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "8f6OvqHl1JDaoHMn3AoX57" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 43 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "0", + "_horizontalAlign": 2, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_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": "02JzaMVu1LpYTvW2fplY7e" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 18 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 680, + "height": 400 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "4bfLFAF9xPVY7skMiEpR2P" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 18 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "a1a282c3-c540-4933-a400-ab611b8857cb@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "00SRJLnURPnoIooQqmoTo3" + }, + { + "__type__": "cc.Node", + "_name": "NewGameButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 11 + }, + "_children": [ + { + "__id__": 49 + } + ], + "_active": true, + "_components": [ + { + "__id__": 52 + }, + { + "__id__": 53 + }, + { + "__id__": 54 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": -400, + "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": "8cXTqzlo9Gro6B/C0UufH1" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 48 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 50 + }, + { + "__id__": 51 + } + ], + "_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": "57Gs0FNqpOy4ZlZHFgLUyG" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 49 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 520, + "height": 110 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "164w7yNKlL6oHrXCyb2c2W" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 49 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 40, + "g": 26, + "b": 4, + "a": 255 + }, + "_string": "New Game", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 54, + "_fontSize": 54, + "_fontFamily": "Arial", + "_lineHeight": 68, + "_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": "4bB/T9Eg9JXLVsgUYh1kLF" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 48 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 560, + "height": 150 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "23j5kU6DxAyJ5aWs1b+O3Z" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 48 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "c57N2+KiZB0JzTx29s1aO8" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 48 + }, + "_enabled": true, + "__prefab": null, + "clickEvents": [], + "_interactable": true, + "_transition": 2, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_hoverSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_pressedSprite": { + "__uuid__": "3ab54557-015a-4b87-be9c-762799ecc41a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_disabledSprite": { + "__uuid__": "c1b43015-8413-4a09-8995-bbefa3b349ab@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_duration": 0.08, + "_zoomScale": 1.04, + "_target": null, + "_id": "7d3bnC8idI9K3Rnxe4qsD6" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 11 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1280, + "height": 720 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "92Ui8I1/JJ+YWS/GD897Yl" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 11 + }, + "_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": 100, + "_originalHeight": 100, + "_alignMode": 1, + "_lockFlags": 0, + "_id": "3a0InujX9BZ6QlqjO3eFzG" + }, + { + "__type__": "41c96ml0tNOUZsj2x45B/tT", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 11 + }, + "_enabled": true, + "__prefab": null, + "playedLabel": { + "__id__": 27 + }, + "wonLabel": { + "__id__": 33 + }, + "lostLabel": { + "__id__": 39 + }, + "streakLabel": { + "__id__": 45 + }, + "statsPanel": { + "__id__": 18 + }, + "newGameButton": { + "__id__": 54 + }, + "_id": "c6+ZKlauFI1LIYpAC/E2Lt" + }, + { + "__type__": "cc.Node", + "_name": "GameRoot", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 10 + }, + "_children": [ + { + "__id__": 59 + }, + { + "__id__": 64 + }, + { + "__id__": 67 + }, + { + "__id__": 70 + }, + { + "__id__": 73 + }, + { + "__id__": 89 + }, + { + "__id__": 96 + } + ], + "_active": false, + "_components": [ + { + "__id__": 120 + }, + { + "__id__": 121 + }, + { + "__id__": 122 + }, + { + "__id__": 123 + } + ], + "_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": "84/Je4E8VGVrWC4FTuJ+uY" + }, + { + "__type__": "cc.Node", + "_name": "Deck", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [ + { + "__id__": 60 + } + ], + "_active": true, + "_components": [ + { + "__id__": 63 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -390, + "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": "00wUf4P5BMDZlvUXZ4JX0p" + }, + { + "__type__": "cc.Node", + "_name": "DeckCount", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 59 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 61 + }, + { + "__id__": 62 + } + ], + "_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": "6b6s3niNtFrJucPzeK2Xtx" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 60 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "70xPD+MZdOG5ZAlT53k3FF" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 60 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Deck 24", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 34, + "_fontSize": 34, + "_fontFamily": "Arial", + "_lineHeight": 43, + "_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": "88AvX/WyJF56hUlbV8Lvbx" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 59 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 80 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "dbeeLLYGhGrJjGsZpna8KD" + }, + { + "__type__": "cc.Node", + "_name": "OpponentLabel", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 65 + }, + { + "__id__": 66 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 770, + "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": "27PMJQLa9HLrJEjM5juWEd" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 64 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 700, + "height": 60 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "3avpNedalKz6V0GNXIih55" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 64 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Opponent: 6", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 38, + "_fontSize": 38, + "_fontFamily": "Arial", + "_lineHeight": 48, + "_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": "7bK8+vnRRJMZJ+f7eUdcZb" + }, + { + "__type__": "cc.Node", + "_name": "Message", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 68 + }, + { + "__id__": 69 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 330, + "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": "e2bXI15fBI/J3y53ng6vkp" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 67 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 900, + "height": 70 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "c8Gp3ZhxJLM6S6wauMrlpZ" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 67 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Your move", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_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": "62Ne3LtolPwogvDsv2aaVn" + }, + { + "__type__": "cc.Node", + "_name": "CardLayer", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 71 + }, + { + "__id__": 72 + } + ], + "_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": "b22IeWiFJC55tRdjKRpUbJ" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 70 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1280, + "height": 720 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "c96IxVFc5FhbawQQns1peK" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 70 + }, + "_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": 100, + "_originalHeight": 100, + "_alignMode": 1, + "_lockFlags": 0, + "_id": "97M8wVHgBBlJfmmqukBJLp" + }, + { + "__type__": "cc.Node", + "_name": "ActionBar", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [ + { + "__id__": 74 + }, + { + "__id__": 81 + } + ], + "_active": true, + "_components": [ + { + "__id__": 88 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": -430, + "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": "26wE8PNQhH24mwk+xvHajT" + }, + { + "__type__": "cc.Node", + "_name": "TakeButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 73 + }, + "_children": [ + { + "__id__": 75 + } + ], + "_active": true, + "_components": [ + { + "__id__": 78 + }, + { + "__id__": 79 + }, + { + "__id__": 80 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -180, + "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": "16BRO2ic9BW5cVxD9Qvtpr" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 74 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 76 + }, + { + "__id__": 77 + } + ], + "_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": "1fDqkTWcROaJRNQLFKwJma" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 75 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 294, + "height": 104 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "9eYthQWeRCqoVC5gju0Xu+" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 75 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Take", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 50, + "_fontSize": 50, + "_fontFamily": "Arial", + "_lineHeight": 63, + "_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": "22f3i60qNA/rg5vw02CZXh" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 74 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 330, + "height": 140 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "a86V9j0+1BbbxdHrgR0JJd" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 74 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "2dPu9Z3MNJlKmB3u+qyYFQ" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 74 + }, + "_enabled": true, + "__prefab": null, + "clickEvents": [], + "_interactable": true, + "_transition": 2, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_hoverSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_pressedSprite": { + "__uuid__": "3ab54557-015a-4b87-be9c-762799ecc41a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_disabledSprite": { + "__uuid__": "c1b43015-8413-4a09-8995-bbefa3b349ab@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_duration": 0.08, + "_zoomScale": 1.04, + "_target": null, + "_id": "bcgmmL7LhLAYozjZ8mbnUy" + }, + { + "__type__": "cc.Node", + "_name": "DoneButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 73 + }, + "_children": [ + { + "__id__": 82 + } + ], + "_active": true, + "_components": [ + { + "__id__": 85 + }, + { + "__id__": 86 + }, + { + "__id__": 87 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 180, + "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": "86eroetTRMZKQgy5aPUK8Q" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 81 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 83 + }, + { + "__id__": 84 + } + ], + "_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": "81e2mkXTRDaa1+W2t86yfc" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 82 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 294, + "height": 104 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "38tGcrWapLBome7Jpu/l/a" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 82 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Done", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 50, + "_fontSize": 50, + "_fontFamily": "Arial", + "_lineHeight": 63, + "_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": "abSFJvSzVBRoUlfa8V04+Y" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 81 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 330, + "height": 140 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "06U8OfleFOLIRELwQNvpqq" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 81 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "59akQjujVOh5l2FZHMb0Be" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 81 + }, + "_enabled": true, + "__prefab": null, + "clickEvents": [], + "_interactable": true, + "_transition": 2, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_hoverSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_pressedSprite": { + "__uuid__": "3ab54557-015a-4b87-be9c-762799ecc41a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_disabledSprite": { + "__uuid__": "c1b43015-8413-4a09-8995-bbefa3b349ab@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_duration": 0.08, + "_zoomScale": 1.04, + "_target": null, + "_id": "adwZ1L151KEqCvRlxcp+ZY" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 73 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1000, + "height": 160 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "40OnCMy8BC/4tcBLRpM5ff" + }, + { + "__type__": "cc.Node", + "_name": "QuitButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [ + { + "__id__": 90 + } + ], + "_active": true, + "_components": [ + { + "__id__": 93 + }, + { + "__id__": 94 + }, + { + "__id__": 95 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": -420, + "y": 840, + "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": "8bHMLtBGhGBqEXEScy8395" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 89 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 91 + }, + { + "__id__": 92 + } + ], + "_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": "31d/s5KTBAIbp3OZxKPRK4" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 90 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 164, + "height": 64 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "e0GSQuhrFPYZCIZkrrNtVO" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 90 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Leave", + "_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": 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": "8a4zOkJUVHe5MYoziE3mq4" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 89 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 200, + "height": 100 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "8dAPXkZ89Cpr8M8n2ZKqjk" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 89 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "75PJNS1kBJx43kAb5wqiOn" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 89 + }, + "_enabled": true, + "__prefab": null, + "clickEvents": [], + "_interactable": true, + "_transition": 2, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_hoverSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_pressedSprite": { + "__uuid__": "3ab54557-015a-4b87-be9c-762799ecc41a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_disabledSprite": { + "__uuid__": "c1b43015-8413-4a09-8995-bbefa3b349ab@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_duration": 0.08, + "_zoomScale": 1.04, + "_target": null, + "_id": "1bWixPpVhKH4BH7jZqi17A" + }, + { + "__type__": "cc.Node", + "_name": "ResultOverlay", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 58 + }, + "_children": [ + { + "__id__": 97 + }, + { + "__id__": 102 + } + ], + "_active": false, + "_components": [ + { + "__id__": 118 + }, + { + "__id__": 119 + } + ], + "_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": "c1EFTmVmRJu4YjvD/Augg0" + }, + { + "__type__": "cc.Node", + "_name": "Dim", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 96 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 98 + }, + { + "__id__": 99 + }, + { + "__id__": 100 + }, + { + "__id__": 101 + } + ], + "_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": "06ntFKU3BOsrsQPnfuInrd" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 97 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1280, + "height": 720 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "2cPbiHurRCwbQeb+MAnicZ" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 97 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 190 + }, + "_spriteFrame": { + "__uuid__": "aa33fa26-eeba-43bd-82ec-48e54101acf0@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "53hQ6CrEZFWabJzXYtTwnf" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 97 + }, + "_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": 120, + "_originalHeight": 120, + "_alignMode": 1, + "_lockFlags": 0, + "_id": "3f9wWH1wlOxLQi4/Hi+3l0" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 97 + }, + "_enabled": true, + "__prefab": null, + "clickEvents": [], + "_interactable": true, + "_transition": 0, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": null, + "_hoverSprite": null, + "_pressedSprite": null, + "_disabledSprite": null, + "_duration": 0.1, + "_zoomScale": 1.2, + "_target": null, + "_id": "27r768QONDOa952hSahMSR" + }, + { + "__type__": "cc.Node", + "_name": "Panel", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 96 + }, + "_children": [ + { + "__id__": 103 + }, + { + "__id__": 106 + }, + { + "__id__": 109 + } + ], + "_active": true, + "_components": [ + { + "__id__": 116 + }, + { + "__id__": 117 + } + ], + "_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": "8b2aiEPK1DAZsr9iqBgLRW" + }, + { + "__type__": "cc.Node", + "_name": "ResultTitle", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 102 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 104 + }, + { + "__id__": 105 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 140, + "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": "20cy5tpppHfISh9koI8leV" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 103 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 720, + "height": 100 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "6fP4x40WpJZpsN5uqqVRVu" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 103 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 244, + "g": 194, + "b": 69, + "a": 255 + }, + "_string": "You win", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 72, + "_fontSize": 72, + "_fontFamily": "Arial", + "_lineHeight": 90, + "_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": "8dWUlPVBJGq5XLepP6Dk/o" + }, + { + "__type__": "cc.Node", + "_name": "ResultBody", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 102 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 107 + }, + { + "__id__": 108 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 20, + "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": "5buBAzsL9MFJRzvDuRdyzZ" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 106 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 700, + "height": 56.7 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "b2bTWemOREn6Ro59u3iq2H" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 106 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Your opponent was left holding the cards.", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 36, + "_fontSize": 36, + "_fontFamily": "Arial", + "_lineHeight": 45, + "_overflow": 3, + "_enableWrapText": true, + "_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": "d1patk9P5Ptbv9aUzwsyJ3" + }, + { + "__type__": "cc.Node", + "_name": "ContinueButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 102 + }, + "_children": [ + { + "__id__": 110 + } + ], + "_active": true, + "_components": [ + { + "__id__": 113 + }, + { + "__id__": 114 + }, + { + "__id__": 115 + } + ], + "_prefab": null, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": -150, + "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": "9d2PMaJHNC66rM6/r4N+IQ" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 109 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 111 + }, + { + "__id__": 112 + } + ], + "_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": "b6iTKeA45NHb1a0YcDoGLh" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 110 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 384, + "height": 94 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "a5/GlRkM1N8Z6ZcWtHSvBp" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 110 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 247, + "g": 240, + "b": 222, + "a": 255 + }, + "_string": "Back", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 47, + "_fontSize": 47, + "_fontFamily": "Arial", + "_lineHeight": 59, + "_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": "6aJHzM+05P4IlERDT+4k7G" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 109 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 420, + "height": 130 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "98OvI0Q/5MgatUgHPmt5kZ" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 109 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "1dRoDWtB9KvbpjnVST3RFI" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 109 + }, + "_enabled": true, + "__prefab": null, + "clickEvents": [], + "_interactable": true, + "_transition": 2, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_hoverSprite": { + "__uuid__": "9aed220f-5475-4846-9698-3415836ee61a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_pressedSprite": { + "__uuid__": "3ab54557-015a-4b87-be9c-762799ecc41a@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_disabledSprite": { + "__uuid__": "c1b43015-8413-4a09-8995-bbefa3b349ab@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_duration": 0.08, + "_zoomScale": 1.04, + "_target": null, + "_id": "23DkTZXZdIy5ruaDXx3AhP" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 102 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 800, + "height": 520 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "7boYcEq+JAD4Cm7DszWUMG" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 102 + }, + "_enabled": true, + "__prefab": null, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "a1a282c3-c540-4933-a400-ab611b8857cb@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "0dT+xdrLBCPYtzqwXTQ/zT" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 96 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1280, + "height": 720 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "05PXLTkIFGorkNs33VpTFY" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 96 + }, + "_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": 100, + "_originalHeight": 100, + "_alignMode": 1, + "_lockFlags": 0, + "_id": "d37jWe4oVNdLdhoG9byOr9" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 58 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1280, + "height": 720 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "ffoQl2FCxFQZVfe3h915A+" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 58 + }, + "_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": 100, + "_originalHeight": 100, + "_alignMode": 1, + "_lockFlags": 0, + "_id": "a8PF3z5OZLKq2om7bCxXKo" + }, + { + "__type__": "a8194WA67dHXrV1bSytQvwf", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 58 + }, + "_enabled": true, + "__prefab": null, + "cardPrefab": { + "__uuid__": "1ad36ebe-345c-4936-be65-c838f51b4eb4", + "__expectedType__": "cc.Prefab" + }, + "library": { + "__id__": 123 + }, + "cardLayer": { + "__id__": 70 + }, + "deckAnchor": { + "__id__": 59 + }, + "deckCountLabel": { + "__id__": 62 + }, + "opponentLabel": { + "__id__": 66 + }, + "messageLabel": { + "__id__": 69 + }, + "takeButton": { + "__id__": 80 + }, + "doneButton": { + "__id__": 87 + }, + "resultOverlay": { + "__id__": 96 + }, + "resultTitle": { + "__id__": 105 + }, + "resultBody": { + "__id__": 108 + }, + "quitButton": { + "__id__": 95 + }, + "continueButton": { + "__id__": 115 + }, + "_id": "32Ab2W4RxAtq2xtNnUvmwD" + }, + { + "__type__": "4e2c4LPhmxLoKpPeMJW0ooP", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 58 + }, + "_enabled": true, + "__prefab": null, + "directory": "cards", + "_id": "40NhuIfvBNPI41+/O3NggM" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 10 + }, + "_enabled": true, + "__prefab": null, + "_contentSize": { + "__type__": "cc.Size", + "width": 1280, + "height": 720 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "9cFYd1gNhBFLm4Skpsvor8" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 10 + }, + "_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": 100, + "_originalHeight": 100, + "_alignMode": 1, + "_lockFlags": 0, + "_id": "e5gmBt3zVKe4n1lXr9iL0l" + }, + { + "__type__": "cc.SafeArea", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 10 + }, + "_enabled": true, + "__prefab": null, + "_symmetric": true, + "_id": "b6+hfzt7hAsbnxKwFWBDtz" + }, + { + "__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": "ec8jeLS7ZF2bWv27p74HGL" + }, + { + "__type__": "cc.Canvas", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 2 + }, + "_enabled": true, + "__prefab": null, + "_cameraComponent": { + "__id__": 5 + }, + "_alignCanvasWithScreen": true, + "_id": "feX43K7kVCNpdRDM4QKhjZ" + }, + { + "__type__": "0b757/JS7JAB5sTthjQZVtu", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 2 + }, + "_enabled": true, + "__prefab": null, + "lobby": { + "__id__": 57 + }, + "game": { + "__id__": 122 + }, + "lobbyRoot": { + "__id__": 11 + }, + "gameRoot": { + "__id__": 58 + }, + "_id": "22OiWnMc9D4ZJbf0K7s057" + }, + { + "__type__": "cc.SceneGlobals", + "ambient": { + "__id__": 131 + }, + "shadows": { + "__id__": 132 + }, + "_skybox": { + "__id__": 133 + }, + "fog": { + "__id__": 134 + }, + "octree": { + "__id__": 135 + }, + "skin": { + "__id__": 136 + }, + "lightProbeInfo": { + "__id__": 137 + }, + "postSettings": { + "__id__": 138 + }, + "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 + } +] \ No newline at end of file diff --git a/assets/scenes/lobby.scene.meta b/assets/scenes/lobby.scene.meta new file mode 100644 index 0000000..3653359 --- /dev/null +++ b/assets/scenes/lobby.scene.meta @@ -0,0 +1 @@ +{"ver":"1.1.50","importer":"scene","imported":true,"uuid":"220f80f8-6216-4ec2-b63b-72365bcbfde9","files":[".json"],"subMetas":{},"userData":{}} diff --git a/assets/scripts/app/App.ts b/assets/scripts/app/App.ts new file mode 100644 index 0000000..cab3d3e --- /dev/null +++ b/assets/scripts/app/App.ts @@ -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(); + } +} diff --git a/assets/scripts/app/App.ts.meta b/assets/scripts/app/App.ts.meta new file mode 100644 index 0000000..96c6d01 --- /dev/null +++ b/assets/scripts/app/App.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "982035ad-66a6-428b-bba3-4fe31ed7a095", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/app/Bootstrap.ts b/assets/scripts/app/Bootstrap.ts new file mode 100644 index 0000000..f0a98c1 --- /dev/null +++ b/assets/scripts/app/Bootstrap.ts @@ -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); + } + }); + } +} diff --git a/assets/scripts/app/Bootstrap.ts.meta b/assets/scripts/app/Bootstrap.ts.meta new file mode 100644 index 0000000..7677006 --- /dev/null +++ b/assets/scripts/app/Bootstrap.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "c91dd91e-e180-44f4-98d1-b58cd4db0169", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/core/rules/intent.ts b/assets/scripts/core/rules/intent.ts new file mode 100644 index 0000000..564747f --- /dev/null +++ b/assets/scripts/core/rules/intent.ts @@ -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; +} diff --git a/assets/scripts/core/rules/intent.ts.meta b/assets/scripts/core/rules/intent.ts.meta new file mode 100644 index 0000000..56ed909 --- /dev/null +++ b/assets/scripts/core/rules/intent.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "b1aa773a-2d2c-43f5-980a-d6e2ffb829fd", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/MainFlow.ts b/assets/scripts/ui/MainFlow.ts new file mode 100644 index 0000000..b1a7044 --- /dev/null +++ b/assets/scripts/ui/MainFlow.ts @@ -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; + } +} diff --git a/assets/scripts/ui/MainFlow.ts.meta b/assets/scripts/ui/MainFlow.ts.meta new file mode 100644 index 0000000..e220edc --- /dev/null +++ b/assets/scripts/ui/MainFlow.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "0b757fc9-4bb2-4007-9b13-b618d0655b6e", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/common/Strings.ts b/assets/scripts/ui/common/Strings.ts new file mode 100644 index 0000000..565dc93 --- /dev/null +++ b/assets/scripts/ui/common/Strings.ts @@ -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; diff --git a/assets/scripts/ui/common/Strings.ts.meta b/assets/scripts/ui/common/Strings.ts.meta new file mode 100644 index 0000000..103db6b --- /dev/null +++ b/assets/scripts/ui/common/Strings.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "672ddd76-ded7-498e-97b1-df2d7d30f662", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/common/Theme.ts b/assets/scripts/ui/common/Theme.ts new file mode 100644 index 0000000..c2cc825 --- /dev/null +++ b/assets/scripts/ui/common/Theme.ts @@ -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; diff --git a/assets/scripts/ui/common/Theme.ts.meta b/assets/scripts/ui/common/Theme.ts.meta new file mode 100644 index 0000000..8413dec --- /dev/null +++ b/assets/scripts/ui/common/Theme.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "3ba498f9-9dcb-48dc-bb1d-1de46602c43a", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/game/CardLibrary.ts b/assets/scripts/ui/game/CardLibrary.ts new file mode 100644 index 0000000..837fa0f --- /dev/null +++ b/assets/scripts/ui/game/CardLibrary.ts @@ -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(); + private readonly _missingReported = new Set(); + 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; + } +} diff --git a/assets/scripts/ui/game/CardLibrary.ts.meta b/assets/scripts/ui/game/CardLibrary.ts.meta new file mode 100644 index 0000000..95f1e0c --- /dev/null +++ b/assets/scripts/ui/game/CardLibrary.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "4e2c42cf-866c-4ba0-aa4f-78c256d28a0f", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/game/CardView.ts b/assets/scripts/ui/game/CardView.ts new file mode 100644 index 0000000..028b7ed --- /dev/null +++ b/assets/scripts/ui/game/CardView.ts @@ -0,0 +1,109 @@ +import { _decorator, Component, Sprite, Tween, tween, UIOpacity, UITransform, v3, Vec3 } from 'cc'; +import { Card } from '../../core/cards/Card'; +import { Layout, Timing } from '../common/Theme'; +import { CardLibrary } from './CardLibrary'; + +const { ccclass, property } = _decorator; + +/** + * One card on screen. + * + * A card node belongs to a `Card` for as long as that card is visible, and + * follows it from hand to table to discard. Movement is therefore just a tween + * to a new position, and the natural-looking animation falls out of the layout + * rather than having to be choreographed per event. + */ +@ccclass('CardView') +export class CardView extends Component { + @property(Sprite) + sprite: Sprite | null = null; + + private _library: CardLibrary | null = null; + private _card: Card | null = null; + private _faceUp = false; + + get card(): Card | null { + return this._card; + } + + get faceUp(): boolean { + return this._faceUp; + } + + /** Called once, when the view is taken from the pool. */ + bind(library: CardLibrary, card: Card | null, faceUp: boolean): void { + this._library = library; + this._card = card; + this._faceUp = faceUp; + this._applyFrame(); + + const transform = this.getComponent(UITransform); + transform?.setContentSize(Layout.cardWidth, Layout.cardHeight); + } + + /** Flips the card, turning it edge-on halfway through so the swap is hidden. */ + flipTo(faceUp: boolean, animated = true): void { + if (this._faceUp === faceUp) { + return; + } + this._faceUp = faceUp; + + if (!animated) { + this._applyFrame(); + return; + } + + const scale = this.node.scale.clone(); + tween(this.node) + .to(Timing.flip / 2, { scale: v3(0.02, scale.y, scale.z) }) + .call(() => this._applyFrame()) + .to(Timing.flip / 2, { scale }) + .start(); + } + + /** Moves, rotates and scales the card into place. */ + moveTo(position: Vec3, scale: number, angle: number, duration: number, delay = 0): void { + const target = { position, scale: v3(scale, scale, 1), angle }; + if (duration <= 0) { + this.node.setPosition(position); + this.node.setScale(target.scale); + this.node.angle = angle; + return; + } + tween(this.node) + .delay(delay) + .to(duration, target, { easing: 'quadOut' }) + .start(); + } + + /** Fades out, then hands the node back through `done`. */ + fadeOut(duration: number, done: () => void): void { + const opacity = this.node.getComponent(UIOpacity) ?? this.node.addComponent(UIOpacity); + tween(opacity) + .to(duration, { opacity: 0 }) + .call(() => { + opacity.opacity = 255; + done(); + }) + .start(); + } + + /** Stops any running tween. Used when a match is torn down mid-animation. */ + cancelAnimations(): void { + Tween.stopAllByTarget(this.node); + const opacity = this.node.getComponent(UIOpacity); + if (opacity) { + Tween.stopAllByTarget(opacity); + opacity.opacity = 255; + } + } + + private _applyFrame(): void { + if (!this.sprite || !this._library) { + return; + } + this.sprite.spriteFrame = this._faceUp && this._card + ? this._library.frameFor(this._card) + : this._library.backFrame; + } +} diff --git a/assets/scripts/ui/game/CardView.ts.meta b/assets/scripts/ui/game/CardView.ts.meta new file mode 100644 index 0000000..3f1f54c --- /dev/null +++ b/assets/scripts/ui/game/CardView.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "da0167b3-fa30-48b1-95e3-91ad10cda5d8", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/game/GameScreen.ts b/assets/scripts/ui/game/GameScreen.ts new file mode 100644 index 0000000..9f08f47 --- /dev/null +++ b/assets/scripts/ui/game/GameScreen.ts @@ -0,0 +1,519 @@ +import { + _decorator, Button, Component, EventTouch, Label, Node, Prefab, + instantiate, tween, UIOpacity, v3, Vec3, +} from 'cc'; +import { Card } from '../../core/cards/Card'; +import { BasicBot } from '../../core/bot/BasicBot'; +import { Match } from '../../core/match/Match'; +import { Action, ActionType, Actions, IllegalActionError } from '../../core/rules/Action'; +import { Phase, PlayerId } from '../../core/rules/GameState'; +import { legalActions } from '../../core/rules/DurakRules'; +import { intentFor } from '../../core/rules/intent'; +import { Layout, Palette, Timing } from '../common/Theme'; +import { Strings } from '../common/Strings'; +import { CardLibrary } from './CardLibrary'; +import { CardView } from './CardView'; + +const { ccclass, property } = _decorator; + +export type MatchOutcome = 'win' | 'loss' | 'draw'; + +/** Seat ids. The human is always seated first; the rules core does not care. */ +const HUMAN: PlayerId = 'player'; +const OPPONENT: PlayerId = 'opponent'; + +/** + * The match screen. + * + * It renders whatever the current `GameState` says, rather than replaying the + * event stream: after every action the whole table is laid out again and the + * card nodes tween to their new places. Because a card node stays bound to its + * card for as long as it is visible, "the six of clubs moved from my hand to the + * table" needs no special case — it is the same node arriving at a new position. + * + * The screen never reads anything the player should not see. The opponent's hand + * is drawn from its *size*, and the only cards ever turned face up are the ones + * the rules have made public. + */ +@ccclass('GameScreen') +export class GameScreen extends Component { + @property(Prefab) + cardPrefab: Prefab | null = null; + + @property(CardLibrary) + library: CardLibrary | null = null; + + @property({ type: Node, tooltip: 'Parent for every card node.' }) + cardLayer: Node | null = null; + + @property(Node) + deckAnchor: Node | null = null; + + @property(Label) + deckCountLabel: Label | null = null; + + @property(Label) + opponentLabel: Label | null = null; + + @property(Label) + messageLabel: Label | null = null; + + @property(Button) + takeButton: Button | null = null; + + @property(Button) + doneButton: Button | null = null; + + @property({ type: Node, tooltip: 'Shown when the match is over.' }) + resultOverlay: Node | null = null; + + @property(Label) + resultTitle: Label | null = null; + + @property(Label) + resultBody: Label | null = null; + + @property(Button) + quitButton: Button | null = null; + + @property({ type: Button, tooltip: 'Dismisses the result overlay.' }) + continueButton: Button | null = null; + + /** Set by `MainFlow`. */ + onFinished: ((outcome: MatchOutcome) => void) | null = null; + onQuitRequested: (() => void) | null = null; + + private _match: Match | null = null; + private _bot = new BasicBot(OPPONENT); + /** Card nodes in use, keyed by the card they show. */ + private _views = new Map(); + /** Face-down nodes standing in for the opponent's hand and the deck. */ + private _anonymous: CardView[] = []; + private _pool: CardView[] = []; + private _busy = false; + private _selected: Card | null = null; + private _pendingOutcome: MatchOutcome | null = null; + + // ----------------------------------------------------------------------- + // Lifecycle + // ----------------------------------------------------------------------- + + onLoad(): void { + // Subscribed in code rather than through the scene's clickEvents list, so + // the wiring is visible in the source and a renamed handler is a compile + // error instead of a button that silently stops working. + this.takeButton?.node.on(Button.EventType.CLICK, this.take, this); + this.doneButton?.node.on(Button.EventType.CLICK, this.done, this); + this.quitButton?.node.on(Button.EventType.CLICK, this.quit, this); + this.continueButton?.node.on(Button.EventType.CLICK, this.dismissResult, this); + } + + onDestroy(): void { + this.takeButton?.node.off(Button.EventType.CLICK, this.take, this); + this.doneButton?.node.off(Button.EventType.CLICK, this.done, this); + this.quitButton?.node.off(Button.EventType.CLICK, this.quit, this); + this.continueButton?.node.off(Button.EventType.CLICK, this.dismissResult, this); + } + + startNewMatch(): void { + this.teardown(); + setActive(this.resultOverlay, false); + + // Bootstrap preloads the card art, so this is all but instant; going + // through whenReady means a cold start cannot deal onto blank cards. + const library = this.library; + if (!library) { + console.error('[game] no card library assigned'); + return; + } + library.whenReady(() => { + if (!this.isValid || !this.node.activeInHierarchy) { + return; + } + this._match = new Match({ + players: [HUMAN, OPPONENT], + seed: (Math.random() * 0x7fffffff) | 0, + }); + this._busy = false; + this._selected = null; + + this.render(Timing.deal); + this.scheduleOnce(() => this._advance(), Timing.deal + 0.2); + }); + } + + /** Releases every card node and forgets the match. Safe to call twice. */ + teardown(): void { + this.unscheduleAllCallbacks(); + for (const view of [...this._views.values(), ...this._anonymous]) { + view.cancelAnimations(); + this._recycle(view); + } + this._views.clear(); + this._anonymous.length = 0; + this._match?.clearListeners(); + this._match = null; + this._selected = null; + this._busy = false; + } + + onDisable(): void { + this.unscheduleAllCallbacks(); + } + + /** Wired to the Leave button. */ + quit(): void { + this.onQuitRequested?.(); + } + + // ----------------------------------------------------------------------- + // Input + // ----------------------------------------------------------------------- + + /** Wired to the Take button. */ + take(): void { + this._submit(Actions.take(HUMAN)); + } + + /** Wired to the Done button. */ + done(): void { + this._submit(Actions.pass(HUMAN)); + } + + private _onCardTapped(card: Card): void { + const match = this._match; + if (!match || this._busy || match.currentActor !== HUMAN) { + return; + } + + const action = this._match ? intentFor(this._match.state, HUMAN, card) : null; + if (!action) { + this._flashMessage(Strings.cannotPlayThat); + this._nudge(card); + return; + } + this._submit(action); + } + + private _submit(action: Action): void { + const match = this._match; + if (!match || this._busy) { + return; + } + try { + match.perform(action); + } catch (error) { + if (error instanceof IllegalActionError) { + this._flashMessage(Strings.cannotPlayThat); + return; + } + throw error; + } + + this._selected = null; + this._busy = true; + this.render(Timing.play); + this.scheduleOnce(() => this._advance(), Timing.play + 0.05); + } + + // ----------------------------------------------------------------------- + // Turn loop + // ----------------------------------------------------------------------- + + /** Hands the move on: finish, wait for the player, or let the bot think. */ + private _advance(): void { + const match = this._match; + if (!match) { + return; + } + + if (match.finished) { + this._busy = true; + this.scheduleOnce(() => this._showResult(), Timing.turnBreak); + return; + } + + if (match.currentActor === HUMAN) { + this._busy = false; + this.render(Timing.play); + return; + } + + this._busy = true; + this.render(Timing.play); + this.scheduleOnce(() => { + const current = this._match; + if (!current || current.currentActor !== OPPONENT) { + return; + } + current.perform(this._bot.decide(current.viewFor(OPPONENT))); + this.render(Timing.play); + this.scheduleOnce(() => this._advance(), Timing.play + 0.05); + }, Timing.botThinking); + } + + private _showResult(): void { + const match = this._match; + if (!match) return; + + const outcome: MatchOutcome = match.loser === null + ? 'draw' + : (match.loser === HUMAN ? 'loss' : 'win'); + + setText(this.resultTitle, { + win: Strings.wonTitle, loss: Strings.lostTitle, draw: Strings.drawTitle, + }[outcome]); + setText(this.resultBody, { + win: Strings.wonBody, loss: Strings.lostBody, draw: Strings.drawBody, + }[outcome]); + + if (this.resultOverlay) { + this.resultOverlay.active = true; + const opacity = this.resultOverlay.getComponent(UIOpacity) + ?? this.resultOverlay.addComponent(UIOpacity); + opacity.opacity = 0; + tween(opacity).to(0.25, { opacity: 255 }).start(); + } + + this._pendingOutcome = outcome; + } + + /** Wired to the result overlay's button. */ + dismissResult(): void { + const outcome = this._pendingOutcome ?? 'draw'; + this._pendingOutcome = null; + this.onFinished?.(outcome); + } + + // ----------------------------------------------------------------------- + // Rendering + // ----------------------------------------------------------------------- + + /** Lays the whole table out from the current state, tweening over `duration`. */ + render(duration: number): void { + const match = this._match; + if (!match || !this.library || !this.cardLayer) { + return; + } + const state = match.state; + const view = match.viewFor(HUMAN); + const live = new Set(); + + // Trump card, lying under the deck. + if (state.deck.length > 0) { + live.add(state.trumpCard); + this._place(state.trumpCard, true, + v3(Layout.region.trump.x, Layout.region.trump.y, 0), 0.62, 90, duration); + } + + // The player's hand: a straight row, tightened as it grows. + const hand = [...view.hand].sort(byTrumpThenRank(state.trumpSuit)); + const step = Math.min( + Layout.handStep, + hand.length > 1 ? (Layout.handMaxWidth - Layout.cardWidth) / (hand.length - 1) : Layout.handStep, + ); + const handLeft = -step * (hand.length - 1) / 2; + hand.forEach((card, i) => { + live.add(card); + const lifted = card === this._selected ? Layout.handLift : 0; + this._place(card, true, + v3(handLeft + i * step, Layout.region.playerHandY + lifted, 0), 1, 0, duration); + }); + + // The table: attacking cards with whatever beat them, three to a row. + state.table.forEach((slot, i) => { + const column = i % 3; + const row = Math.floor(i / 3); + const x = (column - 1) * Layout.region.tableColumnStep; + const y = Layout.region.tableTopY - row * Layout.region.tableRowStep; + + live.add(slot.attack); + this._place(slot.attack, true, v3(x, y, 0), Layout.tableCardScale, 0, duration); + + if (slot.defence) { + live.add(slot.defence); + this._place(slot.defence, true, + v3(x + Layout.beatOffset.x, y + Layout.beatOffset.y, 0), + Layout.tableCardScale, 8, duration); + } + }); + + this._retireCardsNotIn(live, duration); + this._renderAnonymous(state.deck.length, view.opponents[0]?.handSize ?? 0, duration); + this._renderChrome(view.opponents[0]?.handSize ?? 0); + } + + /** Face-down nodes: a short stack for the deck, and the opponent's hand. */ + private _renderAnonymous(deckSize: number, opponentHand: number, duration: number): void { + // Three backs are enough to read as a pile; drawing twenty-four is waste. + const deckBacks = Math.min(deckSize, 3); + const needed = deckBacks + opponentHand; + + while (this._anonymous.length < needed) { + this._anonymous.push(this._take(null, false)); + } + while (this._anonymous.length > needed) { + this._recycle(this._anonymous.pop() as CardView); + } + + for (let i = 0; i < deckBacks; i++) { + this._anonymous[i].moveTo( + v3(Layout.region.deck.x + i * 3, Layout.region.deck.y + i * 3, 0), + 0.62, 0, duration, + ); + } + + const step = Math.min(70, opponentHand > 1 ? 760 / (opponentHand - 1) : 70); + const left = -step * (opponentHand - 1) / 2; + for (let i = 0; i < opponentHand; i++) { + this._anonymous[deckBacks + i].moveTo( + v3(left + i * step, Layout.region.opponentHandY, 0), + Layout.opponentCardScale, 0, duration, + ); + } + } + + private _renderChrome(opponentHand: number): void { + const match = this._match; + if (!match) return; + const state = match.state; + + setText(this.deckCountLabel, `${Strings.deckLeft} ${state.deck.length}`); + setText(this.opponentLabel, `${Strings.opponentHand}: ${opponentHand}`); + setActive(this.deckAnchor, state.deck.length > 0); + + const mine = match.currentActor === HUMAN; + const options = mine ? legalActions(state, HUMAN) : []; + setButton(this.takeButton, mine && options.some((a) => a.type === ActionType.Take)); + setButton(this.doneButton, mine && options.some((a) => a.type === ActionType.Pass)); + + if (match.finished) { + setText(this.messageLabel, ''); + } else if (!mine) { + setText(this.messageLabel, Strings.opponentThinking); + } else if (state.phase === Phase.Defence) { + setText(this.messageLabel, Strings.yourDefence); + } else if (state.phase === Phase.Reinforce) { + setText(this.messageLabel, Strings.addMore); + } else { + setText(this.messageLabel, Strings.yourMove); + } + } + + // ----------------------------------------------------------------------- + // Card node pool + // ----------------------------------------------------------------------- + + private _place(card: Card, faceUp: boolean, position: Vec3, scale: number, angle: number, duration: number): void { + let view = this._views.get(card); + if (!view) { + view = this._take(card, faceUp); + // A card appearing for the first time slides out of the deck. + view.moveTo(v3(Layout.region.deck.x, Layout.region.deck.y, 0), 0.62, 0, 0); + this._views.set(card, view); + } + view.flipTo(faceUp); + view.moveTo(position, scale, angle, duration); + view.node.setSiblingIndex(this.cardLayer?.children.length ?? 0); + } + + /** Cards that have left the visible table — they went to the discard or a hand. */ + private _retireCardsNotIn(live: Set, duration: number): void { + for (const [card, view] of [...this._views]) { + if (live.has(card)) continue; + this._views.delete(card); + + const goingToOpponent = !this._match?.state.discard.includes(card); + const target = goingToOpponent + ? v3(0, Layout.region.opponentHandY, 0) + : v3(Layout.region.discard.x, Layout.region.discard.y, 0); + + view.moveTo(target, 0.4, 0, duration); + view.flipTo(false); + view.fadeOut(duration, () => this._recycle(view)); + } + } + + private _take(card: Card | null, faceUp: boolean): CardView { + let view = this._pool.pop(); + if (!view) { + const node = instantiate(this.cardPrefab as Prefab); + view = node.getComponent(CardView) as CardView; + node.on(Node.EventType.TOUCH_END, (event: EventTouch) => { + event.propagationStopped = true; + const tapped = view?.card; + if (tapped) this._onCardTapped(tapped); + }); + } + view.node.parent = this.cardLayer; + view.node.active = true; + view.bind(this.library as CardLibrary, card, faceUp); + return view; + } + + private _recycle(view: CardView): void { + view.cancelAnimations(); + view.node.active = false; + view.node.parent = null; + if (!this._pool.includes(view)) { + this._pool.push(view); + } + } + + // ----------------------------------------------------------------------- + // Feedback + // ----------------------------------------------------------------------- + + private _flashMessage(text: string): void { + if (!this.messageLabel) return; + this.messageLabel.string = text; + this.messageLabel.color = Palette.bad; + this.scheduleOnce(() => { + if (this.messageLabel) this.messageLabel.color = Palette.cream; + this._renderChrome(this._match?.viewFor(HUMAN).opponents[0]?.handSize ?? 0); + }, 1.1); + } + + /** A small shake, so a rejected tap is felt rather than only read. */ + private _nudge(card: Card): void { + const view = this._views.get(card); + if (!view) return; + const home = view.node.position.clone(); + tween(view.node) + .to(0.05, { position: home.clone().add3f(-10, 0, 0) }) + .to(0.05, { position: home.clone().add3f(10, 0, 0) }) + .to(0.05, { position: home }) + .start(); + } +} + +/** Trumps to the right, ascending — the order a player would hold them in. */ +function byTrumpThenRank(trumpSuit: number) { + return (a: Card, b: Card): number => { + const aTrump = a.suit === trumpSuit ? 1 : 0; + const bTrump = b.suit === trumpSuit ? 1 : 0; + if (aTrump !== bTrump) return aTrump - bTrump; + if (a.suit !== b.suit) return a.suit - b.suit; + return a.rank - b.rank; + }; +} + +function sameAction(wanted: Action) { + return (other: Action): boolean => + other.type === wanted.type + && (other as { card?: Card }).card === (wanted as { card?: Card }).card; +} + +function setText(label: Label | null, text: string): void { + if (label) label.string = text; +} + +function setActive(node: Node | null, active: boolean): void { + if (node) node.active = active; +} + +function setButton(button: Button | null, enabled: boolean): void { + if (!button) return; + button.node.active = enabled; + button.interactable = enabled; +} diff --git a/assets/scripts/ui/game/GameScreen.ts.meta b/assets/scripts/ui/game/GameScreen.ts.meta new file mode 100644 index 0000000..8b62dea --- /dev/null +++ b/assets/scripts/ui/game/GameScreen.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "a8194580-ebb7-475e-b575-6d2cad42fc1f", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/scripts/ui/lobby/LobbyScreen.ts b/assets/scripts/ui/lobby/LobbyScreen.ts new file mode 100644 index 0000000..1b9544b --- /dev/null +++ b/assets/scripts/ui/lobby/LobbyScreen.ts @@ -0,0 +1,82 @@ +import { _decorator, Button, Component, Label, Node } from 'cc'; +import { App } from '../../app/App'; + +const { ccclass, property } = _decorator; + +/** + * The lobby, per LOBBY.md: one button that starts a game, and — since the save + * module is already keeping them — the player's record. + * + * It owns no game logic. Starting a match is reported to `MainFlow` through + * `onStartRequested`, which keeps the lobby ignorant of what a match even is. + */ +@ccclass('LobbyScreen') +export class LobbyScreen extends Component { + @property(Label) + playedLabel: Label | null = null; + + @property(Label) + wonLabel: Label | null = null; + + @property(Label) + lostLabel: Label | null = null; + + @property(Label) + streakLabel: Label | null = null; + + @property(Node) + statsPanel: Node | null = null; + + @property(Button) + newGameButton: Button | null = null; + + /** Set by `MainFlow`. */ + onStartRequested: (() => void) | null = null; + + onLoad(): void { + // Clicks are subscribed here rather than through the scene's clickEvents + // list: the wiring stays visible in the source, and a renamed handler + // becomes a compile error instead of a button that silently does nothing. + this.newGameButton?.node.on(Button.EventType.CLICK, this.startGame, this); + } + + onDestroy(): void { + this.newGameButton?.node.off(Button.EventType.CLICK, this.startGame, this); + } + + onEnable(): void { + this.refresh(); + } + + /** Re-reads the saved statistics. Called whenever the lobby comes back into view. */ + refresh(): void { + if (!App.exists) { + return; + } + const stats = App.instance.stats; + + setText(this.playedLabel, `${stats.played}`); + setText(this.wonLabel, `${stats.won}`); + setText(this.lostLabel, `${stats.lost}`); + setText(this.streakLabel, stats.bestStreak > 0 + ? `${stats.streak} (best ${stats.bestStreak})` + : `${stats.streak}`); + + // Nothing to show before the first game — an empty table of zeroes is + // worse than no table at all. + if (this.statsPanel) { + this.statsPanel.active = stats.played > 0; + } + } + + /** Wired to the New Game button in the scene. */ + startGame(): void { + this.onStartRequested?.(); + } +} + +function setText(label: Label | null, text: string): void { + if (label) { + label.string = text; + } +} diff --git a/assets/scripts/ui/lobby/LobbyScreen.ts.meta b/assets/scripts/ui/lobby/LobbyScreen.ts.meta new file mode 100644 index 0000000..168b263 --- /dev/null +++ b/assets/scripts/ui/lobby/LobbyScreen.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "41c969a5-d2d3-4e51-9b23-db1e3907fb53", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index a44a8a7..49f266c 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -95,5 +95,67 @@ and bottom bars. **Decision.** Use the 36 faces needed for a durak deck, rendered from the SVG sources so the downscale to the 1080-wide budget stays sharp. Attribution and -licence text are recorded in `assets/art/cards/ATTRIBUTION.md`. The card back, +licence text are recorded in `assets/resources/cards/ATTRIBUTION.md`. The card back, table surface and UI chrome are not in that set and are authored for this project. + +## 2026-09-13 · Presentation · The screen renders state, it does not replay events + +The rules emit an event stream, which invites an animation queue that replays it. + +**Decision.** `GameScreen.render(state)` lays the whole table out from the current +state and tweens every card node to its new place. A card node stays bound to its +`Card` for as long as that card is visible. + +**Why.** "The six of clubs moved from my hand to the table" then needs no special +case — it is the same node arriving at a new position. An event-driven queue has +to choreograph every transition by hand and desynchronises the moment one case is +missed. The event stream is still there for sound and for one-off flourishes. + +## 2026-09-13 · Presentation · Card art lives in the `resources` bundle + +The first attempt gave `CardLibrary` a `SpriteAtlas` reference to the auto-atlas +(`cards.pac`) and asked it for frames by name. The build came out with no card +textures at all. + +**Decision.** The 36 faces and the back live in `assets/resources/cards` and are +loaded with `resources.loadDir`. `Bootstrap` preloads the folder in the loader +scene, so the lobby never waits. + +**Why.** A `.pac` is a build-time packing instruction, not a runtime asset: it +packs whatever sprite frames the build already pulled in, and it cannot be loaded +and queried by name. Nothing referenced the individual frames, so nothing was +packed. The `.pac` still earns its keep — all 37 sprites end up in one 2048² +texture, so the whole table costs one draw call. + +## 2026-09-13 · Presentation · Button clicks are wired in code + +**Decision.** Buttons are exposed as `@property(Button)` and subscribed to in +`onLoad` rather than through the scene's `clickEvents` list. + +**Why.** The wiring stays visible in the source, and renaming a handler becomes a +compile error instead of a button that silently stops working. (The editor tool +server also cannot write array-typed properties, which is how `clickEvents` is +stored — so this was the only option available to automation anyway.) + +## 2026-09-13 · Presentation · Interface text is English, collected in one file + +**Decision.** Every player-visible string is in +`assets/scripts/ui/common/Strings.ts`, in English. + +**Why.** The specs, the code and the docs are all in English, and localisation is +out of scope for iteration 1. Keeping the strings together means switching +language — or adding one — is a change to that one file rather than a hunt +through scenes and components. Worth revisiting before release, given the game +is *durak*. + +## 2026-09-13 · Presentation · One tap is the whole interaction + +**Decision.** Tapping a card plays it. When defending, the attack being answered +is worked out from the card rather than selected separately. The logic lives in +`core/rules/intent.ts`, not in the component. + +**Why.** Select-then-target doubles the taps for no gain, because the serialised +rules leave only one unanswered attack at a time. Putting it in the core means +the one piece of interface logic that can silently reject a legal move is covered +by headless tests, including a property test that it never proposes an action the +rules would refuse. diff --git a/docs/PLAN.md b/docs/PLAN.md index 3933651..e3034c2 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -63,32 +63,50 @@ progress. The Cocos layer only renders state and turns taps into actions. - [x] Import into `assets/art/`, configure sprite frames and atlasing - [x] Remove consumed source art from `local/`, record attribution/licence -### M5 — Scenes and bootstrap `[ ]` -- [ ] `loader` scene: module initialisation, then transition to `lobby` -- [ ] `lobby` scene: New Game button, statistics readout -- [ ] Canvas / resolution policy and a reusable safe-area-aware layout root +### M5 — Scenes and bootstrap `[x]` +- [x] `loader` scene: module initialisation, then transition to `lobby` +- [x] `lobby` scene: New Game button, statistics readout +- [x] Canvas / resolution policy and a reusable safe-area-aware layout root -### M6 — Game screen `[ ]` -- [ ] `Card` prefab, face/back flipping, sizing -- [ ] Hand layout (fan), table layout (attack/defence pairs), deck and trump display -- [ ] Deal, attack, defend, take and discard animations driven by core events -- [ ] Tap/drag input producing core actions; illegal moves visibly rejected -- [ ] Bot acts with human-readable pacing +### M6 — Game screen `[x]` +- [x] `Card` prefab, face/back flipping, sizing +- [x] Hand layout (fan), table layout (attack/defence pairs), deck and trump display +- [x] Deal, attack, defend, take and discard animations driven by core events +- [x] Tap/drag input producing core actions; illegal moves visibly rejected +- [x] Bot acts with human-readable pacing -### M7 — Match flow `[ ]` -- [ ] Result overlay (win / lose), stats written through the savegame module -- [ ] Return to lobby; start another match without a scene leak -- [ ] Optional: surrender / leave match +### M7 — Match flow `[x]` +- [x] Result overlay (win / lose), stats written through the savegame module +- [x] Return to lobby; start another match without a scene leak +- [x] Leave-match button, which ends the match as a loss -### M8 — Responsive and touch pass `[ ]` -- [ ] Verify layout from 4:3 to 21:9, portrait -- [ ] All interactive elements meet a minimum tap size -- [ ] Editor preview screenshots at the extreme aspect ratios +### M8 — Responsive and touch pass `[~]` +- [x] Fit-width canvas, safe-area root, widget-stretched background +- [x] Every interactive element authored at or above the 120-unit minimum + (buttons 330×140 and 560×150; hand cards expose ~128 units each) +- [x] Vertical positions kept inside the 4:3 crop +- [ ] **Blocked:** seen at the extreme aspect ratios. Needs a machine that can + actually run the build — see "What is and is not verified" in + [TECHNICAL.md](TECHNICAL.md) -### M9 — Build verification and hand-off `[ ]` -- [ ] Web-mobile build runs end to end -- [ ] Android/iOS build settings documented (ASTC per ART.md) -- [ ] README / TECHNICAL.md final pass +### M9 — Build verification and hand-off `[~]` +- [x] `web-mobile` build completes clean; command recorded in TECHNICAL.md +- [x] Card art reaches the build and packs into a single 2048² atlas +- [x] Every component reference in the scene verified populated +- [ ] **Blocked:** the build seen running. The browser in this environment falls + back to a software renderer that cannot start the engine's main loop +- [ ] Android/iOS build settings (ASTC per ART.md) +- [ ] README + +### Known follow-ups + +- The default skybox cubemap (~1.1 MB) still reaches the build. `skybox.enabled` + is off in both scenes, but the scene keeps its `_envmapHDR` reference and the + builder follows it. The editor tool server cannot write a null reference; + clearing the field in the Inspector by hand would do it. +- Nothing verifies the presentation layer automatically. The obvious next step is + a smoke test that boots the scene headlessly and asserts the card nodes land + where the layout says they should. ## Deliberately out of scope for iteration 1 diff --git a/docs/TECHNICAL.md b/docs/TECHNICAL.md index de4fcfd..8faf5a6 100644 --- a/docs/TECHNICAL.md +++ b/docs/TECHNICAL.md @@ -35,13 +35,13 @@ makes the rules and the save format testable without the engine. ``` assets/ scenes/ - loader.scene module init, then → lobby - lobby.scene main menu; hosts the match UI + loader.scene module init and art preload, then → lobby + lobby.scene Canvas > Background, Safe > LobbyRoot | GameRoot prefabs/ card.prefab one playing card, face or back - ... + resources/ + cards/ 36 faces + back + cards.pac, loaded by path art/ - cards/ 36 faces + back, packed into cards.pac (2048²) ui/ table surface, nine-slice panels and buttons scripts/ core/ PURE TS — no engine imports @@ -55,9 +55,10 @@ assets/ IStorage + MemoryStorage, CocosStorage (engine) app/ Bootstrap, ServiceLocator, SceneRouter ui/ - lobby/ lobby screen controller - game/ match screen: hand, table, deck, animations - common/ reusable widgets, safe-area root + MainFlow.ts owns both screens and moves between them + lobby/ LobbyScreen: statistics and the New Game button + game/ GameScreen, CardView, CardLibrary + common/ Theme (layout, palette, timings), Strings tests/ core/ vitest specs against assets/scripts/core support/ position fixtures and the state invariant checker @@ -119,6 +120,29 @@ sits behind `IStorage`, so all of the save logic is testable headlessly; falls back to an in-memory store when the device refuses to persist (private browsing, a full quota) rather than taking the game down. +## The lobby scene + +Both screens live in one scene, per ARCHITECTURE.md, so starting a match is a +change of visible root rather than a scene load: + +``` +Canvas (1080×1920, Canvas + MainFlow) + Camera orthographic, UI_2D only, clears to table green + Background table_bg, widget-stretched + Safe cc.SafeArea — everything tappable is inside it + LobbyRoot LobbyScreen: title, statistics panel, New Game + GameRoot GameScreen + CardLibrary (inactive until a match starts) + Deck / OpponentLabel / Message / CardLayer / ActionBar / QuitButton + ResultOverlay dimmer, result panel, Back +``` + +`GameScreen` renders from the current `GameState` rather than replaying the +event stream — see docs/DECISIONS.md. Card nodes are pooled and stay bound to +their `Card` while it is visible, so movement is a tween to a new position. + +Buttons are `@property(Button)` references subscribed in `onLoad`; the scene's +`clickEvents` lists are deliberately empty. + ## Conventions - TypeScript, 4-space indent, `PascalCase` for types, `camelCase` for members, @@ -183,10 +207,38 @@ matching `Card.assetName` — that string is the only contract between the rules core and the art. Licence: the faces are LGPL-3.0 and attribution is mandatory. See -[`assets/art/cards/ATTRIBUTION.md`](../assets/art/cards/ATTRIBUTION.md), which +[`assets/resources/cards/ATTRIBUTION.md`](../assets/resources/cards/ATTRIBUTION.md), which also explains what would have to change to drop the dependency. ### Builds -Web: `web-mobile` template. Mobile: ASTC textures per [ART.md](ART.md), PNG for -web. +A headless build, which is what CI would run: + +```bash +"C:/ProgramData/cocos/editors/Creator/3.8.8/CocosCreator.exe" --project "C:/Work/fool-cardgame" --build "platform=web-mobile;debug=true;startScene=" +``` + +It writes to `build/web-mobile` in about 40 seconds. Two caveats: it starts a +second editor instance, so it competes with a running editor for +`temp/logs/project.log` and can fail with a duplicate-class error — close the +editor, or build from its Build panel. And `startScene` must be passed, or the +build has no launch scene and stops on the splash. + +Mobile: ASTC textures per [ART.md](ART.md), PNG for web. + +### What is and is not verified + +The rules, the bot and the save format are covered by `npm test` and are +verified. The presentation layer is verified only as far as this environment +allows: the project builds clean, every component reference in the scene is +populated, and all 37 card sprites pack into one 2048² texture. + +It has **not** been seen running. The browser available here falls back to a +software renderer that cannot start the Cocos main loop (`totalFrames` stays at +0), so no screenshot of the actual game was possible. To check it by eye, open +the project in Cocos Creator and press Preview, or serve `build/web-mobile` over +HTTP — it is a static folder and needs no server features: + +```bash +npx http-server build/web-mobile -p 8123 -c-1 +``` diff --git a/scripts/build-art.mjs b/scripts/build-art.mjs index 49fe005..f3676f4 100644 --- a/scripts/build-art.mjs +++ b/scripts/build-art.mjs @@ -1,10 +1,10 @@ // Builds every sprite the game ships from its sources, so the art in -// assets/art is reproducible rather than hand-placed. +// assets/art and assets/resources is reproducible rather than hand-placed. // // node scripts/build-art.mjs // // Card faces are rendered from the vector sources in art-src/cards (see -// assets/art/cards/ATTRIBUTION.md). Everything else — the card back, the table, +// assets/resources/cards/ATTRIBUTION.md). Everything else — the card back, the table, // the UI chrome — is drawn here as SVG and rasterised, which keeps it tweakable // in one place instead of scattered across binary files. // @@ -15,7 +15,7 @@ import { join } from 'node:path'; import sharp from 'sharp'; const CARD_SRC = 'art-src/cards'; -const CARDS_OUT = 'assets/art/cards'; +const CARDS_OUT = 'assets/resources/cards'; const UI_OUT = 'assets/art/ui'; /** Card sprite size. 37 of these pack into a single 2048² atlas with room to spare. */ diff --git a/tests/core/rules/intent.spec.ts b/tests/core/rules/intent.spec.ts new file mode 100644 index 0000000..5ccca5b --- /dev/null +++ b/tests/core/rules/intent.spec.ts @@ -0,0 +1,143 @@ +import { describe, expect, it } from 'vitest'; +import { Card } from '@core/cards/Card'; +import { ActionType } from '@core/rules/Action'; +import { Phase } from '@core/rules/GameState'; +import { apply, currentActor, legalActions } from '@core/rules/DurakRules'; +import { intentFor } from '@core/rules/intent'; +import { makeState } from '../../support/fixtures'; + +const YOU = 'you'; +const BOT = 'bot'; + +const tap = (state: Parameters[0], code: string) => + intentFor(state, YOU, Card.parse(code)); + +describe('intentFor when opening a turn', () => { + const position = () => makeState({ + hands: { [YOU]: '6C 7D KH', [BOT]: '8C 9D QH' }, + trump: 'S', + deck: '10C 10D', + attacker: YOU, + }); + + it('plays any card from hand', () => { + expect(tap(position(), '6C')).toMatchObject({ type: ActionType.Attack }); + expect(tap(position(), 'KH')).toMatchObject({ type: ActionType.Attack }); + }); + + it('refuses a card that is not in hand', () => { + expect(tap(position(), 'AS')).toBeNull(); + }); + + it('refuses everything when it is not your move', () => { + const state = position(); + expect(intentFor(state, BOT, Card.parse('8C'))).toBeNull(); + }); +}); + +describe('intentFor when defending', () => { + const position = () => makeState({ + hands: { [YOU]: '8D 6S KC', [BOT]: 'AH AD' }, + trump: 'S', + deck: '10C 10D', + attacker: BOT, + defender: YOU, + table: [{ attack: '7D' }], + phase: Phase.Defence, + }); + + it('works out which attack the card beats, with no second tap', () => { + expect(tap(position(), '8D')).toMatchObject({ type: ActionType.Defend, slot: 0 }); + }); + + it('allows a trump', () => { + expect(tap(position(), '6S')).toMatchObject({ type: ActionType.Defend, slot: 0 }); + }); + + it('refuses a card that beats nothing', () => { + expect(tap(position(), 'KC')).toBeNull(); + }); + + it('picks the lowest slot the card can answer', () => { + const state = makeState({ + hands: { [YOU]: 'AD', [BOT]: 'AH AC' }, + trump: 'S', + deck: '10C 10D', + attacker: BOT, + defender: YOU, + table: [{ attack: '7C' }, { attack: '7D' }], + phase: Phase.Defence, + }); + // The ace of diamonds cannot answer the clubs, so slot 1 is the answer. + expect(tap(state, 'AD')).toMatchObject({ slot: 1 }); + }); +}); + +describe('intentFor when adding to an attack', () => { + const position = () => makeState({ + hands: { [YOU]: '7H 9C KD', [BOT]: 'AH AD' }, + trump: 'S', + deck: '10C 10D', + attacker: YOU, + table: [{ attack: '7D', defence: '9D' }], + phase: Phase.Reinforce, + }); + + it('adds a card whose rank is on the table', () => { + expect(tap(position(), '7H')).toMatchObject({ type: ActionType.Attack }); + expect(tap(position(), '9C')).toMatchObject({ type: ActionType.Attack }); + }); + + it('refuses a rank that is not on the table', () => { + expect(tap(position(), 'KD')).toBeNull(); + }); +}); + +describe('intentFor agrees with the rules', () => { + it('never proposes an action the rules would reject', () => { + // Play many matches by tapping cards, and check every proposal is legal. + for (let seed = 0; seed < 400; seed++) { + let state = makeState({ + hands: { [YOU]: '6C 7D 8H 9S 10C JD', [BOT]: '6D 7H 8S 9C 10D JH' }, + trump: 'S', + deck: 'QC QD QH QS KC KD KH KS AC AD AH', + attacker: seed % 2 === 0 ? YOU : BOT, + turnNumber: 1 + (seed % 3), + }); + + for (let step = 0; step < 40 && state.phase !== Phase.Finished; step++) { + const actor = currentActor(state); + if (actor === null) break; + + if (actor === YOU) { + const hand = state.players[0].hand; + for (const card of hand) { + const action = intentFor(state, YOU, card); + if (!action) continue; + // Whatever it proposes, the rules must accept it. + expect(() => apply(state, action)).not.toThrow(); + } + } + + const options = legalActions(state, actor); + state = apply(state, options[seed % options.length]).state; + } + } + }); + + it('proposes something for every card the rules would accept', () => { + const state = makeState({ + hands: { [YOU]: '6C 7D 8H 9S 10C JD', [BOT]: '6D 7H 8S' }, + trump: 'S', + deck: 'QC QD QH', + attacker: YOU, + }); + + const playable = state.players[0].hand.filter((c) => intentFor(state, YOU, c) !== null); + const legalCards = legalActions(state, YOU) + .filter((a) => a.type === ActionType.Attack) + .map((a) => (a as { card: Card }).card); + + expect(new Set(playable)).toEqual(new Set(legalCards)); + }); +});