first commit

This commit is contained in:
zzc
1970-01-01 08:45:37 +08:00
commit e9c9afb3b9
53 changed files with 5254 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
[InternetShortcut]
URL=https://docs.cocos.com/creator/manual/en/scripting/setup.html#custom-script-template

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
#///////////////////////////
# Cocos Creator 3D Project
#///////////////////////////
library/
temp/
local/
build/
profiles/
native
#//////////////////////////
# NPM
#//////////////////////////
node_modules/
#//////////////////////////
# VSCode
#//////////////////////////
.vscode/
#//////////////////////////
# WebStorm
#//////////////////////////
.idea/

BIN
assets/.DS_Store vendored Normal file

Binary file not shown.

14
assets/resources.meta Normal file
View File

@@ -0,0 +1,14 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "b5b90e41-dfc6-4ee6-8975-64853447f305",
"files": [],
"subMetas": {},
"userData": {
"isBundle": true,
"bundleConfigID": "default",
"bundleName": "resources",
"priority": 8
}
}

BIN
assets/resources/.DS_Store vendored Normal file

Binary file not shown.

BIN
assets/resources/ball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

View File

@@ -0,0 +1,134 @@
{
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "cbabcdf5-bcc6-409d-85d2-52375ac79698",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "cbabcdf5-bcc6-409d-85d2-52375ac79698@6c48a",
"displayName": "ball",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0,
"isUuid": true,
"imageUuidOrDatabaseUri": "cbabcdf5-bcc6-409d-85d2-52375ac79698",
"visible": false
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "cbabcdf5-bcc6-409d-85d2-52375ac79698@f9941",
"displayName": "ball",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 16,
"height": 16,
"rawWidth": 16,
"rawHeight": 16,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-8,
-8,
0,
8,
-8,
0,
-8,
8,
0,
8,
8,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
0,
16,
16,
16,
0,
0,
16,
0
],
"nuv": [
0,
0,
1,
0,
0,
1,
1,
1
],
"minPos": [
-8,
-8,
0
],
"maxPos": [
8,
8,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "cbabcdf5-bcc6-409d-85d2-52375ac79698@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
"ver": "1.0.12",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"hasAlpha": true,
"fixAlphaTransparencyArtifacts": false,
"redirect": "cbabcdf5-bcc6-409d-85d2-52375ac79698@6c48a"
}
}

Binary file not shown.

View File

@@ -0,0 +1,113 @@
{
"ver": "2.3.13",
"importer": "fbx",
"imported": true,
"uuid": "08b00b93-6f70-457d-a520-a2aa23678481",
"files": [],
"subMetas": {
"e94cd": {
"importer": "gltf-mesh",
"uuid": "08b00b93-6f70-457d-a520-a2aa23678481@e94cd",
"displayName": "",
"id": "e94cd",
"name": "Икосфера.mesh",
"userData": {
"gltfIndex": 0,
"triangleCount": 4800
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"b31f4": {
"importer": "gltf-material",
"uuid": "08b00b93-6f70-457d-a520-a2aa23678481@b31f4",
"displayName": "",
"id": "b31f4",
"name": "white.material",
"userData": {
"gltfIndex": 0
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"515b9": {
"importer": "gltf-material",
"uuid": "08b00b93-6f70-457d-a520-a2aa23678481@515b9",
"displayName": "",
"id": "515b9",
"name": "black.material",
"userData": {
"gltfIndex": 1
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"564dd": {
"importer": "gltf-scene",
"uuid": "08b00b93-6f70-457d-a520-a2aa23678481@564dd",
"displayName": "",
"id": "564dd",
"name": "football.prefab",
"userData": {
"gltfIndex": 0
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"imageMetas": [],
"fbx": {
"smartMaterialEnabled": true
},
"lods": {
"enable": false,
"hasBuiltinLOD": false,
"options": [
{
"screenRatio": 0.25,
"faceCount": 1
},
{
"screenRatio": 0.125,
"faceCount": 0.25
},
{
"screenRatio": 0.01,
"faceCount": 0.1
}
]
},
"assetFinder": {
"meshes": [
"08b00b93-6f70-457d-a520-a2aa23678481@e94cd"
],
"skeletons": [],
"textures": [],
"materials": [
"08b00b93-6f70-457d-a520-a2aa23678481@b31f4",
"08b00b93-6f70-457d-a520-a2aa23678481@515b9"
],
"scenes": [
"08b00b93-6f70-457d-a520-a2aa23678481@564dd"
]
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,214 @@
{
"ver": "2.3.13",
"importer": "fbx",
"imported": true,
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43",
"files": [],
"subMetas": {
"2f6d1": {
"importer": "gltf-mesh",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@2f6d1",
"displayName": "",
"id": "2f6d1",
"name": "Cube.mesh",
"userData": {
"gltfIndex": 0,
"triangleCount": 28
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"81eaa": {
"importer": "gltf-embeded-image",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@81eaa",
"displayName": "",
"id": "81eaa",
"name": "tex_football_field.image",
"userData": {
"gltfIndex": 0,
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": false,
"type": "texture"
},
"ver": "1.0.3",
"imported": true,
"files": [
".json",
".png"
],
"subMetas": {}
},
"5ba76": {
"importer": "texture",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@5ba76",
"displayName": "",
"id": "5ba76",
"name": "tex_football_field.texture",
"userData": {
"wrapModeS": "repeat",
"wrapModeT": "repeat",
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0,
"isUuid": true,
"imageUuidOrDatabaseUri": "f80f846a-f4fa-4901-b733-79c6212deb43@81eaa"
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"3373f": {
"importer": "gltf-material",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@3373f",
"displayName": "",
"id": "3373f",
"name": "base_football_field.material",
"userData": {
"gltfIndex": 0
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"9cf53": {
"importer": "gltf-material",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@9cf53",
"displayName": "",
"id": "9cf53",
"name": "football_field.material",
"userData": {
"gltfIndex": 1
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"6a01c": {
"importer": "gltf-material",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@6a01c",
"displayName": "",
"id": "6a01c",
"name": "grass_dark_football_field.material",
"userData": {
"gltfIndex": 2
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"683d0": {
"importer": "gltf-material",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@683d0",
"displayName": "",
"id": "683d0",
"name": "ground_dark_football_field.material",
"userData": {
"gltfIndex": 3
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"66bc7": {
"importer": "gltf-material",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@66bc7",
"displayName": "",
"id": "66bc7",
"name": "ground_light_football_field.material",
"userData": {
"gltfIndex": 4
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"4e238": {
"importer": "gltf-scene",
"uuid": "f80f846a-f4fa-4901-b733-79c6212deb43@4e238",
"displayName": "",
"id": "4e238",
"name": "football_field.prefab",
"userData": {
"gltfIndex": 0
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"imageMetas": [
{
"name": "tex_football_field",
"uri": "f80f846a-f4fa-4901-b733-79c6212deb43@81eaa"
}
],
"fbx": {
"smartMaterialEnabled": true
},
"lods": {
"enable": false,
"hasBuiltinLOD": false,
"options": [
{
"screenRatio": 0.25,
"faceCount": 1
},
{
"screenRatio": 0.125,
"faceCount": 0.25
},
{
"screenRatio": 0.01,
"faceCount": 0.1
}
]
},
"assetFinder": {
"meshes": [
"f80f846a-f4fa-4901-b733-79c6212deb43@2f6d1"
],
"skeletons": [],
"textures": [
"f80f846a-f4fa-4901-b733-79c6212deb43@5ba76"
],
"materials": [
"f80f846a-f4fa-4901-b733-79c6212deb43@3373f",
"f80f846a-f4fa-4901-b733-79c6212deb43@9cf53",
"f80f846a-f4fa-4901-b733-79c6212deb43@6a01c",
"f80f846a-f4fa-4901-b733-79c6212deb43@683d0",
"f80f846a-f4fa-4901-b733-79c6212deb43@66bc7"
],
"scenes": [
"f80f846a-f4fa-4901-b733-79c6212deb43@4e238"
]
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,263 @@
{
"ver": "2.3.13",
"importer": "fbx",
"imported": true,
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326",
"files": [],
"subMetas": {
"29428": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@29428",
"displayName": "",
"id": "29428",
"name": "Plane.012.mesh",
"userData": {
"gltfIndex": 7,
"triangleCount": 3704
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"59394": {
"importer": "gltf-material",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@59394",
"displayName": "",
"id": "59394",
"name": "Material.007.material",
"userData": {
"gltfIndex": 2
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"99380": {
"importer": "gltf-material",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@99380",
"displayName": "",
"id": "99380",
"name": "Material.001.material",
"userData": {
"gltfIndex": 1
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"bbd92": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@bbd92",
"displayName": "",
"id": "bbd92",
"name": "Cylinder.004.mesh",
"userData": {
"gltfIndex": 0,
"triangleCount": 124
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"10dfa": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@10dfa",
"displayName": "",
"id": "10dfa",
"name": "Cylinder.005.mesh",
"userData": {
"gltfIndex": 1,
"triangleCount": 124
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"10a81": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@10a81",
"displayName": "",
"id": "10a81",
"name": "Cylinder.006.mesh",
"userData": {
"gltfIndex": 2,
"triangleCount": 124
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"5cf41": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@5cf41",
"displayName": "",
"id": "5cf41",
"name": "Plane.008.mesh",
"userData": {
"gltfIndex": 3,
"triangleCount": 3704
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"c5c89": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@c5c89",
"displayName": "",
"id": "c5c89",
"name": "Plane.009.mesh",
"userData": {
"gltfIndex": 4,
"triangleCount": 3704
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"57ecb": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@57ecb",
"displayName": "",
"id": "57ecb",
"name": "Plane.010.mesh",
"userData": {
"gltfIndex": 5,
"triangleCount": 16
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"38a9f": {
"importer": "gltf-mesh",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@38a9f",
"displayName": "",
"id": "38a9f",
"name": "Plane.011.mesh",
"userData": {
"gltfIndex": 6,
"triangleCount": 3704
},
"ver": "1.1.1",
"imported": true,
"files": [
".bin",
".json"
],
"subMetas": {}
},
"551ec": {
"importer": "gltf-material",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@551ec",
"displayName": "",
"id": "551ec",
"name": "Material.005.material",
"userData": {
"gltfIndex": 0
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"364f4": {
"importer": "gltf-scene",
"uuid": "299a2b65-c675-485f-860f-fa566ac3f326@364f4",
"displayName": "",
"id": "364f4",
"name": "goal_new4.prefab",
"userData": {
"gltfIndex": 0
},
"ver": "1.0.14",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"imageMetas": [],
"fbx": {
"smartMaterialEnabled": true
},
"lods": {
"enable": false,
"hasBuiltinLOD": false,
"options": [
{
"screenRatio": 0.25,
"faceCount": 1
},
{
"screenRatio": 0.125,
"faceCount": 0.25
},
{
"screenRatio": 0.01,
"faceCount": 0.1
}
]
},
"assetFinder": {
"meshes": [
"299a2b65-c675-485f-860f-fa566ac3f326@bbd92",
"299a2b65-c675-485f-860f-fa566ac3f326@10dfa",
"299a2b65-c675-485f-860f-fa566ac3f326@10a81",
"299a2b65-c675-485f-860f-fa566ac3f326@5cf41",
"299a2b65-c675-485f-860f-fa566ac3f326@c5c89",
"299a2b65-c675-485f-860f-fa566ac3f326@57ecb",
"299a2b65-c675-485f-860f-fa566ac3f326@38a9f",
"299a2b65-c675-485f-860f-fa566ac3f326@29428"
],
"skeletons": [],
"textures": [],
"materials": [
"299a2b65-c675-485f-860f-fa566ac3f326@551ec",
"299a2b65-c675-485f-860f-fa566ac3f326@99380",
"299a2b65-c675-485f-860f-fa566ac3f326@59394"
],
"scenes": [
"299a2b65-c675-485f-860f-fa566ac3f326@364f4"
]
}
}
}

9
assets/resources/ui.meta Normal file
View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "5fc9d063-3798-4978-a773-81fbb8a5cdfe",
"files": [],
"subMetas": {},
"userData": {}
}

BIN
assets/resources/ui/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,239 @@
[
{
"__type__": "cc.Prefab",
"_name": "Preview",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "Preview",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [
{
"__id__": 2
}
],
"_active": true,
"_components": [
{
"__id__": 8
}
],
"_prefab": {
"__id__": 10
},
"_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.Node",
"_name": "Sprite",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
},
{
"__id__": 5
}
],
"_prefab": {
"__id__": 7
},
"_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__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 4
},
"_contentSize": {
"__type__": "cc.Size",
"width": 40,
"height": 36
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "68wE+uAUxFYLDEuk6lHNR3"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 6
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "57520716-48c8-4a19-8acf-41c9f8777fb0@f9941",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 1,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "e19APLNrlB/JU0ZdmOMkxq"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "c96ZwVsKFA7Lwh0J8Ej3p5",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 9
},
"_contentSize": {
"__type__": "cc.Size",
"width": 100,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "47igSZnfpM0ZlyosMVKC5z"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
"instance": null,
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "a4fc77e4-d765-48e6-b999-1b6afcb194cc",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "Preview"
}
}

View File

@@ -0,0 +1,114 @@
[
{
"__type__": "cc.Prefab",
"_name": "ball",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "ball",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [],
"_active": true,
"_components": [
{
"__id__": 2
}
],
"_prefab": {
"__id__": 4
},
"_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.SpriteRenderer",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 3
},
"_materials": [
{
"__uuid__": "ade8a15a-dcca-4b3c-84c6-f6476ac875bb",
"__expectedType__": "cc.Material"
}
],
"_visFlags": 0,
"_spriteFrame": {
"__uuid__": "cbabcdf5-bcc6-409d-85d2-52375ac79698@f9941",
"__expectedType__": "cc.SpriteFrame"
},
"_mode": 0,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_flipX": false,
"_flipY": false,
"_size": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "eeQKP+GsNNhqfOqxoFdU6u"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "bdqBOP1c1DX7hkNID5uzfW",
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "facfb653-dd5b-448a-8240-ac3d1cf41068",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "ball"
}
}

View File

@@ -0,0 +1,114 @@
[
{
"__type__": "cc.Prefab",
"_name": "vibration",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "vibration",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [],
"_active": true,
"_components": [
{
"__id__": 2
}
],
"_prefab": {
"__id__": 4
},
"_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.SpriteRenderer",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 3
},
"_materials": [
{
"__uuid__": "ade8a15a-dcca-4b3c-84c6-f6476ac875bb",
"__expectedType__": "cc.Material"
}
],
"_visFlags": 0,
"_spriteFrame": {
"__uuid__": "8ede48ee-13ca-4dcb-aeb5-fd66d88dc691@f9941",
"__expectedType__": "cc.SpriteFrame"
},
"_mode": 0,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_flipX": false,
"_flipY": false,
"_size": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "c3gkb1lSNHOZhW4xgAMR2c"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "28NxmbJepDw6NSNbHjBimN",
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "491ef077-7d08-452e-8f00-040b69aebe45",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "vibration"
}
}

9
assets/scene.meta Normal file
View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "f4a2d32c-901d-44c2-a505-01844eb57404",
"files": [],
"subMetas": {},
"userData": {}
}

2702
assets/scene/game.scene Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
{
"ver": "1.1.50",
"importer": "scene",
"imported": true,
"uuid": "4e8dc402-8873-4978-9793-a1b2e7b8b766",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

9
assets/scripts.meta Normal file
View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "d86bbf2e-0f81-47b2-a0ac-8d514c49e8d7",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,133 @@
// assets/scripts/BallPhysics.ts
import {
_decorator,
Component,
Node,
RigidBody,
Vec3,
math,
SphereCollider,
Contact2DType,
MeshCollider,
ICollisionEvent,
ITriggerEvent,
} from "cc";
const { ccclass, property } = _decorator;
@ccclass("BallPhysics")
export class BallPhysics extends Component {
@property({ tooltip: "马格努斯系数(越大弧线越明显)" }) magnusK = 0.1;
@property({ tooltip: "空气阻力" }) dragK = 0.001;
@property({ tooltip: "风力m/s^2" }) windStrength = 0;
@property({ tooltip: "风向" }) windDir: Vec3 = new Vec3(1, 0, 0);
@property({ tooltip: "自动重置高度阈值(低于视为无效球)" }) resetY = -2;
@property(Node) spawnPoint!: Node;
@property(Node) ball!: Node;
private rb!: RigidBody;
private tmpF = new Vec3();
private v = new Vec3();
private w = new Vec3();
private wind = new Vec3();
private pos = new Vec3();
// ⚽ 保存 spinKickInput 设置进来)
private spin = new Vec3();
onLoad() {
this.rb = this.ball.getComponent(RigidBody)!;
const col = this.ball.getComponent(MeshCollider);
if (col) {
console.log(22223333, col);
col.on("onTriggerEnter", this.onTriggerEnter, this);
col.on("onTriggerStay", this.onTriggerStay, this);
col.on("onCollisionEnter", this.onCollisionEnter, this);
}
this.wind.set(this.windDir).normalize();
}
private onTriggerStay(event: ITriggerEvent) {
console.log(event.type, event);
}
onTriggerEnter(event: ICollisionEvent) {
console.log("⚽ 触发器进入:", event.otherCollider.node.name);
}
onCollisionEnter(event: ICollisionEvent) {
console.log("⚽ 碰撞进入:", event.otherCollider.node.name);
}
init() {
this.rb = this.node.getComponent(RigidBody)!;
this.wind.set(this.windDir).normalize();
this.pos = this.node.worldPosition.clone();
}
setWind(direction: Vec3, strength: number) {
this.wind.set(direction).normalize();
this.windStrength = strength;
}
resetBall() {
if (!this.spawnPoint) return;
this.rb.clearState();
this.node.worldPosition = this.pos; //this.spawnPoint.worldPosition.clone();
this.rb.setLinearVelocity(new Vec3());
this.rb.setAngularVelocity(new Vec3());
}
/** 设置自旋(由 KickInput 调用) */
public setSpin(spin: Vec3) {
this.spin.set(spin);
}
/** 发射足球 */
shootBall(dir: Vec3, speed: number) {
this.rb.clearState();
this.rb.setLinearVelocity(dir.clone().multiplyScalar(speed));
this.rb.setAngularVelocity(this.spin); // 应用横向旋转
}
update(dt: number) {
if (!this.rb) return;
this.rb.getLinearVelocity(this.v);
// 1. 空气阻力(与预测保持一致: -k * v * |v|
const speed = this.v.length();
if (speed > 0.01) {
const drag = this.v.clone().multiplyScalar(-this.dragK * speed);
this.rb.applyForce(drag);
}
// 2. 马格努斯力: F = k * (spin × v)
if (!this.spin.equals(Vec3.ZERO) && speed > 0.01) {
const magnus = new Vec3();
Vec3.cross(magnus, this.spin, this.v);
magnus.multiplyScalar(this.magnusK);
this.rb.applyForce(magnus);
}
// if (!this.spin.equals(Vec3.ZERO) && speed > 0.01) {
// const magnus = new Vec3();
// const vNorm = this.v.clone().normalize();
// Vec3.cross(magnus, this.spin, vNorm);
// magnus.multiplyScalar(this.magnusK * Math.sqrt(speed));
// this.rb.applyForce(magnus);
// }
// 3. 风
if (this.windStrength > 0.0001) {
this.tmpF.set(this.wind).multiplyScalar(this.windStrength);
this.rb.applyForce(this.tmpF);
}
// 4. 掉出场地自动重置
if (this.node.worldPosition.y < this.resetY && this.spawnPoint) {
this.resetBall();
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "3aece382-c6ed-4971-82a0-cf40507368f7",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,32 @@
// assets/scripts/CameraRig.ts
import { _decorator, Component, Node, Vec3, math } from "cc";
const { ccclass, property } = _decorator;
@ccclass("CameraRig")
export class CameraRig extends Component {
@property(Node) ball!: Node;
@property({ tooltip: "跟随平滑0~1越小越平滑" }) smooth = 0.1;
@property(Vec3) offset = new Vec3(0, 2.5, -5);
private _mode: "static" | "follow" = "static";
setModeFollow() {
this._mode = "follow";
}
setModeStatic() {
this._mode = "static";
}
lateUpdate(dt: number) {
if (this._mode !== "follow" || !this.ball) return;
const target = this.ball.worldPosition.clone().add(this.offset);
const p = this.node.worldPosition.clone();
const lerp = new Vec3(
math.lerp(p.x, target.x, 1 - this.smooth),
math.lerp(p.y, target.y, 1 - this.smooth),
math.lerp(p.z, target.z, 1 - this.smooth)
);
this.node.setWorldPosition(lerp);
this.node.lookAt(this.ball.worldPosition);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "ffb4877f-b15c-46cd-b252-dedbe7540235",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,58 @@
// assets/scripts/GameManager.ts
import { _decorator, Component, Node, Label, Vec3 } from "cc";
import { BallPhysics } from "./BallPhysics";
// import { CameraRig } from "./CameraRig";
const { ccclass, property } = _decorator;
@ccclass("GameManager")
export class GameManager extends Component {
@property(Node) ball!: Node;
// @property(Node) cameraRig!: Node;
// @property(Label) scoreLabel!: Label;
// @property(Label) windLabel!: Label;
private score = 0;
private ballPhys!: BallPhysics;
// private cam!: CameraRig;
onLoad() {
this.ballPhys = this.ball.getComponent(BallPhysics)!;
this.ballPhys.init();
// this.cam = this.cameraRig.getComponent(CameraRig)!;
// 监听进球
this.node.on("GOAL", this.onGoal, this);
this.newRound();
}
onGoal() {
this.score += 1;
this.updateScore();
this.scheduleOnce(() => {
this.newRound();
}, 1.0);
}
private updateScore() {
// if (this.scoreLabel) this.scoreLabel.string = `${this.score}`;
}
private newRound() {
// 重置球与镜头
this.ballPhys.resetBall();
// this.cam.setModeStatic();
// 随机风
// const dir = new Vec3(Math.random() - 0.5, 0, Math.random() - 0.5);
// const strength = 4 * Math.random(); // 0~4
// this.ballPhys.setWind(dir, strength);
// if (this.windLabel) {
// const a = (Math.atan2(dir.x, dir.z) * 180) / Math.PI; // 粗略角度显示
// this.windLabel.string = `Wind ${strength.toFixed(1)} @ ${a.toFixed(0)}°`;
// }
// 几百毫秒后把镜头切为跟随(等玩家射门后也可在 KickInput 里触发)
// this.scheduleOnce(() => this.cam.setModeFollow(), 0.6);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "81883817-9f1d-4d28-8109-f62a0dc23285",
"files": [],
"subMetas": {},
"userData": {}
}

109
assets/scripts/GameMrg.ts Normal file
View File

@@ -0,0 +1,109 @@
import {
_decorator,
Component,
Vec3,
RigidBody,
input,
Input,
EventTouch,
} from "cc";
import { TrajectoryPreview } from "./TrajectoryPreview";
const { ccclass, property } = _decorator;
@ccclass("GameMrg")
export class GameMrg extends Component {
@property(RigidBody)
rigidBody: RigidBody = null!;
@property(TrajectoryPreview)
trajectory: TrajectoryPreview = null!;
@property
maxPower: number = 25;
private startPos: Vec3 = new Vec3();
private endPos: Vec3 = new Vec3();
private isDragging: boolean = false;
start() {
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
onDestroy() {
input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
input.off(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
onTouchStart(e: EventTouch) {
this.startPos.set(e.getLocation().x, e.getLocation().y, 0);
this.isDragging = true;
}
onTouchMove(e: EventTouch) {
if (!this.isDragging) return;
this.endPos.set(e.getLocation().x, e.getLocation().y, 0);
const dragVec = new Vec3(
this.startPos.x - this.endPos.x,
this.startPos.y - this.endPos.y,
0
);
if (dragVec.length() < 10) {
this.trajectory.hideTrajectory();
return;
}
// 主方向(始终向前 + 抬升)
const forward = new Vec3(0, 0.5, 1).normalize();
// 力度
const power = Math.min(dragVec.y * 0.05 + 10, this.maxPower);
// 左右弧线
const sideForce = dragVec.x * 0.02;
// 显示轨迹
this.trajectory.showTrajectory(
// this.rigidBody.node.worldPosition,
this.startPos.clone(),
forward,
power,
sideForce
);
}
onTouchEnd(e: EventTouch) {
if (!this.isDragging) return;
this.isDragging = false;
this.trajectory.hideTrajectory();
this.endPos.set(e.getLocation().x, e.getLocation().y, 0);
const dragVec = new Vec3(
this.startPos.x - this.endPos.x,
this.startPos.y - this.endPos.y,
0
);
if (dragVec.length() < 10) return;
// 主方向
const forward = new Vec3(0, 0.5, 1).normalize();
// 力度
const power = Math.min(dragVec.y * 0.05 + 10, this.maxPower);
// 左右弧线
const sideForce = dragVec.x * 0.02;
// 发射冲量
const impulse = forward.multiplyScalar(power);
impulse.x += sideForce;
this.rigidBody.applyImpulse(impulse);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "cb6a4184-4c18-405f-8e18-f0d5829517cd",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,19 @@
// assets/scripts/GoalDetector.ts
import { _decorator, Component, ITriggerEvent } from "cc";
const { ccclass, property } = _decorator;
@ccclass("GoalDetector")
export class GoalDetector extends Component {
@property({ tooltip: "GameManager 节点(接收进球事件)" }) gameManagerPath =
"";
onTriggerEnter(event: ITriggerEvent) {
const other = event.otherCollider?.node;
if (!other) return;
if (other.name.includes("Ball")) {
// 简单通知
const gm = this.node.scene.getChildByPath(this.gameManagerPath);
gm?.emit("GOAL");
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "85ff5590-99dd-47f5-8422-0702fc260fb3",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,45 @@
// assets/scripts/GoalkeeperAI.ts
import { _decorator, Component, Node, RigidBody, Vec3, math } from "cc";
const { ccclass, property } = _decorator;
@ccclass("GoalkeeperAI")
export class GoalkeeperAI extends Component {
@property(Node) ball!: Node;
@property({ tooltip: "球门线Z世界坐标" }) goalLineZ = 10;
@property({ tooltip: "守门员水平活动范围X" }) rangeX = 3.5;
@property({ tooltip: "移动速度m/s" }) speed = 6;
@property({ tooltip: "反应延迟(秒)" }) reactDelay = 0.15;
private targetX = 0;
private tAcc = 0;
private tmp = new Vec3();
update(dt: number) {
if (!this.ball) return;
// 简化预测:用当前速度线性外推到球门线的交点
const rb = this.ball.getComponent(RigidBody);
if (!rb) return;
rb.getLinearVelocity(this.tmp);
const v = this.tmp.clone();
const bp = this.ball.worldPosition.clone();
if (Math.abs(v.z) < 0.1) return; // 几乎不朝球门方向飞
const timeToLine = (this.goalLineZ - bp.z) / v.z; // z 轴朝向球门
if (timeToLine < 0) return; // 已过线或背离
this.tAcc += dt;
if (this.tAcc >= this.reactDelay) {
const predictX = bp.x + v.x * timeToLine;
this.targetX = math.clamp(predictX, -this.rangeX, this.rangeX);
this.tAcc = 0; // 下次再延迟
}
// 移动守门员
const p = this.node.worldPosition;
const dx = this.targetX - p.x;
const step = math.clamp(dx, -this.speed * dt, this.speed * dt);
this.node.setWorldPosition(p.x + step, p.y, p.z);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "30f1b3d4-4345-4002-a1ae-d9a745976704",
"files": [],
"subMetas": {},
"userData": {}
}

172
assets/scripts/KickInput.ts Normal file
View File

@@ -0,0 +1,172 @@
import {
_decorator,
Component,
Node,
EventTouch,
Input,
input,
Vec2,
Vec3,
RigidBody,
math,
Graphics,
MeshRenderer,
geometry,
} from "cc";
import { TrajectoryPreview } from "./TrajectoryPreview";
import { Preview } from "./Preview";
import { BallPhysics } from "./BallPhysics";
const { ccclass, property } = _decorator;
@ccclass("KickInput")
export class KickInput extends Component {
@property(Node) ball!: Node;
// @property(Node) goal!: Node;
@property(Node) cameraRig!: Node;
// 力度与角度控制
@property({ tooltip: "最大初速度m/s" }) maxSpeed = 20;
@property({ tooltip: "最小仰角(度)" }) minPitchDeg = 8;
@property({ tooltip: "最大仰角(度)" }) maxPitchDeg = 18;
// 自旋与弧线
@property({ tooltip: "自旋强度系数" }) spinFactor = 20;
@property(Preview) preview: Preview = null!;
private startPos = new Vec2();
private dragging = false;
private lastPos = new Vec2();
private trail: Vec2[] = [];
private ballPhys: BallPhysics = null;
protected onLoad(): void {
this.ballPhys = this.ball.getComponent(BallPhysics)!;
}
onEnable() {
input.on(Input.EventType.TOUCH_START, this.onStart, this);
input.on(Input.EventType.TOUCH_MOVE, this.onMove, this);
input.on(Input.EventType.TOUCH_END, this.onEnd, this);
input.on(Input.EventType.TOUCH_CANCEL, this.onEnd, this);
}
onDisable() {
input.off(Input.EventType.TOUCH_START, this.onStart, this);
input.off(Input.EventType.TOUCH_MOVE, this.onMove, this);
input.off(Input.EventType.TOUCH_END, this.onEnd, this);
input.off(Input.EventType.TOUCH_CANCEL, this.onEnd, this);
}
private onStart(e: EventTouch) {
this.dragging = true;
e.getLocation(this.startPos);
e.getLocation(this.lastPos);
this.trail.length = 0;
this.trail.push(this.startPos.clone());
}
private onMove(e: EventTouch) {
if (!this.dragging) return;
const p = e.getLocation();
this.trail.push(p.clone());
this.lastPos.set(p);
// 1) 拖拽向量
const drag = this.lastPos.clone().subtract(this.startPos);
const dragLen = drag.length();
// 2) 速度(映射拖拽长度)
const speed = math.clamp(dragLen / 8, 5, this.maxSpeed);
// const speed = 12;
// 3) 仰角 pitch映射拖拽的纵向
const t = math.clamp(drag.y / 300, 0, 1);
const pitchDeg = math.lerp(this.minPitchDeg, this.maxPitchDeg, t);
// 4) 偏航角 yaw映射拖拽的横向
const yawDeg = math.clamp(-drag.x / 8, -45, 45);
// 5) 得到方向向量
const dir = this.dirFromAngles(yawDeg, pitchDeg);
// 6) 自旋(用轨迹估计)
const spin = this.estimateSpin(this.trail, drag).multiplyScalar(
this.spinFactor
);
this.preview.showTrajectory(this.ball.worldPosition, dir, speed, spin);
}
private onEnd() {
if (!this.dragging) return;
this.dragging = false;
this.preview.clear();
// 拖拽向量
const drag = this.lastPos.clone().subtract(this.startPos);
const dragLen = drag.length();
if (!this.ball || !this.ballPhys) return;
// 1) 计算初速度
const speed = math.clamp(dragLen / 8, 5, this.maxSpeed);
// const speed = 12;
// 2) 仰角 pitch
const t = math.clamp(drag.y / 300, 0, 1);
const pitchDeg = math.lerp(this.minPitchDeg, this.maxPitchDeg, t);
// 3) 偏航 yaw
const yawDeg = math.clamp(-drag.x / 8, -45, 45);
// 4) 方向向量
const dir = this.dirFromAngles(yawDeg, pitchDeg);
// 5) 自旋
const spin = this.estimateSpin(this.trail, drag).multiplyScalar(
this.spinFactor
);
this.ballPhys.setSpin(spin);
console.log(`t: ${t}, pitchDeg:${pitchDeg}`);
// 6) 发射
this.ballPhys.shootBall(dir, speed);
}
private dirFromAngles(yawDeg: number, pitchDeg: number) {
const yaw = math.toRadian(yawDeg);
const pitch = math.toRadian(pitchDeg);
// 水平前方Z轴右手坐标根据你场景轴向可能需调整
const x = Math.sin(yaw) * Math.cos(pitch);
const y = Math.sin(pitch);
const z = Math.cos(yaw) * Math.cos(pitch);
return new Vec3(x, y, z).normalize();
}
// 简单估计自旋方向:用拖拽路径的“弯曲方向”
private estimateSpin(path: Vec2[], drag: Vec2): Vec3 {
if (path.length < 4) return new Vec3(0, 0, 0);
// 取开始、中点、终点计算平面曲率符号映射为Y轴为主或Z轴自旋
const a = path[0],
b = path[Math.floor(path.length / 2)],
c = path[path.length - 1];
// 2D 叉积 z 分量(曲率方向)
const ab = new Vec2(b.x - a.x, b.y - a.y);
const bc = new Vec2(c.x - b.x, c.y - b.y);
const cross = ab.x * bc.y - ab.y * bc.x; // >0 逆时针弯曲
// 横向弯 -> 绕Y轴的自旋产生左右弧线
const spinY = math.clamp(drag.x / 200, -3.5, 3.5);
return new Vec3(0, spinY, 0); // 只绕Y轴产生左右弧度
// const spinY = math.clamp(cross / 20000, -1.5, 1.5) * 2.0; // 横向弧度提前
// // 竖向弯 -> 绕X轴/或Z轴的自旋下坠/挑球这里简单给点Z
// const dy = c.y - a.y;
// const spinZ = math.clamp(dy / 1500, -1.0, 1.0);
// return new Vec3(0, spinY, spinZ);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "4e90f5ed-3b95-4d1d-90b7-3b9eb5d8c130",
"files": [],
"subMetas": {},
"userData": {}
}

82
assets/scripts/Preview.ts Normal file
View File

@@ -0,0 +1,82 @@
// assets/scripts/Preview.ts
import { _decorator, Component, Node, Prefab, instantiate, Vec3 } from "cc";
import { BallPhysics } from "./BallPhysics";
const { ccclass, property } = _decorator;
@ccclass("Preview")
export class Preview extends Component {
@property(Prefab) pointPrefab: Prefab = null!;
@property(Node) goal: Node = null!;
@property({ tooltip: "轨迹点数量" }) maxPoints = 30;
@property({ tooltip: "步长时间(秒)" }) timeStep = 0.05;
@property(BallPhysics) ballPhys: BallPhysics = null!;
private points: Node[] = [];
clear() {
for (const p of this.points) p.destroy();
this.points.length = 0;
}
/** 显示预测轨迹 */
showTrajectory(startPos: Vec3, dir: Vec3, speed: number, spin: Vec3) {
this.clear();
if (!this.pointPrefab || !this.ballPhys) return;
const goalZ = this.goal?.worldPosition?.z;
// 初始状态
let pos = startPos.clone();
let v = dir.clone().multiplyScalar(speed);
let w = spin.clone(); // 自旋
// 迭代预测
// let age = 0;
for (let i = 0; i < this.maxPoints; i++) {
// age += this.timeStep;
// 保存点
const p = instantiate(this.pointPrefab);
p.setWorldPosition(pos);
p.setParent(this.node);
this.points.push(p);
// === 模拟 BallPhysics.update(dt) ===
// const dt = this.timeStep;
const dt = this.timeStep * 0.5;
// 空气阻力
const speedNow = v.length();
if (speedNow > 0.01) {
const drag = v.clone().multiplyScalar(-this.ballPhys.dragK * speedNow);
v.add(drag.multiplyScalar(dt));
}
// 马格努斯效应F = k * (ω × v)
if (w.lengthSqr() > 0.0001 && v.lengthSqr() > 0.0001) {
// const tFactor = 1.0 / (1.0 + age * 2.0); // age 是飞行时间,越久衰减越快
// const magnus = w
// .clone()
// .cross(v)
// .multiplyScalar(this.ballPhys.magnusK * tFactor);
// v.add(magnus.multiplyScalar(dt));
const magnus = w.clone().cross(v).multiplyScalar(this.ballPhys.magnusK);
v.add(magnus.multiplyScalar(dt));
}
// 重力
v.y += -9.8 * dt;
// 移动
pos = pos.add(v.clone().multiplyScalar(dt));
if (
(startPos.z > goalZ && pos.z <= goalZ) ||
(startPos.z < goalZ && pos.z >= goalZ)
) {
break;
}
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "274524cf-5678-498a-9486-122ab0771b04",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,63 @@
import { _decorator, Component, Node, Prefab, instantiate, Vec3 } from "cc";
const { ccclass, property } = _decorator;
@ccclass("TrajectoryPreview")
export class TrajectoryPreview extends Component {
@property(Prefab)
pointPrefab: Prefab = null!;
@property
maxPoints: number = 20;
@property
timeStep: number = 0.1;
@property
gravity: Vec3 = new Vec3(0, -9.8, 0);
private points: Node[] = [];
onLoad() {
for (let i = 0; i < this.maxPoints; i++) {
const p = instantiate(this.pointPrefab);
p.active = false;
this.node.addChild(p); // 确保挂在场景下的空节点
this.points.push(p);
}
}
showTrajectory(
startPos: Vec3,
forward: Vec3,
power: number,
sideForce: number
) {
const velocity = forward.multiplyScalar(power);
velocity.x += sideForce;
const ballRadius = 0.01; // ⚽ 球半径
const groundY = 0; // 🟩 地面高度
for (let i = 0; i < this.maxPoints; i++) {
const t = i * this.timeStep;
const pos = new Vec3(
startPos.x + velocity.x * t,
startPos.y + velocity.y * t + 0.5 * this.gravity.y * t * t,
startPos.z + velocity.z * t
);
// ⭐ 限制最低不低于地面
if (pos.y < groundY + ballRadius * 0.5) {
pos.y = groundY + ballRadius * 0.5;
}
this.points[i].setWorldPosition(pos);
this.points[i].active = true;
}
}
hideTrajectory() {
this.points.forEach((p) => (p.active = false));
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "4210fa5e-4d43-4bef-bd48-c7949dccf074",
"files": [],
"subMetas": {},
"userData": {}
}

132
engine-mangle-config.json Normal file
View File

@@ -0,0 +1,132 @@
{
"__doc_url__": "https://docs.cocos.com/creator/3.8/manual/zh/advanced-topics/mangle-properties.html",
"COMMON": {
"mangleProtected": false,
"mangleList": [
"UITransform._sortSiblings",
"UITransform._cleanChangeMap",
"Node._findComponents",
"Node._findChildComponent",
"Node._findChildComponents",
"Node.idGenerator",
"Node._stacks",
"Node._stackId",
"Node._setScene",
"EffectAsset._layoutValid",
"EffectAsset._effects",
"ReflectionProbe.DEFAULT_CUBE_SIZE",
"ReflectionProbe.DEFAULT_PLANER_SIZE",
"WebGLDeviceManager.setInstance",
"WebGL2DeviceManager.setInstance",
"CanvasPool"
],
"dontMangleList": [
"Component"
]
},
"HTML5": {
"extends": "COMMON",
"mangleList": [],
"dontMangleList": []
},
"NATIVE": {
"extends": "COMMON",
"mangleList": [],
"dontMangleList": []
},
"MINIGAME": {
"extends": "COMMON",
"mangleList": [],
"dontMangleList": []
},
"WECHAT": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"BYTEDANCE": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"XIAOMI": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"ALIPAY": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"TAOBAO_MINIGAME": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"OPPO": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"VIVO": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"HUAWEI": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"MIGU": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"HONOR": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"COCOS_RUNTIME": {
"extends": "MINIGAME",
"mangleList": [],
"dontMangleList": []
},
"ANDROID": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
},
"WINDOWS": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
},
"IOS": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
},
"MAC": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
},
"OHOS": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
},
"OPEN_HARMONY": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
},
"LINUX": {
"extends": "NATIVE",
"mangleList": [],
"dontMangleList": []
}
}

7
package.json Executable file
View File

@@ -0,0 +1,7 @@
{
"name": "ball",
"uuid": "914b0113-8a31-4950-8cf8-b48f4361d291",
"creator": {
"version": "3.8.6"
}
}

View File

@@ -0,0 +1,3 @@
{
"__version__": "1.3.9"
}

View File

@@ -0,0 +1,23 @@
{
"__version__": "3.0.9",
"game": {
"name": "未知游戏",
"app_id": "UNKNOW",
"c_id": "0"
},
"appConfigMaps": [
{
"app_id": "UNKNOW",
"config_id": "f5b105"
}
],
"configs": [
{
"app_id": "UNKNOW",
"config_id": "f5b105",
"config_name": "Default",
"config_remarks": "",
"services": []
}
]
}

View File

@@ -0,0 +1,3 @@
{
"__version__": "1.0.1"
}

View File

@@ -0,0 +1,234 @@
{
"__version__": "1.0.12",
"modules": {
"configs": {
"defaultConfig": {
"name": "默认配置",
"cache": {
"base": {
"_value": true
},
"gfx-webgl": {
"_value": true
},
"gfx-webgl2": {
"_value": false
},
"gfx-webgpu": {
"_value": false
},
"animation": {
"_value": true
},
"skeletal-animation": {
"_value": true
},
"3d": {
"_value": true
},
"meshopt": {
"_value": false
},
"2d": {
"_value": true
},
"xr": {
"_value": false
},
"rich-text": {
"_value": true
},
"mask": {
"_value": true
},
"graphics": {
"_value": true
},
"ui-skew": {
"_value": true
},
"affine-transform": {
"_value": true
},
"ui": {
"_value": true
},
"particle": {
"_value": true
},
"physics": {
"_value": true,
"_option": "physics-ammo"
},
"physics-ammo": {
"_value": true,
"_flags": {
"LOAD_BULLET_MANUALLY": false
}
},
"physics-cannon": {
"_value": false
},
"physics-physx": {
"_value": false,
"_flags": {
"LOAD_PHYSX_MANUALLY": false
}
},
"physics-builtin": {
"_value": false
},
"physics-2d": {
"_value": true,
"_option": "physics-2d-box2d"
},
"physics-2d-box2d": {
"_value": true
},
"physics-2d-box2d-wasm": {
"_value": false,
"_flags": {
"LOAD_BOX2D_MANUALLY": false
}
},
"physics-2d-builtin": {
"_value": false
},
"physics-2d-box2d-jsb": {
"_value": false
},
"intersection-2d": {
"_value": true
},
"primitive": {
"_value": true
},
"profiler": {
"_value": true
},
"occlusion-query": {
"_value": false
},
"geometry-renderer": {
"_value": false
},
"debug-renderer": {
"_value": false
},
"particle-2d": {
"_value": true
},
"audio": {
"_value": true
},
"video": {
"_value": true
},
"webview": {
"_value": true
},
"tween": {
"_value": true
},
"websocket": {
"_value": true
},
"websocket-server": {
"_value": false
},
"terrain": {
"_value": true
},
"light-probe": {
"_value": true
},
"tiled-map": {
"_value": true
},
"vendor-google": {
"_value": false
},
"spine": {
"_value": true,
"_option": "spine-3.8"
},
"spine-3.8": {
"_value": true,
"_flags": {
"LOAD_SPINE_MANUALLY": false
}
},
"spine-4.2": {
"_value": false,
"_flags": {
"LOAD_SPINE_MANUALLY": false
}
},
"dragon-bones": {
"_value": true
},
"marionette": {
"_value": true
},
"procedural-animation": {
"_value": false
},
"custom-pipeline-post-process": {
"_value": false
},
"render-pipeline": {
"_value": true,
"_option": "custom-pipeline"
},
"custom-pipeline": {
"_value": true
},
"legacy-pipeline": {
"_value": false
}
},
"flags": {
"LOAD_SPINE_MANUALLY": false,
"LOAD_BULLET_MANUALLY": false
},
"includeModules": [
"2d",
"3d",
"affine-transform",
"animation",
"audio",
"base",
"custom-pipeline",
"dragon-bones",
"gfx-webgl",
"graphics",
"intersection-2d",
"light-probe",
"marionette",
"mask",
"particle",
"particle-2d",
"physics-2d-box2d",
"physics-ammo",
"primitive",
"profiler",
"rich-text",
"skeletal-animation",
"spine-3.8",
"terrain",
"tiled-map",
"tween",
"ui",
"ui-skew",
"video",
"websocket",
"webview"
],
"noDeprecatedFeatures": {
"value": false,
"version": ""
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
{
"__version__": "1.0.1",
"information": {
"customSplash": {
"id": "customSplash",
"label": "customSplash",
"enable": false,
"customSplash": {
"complete": false,
"form": "https://creator-api.cocos.com/api/form/show?"
}
},
"removeSplash": {
"id": "removeSplash",
"label": "removeSplash",
"enable": false,
"removeSplash": {
"complete": false,
"form": "https://creator-api.cocos.com/api/form/show?"
}
}
}
}

View File

@@ -0,0 +1,3 @@
{
"__version__": "1.0.4"
}

View File

@@ -0,0 +1,13 @@
{
"__version__": "1.0.6",
"general": {
"designResolution": {
"width": 1334,
"height": 750,
"fitWidth": false
}
},
"physics": {
"allowSleep": true
}
}

9
tsconfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
/* Base configuration. Do not edit this field. */
"extends": "./temp/tsconfig.cocos.json",
/* Add your custom configuration here. */
"compilerOptions": {
"strict": false
}
}