first commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://docs.cocos.com/creator/manual/en/scripting/setup.html#custom-script-template
|
||||
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal 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
BIN
assets/.DS_Store
vendored
Normal file
Binary file not shown.
14
assets/resources.meta
Normal file
14
assets/resources.meta
Normal 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
BIN
assets/resources/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
assets/resources/ball.png
Normal file
BIN
assets/resources/ball.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 575 B |
134
assets/resources/ball.png.meta
Normal file
134
assets/resources/ball.png.meta
Normal 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"
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/football.fbx
Normal file
BIN
assets/resources/football.fbx
Normal file
Binary file not shown.
113
assets/resources/football.fbx.meta
Normal file
113
assets/resources/football.fbx.meta
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/football_field.fbx
Normal file
BIN
assets/resources/football_field.fbx
Normal file
Binary file not shown.
214
assets/resources/football_field.fbx.meta
Normal file
214
assets/resources/football_field.fbx.meta
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/goal_new4.fbx
Normal file
BIN
assets/resources/goal_new4.fbx
Normal file
Binary file not shown.
263
assets/resources/goal_new4.fbx.meta
Normal file
263
assets/resources/goal_new4.fbx.meta
Normal 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
9
assets/resources/ui.meta
Normal 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
BIN
assets/resources/ui/.DS_Store
vendored
Normal file
Binary file not shown.
239
assets/resources/ui/Preview.prefab
Normal file
239
assets/resources/ui/Preview.prefab
Normal 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
|
||||
}
|
||||
]
|
||||
13
assets/resources/ui/Preview.prefab.meta
Normal file
13
assets/resources/ui/Preview.prefab.meta
Normal 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"
|
||||
}
|
||||
}
|
||||
114
assets/resources/ui/ball.prefab
Normal file
114
assets/resources/ui/ball.prefab
Normal 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
|
||||
}
|
||||
]
|
||||
13
assets/resources/ui/ball.prefab.meta
Normal file
13
assets/resources/ui/ball.prefab.meta
Normal 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"
|
||||
}
|
||||
}
|
||||
114
assets/resources/ui/vibration.prefab
Normal file
114
assets/resources/ui/vibration.prefab
Normal 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
|
||||
}
|
||||
]
|
||||
13
assets/resources/ui/vibration.prefab.meta
Normal file
13
assets/resources/ui/vibration.prefab.meta
Normal 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
9
assets/scene.meta
Normal 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
2702
assets/scene/game.scene
Normal file
File diff suppressed because it is too large
Load Diff
11
assets/scene/game.scene.meta
Normal file
11
assets/scene/game.scene.meta
Normal 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
9
assets/scripts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "d86bbf2e-0f81-47b2-a0ac-8d514c49e8d7",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
133
assets/scripts/BallPhysics.ts
Normal file
133
assets/scripts/BallPhysics.ts
Normal 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();
|
||||
|
||||
// ⚽ 保存 spin(KickInput 设置进来)
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/scripts/BallPhysics.ts.meta
Normal file
9
assets/scripts/BallPhysics.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "3aece382-c6ed-4971-82a0-cf40507368f7",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
32
assets/scripts/CameraRig.ts
Normal file
32
assets/scripts/CameraRig.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
9
assets/scripts/CameraRig.ts.meta
Normal file
9
assets/scripts/CameraRig.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ffb4877f-b15c-46cd-b252-dedbe7540235",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
58
assets/scripts/GameManager.ts
Normal file
58
assets/scripts/GameManager.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
9
assets/scripts/GameManager.ts.meta
Normal file
9
assets/scripts/GameManager.ts.meta
Normal 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
109
assets/scripts/GameMrg.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
9
assets/scripts/GameMrg.ts.meta
Normal file
9
assets/scripts/GameMrg.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "cb6a4184-4c18-405f-8e18-f0d5829517cd",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
19
assets/scripts/GoalDetector.ts
Normal file
19
assets/scripts/GoalDetector.ts
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/scripts/GoalDetector.ts.meta
Normal file
9
assets/scripts/GoalDetector.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "85ff5590-99dd-47f5-8422-0702fc260fb3",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
45
assets/scripts/GoalkeeperAI.ts
Normal file
45
assets/scripts/GoalkeeperAI.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
9
assets/scripts/GoalkeeperAI.ts.meta
Normal file
9
assets/scripts/GoalkeeperAI.ts.meta
Normal 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
172
assets/scripts/KickInput.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
9
assets/scripts/KickInput.ts.meta
Normal file
9
assets/scripts/KickInput.ts.meta
Normal 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
82
assets/scripts/Preview.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/scripts/Preview.ts.meta
Normal file
9
assets/scripts/Preview.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "274524cf-5678-498a-9486-122ab0771b04",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
63
assets/scripts/TrajectoryPreview.ts
Normal file
63
assets/scripts/TrajectoryPreview.ts
Normal 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));
|
||||
}
|
||||
}
|
||||
9
assets/scripts/TrajectoryPreview.ts.meta
Normal file
9
assets/scripts/TrajectoryPreview.ts.meta
Normal 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
132
engine-mangle-config.json
Normal 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
7
package.json
Executable file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "ball",
|
||||
"uuid": "914b0113-8a31-4950-8cf8-b48f4361d291",
|
||||
"creator": {
|
||||
"version": "3.8.6"
|
||||
}
|
||||
}
|
||||
3
settings/v2/packages/builder.json
Normal file
3
settings/v2/packages/builder.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"__version__": "1.3.9"
|
||||
}
|
||||
23
settings/v2/packages/cocos-service.json
Normal file
23
settings/v2/packages/cocos-service.json
Normal 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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
3
settings/v2/packages/device.json
Normal file
3
settings/v2/packages/device.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"__version__": "1.0.1"
|
||||
}
|
||||
234
settings/v2/packages/engine.json
Normal file
234
settings/v2/packages/engine.json
Normal 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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
settings/v2/packages/information.json
Normal file
23
settings/v2/packages/information.json
Normal 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?"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
settings/v2/packages/program.json
Normal file
3
settings/v2/packages/program.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"__version__": "1.0.4"
|
||||
}
|
||||
13
settings/v2/packages/project.json
Normal file
13
settings/v2/packages/project.json
Normal 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
9
tsconfig.json
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user