feat: add builder configuration file
feat: add cocos-service configuration file feat: add device configuration file feat: add engine configuration file feat: add information configuration file feat: add program configuration file feat: add project configuration file feat: add TypeScript configuration file
This commit is contained in:
9
assets/music.meta
Normal file
9
assets/music.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "28332136-19e6-4c1d-8555-e108ef3ab5b2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
BIN
assets/music/bgm2.mp3
Normal file
BIN
assets/music/bgm2.mp3
Normal file
Binary file not shown.
14
assets/music/bgm2.mp3.meta
Normal file
14
assets/music/bgm2.mp3.meta
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"importer": "audio-clip",
|
||||
"imported": true,
|
||||
"uuid": "8cb692c5-0c41-4a9b-b756-e892f17174a9",
|
||||
"files": [
|
||||
".json",
|
||||
".mp3"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"downloadMode": 0
|
||||
}
|
||||
}
|
||||
BIN
assets/music/click.mp3
Normal file
BIN
assets/music/click.mp3
Normal file
Binary file not shown.
14
assets/music/click.mp3.meta
Normal file
14
assets/music/click.mp3.meta
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"importer": "audio-clip",
|
||||
"imported": true,
|
||||
"uuid": "5820b826-c2ed-45b2-a6c0-b4150bcef586",
|
||||
"files": [
|
||||
".json",
|
||||
".mp3"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"downloadMode": 0
|
||||
}
|
||||
}
|
||||
BIN
assets/music/success.mp3
Normal file
BIN
assets/music/success.mp3
Normal file
Binary file not shown.
14
assets/music/success.mp3.meta
Normal file
14
assets/music/success.mp3.meta
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"importer": "audio-clip",
|
||||
"imported": true,
|
||||
"uuid": "535db2a0-6556-4550-825e-31620cae8de0",
|
||||
"files": [
|
||||
".json",
|
||||
".mp3"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"downloadMode": 0
|
||||
}
|
||||
}
|
||||
12
assets/prefab.meta
Normal file
12
assets/prefab.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "689726a6-3b07-4134-8a2e-efab9605bafc",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
9
assets/prefab/game.meta
Normal file
9
assets/prefab/game.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "69e3ca4b-d141-4234-9dd1-f405d9dee36e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/prefab/resNode.meta
Normal file
12
assets/prefab/resNode.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "136ad607-0e1c-4b90-91ca-76da5adabc8b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
117
assets/prefab/resNode/res_main.prefab
Normal file
117
assets/prefab/resNode/res_main.prefab
Normal file
@@ -0,0 +1,117 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "res_main",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "res_main",
|
||||
"_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__": "f5f44OeETZIQbcE4fdL9Jmh",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 3
|
||||
},
|
||||
"SpriteFrameArr": [],
|
||||
"PrefabArr": [
|
||||
{
|
||||
"__uuid__": "9e3c81a2-06f0-455e-8582-70359b348cf8",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
}
|
||||
],
|
||||
"audiosArr": [
|
||||
{
|
||||
"__uuid__": "5820b826-c2ed-45b2-a6c0-b4150bcef586",
|
||||
"__expectedType__": "cc.AudioClip"
|
||||
},
|
||||
{
|
||||
"__uuid__": "8cb692c5-0c41-4a9b-b756-e892f17174a9",
|
||||
"__expectedType__": "cc.AudioClip"
|
||||
},
|
||||
{
|
||||
"__uuid__": "535db2a0-6556-4550-825e-31620cae8de0",
|
||||
"__expectedType__": "cc.AudioClip"
|
||||
}
|
||||
],
|
||||
"MaterialArr": [],
|
||||
"Texture2DArr": [
|
||||
{
|
||||
"__uuid__": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
],
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "a096fKgtdGxJWFFGGAdi8y"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "f8xZbaNcFJS4LctnHRpRy4",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
13
assets/prefab/resNode/res_main.prefab.meta
Normal file
13
assets/prefab/resNode/res_main.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "57d04e5b-f2fe-4c57-945c-c9a9b7f07d78",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "res_main"
|
||||
}
|
||||
}
|
||||
12
assets/prefab/uiPanel.meta
Normal file
12
assets/prefab/uiPanel.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "b775cc71-acaf-4bb6-93e8-4cca0d702eb1",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
1785
assets/prefab/uiPanel/OverUI.prefab
Normal file
1785
assets/prefab/uiPanel/OverUI.prefab
Normal file
File diff suppressed because it is too large
Load Diff
13
assets/prefab/uiPanel/OverUI.prefab.meta
Normal file
13
assets/prefab/uiPanel/OverUI.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "9e3c81a2-06f0-455e-8582-70359b348cf8",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "OverUI"
|
||||
}
|
||||
}
|
||||
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": "19090a79-a429-4a83-a4e2-37e32242724f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"isBundle": true,
|
||||
"bundleConfigID": "default",
|
||||
"bundleName": "resources",
|
||||
"priority": 8
|
||||
}
|
||||
}
|
||||
12
assets/scene.meta
Normal file
12
assets/scene.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "cf0ffdde-f515-4857-8cd7-67ffbb88096f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
1030
assets/scene/MainGame.scene
Normal file
1030
assets/scene/MainGame.scene
Normal file
File diff suppressed because it is too large
Load Diff
11
assets/scene/MainGame.scene.meta
Normal file
11
assets/scene/MainGame.scene.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "scene",
|
||||
"imported": true,
|
||||
"uuid": "0401497c-b8be-4d0f-a5dd-55ed73f46146",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script.meta
Normal file
12
assets/script.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "bf2d81e3-8bc8-4e82-9ec5-d0cdf57a27d4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
9
assets/script/QuickTween.meta
Normal file
9
assets/script/QuickTween.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "33cb078c-e75a-4d19-86e6-9b12cd55b22e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
408
assets/script/QuickTween/QuickTween.ts
Normal file
408
assets/script/QuickTween/QuickTween.ts
Normal file
@@ -0,0 +1,408 @@
|
||||
|
||||
import { Component, Node, Vec3, tween, Quat, Sprite, Color, math, easing, Camera, ITweenOption, IPunchTweenOption, IShakeTweenOption, Label } from 'cc';
|
||||
import { calcPunchData, calcShakeData, quadraticCurve } from './Util';
|
||||
|
||||
//////////////////////
|
||||
// Transform
|
||||
//////////////////////
|
||||
Node.prototype.qtPosition = function (to: Vec3, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { position: to }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtPositionX = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startPos = this.position;
|
||||
return tween(this).to(duration, { position: new Vec3(to, startPos.y, startPos.z) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtPositionY = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startPos = this.position;
|
||||
return tween(this).to(duration, { position: new Vec3(startPos.x, to, startPos.z) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtPositionZ = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startPos = this.position;
|
||||
return tween(this).to(duration, { position: new Vec3(startPos.x, startPos.y, to) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtWorldPosition = function (to: Vec3, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { worldPosition: to }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtWorldPositionX = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startPos = this.worldPosition;
|
||||
return tween(this).to(duration, { worldPosition: new Vec3(to, startPos.y, startPos.z) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtWorldPositionY = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startPos = this.worldPosition;
|
||||
return tween(this).to(duration, { worldPosition: new Vec3(startPos.x, to, startPos.z) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtWorldPositionZ = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startPos = this.worldPosition;
|
||||
return tween(this).to(duration, { worldPosition: new Vec3(startPos.x, startPos.y, to) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtRotation = function (to: Vec3, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { eulerAngles: to }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtRotationQuat = function (to: Quat, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { rotation: to }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtScale = function (to: Vec3 | number, duration: number, opts?: ITweenOption) {
|
||||
let toScale = to;
|
||||
if (!(to instanceof Vec3)) {
|
||||
toScale = new Vec3(to, to, to);
|
||||
}
|
||||
|
||||
return tween(this).to(duration, { scale: toScale }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtScaleX = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startScale = this.scale;
|
||||
return tween(this).to(duration, { scale: new Vec3(to, startScale.y, startScale.z) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtScaleY = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startScale = this.scale;
|
||||
return tween(this).to(duration, { scale: new Vec3(startScale.x, to, startScale.z) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtScaleZ = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startScale = this.scale;
|
||||
return tween(this).to(duration, { scale: new Vec3(startScale.x, startScale.y, to) }, opts);
|
||||
}
|
||||
|
||||
Node.prototype.qtPunchPosition = function (punch: Vec3, duration: number, opts?: IPunchTweenOption) {
|
||||
const vibrato = opts?.vibrato ?? 3;
|
||||
const elasticity = opts?.elasticity ?? 0.5;
|
||||
const { tos, durations } = calcPunchData(this.position.clone(), punch, duration, vibrato, elasticity);
|
||||
|
||||
const punchTween = tween(this);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: opts.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: opts.onComplete
|
||||
}
|
||||
}
|
||||
punchTween.then(tween().to(d, { position: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return punchTween.union();
|
||||
}
|
||||
|
||||
Node.prototype.qtPunchRotation = function (punch: Vec3, duration: number, opts?: IPunchTweenOption) {
|
||||
const vibrato = opts?.vibrato ?? 3;
|
||||
const elasticity = opts?.elasticity ?? 0.5;
|
||||
const { tos, durations } = calcPunchData(this.rotation.clone(), punch, duration, vibrato, elasticity);
|
||||
|
||||
const punchTween = tween(this);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: opts.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: opts.onComplete
|
||||
}
|
||||
}
|
||||
punchTween.then(tween().to(d, { eulerAngles: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return punchTween.union();
|
||||
}
|
||||
|
||||
Node.prototype.qtPunchScale = function (punch: Vec3, duration: number, opts?: IPunchTweenOption) {
|
||||
const vibrato = opts?.vibrato ?? 3;
|
||||
const elasticity = opts?.elasticity ?? 0.5;
|
||||
const { tos, durations } = calcPunchData(this.scale.clone(), punch, duration, vibrato, elasticity);
|
||||
|
||||
const punchTween = tween(this);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: opts.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: opts.onComplete
|
||||
}
|
||||
}
|
||||
punchTween.then(tween().to(d, { scale: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return punchTween.union();
|
||||
}
|
||||
|
||||
Node.prototype.qtJumpPosition = function (to: Vec3, jumpHeight: number, jumpNum: number, duration: number, opts?: ITweenOption) {
|
||||
const tweenPos = new Vec3();
|
||||
const jumpTween = tween(this);
|
||||
const totalNum = jumpNum * 2;
|
||||
|
||||
// 初始化选项对象,确保即使没有传入选项也不会出错
|
||||
const options = opts || {};
|
||||
|
||||
this.jumpY = 0;
|
||||
let startPosY = 0;
|
||||
const yUpTween = tween().to(duration / totalNum, { jumpY: jumpHeight }, {
|
||||
onStart: (target: Node) => {
|
||||
startPosY = target.position.y;
|
||||
target.jumpY = 0;
|
||||
},
|
||||
onUpdate: (target: Node, ratio) => {
|
||||
tweenPos.set(target.position);
|
||||
tweenPos.y = startPosY + target.jumpY;
|
||||
target.position = tweenPos;
|
||||
},
|
||||
onComplete: (target: Node) => {
|
||||
target.jumpY = 0;
|
||||
}, easing: 'quadOut'
|
||||
}).to(duration / totalNum, { jumpY: jumpHeight }, {
|
||||
onStart: (target: Node) => {
|
||||
startPosY = target.position.y;
|
||||
},
|
||||
onUpdate: (target: Node, ratio) => {
|
||||
tweenPos.set(target.position);
|
||||
tweenPos.y = startPosY - target.jumpY;
|
||||
target.position = tweenPos;
|
||||
},
|
||||
onComplete: (target: Node) => {
|
||||
target.jumpY = 0;
|
||||
}, easing: 'quadIn',
|
||||
}).union().repeat(jumpNum);
|
||||
|
||||
this.jumpOffsetY = 0;
|
||||
let offsetY = 0;
|
||||
const offsetYTween = tween().to(duration, { jumpOffsetY: to.y - this.position.y }, {
|
||||
onStart: (target: Node) => {
|
||||
offsetY = to.y - target.position.y;
|
||||
target.jumpOffsetY = 0;
|
||||
},
|
||||
onUpdate: (target: Node, ratio) => {
|
||||
const interpOffsetY = easing.quadOut(ratio) * offsetY;
|
||||
tweenPos.set(target.position);
|
||||
tweenPos.y += interpOffsetY;
|
||||
target.position = tweenPos;
|
||||
},
|
||||
onComplete: (target: Node) => {
|
||||
target.jumpOffsetY = 0;
|
||||
}, easing: 'quadOut'
|
||||
});
|
||||
|
||||
this.jumpX = this.position.x;
|
||||
this.jumpZ = this.position.z;
|
||||
const xzTween = tween().to(duration, { jumpX: to.x, jumpZ: to.z }, {
|
||||
// 使用可选链运算符或者默认值
|
||||
onStart: options.onStart,
|
||||
onUpdate: (target: Node, ratio) => {
|
||||
tweenPos.set(target.position);
|
||||
tweenPos.x = target.jumpX;
|
||||
tweenPos.z = target.jumpZ;
|
||||
target.position = tweenPos;
|
||||
options.onUpdate?.();
|
||||
},
|
||||
onComplete: (target: Node) => {
|
||||
// delete target.jumpX;
|
||||
// delete target.jumpY;
|
||||
// delete target.jumpZ;
|
||||
// delete target.jumpOffsetY;
|
||||
target.jumpX = target.position.x;
|
||||
target.jumpZ = target.position.z;
|
||||
options.onComplete?.();
|
||||
}
|
||||
})
|
||||
|
||||
jumpTween.parallel(yUpTween, offsetYTween, xzTween);
|
||||
return jumpTween;
|
||||
}
|
||||
|
||||
Node.prototype.qtShakePosition = function (strength: Vec3 | number, duration: number, opts?: IShakeTweenOption) {
|
||||
const options = opts || {};
|
||||
|
||||
const vibrato = options?.vibrato ?? 10;
|
||||
const randomness = options?.randomness ?? 90;
|
||||
const fadeOut = options?.fadeOut ?? true;
|
||||
let toStrength: Vec3;
|
||||
let vectorBased = false;
|
||||
if (!(strength instanceof Vec3)) {
|
||||
toStrength = new Vec3(strength, strength, strength);
|
||||
} else {
|
||||
toStrength = strength;
|
||||
vectorBased = true;
|
||||
}
|
||||
const { tos, durations } = calcShakeData(this.position.clone(), duration, toStrength, vibrato, randomness, false, vectorBased, fadeOut)
|
||||
const shakeTween = tween(this);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: options.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: options.onComplete
|
||||
}
|
||||
}
|
||||
shakeTween.then(tween().to(d, { position: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return shakeTween.union();
|
||||
}
|
||||
|
||||
Node.prototype.qtShakeRotation = function (strength: Vec3 | number, duration: number, opts?: IShakeTweenOption) {
|
||||
const vibrato = opts?.vibrato ?? 10;
|
||||
const randomness = opts?.randomness ?? 90;
|
||||
const fadeOut = opts?.fadeOut ?? true;
|
||||
let toStrength: Vec3;
|
||||
let vectorBased = false;
|
||||
if (!(strength instanceof Vec3)) {
|
||||
toStrength = new Vec3(strength, strength, strength);
|
||||
} else {
|
||||
toStrength = strength;
|
||||
vectorBased = true;
|
||||
}
|
||||
const { tos, durations } = calcShakeData(this.eulerAngles.clone(), duration, toStrength, vibrato, randomness, false, vectorBased, fadeOut)
|
||||
const shakeTween = tween(this);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: opts.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: opts.onComplete
|
||||
}
|
||||
}
|
||||
shakeTween.then(tween().to(d, { eulerAngles: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return shakeTween.union();
|
||||
}
|
||||
|
||||
Node.prototype.qtShakeScale = function (strength: Vec3 | number, duration: number, opts?: IShakeTweenOption) {
|
||||
const vibrato = opts?.vibrato ?? 10;
|
||||
const randomness = opts?.randomness ?? 90;
|
||||
const fadeOut = opts?.fadeOut ?? true;
|
||||
let toStrength: Vec3;
|
||||
let vectorBased = false;
|
||||
if (!(strength instanceof Vec3)) {
|
||||
toStrength = new Vec3(strength, strength, strength);
|
||||
} else {
|
||||
toStrength = strength;
|
||||
vectorBased = true;
|
||||
}
|
||||
const { tos, durations } = calcShakeData(this.scale.clone(), duration, toStrength, vibrato, randomness, false, vectorBased, fadeOut)
|
||||
const shakeTween = tween(this);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: opts.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: opts.onComplete
|
||||
}
|
||||
}
|
||||
shakeTween.then(tween().to(d, { scale: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return shakeTween.union();
|
||||
}
|
||||
|
||||
Node.prototype.qtQuadraticCurve = function (p1: Vec3, cp: Vec3, p2: Vec3, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { position: p2, easing: opts?.easing }, {
|
||||
onUpdate(target, ratio) {
|
||||
target.setPosition(quadraticCurve(ratio, p1, cp, p2));
|
||||
},
|
||||
onComplete: opts?.onComplete,
|
||||
onStart: opts?.onStart
|
||||
}).union();
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Sprite
|
||||
//////////////////////
|
||||
// good color lerp
|
||||
// https://www.alanzucconi.com/2016/01/06/colour-interpolation/
|
||||
Sprite.prototype.qtColor = function (to: Color, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { color: to }, opts);
|
||||
}
|
||||
|
||||
Sprite.prototype.qtOpacity = function (to: number, duration: number, opts?: ITweenOption) {
|
||||
const startColor = this.color.clone();
|
||||
const tempColor = new Color();
|
||||
return tween(this).to(duration, { color: new Color(startColor.r, startColor.g, startColor.b, to) }, {
|
||||
onStart: opts.onStart,
|
||||
onUpdate: (target: { _val: number }, ratio: number) => {
|
||||
const lerpA = startColor.a + (to - startColor.a) * ratio
|
||||
tempColor.set(startColor.r, startColor.g, startColor.b, lerpA);
|
||||
this.color = tempColor;
|
||||
opts.onUpdate?.();
|
||||
},
|
||||
onComplete: opts.onComplete
|
||||
});
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Label
|
||||
//////////////////////
|
||||
Label.prototype.qtColor = function (to: Color, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { color: to }, opts);
|
||||
}
|
||||
|
||||
Label.prototype.qtString = function (to: string, duration: number, opts?: ITweenOption) {
|
||||
return tween(this).to(duration, { string: to }, opts);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Camera
|
||||
//////////////////////
|
||||
Camera.prototype.qtShakePosition = function (strength: Vec3 | number, duration: number, opts?: IShakeTweenOption) {
|
||||
const vibrato = opts?.vibrato ?? 10;
|
||||
const randomness = opts?.randomness ?? 90;
|
||||
const fadeOut = opts?.fadeOut ?? true;
|
||||
let toStrength: Vec3;
|
||||
let vectorBased = false;
|
||||
if (!(strength instanceof Vec3)) {
|
||||
toStrength = new Vec3(strength, strength, strength);
|
||||
} else {
|
||||
toStrength = strength;
|
||||
vectorBased = true;
|
||||
}
|
||||
const { tos, durations } = calcShakeData(this.node.position.clone(), duration, toStrength, vibrato, randomness, true, vectorBased, fadeOut)
|
||||
const shakeTween = tween(this.node);
|
||||
tos.forEach((to, index) => {
|
||||
const d = durations[index];
|
||||
let tweenOpts: ITweenOption | undefined;
|
||||
if (index === 0) {
|
||||
tweenOpts = {
|
||||
onStart: opts.onStart
|
||||
}
|
||||
} else if (index === tos.length - 1) {
|
||||
tweenOpts = {
|
||||
onComplete: opts.onComplete
|
||||
}
|
||||
}
|
||||
shakeTween.then(tween().to(d, { position: to }, tweenOpts));
|
||||
});
|
||||
|
||||
return shakeTween.union();
|
||||
}
|
||||
9
assets/script/QuickTween/QuickTween.ts.meta
Normal file
9
assets/script/QuickTween/QuickTween.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "7068ad06-e307-495f-befa-d9239208e9f1",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
160
assets/script/QuickTween/Util.ts
Normal file
160
assets/script/QuickTween/Util.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import { KeyCode, math, Quat, Vec3 } from "cc";
|
||||
|
||||
export function clampLength(vec: Vec3, maxLength: number) {
|
||||
if (vec.lengthSqr() > maxLength * maxLength) {
|
||||
const clampVec = new Vec3();
|
||||
Vec3.normalize(clampVec, vec);
|
||||
clampVec.multiplyScalar(maxLength);
|
||||
return clampVec;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
export function vec3FromAngle(degree: number, length: number) {
|
||||
const radian = math.toRadian(degree);
|
||||
return new Vec3(length * Math.cos(radian), length * Math.sin(radian), 0);
|
||||
}
|
||||
|
||||
export function calcPunchData(start: Vec3, direction: Vec3, duration: number, vibrato: number, elasticity: number) {
|
||||
math.clamp01(elasticity);
|
||||
let strength = direction.length();
|
||||
let toIterations = Math.round(vibrato * duration);
|
||||
if (toIterations < 2) {
|
||||
toIterations = 2;
|
||||
}
|
||||
|
||||
const deltaStrength = strength / toIterations;
|
||||
|
||||
let durations = [];
|
||||
let sum = 0;
|
||||
for (let i = 0; i < toIterations; i++) {
|
||||
const iterationPercent = (i + 1) / toIterations;
|
||||
const deltaDuration = duration * iterationPercent;
|
||||
sum += deltaDuration;
|
||||
durations[i] = deltaDuration;
|
||||
}
|
||||
|
||||
const durationMultiplier = duration / sum;
|
||||
durations = durations.map((d) => d * durationMultiplier);
|
||||
|
||||
// create to vec3 array
|
||||
const tos: Vec3[] = [];
|
||||
for (let i = 0; i < toIterations; i++) {
|
||||
if (i < toIterations - 1) {
|
||||
if (i === 0) {
|
||||
tos[i] = Vec3.add(new Vec3(), start, direction);
|
||||
} else if (i % 2 !== 0) {
|
||||
const deltaVec = clampLength(direction, strength * elasticity);
|
||||
deltaVec.negative();
|
||||
tos[i] = deltaVec.add(start);
|
||||
} else {
|
||||
const deltaVec = clampLength(direction, strength);
|
||||
tos[i] = deltaVec.add(start);
|
||||
}
|
||||
} else {
|
||||
tos[i] = start;
|
||||
}
|
||||
|
||||
strength -= deltaStrength;
|
||||
}
|
||||
|
||||
return {
|
||||
tos,
|
||||
durations
|
||||
}
|
||||
}
|
||||
|
||||
export function calcShakeData(start: Vec3, duration: number, strength: Vec3, vibrato: number, randomness: number, ignoreZAxis: boolean, vectorBased: boolean,
|
||||
fadeOut: boolean) {
|
||||
KeyCode
|
||||
let shakeLength = vectorBased ? strength.length() : strength.x;
|
||||
let toIterations = Math.floor(vibrato * duration);
|
||||
if (toIterations < 2) {
|
||||
toIterations = 2;
|
||||
}
|
||||
const deltaShakeLen = shakeLength / toIterations;
|
||||
let durations = [];
|
||||
let sum = 0;
|
||||
for (let i = 0; i < toIterations; i++) {
|
||||
const iterationPercent = (i + 1) / toIterations;
|
||||
const deltaDuration = fadeOut ? duration * iterationPercent : duration / toIterations;
|
||||
sum += deltaDuration;
|
||||
durations[i] = deltaDuration;
|
||||
}
|
||||
|
||||
const durationMultiplier = duration / sum;
|
||||
durations = durations.map((d) => d * durationMultiplier);
|
||||
|
||||
let angle = math.randomRange(0, 360);
|
||||
const tos: Vec3[] = [];
|
||||
|
||||
for (let i = 0; i < toIterations; i++) {
|
||||
if (i < toIterations - 1) {
|
||||
let randQuat = new Quat();
|
||||
if (i > 0) {
|
||||
angle = angle - 180 + math.randomRange(-randomness, randomness);
|
||||
}
|
||||
// switch(randomnessMode) {
|
||||
// case ShakeRandomnessMode.Harmonic:
|
||||
// if (i > 0) {
|
||||
// angle = angle - 180 + math.randomRange(0, randomness);
|
||||
// }
|
||||
// if (vectorBased || !ignoreZAxis) {
|
||||
// Quat.fromAxisAngle(randQuat, Vec3.UP, math.randomRange(0, randomness));
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// if (i > 0) {
|
||||
// angle = angle - 180 + math.randomRange(-randomness, randomness);
|
||||
// }
|
||||
// if (vectorBased || !ignoreZAxis) {
|
||||
// Quat.fromAxisAngle(randQuat, Vec3.UP, math.randomRange(-randomness, randomness));
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
if (vectorBased) {
|
||||
let to = vec3FromAngle(angle, shakeLength);
|
||||
Vec3.transformQuat(to, to, randQuat);
|
||||
to.x = clampLength(to, strength.x).x;
|
||||
to.y = clampLength(to, strength.y).y;
|
||||
to.z = clampLength(to, strength.z).z;
|
||||
to.normalize().multiplyScalar(shakeLength);
|
||||
tos[i] = to.add(start);
|
||||
if (fadeOut) {
|
||||
shakeLength -= deltaShakeLen;
|
||||
}
|
||||
strength = clampLength(strength, shakeLength);
|
||||
} else {
|
||||
if (ignoreZAxis) {
|
||||
tos[i] = vec3FromAngle(angle, shakeLength).add(start);
|
||||
} else {
|
||||
Quat.fromAxisAngle(randQuat, Vec3.UP, math.randomRange(-randomness, randomness));
|
||||
let to = vec3FromAngle(angle, shakeLength);
|
||||
Vec3.transformQuat(to, to, randQuat);
|
||||
tos[i] = to.add(start);
|
||||
}
|
||||
|
||||
if (fadeOut) {
|
||||
shakeLength -= deltaShakeLen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tos[i] = start;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tos,
|
||||
durations
|
||||
}
|
||||
}
|
||||
|
||||
export function quadraticCurve(t: number, p1: Vec3, cp: Vec3, p2: Vec3) {
|
||||
let out = new Vec3(0, 0, 0);
|
||||
out.x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x;
|
||||
out.y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y;
|
||||
out.z = (1 - t) * (1 - t) * p1.z + 2 * t * (1 - t) * cp.z + t * t * p2.z;
|
||||
return out;
|
||||
}
|
||||
9
assets/script/QuickTween/Util.ts.meta
Normal file
9
assets/script/QuickTween/Util.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "9d1ed435-17ef-4b92-9fd9-391c112c8f2a",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
310
assets/script/QuickTween/quick-tween.d.ts
vendored
Normal file
310
assets/script/QuickTween/quick-tween.d.ts
vendored
Normal file
@@ -0,0 +1,310 @@
|
||||
declare module 'cc' {
|
||||
|
||||
interface IPunchTweenOption extends ITweenOption {
|
||||
// How much the punch will vibrate
|
||||
vibrato?: number,
|
||||
// Represents how much (0 to 1) the vector will go beyond the starting position
|
||||
// when bouncing backwards. 1 creates a full oscillation between the punch direction and the
|
||||
// opposite direction, while 0 oscillates only between the punch and the start scale.
|
||||
elasticity?: number
|
||||
}
|
||||
|
||||
interface IShakeTweenOption extends ITweenOption {
|
||||
vibrato?: number //每秒振动次数
|
||||
randomness?: number // 随机角度值
|
||||
fadeOut?: boolean // 是否淡出
|
||||
}
|
||||
|
||||
interface Node {
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的坐标到指定位置
|
||||
* @en
|
||||
* Moves the target's position to the given value
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param {ITweenOption} opts options for tween
|
||||
* @param {Function} opts.onStart start callback
|
||||
*/
|
||||
qtPosition(to: Vec3, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的坐标到指定位置, 只移动X坐标
|
||||
* @en
|
||||
* Moves the target's position to the given value, tweening only the X axis.
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtPositionX(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的坐标到指定位置, 只移动Y坐标
|
||||
* @en
|
||||
* Moves the target's position to the given value, tweening only the Y axis.
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtPositionY(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的坐标到指定位置, 只移动Z坐标
|
||||
* @en
|
||||
* Moves the target's position to the given value, tweening only the Z axis.
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtPositionZ(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的世界坐标到指定位置
|
||||
* @en
|
||||
* Moves the target's worldPosition to the given value
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtWorldPosition(to: Vec3, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的世界坐标到指定位置, 只移动X坐标
|
||||
* @en
|
||||
* Moves the target's worldPosition to the given value, tweening only the X axis.
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtWorldPositionX(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的世界坐标到指定位置, 只移动Y坐标
|
||||
* @en
|
||||
* Moves the target's worldPosition to the given value, tweening only the Y axis.
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtWorldPositionY(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 移动目标的世界坐标到指定位置, 只移动Z坐标
|
||||
* @en
|
||||
* Moves the target's worldPosition to the given value, tweening only the Z axis.
|
||||
* @param to dest position
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtWorldPositionZ(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 旋转目标到指定值
|
||||
* @en
|
||||
* Rotates the target to ghe given value
|
||||
* @param to dest rotation in eulerAngle
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtRotation(to: Vec3, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 旋转目标到指定值
|
||||
* @en
|
||||
* Rotates the target to ghe given value
|
||||
* @param to dest rotation in quaternion
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtRotationQuat(to: Quat, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 缩放目标到指定值
|
||||
* @en
|
||||
* Scales the target to ghe given value
|
||||
* @param to dest scale value
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtScale(to: Vec3 | number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 缩放目标到指定值,只影响X轴
|
||||
* @en
|
||||
* Scales the target to ghe given value, tweening only X axis
|
||||
* @param to dest scale value
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtScaleX(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 缩放目标到指定值,只影响Y轴
|
||||
* @en
|
||||
* Scales the target to ghe given value, tweening only Y axis
|
||||
* @param to dest scale value
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtScaleY(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
/**
|
||||
* @zh
|
||||
* 缩放目标到指定值,只影响Z轴
|
||||
* @en
|
||||
* Scales the target to ghe given value, tweening only Z axis
|
||||
* @param to dest scale value
|
||||
* @param duration time in seconds
|
||||
* @param opts options for tween
|
||||
*/
|
||||
qtScaleZ(to: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 击打目标位置到指定方向,然后回到初始值
|
||||
* @en
|
||||
* Punches a position towards the given direction and then
|
||||
* back to the starting one as if it was connected to the starting position
|
||||
* via an elastic.
|
||||
* @param punch The direction and strength of the punch, (added to the node's current position)
|
||||
* @param duration Time in seconds
|
||||
* @param {IPunchTweenOption} opts punch tween options
|
||||
* @param {number} opts.vibrato How much the punch will vibrate
|
||||
* @param {number} opts.elasticity Represents how much (0 to 1) the vector will go beyond the starting position
|
||||
* when bouncing backwards. 1 creates a full oscillation between the punch direction and the
|
||||
* opposite direction, while 0 oscillates only between the punch and the start position.
|
||||
*/
|
||||
qtPunchPosition(punch: Vec3, duration: number, opts?: IPunchTweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 击打目标旋转方向到指定值,然后回到初始值
|
||||
* @en
|
||||
* Punches a rotation to the given value and then back to the starting one as if it was connected
|
||||
* to the starting rotation via an elastic.
|
||||
* @param punch The strength of punch, (added to the node's current rotation)
|
||||
* @param duration Time in seconds
|
||||
* @param {IPunchTweenOption} opts punch tween options
|
||||
* @param {number} opts.vibrato How much the punch will vibrate
|
||||
* @param {number} opts.elasticity Represents how much (0 to 1) the vector will go beyond the starting position
|
||||
* when bouncing backwards. 1 creates a full oscillation between the punch direction and the
|
||||
* opposite direction, while 0 oscillates only between the punch and the start rotation.
|
||||
*/
|
||||
qtPunchRotation(punch: Vec3, duration: number, opts?: IPunchTweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 击打目标缩放到指定值,然后回到初始值
|
||||
* @en
|
||||
* Punches a scale to the given value and then back to the starting one as if it was connected
|
||||
* to the starting scale via an elastic.
|
||||
* @param punch The strength of punch, (added to the node's current scale)
|
||||
* @param duration Time in seconds
|
||||
* @param {IPunchTweenOption} opts punch tween options
|
||||
* @param {number} opts.vibrato How much the punch will vibrate
|
||||
* @param {number} opts.elasticity Represents how much (0 to 1) the vector will go beyond the starting position
|
||||
* when bouncing backwards. 1 creates a full oscillation between the punch direction and the
|
||||
* opposite direction, while 0 oscillates only between the punch and the start scale.
|
||||
*/
|
||||
qtPunchScale(punch: Vec3, duration: number, opts?: IPunchTweenOption): Tween<Node>;
|
||||
|
||||
jumpX?: number;
|
||||
jumpY?: number;
|
||||
jumpZ?: number;
|
||||
jumpOffsetY?: number;
|
||||
/**
|
||||
* @zh
|
||||
* 缓动目标的坐标到指定值,在移动过程中同时附加一个Y坐标的高度值来模拟跳跃动作
|
||||
* @en
|
||||
* Tweens the target's position to the given value, while also applying a jump effect along the Y axis.
|
||||
* @param to 目标坐标值
|
||||
* @param jumpHeight 跳跃高度
|
||||
* @param jumpNum 跳跃次数
|
||||
* @param duration 时间
|
||||
* @param opts tween options
|
||||
*/
|
||||
qtJumpPosition(to: Vec3, jumpHeight: number, jumpNum: number, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 使目标的位置在设定的参数下抖动
|
||||
* @en
|
||||
* Shakes the target's position with the given values
|
||||
* @param strength 强度
|
||||
* @param duration 时间
|
||||
* @param {IShakeTweenOption} opts shake tween options
|
||||
* @param {number} opts.vibrato 每秒振动次数
|
||||
* @param {number} opts.randomness 随机角度值
|
||||
* @param {boolean} opts.fadeOut 是否淡出
|
||||
*/
|
||||
qtShakePosition(strength: Vec3 | number, duration: number, opts?: IShakeTweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 使目标的旋转在设定的参数下抖动
|
||||
* @en
|
||||
* Shakes the target's rotation with the given values
|
||||
* @param strength 强度
|
||||
* @param duration 时间
|
||||
* @param {IShakeTweenOption} opts shake tween options
|
||||
* @param {number} opts.vibrato 每秒振动次数
|
||||
* @param {number} opts.randomness 随机角度值
|
||||
* @param {boolean} opts.fadeOut 是否淡出
|
||||
*/
|
||||
qtShakeRotation(strength: Vec3 | number, duration: number, opts?: IShakeTweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 使目标的缩放在设定的参数下抖动
|
||||
* @en
|
||||
* Shakes the target's scale with the given values
|
||||
* @param strength 强度
|
||||
* @param duration 时间
|
||||
* @param {IShakeTweenOption} opts shake tween options
|
||||
* @param {number} opts.vibrato 每秒振动次数
|
||||
* @param {number} opts.randomness 随机角度值
|
||||
* @param {boolean} opts.fadeOut 是否淡出
|
||||
*/
|
||||
qtShakeScale(strength: Vec3 | number, duration: number, opts?: IShakeTweenOption): Tween<Node>;
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 缓动目标的坐标到指定值,使用二次贝塞尔曲线
|
||||
* @en
|
||||
* Tweens the target's position to the given value, using a quadratic Bezier curve.
|
||||
* @param p1 起点
|
||||
* @param cp 控制点
|
||||
* @param p2 终点
|
||||
* @param duration 时间
|
||||
* @param opts tween options
|
||||
*/
|
||||
qtQuadraticCurve(p1: Vec3, cp: Vec3, p2: Vec3, duration: number, opts?: ITweenOption): Tween<Node>;
|
||||
}
|
||||
|
||||
interface Sprite {
|
||||
qtColor(to: Color, duration: number, opts?: ITweenOption): Tween<Sprite>;
|
||||
qtOpacity(to: number, duration: number, opts?: ITweenOption): Tween<Sprite>;
|
||||
}
|
||||
|
||||
interface Label extends Omit<UIRenderer, 'spriteFrame'> {
|
||||
//@ts-expect-error
|
||||
spriteFrame: SpriteFrame | null;
|
||||
qtColor(to: Color, duration: number, opts?: ITweenOption): Tween<Label>;
|
||||
qtString(to: string, duration: number, opts?: ITweenOption): Tween<Label>;
|
||||
}
|
||||
|
||||
interface Camera {
|
||||
/**
|
||||
* @zh
|
||||
* 使目标的位置在设定的参数下抖动
|
||||
* @en
|
||||
* Shakes the target's position with the given values
|
||||
* @param strength 强度
|
||||
* @param duration 时间
|
||||
* @param {IShakeTweenOption} opts shake tween options
|
||||
* @param {number} opts.vibrato 每秒振动次数
|
||||
* @param {number} opts.randomness 随机角度值
|
||||
* @param {boolean} opts.fadeOut 是否淡出
|
||||
*/
|
||||
qtShakePosition(strength: Vec3 | number, duration: number, opts?: IShakeTweenOption): Tween<Node>;
|
||||
}
|
||||
}
|
||||
9
assets/script/QuickTween/quick-tween.d.ts.meta
Normal file
9
assets/script/QuickTween/quick-tween.d.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "af3336d7-4ce2-4d9d-a529-51281d4eaa30",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
assets/script/SplitRender.meta
Normal file
9
assets/script/SplitRender.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "c2d2e44a-ed28-4c85-ba6d-af272f33815c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
325
assets/script/SplitRender/SplitRender.ts
Normal file
325
assets/script/SplitRender/SplitRender.ts
Normal file
@@ -0,0 +1,325 @@
|
||||
import { SplitRenderHelper } from "./SplitRenderHelper";
|
||||
import { _decorator, Node, Vec3, IAssembler, ccenum, Vec2, Mat4, Texture2D, v2, v3, EventTouch, gfx, SpriteFrame, UIRenderer } from 'cc';
|
||||
|
||||
const { ccclass, property, executeInEditMode } = _decorator;
|
||||
|
||||
const vec3_temps: Vec3[] = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
vec3_temps.push(new Vec3());
|
||||
}
|
||||
|
||||
class AssemblerSplit implements IAssembler {
|
||||
createData(com: SplitRender) {
|
||||
let vertexCount = 4;
|
||||
let indexCount = 6;
|
||||
|
||||
const renderData = com.requestRenderData();
|
||||
renderData.dataLength = vertexCount;
|
||||
renderData.resize(vertexCount, indexCount);
|
||||
return renderData;
|
||||
}
|
||||
|
||||
resetData(com: SplitRender) {
|
||||
let points = com.polygon;
|
||||
if (!points || points.length < 3) return;
|
||||
|
||||
let vertexCount = points.length;
|
||||
let indexCount = vertexCount + (vertexCount - 3) * 2;
|
||||
|
||||
com.renderData.clear();
|
||||
com.renderData.dataLength = vertexCount;
|
||||
com.renderData.resize(vertexCount, indexCount);
|
||||
|
||||
let material = com.renderData.material;
|
||||
com.renderData.material = material;
|
||||
}
|
||||
|
||||
updateRenderData(com: SplitRender) {
|
||||
// dynamicAtlasManager.packToDynamicAtlas(com, frame);
|
||||
const renderData = com.renderData;
|
||||
if (renderData.vertDirty) {
|
||||
this.resetData(com);
|
||||
this.updateVertexData(com);
|
||||
this.updateUvs(com);
|
||||
this.updateColor(com);
|
||||
renderData.updateRenderData(com, com.spriteFrame);
|
||||
}
|
||||
}
|
||||
|
||||
updateWorldVerts(com: SplitRender, verts: Float32Array) {
|
||||
let floatsPerVert = 9;
|
||||
|
||||
let matrix: Mat4 = com.node.worldMatrix;
|
||||
let a = matrix.m00, b = matrix.m01, c = matrix.m04, d = matrix.m05,
|
||||
tx = matrix.m12, ty = matrix.m13;
|
||||
|
||||
let justTranslate = a === 1 && b === 0 && c === 0 && d === 1;
|
||||
if (justTranslate) {
|
||||
let polygon = com.polygon;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
verts[i * floatsPerVert] = polygon[i].x + tx;
|
||||
verts[i * floatsPerVert + 1] = polygon[i].y + ty;
|
||||
}
|
||||
} else {
|
||||
let polygon = com.polygon;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
verts[i * floatsPerVert] = a * polygon[i].x + c * polygon[i].y + tx;
|
||||
verts[i * floatsPerVert + 1] = b * polygon[i].x + d * polygon[i].y + ty;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
com.node._uiProps.uiTransformDirty = false;
|
||||
}
|
||||
|
||||
fillBuffers(com: SplitRender, renderer: any) {
|
||||
const chunk = com.renderData.chunk;
|
||||
// indices generated
|
||||
let indicesArr = SplitRenderHelper.splitPolygon(com.polygon);
|
||||
this.updateWorldVerts(com, chunk.vb);
|
||||
|
||||
// quick version
|
||||
const bid = chunk.bufferId;
|
||||
const vid = chunk.vertexOffset;
|
||||
const meshBuffer = chunk.vertexAccessor.getMeshBuffer(bid);
|
||||
const ib = chunk.vertexAccessor.getIndexBuffer(bid);
|
||||
let indexOffset = meshBuffer.indexOffset;
|
||||
|
||||
// fill indices
|
||||
for (let i = 0, l = indicesArr.length; i < l; i++) {
|
||||
ib[indexOffset++] = vid + indicesArr[i];
|
||||
}
|
||||
meshBuffer.indexOffset += indicesArr.length;
|
||||
}
|
||||
|
||||
updateVertexData(com: SplitRender) {
|
||||
const renderData = com.renderData;
|
||||
if (!renderData) {
|
||||
return;
|
||||
}
|
||||
const dataList = renderData.data;
|
||||
|
||||
let polygon = com.polygon;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
dataList[i].x = polygon[i].x;
|
||||
dataList[i].y = polygon[i].y;
|
||||
}
|
||||
|
||||
const chunk = com.renderData.chunk;
|
||||
const vid = chunk.vertexOffset;
|
||||
const ib = chunk.ib as any;
|
||||
|
||||
let indicesArr = SplitRenderHelper.splitPolygon(com.polygon);
|
||||
for (let i = 0, l = indicesArr.length; i < l; i++) {
|
||||
ib[i] = vid + indicesArr[i];
|
||||
}
|
||||
}
|
||||
|
||||
updateUvs(com: SplitRender) {
|
||||
let uvOffset = 3, floatsPerVert = 9;
|
||||
const vData = com.renderData.chunk.vb;
|
||||
|
||||
let uvs = [];
|
||||
if (com.spriteFrame.texture) {
|
||||
uvs = SplitRenderHelper.computeUv(com.polygon, com.spriteFrame.texture.width, com.spriteFrame.texture.height)
|
||||
}
|
||||
|
||||
let polygon = com.polygon;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
vData[uvOffset] = uvs[i].x;
|
||||
vData[uvOffset + 1] = uvs[i].y;
|
||||
uvOffset += floatsPerVert;
|
||||
}
|
||||
}
|
||||
|
||||
updateColor(com: SplitRender) {
|
||||
const renderData = com.renderData!;
|
||||
|
||||
let colorOffset = 5, floatsPerVert = renderData.floatStride;
|
||||
let vData = renderData.chunk.vb;
|
||||
|
||||
const color = com.color;
|
||||
const colorR = color.r / 255;
|
||||
const colorG = color.g / 255;
|
||||
const colorB = color.b / 255;
|
||||
const colorA = color.a / 255;
|
||||
|
||||
let polygon = com.polygon;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
vData![colorOffset] = colorR;
|
||||
vData![colorOffset + 1] = colorG;
|
||||
vData![colorOffset + 2] = colorB;
|
||||
vData![colorOffset + 3] = colorA;
|
||||
colorOffset += floatsPerVert;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum TextureType {
|
||||
Cut, // 裁剪
|
||||
Stretch // 拉伸, 暂未实现
|
||||
}
|
||||
ccenum(TextureType);
|
||||
|
||||
let _vec2_temp = new Vec2();
|
||||
let _mat4_temp = new Mat4();
|
||||
|
||||
@ccclass('SplitRender')
|
||||
@executeInEditMode
|
||||
export class SplitRender extends UIRenderer {
|
||||
static Type = TextureType;
|
||||
|
||||
@property({ type: SpriteFrame, serializable: true })
|
||||
protected _spriteFrame: SpriteFrame | null = null;
|
||||
@property({ type: SpriteFrame, serializable: true })
|
||||
get spriteFrame() {
|
||||
return this._spriteFrame;
|
||||
}
|
||||
|
||||
set spriteFrame(value) {
|
||||
if (!value || this._spriteFrame === value) {
|
||||
this._spriteFrame = value;
|
||||
return;
|
||||
}
|
||||
|
||||
this._spriteFrame = value;
|
||||
|
||||
let l = -value.width / 2, b = -value.height / 2, t = value.height / 2, r = value.width / 2;
|
||||
this.polygon = [v2(l, b), v2(r, b), v2(r, t), v2(l, t)];
|
||||
|
||||
this.markForUpdateRenderData(false);
|
||||
this._applySpriteSize();
|
||||
}
|
||||
|
||||
@property({ type: TextureType, serializable: true })
|
||||
_type: TextureType = 0;
|
||||
@property({ type: TextureType, serializable: true })
|
||||
get type() {
|
||||
return this._type;
|
||||
}
|
||||
set type(val: TextureType) {
|
||||
this._type = val;
|
||||
this.markForUpdateRenderData();
|
||||
}
|
||||
|
||||
@property
|
||||
editing: boolean = false;
|
||||
|
||||
@property({ type: [Vec2], serializable: true })
|
||||
_polygon: Vec2[] = [];
|
||||
@property({ type: [Vec2], serializable: true })
|
||||
public get polygon() {
|
||||
return this._polygon;
|
||||
}
|
||||
public set polygon(points: Vec2[]) {
|
||||
this._polygon = points;
|
||||
this.markForUpdateRenderData();
|
||||
}
|
||||
|
||||
protected _assembler: IAssembler = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
onLoad() {
|
||||
this._renderEntity.setNode(this.node);
|
||||
this.node['_hitTest'] = this._hitTest.bind(this);
|
||||
}
|
||||
|
||||
start() {
|
||||
// this.node.on(Node.EventType.TOUCH_START, (e: EventTouch) => {
|
||||
// console.log("click texture plus -");
|
||||
// }, this);
|
||||
|
||||
// this.node.on(Node.EventType.TOUCH_MOVE, (e: EventTouch) => {
|
||||
// console.log("click texture plus +");
|
||||
// this.node.setPosition(v3(this.node.position.x + e.getDeltaX(),
|
||||
// this.node.position.y + e.getDeltaY(),
|
||||
// this.node.position.z));
|
||||
// }, this);
|
||||
// console.log(this.node.uuid);
|
||||
}
|
||||
|
||||
_hitTest(cameraPt: Vec2) {
|
||||
let node = this.node;
|
||||
let testPt = _vec2_temp;
|
||||
|
||||
node.updateWorldTransform();
|
||||
// If scale is 0, it can't be hit.
|
||||
if (!Mat4.invert(_mat4_temp, node.worldMatrix)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vec2.transformMat4(testPt, cameraPt, _mat4_temp);
|
||||
return SplitRenderHelper.isPointInsidePolygon(testPt, this.polygon);
|
||||
}
|
||||
|
||||
private _applySpriteSize() {
|
||||
if (this._spriteFrame) {
|
||||
const size = this._spriteFrame.originalSize;
|
||||
this.node._uiProps.uiTransformComp!.setContentSize(size);
|
||||
}
|
||||
|
||||
this._activateMaterial();
|
||||
}
|
||||
|
||||
private _activateMaterial() {
|
||||
const spriteFrame = this._spriteFrame;
|
||||
const material = this.getRenderMaterial(0);
|
||||
if (spriteFrame) {
|
||||
if (material) {
|
||||
this.markForUpdateRenderData();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.renderData) {
|
||||
this.renderData.material = material;
|
||||
}
|
||||
}
|
||||
|
||||
protected _render(render: any) {
|
||||
render.commitComp(this, this.renderData, this._spriteFrame, this._assembler!);
|
||||
}
|
||||
|
||||
protected _canRender() {
|
||||
if (!super._canRender()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const spriteFrame = this._spriteFrame;
|
||||
if (!spriteFrame || !spriteFrame.texture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected _flushAssembler(): void {
|
||||
if (this._assembler == null) {
|
||||
this.destroyRenderData();
|
||||
this._assembler = new AssemblerSplit();
|
||||
}
|
||||
|
||||
if (!this.renderData) {
|
||||
if (this._assembler && this._assembler.createData) {
|
||||
this._renderData = this._assembler.createData(this);
|
||||
this.renderData!.material = this.getRenderMaterial(0);
|
||||
this.markForUpdateRenderData();
|
||||
this._updateColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected updateMaterial() {
|
||||
if (this._customMaterial) {
|
||||
this.setSharedMaterial(this._customMaterial, 0);
|
||||
// this._customMaterial.overridePipelineStates({ priority: 128 }, 0);
|
||||
// this._blendHash = -1;
|
||||
return;
|
||||
}
|
||||
const mat = this._updateBuiltinMaterial();
|
||||
this.setSharedMaterial(mat, 0);
|
||||
this._updateBlendFunc();
|
||||
}
|
||||
}
|
||||
9
assets/script/SplitRender/SplitRender.ts.meta
Normal file
9
assets/script/SplitRender/SplitRender.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ccd6bd1c-e0c8-4fa3-a9e3-60b1929a51d0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
375
assets/script/SplitRender/SplitRenderHelper.ts
Normal file
375
assets/script/SplitRender/SplitRenderHelper.ts
Normal file
@@ -0,0 +1,375 @@
|
||||
import { math, v2, Vec2, Vec3 } from 'cc';
|
||||
|
||||
export class SplitRenderHelper {
|
||||
//ab与ac的叉积
|
||||
static ab_cross_ac(a, b, c) {
|
||||
return SplitRenderHelper.cross(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y);
|
||||
}
|
||||
static dot(x1, y1, x2, y2) {
|
||||
return x1 * x2 + y1 * y2;
|
||||
}
|
||||
static cross(x1, y1, x2, y2) {
|
||||
return x1 * y2 - x2 * y1;
|
||||
}
|
||||
static dblcmp(a: number, b: number) {
|
||||
if (Math.abs(a - b) <= 0.000001) return 0;
|
||||
if (a > b) return 1;
|
||||
else return -1;
|
||||
}
|
||||
//求a点是不是在线段上,>0不在,=0与端点重合,<0在。
|
||||
static point_on_line(a, p1, p2) {
|
||||
return SplitRenderHelper.dblcmp(SplitRenderHelper.dot(p1.x - a.x, p1.y - a.y, p2.x - a.x, p2.y - a.y), 0);
|
||||
}
|
||||
// 判断一个点是否在三角形内
|
||||
static isInTriangle(point: Vec2, triA: Vec2, triB: Vec2, triC: Vec2) {
|
||||
let AB: Vec2 = new Vec2();
|
||||
Vec2.subtract(AB, triB, triA);
|
||||
|
||||
let AC: Vec2 = new Vec2();
|
||||
Vec2.subtract(AC, triC, triA);
|
||||
|
||||
let BC: Vec2 = new Vec2();
|
||||
Vec2.subtract(BC, triC, triB);
|
||||
|
||||
let AD: Vec2 = new Vec2();
|
||||
Vec2.subtract(AD, point, triA);
|
||||
|
||||
let BD: Vec2 = new Vec2();
|
||||
Vec2.subtract(BD, point, triB);
|
||||
|
||||
//@ts-ignore
|
||||
return (AB.cross(AC) >= 0 ^ AB.cross(AD) < 0) && (AB.cross(AC) >= 0 ^ AC.cross(AD) >= 0) && (BC.cross(AB) > 0 ^ BC.cross(BD) >= 0);
|
||||
}
|
||||
static isInPolygon(checkPoint: Vec2, polygonPoints: Vec2[]) {
|
||||
var counter = 0;
|
||||
var i: number;
|
||||
var xinters;
|
||||
var p1: Vec2, p2: Vec2;
|
||||
var pointCount = polygonPoints.length;
|
||||
p1 = polygonPoints[0];
|
||||
|
||||
for (i = 1; i <= pointCount; i++) {
|
||||
p2 = polygonPoints[i % pointCount];
|
||||
if (
|
||||
checkPoint.x > Math.min(p1.x, p2.x) &&
|
||||
checkPoint.x <= Math.max(p1.x, p2.x)
|
||||
) {
|
||||
if (checkPoint.y <= Math.max(p1.y, p2.y)) {
|
||||
if (p1.x != p2.x) {
|
||||
xinters = (checkPoint.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
|
||||
if (p1.y == p2.y || checkPoint.y <= xinters) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
if (counter % 2 == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static computeUv(points: Vec2[], width: number, height: number) {
|
||||
let uvs: Vec2[] = [];
|
||||
for (const p of points) {
|
||||
// uv原点是左上角
|
||||
let x = math.clamp(0, 1, (p.x + width / 2) / width);
|
||||
let y = math.clamp(0, 1, 1. - (p.y + height / 2) / height);
|
||||
uvs.push(v2(x, y));
|
||||
}
|
||||
return uvs;
|
||||
}
|
||||
static splitPolygon(points: Vec2[]): number[] {
|
||||
if (points.length <= 3) return [0, 1, 2];
|
||||
let pointMap: { [key: string]: number } = {}; // point与idx的映射
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
let p = points[i];
|
||||
pointMap[`${p.x}-${p.y}`] = i;
|
||||
}
|
||||
const getIdx = (p: Vec2) => {
|
||||
return pointMap[`${p.x}-${p.y}`]
|
||||
}
|
||||
points = points.concat([]);
|
||||
let idxs: number[] = [];
|
||||
|
||||
let index = 0;
|
||||
while (points.length > 3) {
|
||||
let p1 = points[(index) % points.length]
|
||||
, p2 = points[(index + 1) % points.length]
|
||||
, p3 = points[(index + 2) % points.length];
|
||||
let splitPoint = (index + 1) % points.length;
|
||||
|
||||
let v1: Vec2 = new Vec2();
|
||||
Vec2.subtract(v1, p2, p1);
|
||||
let v2: Vec2 = new Vec2();
|
||||
Vec2.subtract(v2, p3, p2);
|
||||
|
||||
if (v1.cross(v2) < 0) { // 是一个凹角, 寻找下一个
|
||||
index = (index + 1) % points.length;
|
||||
continue;
|
||||
}
|
||||
let hasPoint = false;
|
||||
for (const p of points) {
|
||||
if (p != p1 && p != p2 && p != p3 && this.isInTriangle(p, p1, p2, p3)) {
|
||||
hasPoint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPoint) { // 当前三角形包含其他点, 寻找下一个
|
||||
index = (index + 1) % points.length;
|
||||
continue;
|
||||
}
|
||||
// 找到了耳朵, 切掉
|
||||
idxs.push(getIdx(p1), getIdx(p2), getIdx(p3));
|
||||
points.splice(splitPoint, 1);
|
||||
}
|
||||
for (const p of points) {
|
||||
idxs.push(getIdx(p));
|
||||
}
|
||||
return idxs;
|
||||
}
|
||||
//点发出的右射线和线段的关系
|
||||
// 返回值: -1:不相交, 0:相交, 1:点在线段上
|
||||
static rayPointToLine(point: Vec2, linePA: Vec2, linePB: Vec2) {
|
||||
// 定义最小和最大的X Y轴值
|
||||
let minX = Math.min(linePA.x, linePB.x);
|
||||
let maxX = Math.max(linePA.x, linePB.x);
|
||||
let minY = Math.min(linePA.y, linePB.y);
|
||||
let maxY = Math.max(linePA.y, linePB.y);
|
||||
|
||||
// 射线与边无交点的其他情况
|
||||
if (point.y < minY || point.y > maxY || point.x > maxX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 剩下的情况, 计算射线与边所在的直线的交点的横坐标
|
||||
let x0 = linePA.x + ((linePB.x - linePA.x) / (linePB.y - linePA.y)) * (point.y - linePA.y);
|
||||
if (x0 > point.x) {
|
||||
return 0;
|
||||
}
|
||||
if (x0 == point.x) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//点和多边形的关系
|
||||
//返回值: -1:在多边形外部, 0:在多边形内部, 1:在多边形边线内, 2:跟多边形某个顶点重合
|
||||
static relationPointToPolygon(point: Vec2, polygon: Vec2[]) {
|
||||
let count = 0;
|
||||
for (let i = 0; i < polygon.length; ++i) {
|
||||
if (polygon[i].equals(point)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
let pa = polygon[i];
|
||||
let pb = polygon[0];
|
||||
if (i < polygon.length - 1) {
|
||||
pb = polygon[i + 1];
|
||||
}
|
||||
|
||||
let re = SplitRenderHelper.rayPointToLine(point, pa, pb);
|
||||
if (re == 1) {
|
||||
return 1;
|
||||
}
|
||||
if (re == 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count % 2 == 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//求两条线段的交点
|
||||
//返回值:[n,p] n:0相交,1在共有点,-1不相交 p:交点
|
||||
static lineCrossPoint(p1: Vec2, p2: Vec2, q1: Vec2, q2: Vec2): [number, Vec2] {
|
||||
let a = p1, b = p2, c = q1, d = q2;
|
||||
let s1, s2, s3, s4;
|
||||
let d1, d2, d3, d4;
|
||||
let p: Vec2 = new Vec2(0, 0);
|
||||
|
||||
d1 = SplitRenderHelper.dblcmp(s1 = SplitRenderHelper.ab_cross_ac(a, b, c), 0);
|
||||
d2 = SplitRenderHelper.dblcmp(s2 = SplitRenderHelper.ab_cross_ac(a, b, d), 0);
|
||||
d3 = SplitRenderHelper.dblcmp(s3 = SplitRenderHelper.ab_cross_ac(c, d, a), 0);
|
||||
d4 = SplitRenderHelper.dblcmp(s4 = SplitRenderHelper.ab_cross_ac(c, d, b), 0);
|
||||
|
||||
if ((d1 ^ d2) == -2 && (d3 ^ d4) == -2) {
|
||||
p.x = (c.x * s2 - d.x * s1) / (s2 - s1);
|
||||
p.y = (c.y * s2 - d.y * s1) / (s2 - s1);
|
||||
return [0, p];
|
||||
}
|
||||
|
||||
if (d1 == 0 && SplitRenderHelper.point_on_line(c, a, b) <= 0) {
|
||||
p = c;
|
||||
return [1, p];
|
||||
}
|
||||
if (d2 == 0 && SplitRenderHelper.point_on_line(d, a, b) <= 0) {
|
||||
p = d;
|
||||
return [1, p];
|
||||
}
|
||||
if (d3 == 0 && SplitRenderHelper.point_on_line(a, c, d) <= 0) {
|
||||
p = a;
|
||||
return [1, p];
|
||||
}
|
||||
if (d4 == 0 && SplitRenderHelper.point_on_line(b, c, d) <= 0) {
|
||||
p = b;
|
||||
return [1, p];
|
||||
}
|
||||
return [-1, null];
|
||||
}
|
||||
//线段对多边形进行切割
|
||||
//返回多边形数组
|
||||
//如果没有被切割,返回空数组
|
||||
static lineCutPolygon(pa: Vec2, pb: Vec2, polygon: Vec2[]) {
|
||||
// 检查切割线的端点是否在多边形内部
|
||||
const extendPoint = (point: Vec2, direction: Vec2) => {
|
||||
const extendedPoint = new Vec2(point.x + direction.x * 1000, point.y + direction.y * 1000);
|
||||
return extendedPoint;
|
||||
};
|
||||
|
||||
if (SplitRenderHelper.isInPolygon(pa, polygon)) {
|
||||
const direction = Vec2.subtract(new Vec2(), pa, pb).normalize();
|
||||
pa = extendPoint(pa, direction);
|
||||
}
|
||||
if (SplitRenderHelper.isInPolygon(pb, polygon)) {
|
||||
const direction = Vec2.subtract(new Vec2(), pb, pa).normalize();
|
||||
pb = extendPoint(pb, direction);
|
||||
}
|
||||
|
||||
let ret: Array<Vec2[]> = [];
|
||||
let points: Vec2[] = [];
|
||||
let pointIndex: number[] = [];
|
||||
|
||||
for (let i = 0; i < polygon.length; ++i) {
|
||||
points.push(polygon[i]);
|
||||
|
||||
let a = polygon[i];
|
||||
let b = polygon[0];
|
||||
if (i < polygon.length - 1) b = polygon[i + 1];
|
||||
|
||||
let c = SplitRenderHelper.lineCrossPoint(pa, pb, a, b);
|
||||
if (c[0] == 0) {
|
||||
pointIndex.push(points.length);
|
||||
points.push(c[1] as Vec2);
|
||||
}
|
||||
else if (c[0] > 0) {
|
||||
if ((c[1] as Vec2).equals(a)) {
|
||||
pointIndex.push(points.length - 1);
|
||||
}
|
||||
else {
|
||||
pointIndex.push(points.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pointIndex.length > 1) {
|
||||
let cp0 = points[pointIndex[0]];
|
||||
let cp1 = points[pointIndex[1]];
|
||||
|
||||
let r = SplitRenderHelper.relationPointToPolygon(new Vec2((cp0.x + cp1.x) / 2, (cp0.y + cp1.y) / 2), polygon);
|
||||
let inPolygon: boolean = r >= 0;
|
||||
|
||||
let cp0_cp1: Vec2 = new Vec2();
|
||||
let len_0_1 = Vec2.subtract(cp0_cp1, cp0, cp1).length()
|
||||
|
||||
let cp0_cp: Vec2 = new Vec2();
|
||||
let len_0_ = Vec2.subtract(cp0_cp, cp0, points[pointIndex[pointIndex.length - 1]]).length()
|
||||
|
||||
if (pointIndex.length > 2 && len_0_1 > len_0_) {
|
||||
cp1 = points[pointIndex[pointIndex.length - 1]];
|
||||
r = SplitRenderHelper.relationPointToPolygon(new Vec2((cp0.x + cp1.x) / 2, (cp0.y + cp1.y) / 2), polygon);
|
||||
inPolygon = r < 0;
|
||||
}
|
||||
|
||||
let firstInPolygon = inPolygon;
|
||||
|
||||
let index = 0;
|
||||
let startIndex = pointIndex[index];
|
||||
let oldPoints = [];
|
||||
let newPoints = [];
|
||||
let count = 0;
|
||||
|
||||
oldPoints.push(points[startIndex]);
|
||||
if (inPolygon) {
|
||||
newPoints.push(points[startIndex]);
|
||||
}
|
||||
|
||||
index++;
|
||||
count++;
|
||||
startIndex++;
|
||||
|
||||
while (count < points.length) {
|
||||
if (startIndex == points.length) startIndex = 0;
|
||||
let p = points[startIndex];
|
||||
if (index >= 0 && startIndex == pointIndex[index]) {
|
||||
index++;
|
||||
if (index >= pointIndex.length) index = 0;
|
||||
if (inPolygon) {
|
||||
newPoints.push(p);
|
||||
ret.push(newPoints);
|
||||
newPoints = [];
|
||||
}
|
||||
else {
|
||||
newPoints = [];
|
||||
newPoints.push(p);
|
||||
}
|
||||
oldPoints.push(p);
|
||||
inPolygon = !inPolygon;
|
||||
}
|
||||
else {
|
||||
if (inPolygon) {
|
||||
newPoints.push(p);
|
||||
}
|
||||
else {
|
||||
oldPoints.push(p);
|
||||
}
|
||||
}
|
||||
startIndex++;
|
||||
count++;
|
||||
}
|
||||
if (inPolygon) {
|
||||
if (!firstInPolygon && newPoints.length > 1) {
|
||||
newPoints.push(points[pointIndex[0]]);
|
||||
ret.push(newPoints);
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < newPoints.length; ++i) {
|
||||
oldPoints.push(newPoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret.push(oldPoints);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// 实用函数
|
||||
static isPointInsidePolygon(p: Vec2, polygon: Vec2[]) {
|
||||
let windingNumber = 0;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
const a = polygon[i];
|
||||
const b = polygon[(i + 1) % polygon.length];
|
||||
if (a.y <= p.y) {
|
||||
if (b.y > p.y && (b.x - a.x) * (p.y - a.y) > (p.x - a.x) * (b.y - a.y))
|
||||
windingNumber++;
|
||||
} else {
|
||||
if (b.y <= p.y && (b.x - a.x) * (p.y - a.y) < (p.x - a.x) * (b.y - a.y))
|
||||
windingNumber--;
|
||||
}
|
||||
}
|
||||
return windingNumber !== 0;
|
||||
}
|
||||
static calculatePolygonArea(polygon: Vec2[]) {
|
||||
let area = 0;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
const j = (i + 1) % polygon.length;
|
||||
area += polygon[i].x * polygon[j].y;
|
||||
area -= polygon[j].x * polygon[i].y;
|
||||
}
|
||||
return Math.abs(area) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
9
assets/script/SplitRender/SplitRenderHelper.ts.meta
Normal file
9
assets/script/SplitRender/SplitRenderHelper.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e6b2c70f-62b1-4940-988f-c42a322beca3",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
219
assets/script/SplitRender/ToolsSplit.ts
Normal file
219
assets/script/SplitRender/ToolsSplit.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
import { SplitRenderHelper } from "./SplitRenderHelper";
|
||||
import { SplitRender } from "./SplitRender";
|
||||
|
||||
import { _decorator, Component, Node, Texture2D, Graphics, Vec2, view, Vec3, SpriteFrame, EventTouch, v2, tween, Camera, color, Layers, profiler, UITransform, Sprite, RigidBody2D, ERigidBody2DType, PolygonCollider2D, Physics2DUtils, PhysicsSystem2D, ERaycast2DType, UIOpacity, Collider, Collider2D, director, Director, misc, Label, Color } from 'cc';
|
||||
const { ccclass, property, executeInEditMode } = _decorator;
|
||||
|
||||
@ccclass('ToolsSplit')
|
||||
export default class ToolsSplit extends Component {
|
||||
@property(Node)
|
||||
textureRoot: Node = null;
|
||||
|
||||
@property(Graphics)
|
||||
|
||||
graphics: Graphics = null;
|
||||
|
||||
@property(SpriteFrame)
|
||||
pic: SpriteFrame = null;
|
||||
|
||||
@property(Camera)
|
||||
cam: Camera = null;
|
||||
|
||||
@property(Label)
|
||||
moveStepLabel: Label = null;
|
||||
|
||||
private textures: SplitRender[] = [];
|
||||
private startPoint: Vec2 = null;
|
||||
private endPoint: Vec2 = null;
|
||||
|
||||
gameWidth: number = 0;
|
||||
gameHeight: number = 0;
|
||||
|
||||
canTouch: boolean = true;
|
||||
|
||||
protected onLoad(): void {
|
||||
|
||||
}
|
||||
|
||||
start() {
|
||||
profiler.hideStats();
|
||||
|
||||
this.init();
|
||||
this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
|
||||
this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
||||
this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
|
||||
this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
|
||||
this.graphics.node.setPosition(new Vec3(-view.getVisibleSize().width / 2, -view.getVisibleSize().height / 2));
|
||||
}
|
||||
|
||||
init() {
|
||||
// let node = new Node();
|
||||
// let t = node.addComponent(SplitRender);
|
||||
// node.parent = this.textureRoot;
|
||||
// node.layer = Layers.Enum.UI_2D;
|
||||
// t.spriteFrame = this.pic;
|
||||
// this.textures.push(t);
|
||||
|
||||
this.gameWidth = view.getVisibleSize().width;
|
||||
this.gameHeight = view.getVisibleSize().height;
|
||||
|
||||
this.node.getComponent(UITransform).setContentSize(this.gameWidth, this.gameHeight);
|
||||
}
|
||||
|
||||
setTextures(textures: SplitRender[]) {
|
||||
for (let i = 0; i < textures.length; i++) {
|
||||
const texture = textures[i];
|
||||
this.textures.push(texture);
|
||||
}
|
||||
}
|
||||
|
||||
setPerTexture(texture: SplitRender) {
|
||||
this.textures.push(texture);
|
||||
}
|
||||
|
||||
onTouchStart(e: EventTouch) {
|
||||
if (this.moveStepLabel.string == "0") {
|
||||
return;
|
||||
}
|
||||
if (!this.canTouch) {
|
||||
return;
|
||||
}
|
||||
this.startPoint = e.getUILocation();
|
||||
}
|
||||
|
||||
onTouchMove(e: EventTouch) {
|
||||
if (this.moveStepLabel.string == "0") {
|
||||
return;
|
||||
}
|
||||
if (!this.canTouch) {
|
||||
return;
|
||||
}
|
||||
this.graphics.clear();
|
||||
this.graphics.moveTo(this.startPoint.x, this.startPoint.y);
|
||||
let p = e.getUILocation();
|
||||
this.graphics.lineTo(p.x, p.y);
|
||||
this.graphics.stroke();
|
||||
}
|
||||
|
||||
onTouchEnd(e: EventTouch) {
|
||||
if (this.moveStepLabel.string == "0") {
|
||||
return;
|
||||
}
|
||||
if (!this.canTouch) {
|
||||
return;
|
||||
}
|
||||
this.canTouch = false;
|
||||
this.graphics.clear();
|
||||
this.endPoint = e.getUILocation();
|
||||
}
|
||||
|
||||
|
||||
cutPolygonCollider2D(originPolygon: Vec2[], startPoint: Vec2, endPoint: Vec2) {
|
||||
let newPolygon = SplitRenderHelper.lineCutPolygon(startPoint, endPoint, originPolygon);
|
||||
return newPolygon;
|
||||
}
|
||||
|
||||
private doSplit() {
|
||||
let h = this.pic.height, w = this.pic.width;
|
||||
for (let i = 0; i < 15; i++) {
|
||||
let p0 = v2(-(w / 2 + 10), (Math.random() * h) - h / 2);
|
||||
let p1 = v2(w / 2 + 10, (Math.random() * h) - h / 2);
|
||||
this.useLineCutPolygon(p0, p1, false);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
let p0 = v2(Math.random() * w - w / 2, -(h / 2 + 10));
|
||||
let p1 = v2(Math.random() * w - w / 2, (h / 2 + 10));
|
||||
this.useLineCutPolygon(p0, p1, false);
|
||||
}
|
||||
}
|
||||
|
||||
private useLineCutPolygon(p0: Vec2, p1: Vec2, isWorld = true) {
|
||||
for (let i = this.textures.length - 1; i >= 0; i--) {
|
||||
let texture = this.textures[i];
|
||||
let pa = p0.clone();
|
||||
let pb = p1.clone();
|
||||
if (isWorld) {
|
||||
let mat = texture.node.worldMatrix.clone().invert();
|
||||
pa = pa.transformMat4(mat);
|
||||
pb = pb.transformMat4(mat);
|
||||
}
|
||||
let polygons = SplitRenderHelper.lineCutPolygon(pa, pb, texture.polygon);
|
||||
if (polygons.length <= 0) {
|
||||
console.log("No Polygon")
|
||||
continue
|
||||
};
|
||||
this.splitTexture(texture, polygons);
|
||||
}
|
||||
}
|
||||
|
||||
private splitTexture(texture: SplitRender, polygons: Vec2[][]) {
|
||||
texture.polygon = polygons[0];
|
||||
let newnode: Node = null;
|
||||
for (let i = 1; i < polygons.length; i++) {
|
||||
let node = new Node("Split");
|
||||
newnode = node;
|
||||
node.layer = Layers.Enum.UI_2D;
|
||||
let t = node.addComponent(SplitRender);
|
||||
node.parent = this.textureRoot;
|
||||
node.setPosition(new Vec3(texture.node.position.x, texture.node.position.y));
|
||||
node.setRotationFromEuler(texture.node.eulerAngles.x, texture.node.eulerAngles.y, texture.node.eulerAngles.z);
|
||||
t.spriteFrame = texture.spriteFrame;
|
||||
t.polygon = polygons[i];
|
||||
|
||||
this.textures.push(t);
|
||||
}
|
||||
}
|
||||
|
||||
onClickFly() {
|
||||
for (let i = 0; i < this.textures.length; i++) {
|
||||
let center = this.getPolygonCenter(this.textures[i].polygon);
|
||||
let dir = center.normalize();
|
||||
tween(this.textures[i].node).by(0.5, { position: new Vec3(dir.x * 100, dir.y * 100, 0) }).start();
|
||||
}
|
||||
}
|
||||
|
||||
onClickReset() {
|
||||
for (let i = 0; i < this.textures.length; i++) {
|
||||
let center = this.getPolygonCenter(this.textures[i].polygon);
|
||||
let dir = center.normalize();
|
||||
tween(this.textures[i].node).by(0.5, { position: new Vec3(-dir.x * 100, -dir.y * 100, 0) }).call(() => {
|
||||
if (i === this.textures.length - 1) {
|
||||
this.textureRoot.destroyAllChildren();
|
||||
this.textureRoot.removeAllChildren();
|
||||
this.textures = [];
|
||||
this.init();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
onFallDown() {
|
||||
for (let i = 0; i < this.textures.length; i++) {
|
||||
let center = this.getPolygonCenter(this.textures[i].polygon);
|
||||
tween(this.textures[i].node).delay((center.y + this.pic.height) / this.pic.height).by(2, { position: new Vec3(0, -500, 0) }, { easing: 'circIn' }).start();
|
||||
}
|
||||
}
|
||||
onResetFallDown() {
|
||||
this.textureRoot.destroyAllChildren();
|
||||
this.textureRoot.removeAllChildren();
|
||||
this.textures = [];
|
||||
this.init();
|
||||
}
|
||||
|
||||
private getPolygonCenter(polygon: Vec2[]) {
|
||||
let x = 0, y = 0;
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
x += polygon[i].x;
|
||||
y += polygon[i].y;
|
||||
}
|
||||
x = x / polygon.length;
|
||||
y = y / polygon.length;
|
||||
return v2(x, y)
|
||||
}
|
||||
|
||||
getTextureList() {
|
||||
return this.textures;
|
||||
}
|
||||
}
|
||||
|
||||
9
assets/script/SplitRender/ToolsSplit.ts.meta
Normal file
9
assets/script/SplitRender/ToolsSplit.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0ad0fcaa-5dac-47ec-8cc4-e0c36da51296",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/ads.meta
Normal file
12
assets/script/ads.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "e76c6dab-039b-4721-ab97-2fa8baa6cdca",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
71
assets/script/ads/AdManager.ts
Normal file
71
assets/script/ads/AdManager.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { PlatformManager, releaseType } from "../manager/PlatformManager";
|
||||
import { AdManager_H5 } from "./AdManager_H5";
|
||||
import { AdManager_WX } from "./AdManager_WX";
|
||||
import { AdManager_ZJ } from "./AdManager_ZJ";
|
||||
|
||||
export class AdManager {
|
||||
private static isLoadAd: boolean = false; //是否加载过广告了
|
||||
/** 初始化所有广告 */
|
||||
public static initAds() {
|
||||
|
||||
}
|
||||
/** 加载所有广告 */
|
||||
public static loadAds() {
|
||||
if (this.isLoadAd) { return; }
|
||||
if (PlatformManager.releaseType == releaseType.applet_ziJie) {
|
||||
AdManager_ZJ._ins.loadAllAd();
|
||||
} else if (PlatformManager.releaseType == releaseType.applet_wechat) {
|
||||
AdManager_WX._ins.loadAllAd();
|
||||
}
|
||||
|
||||
this.isLoadAd = true;
|
||||
}
|
||||
/** Banner 广告 */
|
||||
public static showBanner() {
|
||||
if (PlatformManager.releaseType == releaseType.applet_ziJie) {
|
||||
AdManager_ZJ._ins.showBanner();
|
||||
} else if (PlatformManager.releaseType == releaseType.applet_wechat) {
|
||||
AdManager_WX._ins.showBanner();
|
||||
}
|
||||
}
|
||||
/** 隐藏 Banner 广告 */
|
||||
public static hideBanner() {
|
||||
if (PlatformManager.releaseType == releaseType.applet_ziJie) {
|
||||
AdManager_ZJ._ins.hideBanner();
|
||||
} else if (PlatformManager.releaseType == releaseType.applet_wechat) {
|
||||
AdManager_WX._ins.hideBanner();
|
||||
}
|
||||
}
|
||||
/** 插屏广告 */
|
||||
public static showIntersAd() {
|
||||
let rType = PlatformManager.releaseType;
|
||||
if(rType == releaseType.test_TEST){ return; }
|
||||
|
||||
if(rType == releaseType.h5_weiSan || rType == releaseType.h5_common){
|
||||
AdManager_H5._ins.showIntersAd();
|
||||
}else if(rType == releaseType.applet_ziJie){
|
||||
AdManager_ZJ._ins.showIntersAd();
|
||||
}else if(PlatformManager.releaseType == releaseType.applet_wechat){
|
||||
AdManager_WX._ins.showIntersAd();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 播放视频激励广告
|
||||
* @param finishBack 视频完成回调
|
||||
* @param errorBack 视频失败回调
|
||||
*/
|
||||
public static showVideoAd(finishBack?: () => void, errorBack?: () => void) {
|
||||
let rType = PlatformManager.releaseType
|
||||
if(rType == releaseType.test_TEST){ //测试直接成功
|
||||
if(finishBack){ finishBack(); };
|
||||
return;
|
||||
}
|
||||
if(rType == releaseType.h5_weiSan || rType == releaseType.h5_common){
|
||||
AdManager_H5._ins.showVideoAd(finishBack,errorBack);
|
||||
}else if( rType == releaseType.applet_ziJie ){
|
||||
AdManager_ZJ._ins.showVideoAd(finishBack,errorBack);
|
||||
}else if(PlatformManager.releaseType == releaseType.applet_wechat){
|
||||
AdManager_WX._ins.showVideoAd(finishBack,errorBack);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/script/ads/AdManager.ts.meta
Normal file
9
assets/script/ads/AdManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "866659ab-db45-47c7-8563-ac336d1d40bb",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
63
assets/script/ads/AdManager_H5.ts
Normal file
63
assets/script/ads/AdManager_H5.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
export class AdManager_H5 {
|
||||
/** 单例模式 */
|
||||
private static _instance: AdManager_H5 = new AdManager_H5();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private videoBack:() => void | null; //视频广告完成回调
|
||||
private errorBack:() => void | null; //视频广告失败回调
|
||||
|
||||
/** 播放插屏广告 */
|
||||
public showIntersAd(){
|
||||
adBreak({
|
||||
type: 'next',
|
||||
name: 'restart-game'
|
||||
});
|
||||
}
|
||||
|
||||
/** 播放视频广告 */
|
||||
public showVideoAd( finishBack?:() => void,errorBack?:() => void ){
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
if(finishBack){
|
||||
this.videoBack = finishBack;
|
||||
}if(errorBack){
|
||||
this.errorBack = errorBack;
|
||||
}
|
||||
adBreak({
|
||||
type: 'reward',
|
||||
name: 'dasdf',
|
||||
beforeReward: (showAdFn: any) => {
|
||||
showAdFn();
|
||||
},
|
||||
adDismissed: () => {
|
||||
this.errorVideo();
|
||||
},
|
||||
adViewed: () => {
|
||||
this.finishVideo();
|
||||
},
|
||||
adBreakDone: (placementInfo: any) => {
|
||||
// this.finishVideo();
|
||||
},
|
||||
});
|
||||
}
|
||||
/** 视频播放完成 */
|
||||
finishVideo(){
|
||||
if(this.videoBack){
|
||||
this.videoBack();
|
||||
}
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
}
|
||||
/** 视频播放失败 */
|
||||
errorVideo(){
|
||||
if(this.errorBack){
|
||||
this.errorBack();
|
||||
}
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
}
|
||||
}
|
||||
9
assets/script/ads/AdManager_H5.ts.meta
Normal file
9
assets/script/ads/AdManager_H5.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "d5436ac1-1463-4bfb-be45-9f23ca0efe0f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
238
assets/script/ads/AdManager_WX.ts
Normal file
238
assets/script/ads/AdManager_WX.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import { Asset, resources } from "cc";
|
||||
import { PlatformManager, releaseType } from "../manager/PlatformManager";
|
||||
|
||||
export class AdManager_WX {
|
||||
/** 单例模式 */
|
||||
private static _instance: AdManager_WX = new AdManager_WX();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
/** appID */
|
||||
app_id: string = "wx2c68756779fd1535";
|
||||
/** bannerID */
|
||||
ad_banner_id: string = "adunit-64d55f82495fec1d";
|
||||
/** 插屏ID */
|
||||
ad_inter_id: string = "adunit-3e889a9a21c90ec2";
|
||||
/** 激励ID */
|
||||
ad_video_id: string = "adunit-fc615ecff3915673";
|
||||
|
||||
ad_banner: any = null; //banner广告;
|
||||
ad_video: any = null; //视频广告;
|
||||
|
||||
gameName:string = "魔方拆拆乐"; //游戏名字
|
||||
|
||||
videoBack: () => void | null; //视频广告完成回调
|
||||
errorBack: (isOut: boolean) => void | null; //视频广告失败回调
|
||||
|
||||
/** 加载或者初始化所有广告 */
|
||||
loadAllAd() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
|
||||
// this.initBanner();
|
||||
this.initVideoAd();
|
||||
this.addShareMenu();
|
||||
};
|
||||
/** 初始化加载 视频广告 */
|
||||
private initVideoAd() {
|
||||
let self = this;
|
||||
|
||||
this.ad_video = wx.createRewardedVideoAd({ adUnitId: self.ad_video_id })
|
||||
this.ad_video.load().then(() => {
|
||||
console.log("视频广告加载完成!");
|
||||
}).catch((err: any) => {
|
||||
console.log("视频加载失败:" + err.errMsg)
|
||||
});
|
||||
this.ad_video.onError((err: any) => {
|
||||
this.errorVideo();
|
||||
console.log("视频出错:" + err);
|
||||
});
|
||||
this.ad_video.onClose((res: any) => {
|
||||
// 用户点击了【关闭广告】按钮
|
||||
// 小于 2.1.0 的基础库版本,res 是一个 undefined
|
||||
if (res && res.isEnded || res === undefined) {
|
||||
console.log("正常播放结束,可以下发游戏奖励");
|
||||
this.finishVideo();
|
||||
} else {
|
||||
this.errorVideo(true);
|
||||
console.log("播放中途退出,不下发游戏奖励");
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 初始化加载 banner */
|
||||
private initBanner() {
|
||||
var self = this;
|
||||
let bannerAd = wx.createBannerAd({
|
||||
adUnitId: self.ad_banner_id,
|
||||
style: { left: 0, top: 0, width: 720 }
|
||||
}
|
||||
)
|
||||
bannerAd.onResize((res: any) => {
|
||||
var phone = wx.getSystemInfoSync();
|
||||
var w = phone.screenWidth / 2;
|
||||
var h = phone.screenHeight;
|
||||
bannerAd.style.left = w - bannerAd.style.realWidth / 2 + 0.1;
|
||||
bannerAd.style.top = h - bannerAd.style.realHeight + 0.1;
|
||||
bannerAd.style.width = phone.screenWidth * 0.8;
|
||||
console.log("bannerAd加载成功");
|
||||
})
|
||||
bannerAd.onError((err: any) => {
|
||||
console.log(err)
|
||||
});
|
||||
this.ad_banner = bannerAd;
|
||||
};
|
||||
/** 显示Banner广告 */
|
||||
public showBanner() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
if (!this.ad_banner) {
|
||||
this.initBanner();
|
||||
// return;
|
||||
};
|
||||
this.ad_banner.show();
|
||||
};
|
||||
/** 隐藏Banner广告 */
|
||||
public hideBanner() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
if (!this.ad_banner) { return; }
|
||||
this.ad_banner.hide();
|
||||
};
|
||||
/** 播放插屏广告 */
|
||||
public showIntersAd() {
|
||||
// return;
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
// 定义插屏广告
|
||||
let interstitialAd = null;
|
||||
interstitialAd = wx.createInterstitialAd({
|
||||
adUnitId: this.ad_inter_id
|
||||
});
|
||||
interstitialAd.show().catch((err: any) => {
|
||||
console.error(err)
|
||||
});
|
||||
console.log("showIntersAd");
|
||||
}
|
||||
/** 播放视频广告 成功回调 失败回调 */
|
||||
public showVideoAd(finishBack?: () => void, errorBack?: () => void) {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
// wx.showToast({
|
||||
// title: '暂无视频广告!',
|
||||
// icon: 'none',
|
||||
// duration: 1500//持续的时间
|
||||
// })
|
||||
// return;
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
if (finishBack) {
|
||||
this.videoBack = finishBack;
|
||||
} if (errorBack) {
|
||||
this.errorBack = errorBack;
|
||||
}
|
||||
|
||||
if (!this.ad_video) {
|
||||
this.initVideoAd();
|
||||
}
|
||||
var self = this;
|
||||
this.ad_video.show().then(() => {
|
||||
console.log("广告显示成功");
|
||||
}).catch((err: any) => {
|
||||
this.errorVideo();
|
||||
console.log("广告组件出现问题", err);
|
||||
// 再手动加载一次
|
||||
this.ad_video.load().then(() => {
|
||||
console.log("手动加载成功");
|
||||
this.ad_video.show(); // 加载成功后需要再显示广告
|
||||
});
|
||||
});
|
||||
}
|
||||
/** 视频播放完成 */
|
||||
finishVideo() {
|
||||
if (this.videoBack) {
|
||||
this.videoBack();
|
||||
}
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
}
|
||||
/** 视频播放失败 isOut 是否中途退出*/
|
||||
errorVideo(isOut: boolean = false) {
|
||||
if (this.errorBack) {
|
||||
this.errorBack(isOut);
|
||||
}
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
};
|
||||
|
||||
/** 分享视频 shareTitle 分享内容 imgUrl 分享图路径 resource下的 */
|
||||
shareFriends(shareTitle?: string , imgUrl:string = "share") {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
var self = this;
|
||||
// wx.showShareMenu();
|
||||
|
||||
shareTitle = shareTitle || '快来大战25个回合~~';
|
||||
resources.load(imgUrl, Asset , ( err:Error , asset: Asset ) => {
|
||||
wx.shareAppMessage({
|
||||
title: shareTitle ,
|
||||
imageUrl: asset.nativeUrl ,
|
||||
success(res:any) {
|
||||
console.log("分享成功:", res);
|
||||
return;
|
||||
},
|
||||
fail(res:any) {
|
||||
// 转发失败
|
||||
wx.showToast({
|
||||
title: '分享失败',
|
||||
icon: 'none',
|
||||
duration: 1500//持续的时间
|
||||
})
|
||||
return;
|
||||
}
|
||||
});
|
||||
} );
|
||||
};
|
||||
/** 添加右上角三个点分享 */
|
||||
addShareMenu(shareTitle?: string ,imgUrl:string = "share") {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
|
||||
shareTitle = shareTitle || ""
|
||||
wx.showShareMenu( {
|
||||
withShareTicket: true,
|
||||
menus: ['shareAppMessage', 'shareTimeline'],
|
||||
} );
|
||||
console.log("添加右上角三个点分享");
|
||||
resources.load( imgUrl , Asset , (err:Error , asset: Asset) => {
|
||||
console.log(asset.nativeUrl);
|
||||
wx.onShareAppMessage(() => {
|
||||
return {
|
||||
title: this.gameName,
|
||||
imageUrl: asset.nativeUrl // 图片 URL
|
||||
}
|
||||
});
|
||||
} );
|
||||
};
|
||||
/** 跳转其他更多游戏 */
|
||||
toMoreGame() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
wx.navigateToMiniProgram({
|
||||
appId: 'wxda02fde13d108205', //其他游戏的appid
|
||||
path: 'page/index/index?id=123',
|
||||
extraData: {
|
||||
foo: 'bar'
|
||||
},
|
||||
envVersion: 'develop',
|
||||
success(res: any) {
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 震动 */
|
||||
vibrate(){
|
||||
if (PlatformManager.releaseType != releaseType.applet_wechat) { return; }
|
||||
// console.log("vibrateShort")
|
||||
wx.vibrateShort({
|
||||
type:'medium'
|
||||
})
|
||||
}
|
||||
/** 添加桌面功能 */
|
||||
addTable() {
|
||||
}
|
||||
/** 是否已经添加过桌面了 */
|
||||
isAddTable() {
|
||||
}
|
||||
}
|
||||
9
assets/script/ads/AdManager_WX.ts.meta
Normal file
9
assets/script/ads/AdManager_WX.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "40cc7426-fd89-45f9-9c7d-70068f7a2949",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
296
assets/script/ads/AdManager_ZJ.ts
Normal file
296
assets/script/ads/AdManager_ZJ.ts
Normal file
@@ -0,0 +1,296 @@
|
||||
import { PlatformManager, releaseType } from "../manager/PlatformManager";
|
||||
|
||||
export class AdManager_ZJ {
|
||||
/** 单例模式 */
|
||||
private static _instance: AdManager_ZJ = new AdManager_ZJ();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
/** appID */
|
||||
app_id: string = "tta582d33f3abc001a02";
|
||||
/** 插屏ID */
|
||||
ad_inter_id: string = "2mrqugugp7e9f29c36";
|
||||
/** 激励ID */
|
||||
ad_video_id: string = "9e617go08ho2094lcq";
|
||||
/** bannerID */
|
||||
ad_banner_id: string = "5qmmte1agjm5fjd50r";
|
||||
|
||||
/** 录屏相关 */
|
||||
recorder: any = null;
|
||||
videoPath: any = null; //录屏路径
|
||||
videoTimer: any = null; //录屏计时器 300s 内要停止录屏
|
||||
|
||||
ad_banner: any = null; //banner广告;
|
||||
ad_video: any = null; //视频广告;
|
||||
|
||||
videoBack: () => void | null; //视频广告完成回调
|
||||
errorBack: (isOut:boolean) => void | null; //视频广告失败回调
|
||||
|
||||
/** 加载或者初始化所有广告 */
|
||||
loadAllAd() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
|
||||
this.initBanner();
|
||||
this.initVideoAd();
|
||||
};
|
||||
/** 初始化加载 视频广告 */
|
||||
private initVideoAd() {
|
||||
let self = this;
|
||||
this.ad_video = tt.createRewardedVideoAd({
|
||||
adUnitId: self.ad_video_id,
|
||||
});
|
||||
|
||||
this.ad_video.onLoad(() => {
|
||||
console.log("视频广告加载完成!");
|
||||
});
|
||||
this.ad_video.load();
|
||||
};
|
||||
/** 初始化加载 banner */
|
||||
private initBanner() {
|
||||
let self = this;
|
||||
let iphoneData = tt.getSystemInfoSync();
|
||||
var bannerData = {
|
||||
left: iphoneData.screenWidth,//广告位区域左上角横坐标
|
||||
top: iphoneData.screenHeight,//广告位区域左上角纵坐标
|
||||
width: iphoneData.screenWidth,//广告位区域宽度
|
||||
}
|
||||
|
||||
this.ad_banner = tt.createBannerAd({
|
||||
adUnitId: self.ad_banner_id,
|
||||
adIntervals: 20,
|
||||
style: bannerData,
|
||||
});
|
||||
};
|
||||
/** 显示Banner广告 */
|
||||
public showBanner() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
if (!this.ad_banner) {
|
||||
this.initBanner();
|
||||
// return;
|
||||
};
|
||||
|
||||
if (this.ad_banner.show) {
|
||||
this.ad_banner.show();
|
||||
}
|
||||
|
||||
this.ad_banner.onLoad( () => {
|
||||
this.ad_banner.show().then(() => {
|
||||
console.log("广告显示成功");
|
||||
}).catch((err: any) => {
|
||||
console.log("广告组件出现问题", err);
|
||||
this.ad_banner = null;
|
||||
});
|
||||
} );
|
||||
};
|
||||
/** 隐藏Banner广告 */
|
||||
public hideBanner() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
if (!this.ad_banner) { return; }
|
||||
this.ad_banner.hide();
|
||||
};
|
||||
/** 播放插屏广告 */
|
||||
public showIntersAd() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
let self = this;
|
||||
var interstitialAd = tt.createInterstitialAd({
|
||||
adUnitId: self.ad_inter_id,
|
||||
});
|
||||
interstitialAd.load()
|
||||
.then(() => {
|
||||
interstitialAd.show().then(() => {
|
||||
console.log("插屏广告展示成功");
|
||||
});
|
||||
}).catch((err: any) => {
|
||||
console.log(err);
|
||||
});
|
||||
console.log("showIntersAd");
|
||||
}
|
||||
/** 播放视频广告 成功回调 失败回调 */
|
||||
public showVideoAd(finishBack?: () => void, errorBack?: () => void) {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
if (finishBack) {
|
||||
this.videoBack = finishBack;
|
||||
} if (errorBack) {
|
||||
this.errorBack = errorBack;
|
||||
}
|
||||
|
||||
if(!this.ad_video){
|
||||
this.initVideoAd();
|
||||
}
|
||||
|
||||
this.ad_video.show().then(() => {
|
||||
console.log("广告显示成功");
|
||||
}).catch((err: any) => {
|
||||
this.errorVideo();
|
||||
console.log("广告组件出现问题", err);
|
||||
// 再手动加载一次
|
||||
this.ad_video.load().then(() => {
|
||||
console.log("手动加载成功");
|
||||
this.ad_video.show(); // 加载成功后需要再显示广告
|
||||
});
|
||||
});
|
||||
|
||||
this.ad_video.onClose((res: any) => {
|
||||
if (res.isEnded) {
|
||||
console.log("获取奖励")
|
||||
this.finishVideo();
|
||||
} else {
|
||||
console.log("没有观看完毕--")
|
||||
this.errorVideo(true);
|
||||
}
|
||||
if (res.count) {
|
||||
//在支持多例模式的版本上会返回该字段,并且是否返回该字段与multiton是否为true无关
|
||||
//判断观看了几次广告
|
||||
}
|
||||
});
|
||||
}
|
||||
/** 视频播放完成 */
|
||||
finishVideo() {
|
||||
if (this.videoBack) {
|
||||
this.videoBack();
|
||||
}
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
}
|
||||
/** 视频播放失败 isOut 是否中途退出*/
|
||||
errorVideo(isOut:boolean = false) {
|
||||
if (this.errorBack) {
|
||||
this.errorBack(isOut);
|
||||
}
|
||||
this.videoBack = null;
|
||||
this.errorBack = null;
|
||||
};
|
||||
|
||||
|
||||
/** 开始录屏 */
|
||||
createVideoScreen() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
if (this.videoTimer !== null) {
|
||||
clearTimeout(this.videoTimer);
|
||||
this.videoTimer = null;
|
||||
}
|
||||
var self = this;
|
||||
|
||||
this.recorder = tt.getGameRecorderManager();
|
||||
this.recorder.onStart((s: any) => {
|
||||
console.log("开始录屏:", s);
|
||||
});
|
||||
this.recorder.onError((s: any) => {
|
||||
console.log("录屏错误:", s);
|
||||
});
|
||||
this.recorder.start({
|
||||
duration: 300
|
||||
});
|
||||
|
||||
this.videoTimer = setTimeout(() => {
|
||||
self.stopVideoScreen();
|
||||
}, 1000 * 280); //280s 后停止录屏
|
||||
};
|
||||
/** 停止录屏 */
|
||||
stopVideoScreen() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
if (this.videoTimer !== null) {
|
||||
clearTimeout(this.videoTimer);
|
||||
this.videoTimer = null;
|
||||
}
|
||||
var self = this;
|
||||
|
||||
console.log(this.recorder)
|
||||
if (!this.recorder || !this.recorder.stop) { return; }
|
||||
|
||||
this.recorder.onStop((s: any) => {
|
||||
self.videoPath = s.videoPath;
|
||||
});
|
||||
this.recorder.stop();
|
||||
};
|
||||
/** 分享视频 shareTopics 分享话题 shareTitle 分享内容 */
|
||||
shareScreenVideo(shareTopics?: [string], shareTitle?: string) {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
shareTopics = shareTopics || ['大战小黑'];
|
||||
shareTitle = shareTitle || '来大战25个回合~~';
|
||||
|
||||
var self = this;
|
||||
tt.shareAppMessage({
|
||||
channel: 'video',
|
||||
title: shareTitle,
|
||||
imageUrl: '',
|
||||
query: '',
|
||||
extra: {
|
||||
videoPath: self.videoPath, // 可用录屏得到的视频地址
|
||||
videoTopics: shareTopics
|
||||
},
|
||||
success() {
|
||||
// EventManager.dispachEvent(EventData.SHARE_SUCESS); //抛出分享成功的事件
|
||||
console.log('分享视频成功');
|
||||
},
|
||||
fail(e: any) {
|
||||
console.log('分享视频失败' + e);
|
||||
}
|
||||
});
|
||||
console.log("shareScreenVideo")
|
||||
};
|
||||
/** 添加更多游戏 */
|
||||
addMoreGame( ){
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
|
||||
setTimeout( () => {
|
||||
let iphoneData = tt.getSystemInfoSync();
|
||||
console.log(iphoneData);
|
||||
tt.showGridGamePanel({
|
||||
query: { //Json 格式
|
||||
'花花僵尸': 'ttd12aa7974e142ca002'
|
||||
// '套个甜甜圈神龙版': 'tt3fa54918a09c3fc802',
|
||||
// '山楂串': 'ttcf15b9a8502cccbb02',
|
||||
// '合成大西瓜原创版': 'tt425534e8dd6e24d1'
|
||||
},
|
||||
type: 'one', // 'four', 'two'
|
||||
size: 'medium',
|
||||
position: {
|
||||
top: iphoneData.screenHeight / 2 - 70,
|
||||
left: iphoneData.screenWidth - 70,
|
||||
},
|
||||
fail(res:any) {
|
||||
console.log(res);
|
||||
}
|
||||
});
|
||||
}, 100 );
|
||||
};
|
||||
/** 隐藏更多游戏 */
|
||||
hideMoreGame() {
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
|
||||
tt.hideGridGamePanel();
|
||||
};
|
||||
/** 添加桌面功能 */
|
||||
addTable(){
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
|
||||
tt.addShortcut( {
|
||||
success: function (res:any) {
|
||||
console.log("添加桌面成功!" + res);
|
||||
// EventManager.dispachEvent(EventData.ADD_TABLE_SUCESS);
|
||||
},
|
||||
fail: function (res:any) {
|
||||
console.log("添加桌面失败!" + res);
|
||||
}
|
||||
} );
|
||||
}
|
||||
/** 是否已经添加过桌面了 */
|
||||
isAddTable(){
|
||||
if (PlatformManager.releaseType != releaseType.applet_ziJie) { return; }
|
||||
|
||||
tt.checkShortcut({
|
||||
success: function (res:any) {
|
||||
console.log(res.status);
|
||||
if (res.status.exist) {
|
||||
console.log("已经添加桌面了")
|
||||
}
|
||||
},
|
||||
fail: function (res:any) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
9
assets/script/ads/AdManager_ZJ.ts.meta
Normal file
9
assets/script/ads/AdManager_ZJ.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "f553f7d0-d48b-43f6-856a-e752bf4c4ac0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/common.meta
Normal file
12
assets/script/common.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "48d0041f-b88c-4aee-a367-495e14e1b9d0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
427
assets/script/common/AStar.ts
Normal file
427
assets/script/common/AStar.ts
Normal file
@@ -0,0 +1,427 @@
|
||||
type index = {
|
||||
x: number,
|
||||
y: number
|
||||
}
|
||||
|
||||
/**
|
||||
* AStar类用于实现A*寻路算法。
|
||||
*/
|
||||
export class AStar {
|
||||
private map: any[][] = []; // 地图数组
|
||||
private weightMap: number[][] = null; // 权重地图数组
|
||||
private openlist: index[] = []; // 开放列表,存储待评估的节点
|
||||
private closelist: index[] = []; // 封闭列表,存储已评估的节点
|
||||
private parentMap: Map<index, index>; // 父节点映射,用于回溯路径
|
||||
private gcostMap: Map<index, number>; // g成本映射,记录从起点到当前节点的成本
|
||||
private hcostMap: Map<index, number>; // h成本映射,记录从当前节点到终点的估算成本
|
||||
private startValue: number = 0;
|
||||
private endValue: number = 0;
|
||||
private pathValue: number = 0;
|
||||
private isEightDirections: boolean = false;
|
||||
private neighborMap: Map<index, index[]>;
|
||||
|
||||
constructor() {
|
||||
this.openlist = [];
|
||||
this.closelist = [];
|
||||
this.parentMap = new Map();
|
||||
this.gcostMap = new Map();
|
||||
this.hcostMap = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置地图。
|
||||
* @param map 二维数组表示的地图
|
||||
*/
|
||||
setMap(map: number[][]) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置权重地图。
|
||||
* @param weightMap 二维数组表示的权重地图
|
||||
*/
|
||||
setWeightMap(weightMap: number[][]) {
|
||||
this.weightMap = weightMap;
|
||||
}
|
||||
|
||||
setValue(startValue: number, endValue: number, pathValue: number) {
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.pathValue = pathValue;
|
||||
}
|
||||
|
||||
setEightDirections(isEightDirections: boolean) {
|
||||
this.isEightDirections = isEightDirections;
|
||||
}
|
||||
|
||||
setNeighborMap(neighborMap: Map<index, index[]>) {
|
||||
this.neighborMap = neighborMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在给定范围内根据指定类型搜索从起点到终点的路径。
|
||||
* @param start 起点索引
|
||||
* @param end 终点索引
|
||||
* @param type 搜索类型(可能影响启发式函数的选择)
|
||||
* @returns 返回找到的路径数组,如果无路径则返回空数组
|
||||
*/
|
||||
search(start: index, end: index, type: number) {
|
||||
this.init(); // 初始化搜索环境
|
||||
|
||||
if (this.map[start.y][start.x] !== this.startValue ||
|
||||
this.map[end.y][end.x] !== this.endValue) {
|
||||
console.log("Invalid start or end point");
|
||||
return [];
|
||||
}
|
||||
|
||||
// 初始化起点信息,并将其加入开放列表
|
||||
this.openlist.push(start);
|
||||
this.gcostMap.set(start, 0); // 起点到起点的距离为0
|
||||
this.hcostMap.set(start, this.getHeuristicCost(start, end, type)); // 起点到终点的启发式成本
|
||||
this.parentMap.set(start, null); // 起点的父节点设置为null
|
||||
|
||||
// 循环直到开放列表为空,即所有可能的路径都被考虑
|
||||
while (this.openlist.length > 0) {
|
||||
const current = this.getMinCostNode(this.openlist); // 从开放列表中选择成本最小的节点
|
||||
|
||||
if (!current) {
|
||||
this.openlist.splice(this.openlist.indexOf(current), 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断是否到达终点
|
||||
if (this.isArrived(current, end)) {
|
||||
return this.reconstructPath(end); // 如果到达终点,返回路径重构的结果
|
||||
} else {
|
||||
// 从开放列表移除当前节点,将其加入封闭列表
|
||||
this.openlist.splice(this.openlist.indexOf(current), 1);
|
||||
this.closelist.push(current);
|
||||
|
||||
// 遍历当前节点的所有邻居节点
|
||||
const neighbors = this.getNeighbors(current);
|
||||
for (const neighbor of neighbors) {
|
||||
const hCost = this.getHeuristicCost(neighbor, end, type); // 计算邻居节点到终点的启发式成本
|
||||
const gCost = this.gcostMap.get(current) + this.getGCost(current, neighbor, type); // 计算当前节点到邻居节点的实际成本
|
||||
const totalCost = gCost + hCost; // 计算总成本
|
||||
|
||||
// 根据邻居节点的状态进行处理
|
||||
if (!this.isInClosedList(neighbor)) {
|
||||
if (!this.isInOpenList(neighbor)) {
|
||||
this.openlist.push(neighbor); // 如果邻居未在开放列表中,将其加入
|
||||
this.updateCost(neighbor, gCost, hCost); // 更新邻居节点的成本信息
|
||||
this.updateParent(neighbor, current); // 更新邻居节点的父节点信息
|
||||
} else {
|
||||
// 如果邻居已在开放列表中,但通过当前节点发现更优路径
|
||||
if (totalCost < this.getCost(neighbor)) {
|
||||
this.updateCost(neighbor, gCost, hCost); // 更新成本信息
|
||||
this.updateParent(neighbor, current); // 更新父节点信息
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("No path found.");
|
||||
return []; // 如果无法找到路径,返回空数组
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化算法状态。
|
||||
*/
|
||||
private init() {
|
||||
// 重置所有列表和映射
|
||||
this.openlist = [];
|
||||
this.closelist = [];
|
||||
this.parentMap = new Map();
|
||||
this.gcostMap = new Map();
|
||||
this.hcostMap = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前节点的邻居。
|
||||
* @param current 当前节点坐标
|
||||
* @returns 邻居节点数组
|
||||
*/
|
||||
private getNeighbors(current: index) {
|
||||
if (this.neighborMap.size === 0) {
|
||||
const neighbors: index[] = [];
|
||||
|
||||
// 尝试获取四个方向的邻居节点
|
||||
const upindex = { x: current.x, y: current.y + 1 };
|
||||
const downindex = { x: current.x, y: current.y - 1 };
|
||||
const leftindex = { x: current.x - 1, y: current.y };
|
||||
const rightindex = { x: current.x + 1, y: current.y };
|
||||
|
||||
const upleftindex = { x: current.x - 1, y: current.y + 1 };
|
||||
const uprightindex = { x: current.x + 1, y: current.y + 1 };
|
||||
const downleftindex = { x: current.x - 1, y: current.y - 1 };
|
||||
const downrightindex = { x: current.x + 1, y: current.y - 1 };
|
||||
|
||||
// 如果合法则加入邻居列表
|
||||
if (this.isValidIndex(upindex) && (this.map[upindex.y][upindex.x] == this.pathValue ||
|
||||
this.map[upindex.y][upindex.x] == this.endValue)) {
|
||||
neighbors.push(upindex);
|
||||
}
|
||||
if (this.isValidIndex(downindex) && (this.map[downindex.y][downindex.x] == this.pathValue ||
|
||||
this.map[downindex.y][downindex.x] == this.endValue)) {
|
||||
neighbors.push(downindex);
|
||||
}
|
||||
if (this.isValidIndex(leftindex) && (this.map[leftindex.y][leftindex.x] == this.pathValue ||
|
||||
this.map[leftindex.y][leftindex.x] == this.endValue)) {
|
||||
neighbors.push(leftindex);
|
||||
}
|
||||
if (this.isValidIndex(rightindex) && (this.map[rightindex.y][rightindex.x] == this.pathValue ||
|
||||
this.map[rightindex.y][rightindex.x] == this.endValue)) {
|
||||
neighbors.push(rightindex);
|
||||
}
|
||||
|
||||
if (this.isEightDirections) {
|
||||
if (this.isValidIndex(upleftindex) && (this.map[upleftindex.y][upleftindex.x] == this.pathValue ||
|
||||
this.map[upleftindex.y][upleftindex.x] == this.endValue)) {
|
||||
neighbors.push(upleftindex);
|
||||
}
|
||||
if (this.isValidIndex(downleftindex) && (this.map[downleftindex.y][downleftindex.x] == this.pathValue ||
|
||||
this.map[downleftindex.y][downleftindex.x] == this.endValue)) {
|
||||
neighbors.push(downleftindex);
|
||||
}
|
||||
if (this.isValidIndex(downrightindex) && (this.map[downrightindex.y][downrightindex.x] == this.pathValue ||
|
||||
this.map[downrightindex.y][downrightindex.x] == this.endValue)) {
|
||||
neighbors.push(downrightindex);
|
||||
}
|
||||
if (this.isValidIndex(uprightindex) && (this.map[uprightindex.y][uprightindex.x] == this.pathValue ||
|
||||
this.map[uprightindex.y][uprightindex.x] == this.endValue)) {
|
||||
neighbors.push(uprightindex);
|
||||
}
|
||||
}
|
||||
|
||||
return neighbors;
|
||||
} else {
|
||||
const _neighbors = this.neighborMap.get(current);
|
||||
const neighbors: index[] = [];
|
||||
for (const neighbor of _neighbors) {
|
||||
if (this.map[neighbor.y][neighbor.x] == this.pathValue ||
|
||||
this.map[neighbor.y][neighbor.x] == this.endValue) {
|
||||
neighbors.push(neighbor);
|
||||
}
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算从当前节点到邻居节点的实际成本
|
||||
* @param current 当前节点
|
||||
* @param neighbor 邻居节点
|
||||
* @param type 距离计算类型
|
||||
* @returns 返回从当前节点到邻居节点的成本
|
||||
*/
|
||||
private getGCost(current: index, neighbor: index, type: number = 0) {
|
||||
let baseCost = 0;
|
||||
|
||||
// 计算基础距离成本
|
||||
switch (type) {
|
||||
case 0: {
|
||||
// 计算曼哈顿距离
|
||||
baseCost = Math.abs(current.x - neighbor.x) + Math.abs(current.y - neighbor.y);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// 计算欧几里得距离
|
||||
baseCost = Math.sqrt(Math.pow(current.x - neighbor.x, 2) + Math.pow(current.y - neighbor.y, 2));
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// 计算切比雪夫距离
|
||||
const x = Math.abs(current.x - neighbor.x);
|
||||
const y = Math.abs(current.y - neighbor.y);
|
||||
const minxy = Math.min(x, y);
|
||||
baseCost = x + y + (Math.sqrt(2) - 2) * minxy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果存在权重地图,应用权重
|
||||
if (this.weightMap && this.isValidIndex(neighbor)) {
|
||||
const weight = this.weightMap[neighbor.y][neighbor.x];
|
||||
return baseCost * weight;
|
||||
}
|
||||
|
||||
return baseCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的起始点和目标点,以及类型参数,计算启发式成本。
|
||||
* @param start 起始点的索引,包含 x 和 y 坐标。
|
||||
* @param end 目标点的索引,包含 x 和 y 坐标。
|
||||
* @param type 计算成本的类型,0 表示曼哈顿距离,1 表示欧几里得距离,2 表示切比雪夫距离,默认为 0。
|
||||
* @returns 返回根据指定类型计算出的启发式成本。
|
||||
*/
|
||||
private getHeuristicCost(start: index, end: index, type: number = 0) {
|
||||
switch (type) {
|
||||
case 0: {
|
||||
// 计算曼哈顿距离
|
||||
return Math.abs(start.x - end.x) + Math.abs(start.y - end.y);
|
||||
}
|
||||
case 1: {
|
||||
// 计算欧几里得距离
|
||||
return Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
|
||||
}
|
||||
case 2: {
|
||||
// 计算切比雪夫距离
|
||||
const x = Math.abs(start.x - end.x);
|
||||
const y = Math.abs(start.y - end.y);
|
||||
const minxy = Math.min(x, y);
|
||||
return x + y + (Math.sqrt(2) - 2) * minxy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查节点是否在封闭列表中。
|
||||
* @param node 节点坐标
|
||||
* @returns {boolean} 如果节点在封闭列表中返回true,否则返回false
|
||||
*/
|
||||
private isInClosedList(node: index): boolean {
|
||||
// 遍历封闭列表查找节点
|
||||
let _index = -1;
|
||||
for (let i = 0; i < this.closelist.length; i++) {
|
||||
if (this.closelist[i].x == node.x && this.closelist[i].y == node.y) {
|
||||
_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _index != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查节点是否在开放列表中。
|
||||
* @param node 节点坐标
|
||||
* @returns {boolean} 如果节点在开放列表中返回true,否则返回false
|
||||
*/
|
||||
private isInOpenList(node: index): boolean {
|
||||
// 遍历开放列表查找节点
|
||||
let _index = -1;
|
||||
for (let i = 0; i < this.openlist.length; i++) {
|
||||
if (this.openlist[i].x == node.x && this.openlist[i].y == node.y) {
|
||||
_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _index != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点的成本。
|
||||
* @param node 节点坐标
|
||||
* @returns 节点的总成本
|
||||
*/
|
||||
private getCost(node: index): number {
|
||||
let gcost = 0;
|
||||
let hcost = 0;
|
||||
this.gcostMap.forEach((value, key) => {
|
||||
if (key.x == node.x && key.y == node.y) {
|
||||
gcost = value;
|
||||
}
|
||||
});
|
||||
this.hcostMap.forEach((value, key) => {
|
||||
if (key.x == node.x && key.y == node.y) {
|
||||
hcost = value;
|
||||
}
|
||||
});
|
||||
return gcost + hcost;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开放列表中成本最小的节点。
|
||||
* @param list 开放列表
|
||||
* @returns 成本最小的节点
|
||||
*/
|
||||
private getMinCostNode(list: index[]): index {
|
||||
let _minindex = -1;
|
||||
let _mincost = Number.MAX_SAFE_INTEGER;
|
||||
// 寻找成本最小的节点
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const cost = this.getCost(list[i]);
|
||||
if (cost < _mincost) {
|
||||
_minindex = i;
|
||||
_mincost = cost;
|
||||
}
|
||||
}
|
||||
return list[_minindex];
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节点的成本和父节点信息。
|
||||
* @param node 节点坐标
|
||||
* @param gcost 从起点到当前节点的实际成本
|
||||
* @param hcost 从当前节点到终点的估算成本
|
||||
*/
|
||||
private updateCost(node: index, gcost: number, hcost: number) {
|
||||
this.gcostMap.set(node, gcost);
|
||||
this.hcostMap.set(node, hcost);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新节点的父节点。
|
||||
* @param node 节点坐标
|
||||
* @param parent 父节点坐标
|
||||
*/
|
||||
private updateParent(node: index, parent: index) {
|
||||
const existingparent = this.parentMap.get(node);
|
||||
// 仅当新的父节点成本更低时更新
|
||||
if (!existingparent || this.getCost(parent) < this.getCost(existingparent)) {
|
||||
this.parentMap.set(node, parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据父节点映射重构路径。
|
||||
* @param endPoint 终点坐标
|
||||
* @returns 从起点到终点的路径
|
||||
*/
|
||||
private reconstructPath(endPoint: index) {
|
||||
const path = [endPoint];
|
||||
let currentnode = endPoint;
|
||||
|
||||
// 逆向回溯路径
|
||||
while (currentnode) {
|
||||
let parent = null;
|
||||
this.parentMap.forEach((value, key) => {
|
||||
if (currentnode.x == key.x && currentnode.y == key.y) {
|
||||
parent = value;
|
||||
}
|
||||
})
|
||||
if (parent) {
|
||||
path.unshift(parent);
|
||||
currentnode = parent;
|
||||
} else {
|
||||
currentnode = null;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查给定的索引是否为有效索引。
|
||||
* @param index 一个包含x和y属性的对象,代表要检查的索引位置。
|
||||
* @returns 返回一个布尔值,如果索引位置有效,则为true;否则为false。
|
||||
*/
|
||||
private isValidIndex(index: index): boolean {
|
||||
return index.x >= 0 && index.x < this.map[0].length && index.y >= 0 && index.y < this.map.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前节点是否到达了目标节点。
|
||||
* @param node 一个包含x和y属性的对象,代表当前节点的位置。
|
||||
* @param end 一个包含x和y属性的对象,代表目标节点的位置。
|
||||
* @returns 返回一个布尔值,如果当前节点已到达目标节点,则为true;否则为false。
|
||||
*/
|
||||
private isArrived(node: index, end: index) {
|
||||
// 比较当前节点和目标节点的坐标,判断是否已经到达目标位置
|
||||
return node.x == end.x && node.y == end.y;
|
||||
}
|
||||
}
|
||||
|
||||
9
assets/script/common/AStar.ts.meta
Normal file
9
assets/script/common/AStar.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0da25f34-2c17-4ebe-a9d6-1a4c2c03a99b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
185
assets/script/common/AudioTools.ts
Normal file
185
assets/script/common/AudioTools.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { AudioClip, Node, AudioSource, tween } from "cc";
|
||||
import { ResModel } from "../model/ResModel";
|
||||
import { LoadTools } from "./LoadTools";
|
||||
|
||||
/** 声音相关工具类 */
|
||||
export class AudioTools {
|
||||
/** 单例模式 */
|
||||
private static _instance: AudioTools = new AudioTools();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
private audioDic: Map<string, AudioSource> = new Map();
|
||||
private audioVolumeDic: Map<string, number> = new Map();
|
||||
private audioPermanentDic: Map<AudioSource, boolean> = new Map();
|
||||
bgAudio: AudioSource; //背景音乐
|
||||
isPlayAudio: boolean = true; //是否播放音效
|
||||
isPlayBG: boolean = true; //是否播放音乐
|
||||
|
||||
/** 播放背景音乐 */
|
||||
playBG(audioUrl: string, value = 0.5) {
|
||||
if (!this.isPlayBG) { return; }
|
||||
if (ResModel._ins.AudioClipDic.get(audioUrl) != null) {
|
||||
this.bgAudio = this.newAudioSource(ResModel._ins.AudioClipDic.get(audioUrl), value, true);
|
||||
this.audioDic.set(audioUrl, this.bgAudio);
|
||||
this.audioVolumeDic.set(audioUrl, value);
|
||||
this.audioPermanentDic.set(this.bgAudio, true);
|
||||
return this.bgAudio;
|
||||
} else {
|
||||
LoadTools._ins.loadResAny('music/' + audioUrl + '.mp3', AudioClip, (audio: AudioClip) => {
|
||||
this.bgAudio = this.newAudioSource(audio, value, true);
|
||||
this.audioDic.set(audioUrl, this.bgAudio);
|
||||
this.audioVolumeDic.set(audioUrl, value);
|
||||
this.audioPermanentDic.set(this.bgAudio, true);
|
||||
return this.bgAudio;
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 播放游戏音效
|
||||
* @param audioUrl 音效文件的res/music/的路径 或者 resArr拖动的名字
|
||||
* @param value 音量大小
|
||||
* @param isLoop 是否循环播放
|
||||
* @param isPermanent 是否永久播放
|
||||
*/
|
||||
playAudio(audioUrl: string, value = 0.5, isLoop = false, isPermanent = false) {
|
||||
if (!this.isPlayAudio) { return; }
|
||||
if (ResModel._ins.AudioClipDic.get(audioUrl) != null) {
|
||||
let audioE = this.newAudioSource(ResModel._ins.AudioClipDic.get(audioUrl), value, isLoop);
|
||||
this.audioDic.set(audioUrl, audioE);
|
||||
this.audioVolumeDic.set(audioUrl, value);
|
||||
this.audioPermanentDic.set(audioE, isPermanent);
|
||||
return audioE;
|
||||
} else {
|
||||
LoadTools._ins.loadResAny('music/' + audioUrl + '.mp3', AudioClip, (audio: AudioClip) => {
|
||||
let audioE = this.newAudioSource(audio, value, isLoop);
|
||||
this.audioDic.set(audioUrl, audioE);
|
||||
this.audioVolumeDic.set(audioUrl, value);
|
||||
this.audioPermanentDic.set(audioE, isPermanent);
|
||||
return audioE;
|
||||
});
|
||||
}
|
||||
};
|
||||
/** 停止播放某个音效 */
|
||||
stopAudio(audioName: string) {
|
||||
let audioE = this.audioDic.get(audioName);
|
||||
if (audioE != null) {
|
||||
audioE.stop();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 新建一个audioSource 来播放音效
|
||||
* @param audioUrl 音效文件的res/music/的路径 或者 resArr拖动的名字
|
||||
* @param value 音量大小
|
||||
* @param isLoop 是否循环播放
|
||||
*/
|
||||
playAudioSource(audioUrl: string, value = 0.5, isLoop = false) {
|
||||
if (!this.isPlayAudio) { return; }
|
||||
if (ResModel._ins.AudioClipDic.get(audioUrl) != null) {
|
||||
return this.newAudioSource(ResModel._ins.AudioClipDic.get(audioUrl), value, isLoop);
|
||||
} else {
|
||||
LoadTools._ins.loadResAny(audioUrl, AudioClip, (audioE: AudioClip) => {
|
||||
this.newAudioSource(audioE, value, isLoop);
|
||||
});
|
||||
}
|
||||
}
|
||||
/** 新建一个 audioSource 播放音效 */
|
||||
newAudioSource(audioClip: AudioClip, value = 0.5, isLoop = false) {
|
||||
if (!this.isPlayAudio) { return; }
|
||||
let node = new Node();
|
||||
let audioE = node.addComponent(AudioSource);
|
||||
audioE.clip = audioClip;
|
||||
audioE.loop = isLoop;
|
||||
audioE.volume = value;
|
||||
|
||||
audioE.play();
|
||||
if (isLoop == false) {
|
||||
tween(node).delay(audioE.duration + 0.1)
|
||||
.removeSelf().union().start();
|
||||
}
|
||||
return audioE;
|
||||
};
|
||||
|
||||
/** 停止所有音效 */
|
||||
stopAllAudio() {
|
||||
this.isPlayAudio = false;
|
||||
this.isPlayBG = false;
|
||||
for (let audioE of this.audioDic.values()) {
|
||||
audioE.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** 恢复所有音效 */
|
||||
resumeAllAudio() {
|
||||
for (let audioE of this.audioDic.values()) {
|
||||
if (this.audioPermanentDic.get(audioE) && !audioE.playing) {
|
||||
audioE.play();
|
||||
}
|
||||
audioE.volume = this.audioVolumeDic.get(audioE.clip.name);
|
||||
}
|
||||
this.isPlayAudio = true;
|
||||
this.isPlayBG = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复指定音效
|
||||
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
|
||||
*/
|
||||
resumeAudioByName(audioName: string) {
|
||||
let audioE = this.audioDic.get(audioName);
|
||||
if (audioE != null) {
|
||||
if (!audioE.playing) {
|
||||
audioE.play();
|
||||
}
|
||||
audioE.volume = this.audioVolumeDic.get(audioE.clip.name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指定音效的音量
|
||||
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
|
||||
* @param value 音量大小
|
||||
*/
|
||||
setAudioVolume(audioName: string, value: number) {
|
||||
let audioE = this.audioDic.get(audioName);
|
||||
if (audioE != null) {
|
||||
audioE.volume = value;
|
||||
this.audioVolumeDic.set(audioName, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指定音效的循环播放
|
||||
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
|
||||
* @param isLoop 是否循环播放
|
||||
*/
|
||||
setAudioLoop(audioName: string, isLoop: boolean) {
|
||||
let audioE = this.audioDic.get(audioName);
|
||||
if (audioE != null) {
|
||||
audioE.loop = isLoop;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指定音效的静音
|
||||
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
|
||||
*/
|
||||
muteAudio(audioName: string) {
|
||||
let audioE = this.audioDic.get(audioName);
|
||||
if (audioE != null) {
|
||||
audioE.volume = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置所有音效的静音
|
||||
*/
|
||||
muteAllAudio() {
|
||||
for (let audioE of this.audioDic.values()) {
|
||||
audioE.volume = 0.0;
|
||||
}
|
||||
this.isPlayAudio = false;
|
||||
this.isPlayBG = false;
|
||||
}
|
||||
}
|
||||
9
assets/script/common/AudioTools.ts.meta
Normal file
9
assets/script/common/AudioTools.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b2bc325c-94d6-4223-8d5a-918cbdadfd93",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
98
assets/script/common/BFS.ts
Normal file
98
assets/script/common/BFS.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
class Queue<T> {
|
||||
private items: T[];
|
||||
|
||||
constructor() {
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
enqueue(item: T): void {
|
||||
this.items.push(item);
|
||||
}
|
||||
|
||||
dequeue(): T | undefined {
|
||||
return this.items.shift();
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.items.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
type index = {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export class BFSPathfinding {
|
||||
private map: number[][];
|
||||
private visited: boolean[][];
|
||||
private rows: number;
|
||||
private cols: number;
|
||||
private directions: index[];
|
||||
|
||||
constructor() {
|
||||
this.map = [];
|
||||
this.rows = 0;
|
||||
this.cols = 0;
|
||||
this.visited = [];
|
||||
this.directions = [];
|
||||
}
|
||||
|
||||
setMap(map: number[][]) {
|
||||
this.map = map;
|
||||
this.rows = this.map.length;
|
||||
this.cols = this.map[0].length;
|
||||
this.visited = Array.from({ length: this.rows }, () => Array(this.cols).fill(false));
|
||||
this.directions = [{ x: 0, y: -1 }, { x: 0, y: 1 }, { x: -1, y: 0 }, { x: 1, y: 0 }];
|
||||
}
|
||||
|
||||
findPath(start: index, end: index): index[] {
|
||||
if (this.map[start.y][start.x] !== 0 ||
|
||||
this.map[end.y][end.x] !== 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const queue = new Queue<index>();
|
||||
const prev: index[][] = Array.from({ length: this.rows }, () => Array(this.cols).fill(null));
|
||||
|
||||
queue.enqueue(start);
|
||||
this.visited[start.y][start.x] = true;
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
const current = queue.dequeue()!;
|
||||
if (current.x === end.x && current.y === end.y) {
|
||||
return this.constructPath(prev, start, end);
|
||||
}
|
||||
|
||||
for (const direction of this.directions) {
|
||||
const nextX = current.x + direction.x;
|
||||
const nextY = current.y + direction.y;
|
||||
|
||||
if (this.isValid(nextX, nextY) && this.map[nextY][nextX] === 0 && !this.visited[nextY][nextX]) {
|
||||
queue.enqueue({ x: nextX, y: nextY });
|
||||
this.visited[nextY][nextX] = true;
|
||||
prev[nextY][nextX] = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private isValid(x: number, y: number): boolean {
|
||||
return x >= 0 && x < this.cols && y >= 0 && y < this.rows;
|
||||
}
|
||||
|
||||
private constructPath(prev: index[][], start: index, end: index): index[] {
|
||||
const path: index[] = [];
|
||||
let current = end;
|
||||
|
||||
while (current !== start) {
|
||||
path.unshift(current);
|
||||
current = prev[current.y][current.x]!;
|
||||
}
|
||||
path.unshift(start);
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
9
assets/script/common/BFS.ts.meta
Normal file
9
assets/script/common/BFS.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "8ac0c6a2-e192-4b14-8cbe-97c0f60d1c1e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
281
assets/script/common/LoadTools.ts
Normal file
281
assets/script/common/LoadTools.ts
Normal file
@@ -0,0 +1,281 @@
|
||||
import { director, Node, instantiate, Prefab, Vec3, v3, SpriteFrame, Sprite, AssetManager, resources, assetManager, AudioClip, Material, Texture2D, Label } from "cc";
|
||||
import { ResModel } from "../model/ResModel";
|
||||
import { weiSan } from "./weiSanTools";
|
||||
import { EventManager, EventData } from "../manager/EventManager";
|
||||
import { PoolManager } from "../manager/PoolManager";
|
||||
|
||||
/** 加载资源相关工具类 */
|
||||
export class LoadTools {
|
||||
/** 单例模式 */
|
||||
private static _instance: LoadTools = new LoadTools();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载游戏场景
|
||||
* @param sceneName 加载场景的名字
|
||||
* @param callFunc 加载回调
|
||||
*/
|
||||
loadScene(sceneName: string, callFunc: any, isClear = true) {
|
||||
if (isClear) {
|
||||
ResModel._ins.clearResDic();
|
||||
}
|
||||
director.preloadScene(sceneName, () => {
|
||||
director.loadScene(sceneName, callFunc);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 加载resource 下的预制体 资源
|
||||
* @param url resource 下的资源路径
|
||||
* @param callBack 加载完成回调
|
||||
*/
|
||||
loadResPrefab(url: string, callBack?: any, parent?: Node, Pos?: Vec3) {
|
||||
this.loadResAny(url, Prefab, (prefab: Prefab) => {
|
||||
let clone = instantiate(prefab);
|
||||
if (parent) { parent.addChild(clone) };
|
||||
if (Pos) { clone.position = v3(Pos.x, Pos.y, 0) };
|
||||
if (callBack != null) {
|
||||
callBack(clone);
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 加载resource 下的图片资源并渲染到节点上
|
||||
* @param url resource 下的资源路径
|
||||
* @param callBack 加载完成回调
|
||||
*/
|
||||
loadResSpriteFrame(url: string, sprite: Node, parent?: Node, Pos?: Vec3, callBack?: any) {
|
||||
resources.load(url + "/spriteFrame", SpriteFrame, function (error: any, SpriteFrame: SpriteFrame) {
|
||||
if (error) {
|
||||
weiSan.error(error);
|
||||
} else {
|
||||
sprite.getComponent(Sprite).spriteFrame = SpriteFrame;
|
||||
if (parent) { parent.addChild(sprite) };
|
||||
if (Pos) { sprite.position = v3(Pos.x, Pos.y, 0) };
|
||||
if (callBack != null) {
|
||||
callBack(sprite);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 加载resource 下的游戏资源
|
||||
* @param url resource 下的资源路径
|
||||
* @param resType 加载资源的类型
|
||||
* @param callBack 加载完成回调
|
||||
*/
|
||||
loadResAny(url: string, resType: any, callBack?: any) {
|
||||
resources.load(url, resType, function (error: any, res: any) {
|
||||
if (error) {
|
||||
weiSan.error(error);
|
||||
} else {
|
||||
if (callBack != null) {
|
||||
callBack(res);
|
||||
}
|
||||
if (resType == Prefab) {
|
||||
ResModel._ins.PrefabDic.set(url, res);
|
||||
} else if (resType == SpriteFrame) {
|
||||
if (!ResModel._ins.SpriteFrameDic.has(url)) {
|
||||
ResModel._ins.SpriteFrameDic.set(url, res);
|
||||
}
|
||||
} else if (resType == AudioClip) {
|
||||
if (!ResModel._ins.AudioClipDic.has(url)) {
|
||||
ResModel._ins.AudioClipDic.set(url, res);
|
||||
}
|
||||
} else if (resType == Material) {
|
||||
if (!ResModel._ins.MaterialDic.has(url)) {
|
||||
ResModel._ins.MaterialDic.set(url, res);
|
||||
}
|
||||
} else if (resType == Texture2D) {
|
||||
if (!ResModel._ins.TextureDic.has(url)) {
|
||||
ResModel._ins.TextureDic.set(url, res);
|
||||
}
|
||||
} else if (resType === Prefab) {
|
||||
if (!ResModel._ins.PrefabDic.has(url)) {
|
||||
ResModel._ins.PrefabDic.set(url, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/** 加载bundle 场景 */
|
||||
loadBundleScene(bundleName: string, sceneName: string, onFinishBack?: () => void, isInScene: boolean = true) {
|
||||
assetManager.loadBundle(
|
||||
bundleName,
|
||||
(err: any, bundle: AssetManager.Bundle) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
else {
|
||||
if (!isInScene) { return; }
|
||||
bundle.loadScene(sceneName, (err, scene) => {
|
||||
if (onFinishBack) {
|
||||
onFinishBack();
|
||||
}
|
||||
director.runScene(scene);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分帧加载预制体节点
|
||||
* @param prefabName 要加载的预制体名称
|
||||
* @param perFrameNum 每帧加载的数量
|
||||
* @param totalNum 总共需要加载的数量
|
||||
* @param usePool 是否使用对象池,默认为true
|
||||
* @param callBack 对每个创建的节点进行操作的回调函数
|
||||
* @returns Promise<Node[]> 返回所有创建的节点数组
|
||||
*/
|
||||
loadPrefabByFrame(prefabName: string, perFrameNum: number, totalNum: number, usePool: boolean = true, callBack?: (node: Node, index: number) => void): Promise<Node[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 参数验证
|
||||
if (!prefabName || prefabName.trim() === '') {
|
||||
const error = 'prefabName cannot be empty';
|
||||
weiSan.error(error);
|
||||
reject(new Error(error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (perFrameNum <= 0) {
|
||||
const error = 'perFrameNum must be greater than 0';
|
||||
weiSan.error(error);
|
||||
reject(new Error(error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalNum <= 0) {
|
||||
const error = 'totalNum must be greater than 0';
|
||||
weiSan.error(error);
|
||||
reject(new Error(error));
|
||||
return;
|
||||
}
|
||||
|
||||
// 触发加载开始事件
|
||||
EventManager.dispatchEvent(EventData.PREFAB_LOAD_START, {
|
||||
prefabName: prefabName,
|
||||
totalNum: totalNum,
|
||||
usePool: usePool
|
||||
});
|
||||
|
||||
// 创建节点的函数
|
||||
const createNodeFunction = (prefab?: Prefab): Node | null => {
|
||||
if (usePool) {
|
||||
// 使用对象池创建节点
|
||||
return PoolManager._ins.getNode(prefabName);
|
||||
} else {
|
||||
// 使用传统方式创建节点
|
||||
if (!prefab) {
|
||||
weiSan.error(`Prefab is required when not using pool: ${prefabName}`);
|
||||
return null;
|
||||
}
|
||||
return instantiate(prefab);
|
||||
}
|
||||
};
|
||||
|
||||
if (usePool) {
|
||||
// 使用对象池时,直接开始分帧创建
|
||||
this.startFrameBasedCreation(prefabName, perFrameNum, totalNum, usePool, callBack, createNodeFunction, resolve, reject);
|
||||
} else {
|
||||
// 不使用对象池时,先加载预制体资源
|
||||
this.loadResAny(prefabName, Prefab, (prefab: Prefab) => {
|
||||
if (!prefab) {
|
||||
const error = `Failed to load prefab: ${prefabName}`;
|
||||
weiSan.error(error);
|
||||
reject(new Error(error));
|
||||
return;
|
||||
}
|
||||
this.startFrameBasedCreation(prefabName, perFrameNum, totalNum, usePool, callBack, createNodeFunction, resolve, reject, prefab);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始分帧创建节点的核心逻辑
|
||||
*/
|
||||
private startFrameBasedCreation(
|
||||
prefabName: string,
|
||||
perFrameNum: number,
|
||||
totalNum: number,
|
||||
usePool: boolean,
|
||||
callBack: ((node: Node, index: number) => void) | undefined,
|
||||
createNodeFunction: (prefab?: Prefab) => Node | null,
|
||||
resolve: (value: Node[]) => void,
|
||||
reject: (reason?: any) => void,
|
||||
prefab?: Prefab
|
||||
) {
|
||||
// 开始分帧创建节点
|
||||
const createdNodes: Node[] = [];
|
||||
let currentCount = 0;
|
||||
|
||||
const createNodesPerFrame = () => {
|
||||
const remainingCount = totalNum - currentCount;
|
||||
const currentFrameCount = Math.min(perFrameNum, remainingCount);
|
||||
|
||||
// 创建当前帧的节点
|
||||
for (let i = 0; i < currentFrameCount; i++) {
|
||||
try {
|
||||
const node = createNodeFunction(prefab);
|
||||
if (!node) {
|
||||
const error = `Failed to create node: ${prefabName}`;
|
||||
weiSan.error(error);
|
||||
reject(new Error(error));
|
||||
return;
|
||||
}
|
||||
|
||||
createdNodes.push(node);
|
||||
|
||||
// 执行回调函数
|
||||
if (callBack) {
|
||||
try {
|
||||
callBack(node, currentCount);
|
||||
} catch (callbackError) {
|
||||
weiSan.warn(`Callback error for node ${currentCount}: ${callbackError}`);
|
||||
}
|
||||
}
|
||||
|
||||
currentCount++;
|
||||
} catch (error) {
|
||||
weiSan.error(`Error creating node instance: ${error}`);
|
||||
reject(new Error(`Error creating node instance: ${error}`));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算进度并触发进度事件
|
||||
const progress = (currentCount / totalNum) * 100;
|
||||
EventManager.dispatchEvent(EventData.PREFAB_LOAD_PROGRESS, {
|
||||
prefabName: prefabName,
|
||||
currentNum: currentCount,
|
||||
totalNum: totalNum,
|
||||
progress: progress
|
||||
});
|
||||
|
||||
// 检查是否完成
|
||||
if (currentCount >= totalNum) {
|
||||
// 触发完成事件
|
||||
EventManager.dispatchEvent(EventData.PREFAB_LOAD_COMPLETE, {
|
||||
prefabName: prefabName,
|
||||
totalNum: totalNum,
|
||||
nodes: createdNodes
|
||||
});
|
||||
|
||||
weiSan.log(`Successfully loaded ${totalNum} instances of prefab: ${prefabName}`);
|
||||
resolve(createdNodes);
|
||||
} else {
|
||||
// 继续下一帧,使用 setTimeout 来实现分帧
|
||||
setTimeout(() => {
|
||||
createNodesPerFrame();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
// 开始第一帧的创建
|
||||
createNodesPerFrame();
|
||||
}
|
||||
}
|
||||
9
assets/script/common/LoadTools.ts.meta
Normal file
9
assets/script/common/LoadTools.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "6a25c810-7df7-4956-9123-e14f337f08f5",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
706
assets/script/common/Tools.ts
Normal file
706
assets/script/common/Tools.ts
Normal file
@@ -0,0 +1,706 @@
|
||||
import { SpriteFrame, Vec3, Node, Vec2, Button, v2, sys, instantiate, game, Game, v3, Sprite, misc, UITransform, Layers, Camera, Canvas, director, Director, ImageAsset, renderer, RenderTexture, Size, Texture2D, view, sp } from "cc";
|
||||
import { PlatformManager } from "../manager/PlatformManager";
|
||||
import { ResModel } from "../model/ResModel";
|
||||
import { LoadTools } from "./LoadTools";
|
||||
import { AStar } from "./AStar";
|
||||
import { BFSPathfinding } from "./BFS";
|
||||
import { SplitRenderHelper } from "../SplitRender/SplitRenderHelper";
|
||||
|
||||
export type index = {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
game._calculateDT = function _calculateDT(useFixedDeltaTime: boolean): number {
|
||||
this._useFixedDeltaTime = useFixedDeltaTime;
|
||||
|
||||
if (useFixedDeltaTime) {
|
||||
this._startTime = performance.now();
|
||||
return this.frameTime / 1000;
|
||||
}
|
||||
|
||||
const now = performance.now();
|
||||
this._deltaTime = now > this._startTime ? (now - this._startTime) / 1000 : 0;
|
||||
if (this._deltaTime > Game.DEBUG_DT_THRESHOLD) {
|
||||
this._deltaTime = this.frameTime / 1000;
|
||||
}
|
||||
this._startTime = now;
|
||||
return this._deltaTime * Tools.getTimeScale();
|
||||
}
|
||||
|
||||
/** 游戏常用工具类 */
|
||||
export class Tools {
|
||||
private static timeScale = 1;
|
||||
|
||||
private static aStar: AStar = new AStar();
|
||||
|
||||
private static bfs: BFSPathfinding = new BFSPathfinding();
|
||||
|
||||
/**
|
||||
* 使用A*算法进行搜索。
|
||||
* @param map 二维数字数组,代表地图或其他需要搜索的结构。
|
||||
* @param start 搜索的起始点,其格式为 index 类型。
|
||||
* @param end 搜索的终点,其格式为 index 类型。
|
||||
* @param type 搜索类型,用数字表示,默认为 0。不同的类型可能影响搜索算法的行为。
|
||||
* @returns 返回搜索结果,通常是一个路径数组或者搜索到的目标。
|
||||
*/
|
||||
public static aStarSearch(map: number[][], start: index, end: index, type: number = 0) {
|
||||
this.aStar.setMap(map);
|
||||
return this.aStar.search(start, end, type);
|
||||
}
|
||||
|
||||
public static setaStarValue(startValue: number, endValue: number, pathValue: number) {
|
||||
this.aStar.setValue(startValue, endValue, pathValue);
|
||||
}
|
||||
|
||||
public static setaStarEightDirections(isEightDirections: boolean) {
|
||||
this.aStar.setEightDirections(isEightDirections);
|
||||
}
|
||||
|
||||
public static setaStarWeightMap(weightMap: number[][]) {
|
||||
this.aStar.setWeightMap(weightMap);
|
||||
}
|
||||
|
||||
public static setaStarNeighborMap(neighborMap: Map<index, index[]>) {
|
||||
this.aStar.setNeighborMap(neighborMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用广度优先搜索算法在地图上寻找从起点到终点的路径。
|
||||
* @param map 二维数字数组表示的地图。
|
||||
* @param start 起点的索引。
|
||||
* @param end 终点的索引。
|
||||
* @returns 返回一个路径数组,如果不存在路径则返回空数组。
|
||||
*/
|
||||
public static bfsSearch(map: number[][], start: index, end: index) {
|
||||
this.bfs.setMap(map); // 设置广度优先搜索对象的地图
|
||||
return this.bfs.findPath(start, end); // 执行搜索并返回路径
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储本地数据
|
||||
* @param {*} isObject 是否是一个对象或者数组
|
||||
*/
|
||||
public static setStorage(key: string, value: any, isObject = false) {
|
||||
PlatformManager.setStorage(key, value, isObject);
|
||||
}
|
||||
/**
|
||||
* 获取存储数据
|
||||
* @param {*} isObject 是否是一个对象或者数组
|
||||
*/
|
||||
public static getStorage(key: string, isObject = false) {
|
||||
return PlatformManager.getStorage(key, isObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取时间缩放
|
||||
* @returns 时间缩放
|
||||
*/
|
||||
public static getTimeScale() {
|
||||
return Tools.timeScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置时间缩放
|
||||
* @param scale 时间缩放
|
||||
*/
|
||||
public static setTimeScale(scale: number) {
|
||||
Tools.timeScale = scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取截图
|
||||
* @param node 截图的节点
|
||||
* @param parent 截图的父节点
|
||||
* @param pos 截图的位置
|
||||
* @param canvas 默认摄像机渲染的canvas
|
||||
* @param normalCamera 默认摄像机
|
||||
*/
|
||||
public static getScreenShot(node: Node, parent: Node, pos: Vec3, canvas: Canvas, normalCamera: Camera) {
|
||||
const newCamera = new Node("PhotoCamera");
|
||||
|
||||
newCamera.setParent(canvas.node);
|
||||
newCamera.setPosition(0, 0, 1000);
|
||||
newCamera.addComponent(Camera);
|
||||
newCamera.getComponent(Camera).visibility = normalCamera.visibility;
|
||||
newCamera.getComponent(Camera).clearFlags = normalCamera.clearFlags;
|
||||
newCamera.getComponent(Camera).near = normalCamera.near;
|
||||
newCamera.getComponent(Camera).far = normalCamera.far;
|
||||
newCamera.getComponent(Camera).projection = renderer.scene.CameraProjection.ORTHO;
|
||||
newCamera.getComponent(Camera).orthoHeight = normalCamera.orthoHeight;
|
||||
|
||||
const newRenderTexture = new RenderTexture();
|
||||
newRenderTexture.reset({
|
||||
width: view.getVisibleSize().width,
|
||||
height: view.getVisibleSize().height
|
||||
});
|
||||
newCamera.getComponent(Camera).targetTexture = newRenderTexture;
|
||||
|
||||
director.once(Director.EVENT_AFTER_DRAW, () => {
|
||||
const newSpriteFrame = new SpriteFrame();
|
||||
|
||||
let data = newRenderTexture.readPixels(Math.round(node.getWorldPosition().x - node.getComponent(UITransform).width / 2 * node.scale.x),
|
||||
Math.round(node.getWorldPosition().y - node.getComponent(UITransform).height / 2 * node.scale.y),
|
||||
node.getComponent(UITransform).width * node.scale.x, node.getComponent(UITransform).height * node.scale.y)
|
||||
|
||||
let image = new ImageAsset();
|
||||
image.reset({
|
||||
_data: data,
|
||||
_compressed: false,
|
||||
width: node.getComponent(UITransform).width * node.scale.x,
|
||||
height: node.getComponent(UITransform).height * node.scale.y,
|
||||
format: Texture2D.PixelFormat.RGBA8888
|
||||
})
|
||||
|
||||
let newTexture = new Texture2D();
|
||||
newTexture.image = image;
|
||||
newSpriteFrame.texture = newTexture;
|
||||
newSpriteFrame.packable = false;
|
||||
|
||||
if (sys.isNative && (sys.os === sys.OS.IOS || sys.os === sys.OS.OSX)) {
|
||||
newSpriteFrame.flipUVY = false;
|
||||
} else {
|
||||
newSpriteFrame.flipUVY = true;
|
||||
}
|
||||
|
||||
let newSprite = new Node("PhotoSprite");
|
||||
newSprite.addComponent(Sprite);
|
||||
newSprite.setParent(parent);
|
||||
newSprite.setPosition(pos);
|
||||
newSprite.layer = Layers.Enum.UI_2D;
|
||||
newSprite.getComponent(UITransform)
|
||||
.setContentSize(new Size(node.getComponent(UITransform).width,
|
||||
node.getComponent(UITransform).height));
|
||||
newSprite.getComponent(Sprite).spriteFrame = newSpriteFrame;
|
||||
|
||||
newCamera.getComponent(Camera).targetTexture = null;
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件。
|
||||
* @param textToWrite 要保存的文件内容
|
||||
* @param fileNameToSaveAs 要保存的文件名
|
||||
* @param fileType 要保存的文件格式,默认为Json
|
||||
*/
|
||||
public static saveForBrowser(textToWrite: any, fileNameToSaveAs: string, fileType: string = 'application/json') {
|
||||
if (sys.isBrowser) {
|
||||
console.log("浏览器");
|
||||
let textFileAsBlob = new Blob([textToWrite], { type: fileType });
|
||||
let downloadLink = document.createElement("a");
|
||||
downloadLink.download = fileNameToSaveAs;
|
||||
downloadLink.innerHTML = "Download File";
|
||||
downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
|
||||
|
||||
downloadLink.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取spine指定动画时间,如果没有该动画 则返回0
|
||||
* @param spine 骨骼动画
|
||||
* @param aniName 动画名称
|
||||
* @returns 动画时间
|
||||
*/
|
||||
public static getSpineAnimationTime(spine: sp.Skeleton, aniName: string) {
|
||||
const state = spine.getState();
|
||||
if (state == undefined) throw `[ERROR SPINE ANIMATION] 无法获取获取动画状态`;
|
||||
const { animations } = state.data.skeletonData;
|
||||
let result = 0;
|
||||
for (const key in animations) {
|
||||
if (Object.prototype.hasOwnProperty.call(animations, key)) {
|
||||
const element = animations[key];
|
||||
if (element.name == aniName) {
|
||||
result = element.duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------节点预制体相关-------------------------------
|
||||
/**
|
||||
* 新建一个预制体在场景里
|
||||
* @param preName 预制体名字或url
|
||||
* @param callFunc 加载预制体 完成后回调
|
||||
* @param parent 存放预制体的父节点
|
||||
* @param Pos 预制体的坐标
|
||||
* @param zIndex 预制体的层级
|
||||
*/
|
||||
public static newPrefab(preName: string, parent?: Node, Pos?: Vec3, callFunc?: (age?: Node) => void): Node {
|
||||
return NodeTools._ins.newPrefab(preName, callFunc, parent, Pos);
|
||||
}
|
||||
/**
|
||||
* 新建一个图片在场景里
|
||||
* @param sprName 图片名字或url
|
||||
* @param callFunc 加载预制体 完成后回调
|
||||
* @param parent 存放预制体的父节点
|
||||
* @param Pos 预制体的坐标
|
||||
* @param zIndex 预制体的层级
|
||||
*/
|
||||
public static newSprite(sprName: string, parent?: Node, Pos?: Vec3, callFunc?: (age?: Node) => void): Node {
|
||||
return NodeTools._ins.newSprite(sprName, callFunc, parent, Pos);
|
||||
}
|
||||
/**
|
||||
* 设置一个节点的SpriteFrame
|
||||
* @param nodeT 节点的Node
|
||||
* @param sprUrl 图片的url或者存放到resArr的名字
|
||||
*/
|
||||
public static setSpriteFrame(nodeT: Node, sprUrl: string) {
|
||||
NodeTools._ins.setSpriteFrame(nodeT, sprUrl);
|
||||
}
|
||||
/** 设置一个节点的 groupIndex 包含子物体 */
|
||||
public static setNodeLayerIndex(nodeT: Node, layer: Layers.Enum) {
|
||||
NodeTools._ins.setNodeLayerIndex(nodeT, layer);
|
||||
}
|
||||
/**
|
||||
* 设置一个Button的按下和松开的SpriteFrame
|
||||
* @param norUrl 默认状态的名字或者路径
|
||||
* @param preUrl 按下状态的名字或者路径
|
||||
*/
|
||||
public static setBtnClickSpr(Btn: Button, norUrl: string, preUrl: string) {
|
||||
NodeTools._ins.setBtnClickSpr(Btn, norUrl, preUrl);
|
||||
};
|
||||
/** 切换父物体 不改变显示位置*/
|
||||
public static setNodeParent(node: Node, parent: Node) {
|
||||
NodeTools._ins.setNodeParent(node, parent);
|
||||
};
|
||||
//----------------------------------数学数组相关----------------------------------
|
||||
|
||||
/**
|
||||
* 将多维数组展平
|
||||
* @param arr 需要展平的多维数组
|
||||
* @returns 展平后的数组
|
||||
*/
|
||||
public static flatArray(arr: any[]) {
|
||||
return arr.reduce((acc, curr) => {
|
||||
return acc.concat(Array.isArray(curr) ? Tools.flatArray(curr) : curr);
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数组中随机获取元素
|
||||
* @param arr 需要随机获取元素的数组
|
||||
* @param num 需要获取的元素数量
|
||||
* @param sortFunc 排序函数,可选
|
||||
* @returns 返回随机获取的元素数组
|
||||
*/
|
||||
public static randomGetElementFromArray(arr: any[], num: number, sortFunc: (a: any, b: any) => number = null) {
|
||||
const tempArr = arr.slice();
|
||||
const resultArr = [];
|
||||
while (resultArr.length < num) {
|
||||
const randomIndex = Tools.random(0, tempArr.length - 1);
|
||||
resultArr.push(tempArr[randomIndex]);
|
||||
tempArr.splice(randomIndex, 1);
|
||||
}
|
||||
if (sortFunc) {
|
||||
resultArr.sort(sortFunc);
|
||||
}
|
||||
return resultArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机数
|
||||
* @param isInteger 是否随机整数 默认整数
|
||||
*/
|
||||
public static random(x1: number, x2: number, isInteger = true): number {
|
||||
return MathTools._ins.random(x1, x2, isInteger);
|
||||
}
|
||||
/**
|
||||
* 根据概率数组 随机概率 返回数组的index
|
||||
* @param chooseArr 需要随机概率的数组 例如[0.05,0.1,0.2,0.3]
|
||||
*/
|
||||
public static chooseRandom(chooseArr: Array<number>) {
|
||||
return MathTools._ins.chooseRandom(chooseArr);
|
||||
}
|
||||
/** 传入一个弧度 返回一个Y轴折射后的弧度 */
|
||||
public static refractionY(rad: number) {
|
||||
return MathTools._ins.refractionY(rad);
|
||||
};
|
||||
/** 传入一个弧度 返回一个轴折射后的弧度 */
|
||||
public static refractionX(rad: number) {
|
||||
return MathTools._ins.refractionX(rad);
|
||||
};
|
||||
/** 重新打乱一个数组的顺序 洗牌 */
|
||||
public static againSortArr(Arr: Array<any>) {
|
||||
MathTools._ins.againSortArr(Arr);
|
||||
};
|
||||
/**
|
||||
* 将一个数组 按照里面的对象排序
|
||||
* @param tempArr 传入的数组
|
||||
* @param sortName 对象属性名字
|
||||
* @param isReverse 是否倒序
|
||||
*/
|
||||
public static sortArrForObject(tempArr: Array<any>, sortName: string, isReverse = false) {
|
||||
MathTools._ins.sortArrForObject(tempArr, sortName, isReverse);
|
||||
};
|
||||
/**
|
||||
* 取一定范围内不重复的数字
|
||||
* @param minNum 最小取值范围
|
||||
* @param maxNum 最大取值范围
|
||||
* @param getNum 取几个数字
|
||||
*/
|
||||
public static getDiffNumRandom(minNum: number, maxNum: number, getNum: number) {
|
||||
return MathTools._ins.getDiffNumRandom(minNum, maxNum, getNum);
|
||||
};
|
||||
//--------------------------------向量坐标计算相关------------------------------------
|
||||
/**
|
||||
* 根据两个点 求角度
|
||||
* @param pos1 起始点坐标
|
||||
* @param pos2 结束点坐标
|
||||
* @param isVertical 是否以竖直方向为0度开始
|
||||
*/
|
||||
public static getAngleForPos(pos1: Vec2, pos2: Vec2, isVertical = false): number {
|
||||
return VecTools._ins.getAngleForPos(pos1, pos2, isVertical);
|
||||
};
|
||||
/** 获取两个坐标之间的距离 */
|
||||
public static getDistance(pos1: Vec3 | Vec2, pos2: Vec3 | Vec2): number {
|
||||
if (pos1 instanceof Vec2 && pos2 instanceof Vec2) {
|
||||
return Vec2.distance(pos1, pos2);
|
||||
}
|
||||
if (pos1 instanceof Vec3 && pos2 instanceof Vec3) {
|
||||
return Vec3.distance(pos1, pos2);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 根据一个角度和长度 计算相对应的坐标
|
||||
* @param angle 角度
|
||||
* @param len 该角度上的长度
|
||||
* @param startPos 初始的坐标
|
||||
*/
|
||||
public static getPosForAngleLen(angle: number, len: number, startPos: Vec2 = v2(0, 0)) {
|
||||
return VecTools._ins.getPosForAngleLen(angle, len, startPos);
|
||||
}
|
||||
/**
|
||||
* 获取节点在另一个节点下的坐标
|
||||
* @param obj 节点
|
||||
* @param mainObj 相对于的另一个节点
|
||||
*/
|
||||
public static getToNodePosForNode(obj: Node, mainObj: Node): Vec2 {
|
||||
return VecTools._ins.getToNodePosForNode(obj, mainObj);
|
||||
};
|
||||
/** 获取节点的世界坐标 */
|
||||
public static getToWorldPosAR(obj: Node) {
|
||||
return VecTools._ins.getToWorldPosAR(obj);
|
||||
}
|
||||
/**
|
||||
* 通过世界坐标 获取相对节点的坐标
|
||||
* @param worldPos 世界坐标
|
||||
* @param obj 相对节点下的
|
||||
*/
|
||||
public static getToNodePosForWorld(worldPos: Vec3, obj: Node) {
|
||||
return VecTools._ins.getToNodePosForWorld(worldPos, obj);
|
||||
}
|
||||
/** 二维向量转三维向量 */
|
||||
public static getVec3ForVec2(vec2: Vec2) {
|
||||
return VecTools._ins.getVec3ForVec2(vec2);
|
||||
}
|
||||
/** 三维向量转二维向量 */
|
||||
public static getVec2ForVec3(vec3: Vec3) {
|
||||
return VecTools._ins.getVec2ForVec3(vec3);
|
||||
}
|
||||
/** 获取两向量方向 */
|
||||
public static getDirection(startPos: Vec3 | Vec2, endPos: Vec3 | Vec2) {
|
||||
return VecTools._ins.getDirection(startPos, endPos);
|
||||
}
|
||||
/** 获取多边形面积 */
|
||||
public static getPolygonArea(polygon: Vec2[]) {
|
||||
return VecTools._ins.getPolygonArea(polygon);
|
||||
}
|
||||
//--------------------------------数组操作相关------------------------------------
|
||||
/** 根据value值 从数组里面移除 */
|
||||
public static removeArrForValue(tempArr: Array<any>, value: any) {
|
||||
return tempArr.splice(tempArr.indexOf(value), 1);
|
||||
}
|
||||
/** 从数组里面添加一个该数组里没有的元素 */
|
||||
public static addArrNoValue(tempArr: Array<any>, value: any) {
|
||||
if (tempArr.indexOf(value) < 0) {
|
||||
tempArr.push(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/** 从数组指定位置 插入某个元素 */
|
||||
public static addArrIndex(tempArr: Array<any>, index: number, value: any) {
|
||||
return tempArr.splice(index, 0, value);
|
||||
}
|
||||
//--------------------------------其他------------------------------------
|
||||
/**
|
||||
* 字符串指定位置插入新字符
|
||||
* @param source 需要操作的字符串
|
||||
* @param start 从那个位置开始插入
|
||||
* @param newStr 插入的新的字符
|
||||
*/
|
||||
public static insertStrForIndex(source: string, start: number, newStr: string): string {
|
||||
return source.slice(0, start) + newStr + source.slice(start);
|
||||
};
|
||||
/**
|
||||
* 数字整数前边补零 并返回字符串
|
||||
* @param num 传入的数字
|
||||
* @param length 前边补几个零
|
||||
*/
|
||||
public static prefixInteger(num: number, length = 2): string {
|
||||
return (Array(length).join('0') + num).slice(-length);
|
||||
};
|
||||
/** 获取系统语言 */
|
||||
public static getLanguageType(): string {
|
||||
var langNumType = "EN"; //默认英语
|
||||
if (sys.language == sys.Language.CHINESE) {
|
||||
if (sys.languageCode.toLowerCase().indexOf("zh-cn") != -1 ||
|
||||
sys.languageCode.toLowerCase().indexOf("zh_cn") != -1 ||
|
||||
sys.languageCode.toLowerCase().indexOf("zh-hans-cn") != -1) {
|
||||
langNumType = "CN"; //简体
|
||||
} else {
|
||||
langNumType = "CHT"; //繁体
|
||||
}
|
||||
}
|
||||
// else if ( sys.language == sys.Language.KOREAN ) {
|
||||
// langNumType = "KOR"; //韩语
|
||||
// }
|
||||
// else if (sys.language == sys.Language.JAPANESE) {
|
||||
// langNumType = "JP"; //日语
|
||||
// }
|
||||
// else if ( window.navigator.language == "th-TH" ) {
|
||||
// langNumType = "TH"; //泰语
|
||||
// }
|
||||
return langNumType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 节点相关 工具类 */
|
||||
class NodeTools {
|
||||
/** 单例模式 */
|
||||
private static _instance: NodeTools = new NodeTools();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 新建一个预制体在场景里 */
|
||||
public newPrefab(preName: string, callFunc?: (age?: Node) => void, parent?: Node, Pos?: Vec3): Node {
|
||||
let prefab = ResModel._ins.PrefabDic.get(preName);
|
||||
let clone: Node = null;
|
||||
if (prefab != null) {
|
||||
clone = instantiate(prefab);
|
||||
if (parent) { parent.addChild(clone) };
|
||||
if (Pos) { clone.position = v3(Pos.x, Pos.y, Pos.z) };
|
||||
if (callFunc != null) {
|
||||
callFunc(clone);
|
||||
}
|
||||
} else {
|
||||
LoadTools._ins.loadResPrefab(preName, callFunc, parent, Pos);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
/** 新建一个图片在场景里 */
|
||||
public newSprite(sprName: string, callFunc?: (age?: Node) => void, parent?: Node, Pos?: Vec3) {
|
||||
let sprite = new Node();
|
||||
sprite.name = sprName;
|
||||
sprite.layer = Layers.Enum.UI_2D;
|
||||
if (ResModel._ins.SpriteFrameDic.get(sprName) != null) {
|
||||
sprite.addComponent(Sprite).spriteFrame = ResModel._ins.SpriteFrameDic.get(sprName);
|
||||
if (parent) { parent.addChild(sprite) };
|
||||
if (Pos) { sprite.position = v3(Pos.x, Pos.y, Pos.z) };
|
||||
if (callFunc != null) {
|
||||
callFunc(sprite);
|
||||
}
|
||||
} else {
|
||||
sprite.addComponent(Sprite);
|
||||
LoadTools._ins.loadResSpriteFrame(sprName, sprite, parent, Pos, callFunc);
|
||||
}
|
||||
return sprite;
|
||||
}
|
||||
/** 设置一个节点的SpriteFrame */
|
||||
public setSpriteFrame(nodeT: Node, sprUrl: string) {
|
||||
if (nodeT.getComponent(Sprite) == null) {
|
||||
nodeT.addComponent(Sprite);
|
||||
}
|
||||
if (ResModel._ins.SpriteFrameDic.get(sprUrl)) {
|
||||
nodeT.getComponent(Sprite).spriteFrame = ResModel._ins.SpriteFrameDic.get(sprUrl)
|
||||
} else {
|
||||
LoadTools._ins.loadResAny(sprUrl, SpriteFrame, (spriteFrame: SpriteFrame) => {
|
||||
nodeT.getComponent(Sprite).spriteFrame = spriteFrame;
|
||||
})
|
||||
}
|
||||
}
|
||||
/** 设置一个节点的 所属层 包含子物体 */
|
||||
public setNodeLayerIndex(nodeT: Node, layer: Layers.Enum) {
|
||||
nodeT.layer = layer;
|
||||
for (let i = 0; i < nodeT.children.length; i++) {
|
||||
this.setNodeLayerIndex(nodeT.children[i], layer);
|
||||
}
|
||||
}
|
||||
/** 设置一个Button的按下和松开的SpriteFrame */
|
||||
public setBtnClickSpr(Btn: Button, norUrl: string, preUrl: string) {
|
||||
if (ResModel._ins.SpriteFrameDic.get(norUrl)) {
|
||||
Btn.getComponent(Button).normalSprite = ResModel._ins.SpriteFrameDic.get(norUrl)
|
||||
Btn.getComponent(Button).hoverSprite = ResModel._ins.SpriteFrameDic.get(norUrl)
|
||||
Btn.getComponent(Button).pressedSprite = ResModel._ins.SpriteFrameDic.get(preUrl)
|
||||
} else {
|
||||
LoadTools._ins.loadResAny(norUrl, SpriteFrame, (spr: SpriteFrame) => {
|
||||
Btn.getComponent(Button).normalSprite = spr;
|
||||
Btn.getComponent(Button).hoverSprite = spr;
|
||||
});
|
||||
LoadTools._ins.loadResAny(preUrl, SpriteFrame, (spr: SpriteFrame) => {
|
||||
Btn.getComponent(Button).pressedSprite = spr;
|
||||
});
|
||||
}
|
||||
};
|
||||
/** 切换父物体 不改变坐标 */
|
||||
public setNodeParent(node: Node, parent: Node) {
|
||||
let Pos = VecTools._ins.getToNodePosForNode(node, parent);
|
||||
node.parent = parent;
|
||||
node.position = v3(Pos.x, Pos.y);
|
||||
};
|
||||
}
|
||||
|
||||
/** 数学数组计算相关 工具类 */
|
||||
class MathTools {
|
||||
/** 单例模式 */
|
||||
private static _instance: MathTools = new MathTools();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 获取随机数 */
|
||||
public random(x1: number, x2: number, isInteger = true): number {
|
||||
if (isInteger) {
|
||||
return x1 + Math.floor(Math.random() * (x2 - x1 + 1));
|
||||
}
|
||||
return Math.random() * (x2 - x1) + x1;
|
||||
}
|
||||
/** 根据概率数组 随机概率 返回数组的index */
|
||||
public chooseRandom(chooseArr: Array<number>) {
|
||||
let total = 0; //概率总值
|
||||
//首先计算出概率的总值,用来计算随机范围
|
||||
for (let i = 0; i < chooseArr.length; i++) {
|
||||
total += chooseArr[i];
|
||||
}
|
||||
let randNum = this.random(0, total, false)
|
||||
for (let i = 0; i < chooseArr.length; i++) {
|
||||
if (randNum < chooseArr[i] && chooseArr[i] > 0) {
|
||||
return i;
|
||||
} else {
|
||||
randNum -= chooseArr[i];
|
||||
}
|
||||
}
|
||||
return chooseArr.length - 1;
|
||||
}
|
||||
/** 弧度折射Y轴 */
|
||||
public refractionY(rad: number) {
|
||||
return Math.atan2(Math.sin(rad), -Math.cos(rad));
|
||||
};
|
||||
/** 弧度折射X轴 */
|
||||
public refractionX(rad: number) {
|
||||
return Math.atan2(-Math.sin(rad), Math.cos(rad));
|
||||
};
|
||||
/** 重新洗牌 一个数组 */
|
||||
public againSortArr(Arr: Array<any>) {
|
||||
for (let i = 0; i < Arr.length; i++) {
|
||||
let tempR = Tools.random(0, Arr.length - 1);
|
||||
if (tempR != i) {
|
||||
let temp = Arr[i];
|
||||
Arr[i] = Arr[tempR];
|
||||
Arr[tempR] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 数组 对象排序 对象属性 是否倒序 */
|
||||
public sortArrForObject(tempArr: Array<any>, sortName: string, isReverse = false) {
|
||||
if (!isReverse) {
|
||||
tempArr.sort((a, b) => {
|
||||
return a[sortName] - b[sortName];
|
||||
});
|
||||
} else {
|
||||
tempArr.sort((a, b) => {
|
||||
return b[sortName] - a[sortName];
|
||||
});
|
||||
}
|
||||
};
|
||||
/** 取一定范围内不重复的数字 */
|
||||
public getDiffNumRandom(minNum: number, maxNum: number, getNum: number) {
|
||||
var arr = [];
|
||||
for (let i = minNum; i <= maxNum; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
const tempLen = arr.length - getNum;
|
||||
for (let i = 0; i < tempLen; i++) {
|
||||
let tempI = Tools.random(0, arr.length - 1);
|
||||
arr.splice(tempI, 1);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
}
|
||||
|
||||
/** 向量坐标转换相关工具类 */
|
||||
class VecTools {
|
||||
/** 单例模式 */
|
||||
private static _instance: VecTools = new VecTools();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 根据两个点 求角度 */
|
||||
public getAngleForPos(pos1: Vec2, pos2: Vec2, isVertical = false): number {
|
||||
let rad = 0;
|
||||
if (isVertical) {
|
||||
rad = -Math.atan2(pos2.x - pos1.x, pos2.y - pos1.y);
|
||||
} else {
|
||||
rad = Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x);
|
||||
}
|
||||
return misc.radiansToDegrees(rad);
|
||||
}
|
||||
/** 根据一个角度和长度 计算相对应的坐标 */
|
||||
public getPosForAngleLen(angle: number, len: number, startPos: Vec2 = v2(0, 0)) {
|
||||
let rad = misc.degreesToRadians(angle);
|
||||
return v2(startPos.x + Math.cos(rad) * len, startPos.y + Math.sin(rad) * len);
|
||||
}
|
||||
/** 获取节点在另一个节点下的坐标 */
|
||||
public getToNodePosForNode(obj: Node, mainObj: Node): Vec2 {
|
||||
let worldPos = obj.parent.getComponent(UITransform).convertToWorldSpaceAR(obj.position);
|
||||
let nodePos = mainObj.getComponent(UITransform).convertToNodeSpaceAR(worldPos)
|
||||
return v2(nodePos.x, nodePos.y);
|
||||
};
|
||||
/** 获取节点的世界坐标 */
|
||||
public getToWorldPosAR(obj: Node) {
|
||||
return obj.parent.getComponent(UITransform).convertToWorldSpaceAR(obj.position);
|
||||
}
|
||||
/** 通过世界坐标 获取相对节点的坐标 */
|
||||
public getToNodePosForWorld(worldPos: Vec3, obj: Node) {
|
||||
return obj.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
|
||||
}
|
||||
|
||||
/** 二维向量转三维向量 */
|
||||
public getVec3ForVec2(vec2: Vec2) {
|
||||
return v3(vec2.x, vec2.y, 0);
|
||||
}
|
||||
|
||||
/** 三维向量转二维向量 */
|
||||
public getVec2ForVec3(vec3: Vec3) {
|
||||
return v2(vec3.x, vec3.y);
|
||||
}
|
||||
|
||||
/** 获取两向量方向和距离
|
||||
* @param startPos 起始位置
|
||||
* @param endPos 结束位置
|
||||
*/
|
||||
public getDirection(startPos: Vec3 | Vec2, endPos: Vec3 | Vec2) {
|
||||
if (startPos instanceof Vec2 && endPos instanceof Vec2) {
|
||||
const deltaPos = endPos.clone().subtract(startPos);
|
||||
const direction = deltaPos.normalize();
|
||||
return direction;
|
||||
} else if (startPos instanceof Vec3 && endPos instanceof Vec3) {
|
||||
const deltaPos = endPos.clone().subtract(startPos);
|
||||
const direction = deltaPos.normalize();
|
||||
return direction;
|
||||
}
|
||||
}
|
||||
|
||||
public getPolygonArea(polygon: Vec2[]) {
|
||||
return SplitRenderHelper.calculatePolygonArea(polygon);
|
||||
}
|
||||
}
|
||||
9
assets/script/common/Tools.ts.meta
Normal file
9
assets/script/common/Tools.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "f3cbf87f-aa09-459e-8527-cd6f1be98ffb",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
31
assets/script/common/weiSanTools.ts
Normal file
31
assets/script/common/weiSanTools.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
export class weiSan {
|
||||
/** 是否开启 Log 信息 */
|
||||
private static isLog = true;
|
||||
private static logName:string = "微伞游戏Log:"
|
||||
private static logInfo:string = "本游戏包含的所有内容(包括但不限于:代码、图片、视像及声音内容、名称)的所有权归北京米兜科技有限公司所有。任何单位或个人将本游戏提供的内容与服务用于商业、盈利、广告性等目的时,需征得北京米兜科技有限公司相关权利人的书面许可;将本网站提供的内容与服务用于非商业用途时,应遵守著作权法以及其他相关法律的规定,不得侵犯游戏所有者及相关权利人的权益。"
|
||||
|
||||
/** 普通log信息 */
|
||||
public static log(...data: any[]): void {
|
||||
if (!this.isLog) { return; }
|
||||
console.log(this.logName,...data);
|
||||
}
|
||||
/** 追踪函数调用的log */
|
||||
public static logTrace(...data: any[]){
|
||||
if (!this.isLog) { return; }
|
||||
console.trace(this.logName,...data);
|
||||
}
|
||||
/** 打印错误log信息 */
|
||||
public static error(...data: any[]): void {
|
||||
if (!this.isLog) { return; }
|
||||
console.error(this.logName,...data);
|
||||
}
|
||||
/** 打印警告log信息 */
|
||||
public static warn(...data: any[]): void {
|
||||
if (!this.isLog) { return; }
|
||||
console.warn(this.logName,...data);
|
||||
}
|
||||
|
||||
public static initLog(){
|
||||
console.log(this.logInfo);
|
||||
}
|
||||
}
|
||||
9
assets/script/common/weiSanTools.ts.meta
Normal file
9
assets/script/common/weiSanTools.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "289a2b50-88c3-4705-9e74-63d767daaefb",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/ctrl.meta
Normal file
12
assets/script/ctrl.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "5a099d6e-5ecf-49ae-a8e5-058876a83969",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
41
assets/script/ctrl/GameCtrl.ts
Normal file
41
assets/script/ctrl/GameCtrl.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { GameModel } from "../model/GameModel";
|
||||
|
||||
/** 游戏控制类相关 */
|
||||
export class GameCtrl {
|
||||
/** 单例模式 */
|
||||
private static _instance: GameCtrl = new GameCtrl();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 当前游戏状态 */
|
||||
gameState: GameState;
|
||||
/** 是否可点击 屏幕 */
|
||||
boolTouch: boolean = false;
|
||||
|
||||
/** 初始化游戏 相关数据 */
|
||||
initGame() {
|
||||
this.gameState = GameState.Default;
|
||||
// GameModel._ins.gameScore = 0;
|
||||
this.boolTouch = false;
|
||||
}
|
||||
/** 结束游戏 相关数据 */
|
||||
overGame() {
|
||||
this.gameState = GameState.Over;
|
||||
this.boolTouch = false;
|
||||
// PoolManager.clearAllPool();
|
||||
}
|
||||
}
|
||||
|
||||
/** 游戏状态枚举 */
|
||||
export enum GameState {
|
||||
/** 默认状态 */
|
||||
Default = 0,
|
||||
/** 游戏开始 */
|
||||
Start = 1,
|
||||
/** 游戏暂停 */
|
||||
Pause = 2,
|
||||
/** 游戏结束 */
|
||||
Over = 3,
|
||||
}
|
||||
9
assets/script/ctrl/GameCtrl.ts.meta
Normal file
9
assets/script/ctrl/GameCtrl.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "5607ac44-fb94-4b73-aa20-1a81fd484128",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/game.meta
Normal file
12
assets/script/game.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "f216decb-b5bd-47a9-94dd-5b7f8b17fa56",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
94
assets/script/game/MainGame.ts
Normal file
94
assets/script/game/MainGame.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
import { _decorator, Component, Node, view, macro, v3, Vec3, EventTouch } from 'cc';
|
||||
import { Tools } from '../common/Tools';
|
||||
import { weiSan } from '../common/weiSanTools';
|
||||
import { GameCtrl, GameState } from '../ctrl/GameCtrl';
|
||||
import { EventData, EventManager } from '../manager/EventManager';
|
||||
import { UIManager } from '../manager/UIManager';
|
||||
import { GameModel } from '../model/GameModel';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('MainGame')
|
||||
export class MainGame extends Component {
|
||||
|
||||
|
||||
/** 屏幕宽度 */
|
||||
gameWidth: number;
|
||||
/** 屏幕高度 */
|
||||
gameHeight: number;
|
||||
|
||||
onLoad() {
|
||||
|
||||
this.gameWidth = view.getVisibleSize().width;
|
||||
this.gameHeight = view.getVisibleSize().height;
|
||||
GameModel._ins.mainGame = this;
|
||||
|
||||
this.addTouchEvents();
|
||||
this.addInitListener();
|
||||
}
|
||||
|
||||
start() {
|
||||
this.initGame();
|
||||
}
|
||||
|
||||
update(deltaTime: number) {
|
||||
// [4]
|
||||
}
|
||||
/** 触摸开始点坐标 */
|
||||
touchStartPos: Vec3;
|
||||
/** 触摸事件 监听 */
|
||||
addTouchEvents(): void {
|
||||
macro.ENABLE_MULTI_TOUCH = false; //是否开起多点触摸
|
||||
|
||||
this.node.on(Node.EventType.TOUCH_START, this.touchStartBack, this);
|
||||
this.node.on(Node.EventType.TOUCH_MOVE, this.touchMoveBack, this);
|
||||
this.node.on(Node.EventType.TOUCH_END, this.touchEndBack, this);
|
||||
};
|
||||
/** 触摸开始 回调 */
|
||||
touchStartBack(touches: EventTouch) {
|
||||
if (!GameCtrl._ins.boolTouch) { return; }
|
||||
this.touchStartPos = Tools.getToNodePosForWorld(v3(touches.getUILocation().x, touches.getUILocation().y), this.node);
|
||||
}
|
||||
/** 触摸移动 回调 */
|
||||
touchMoveBack(touches: EventTouch) {
|
||||
if (!GameCtrl._ins.boolTouch) { return; }
|
||||
}
|
||||
/** 触摸结束 回调 */
|
||||
touchEndBack(touches: EventTouch) {
|
||||
if (!GameCtrl._ins.boolTouch) { return; }
|
||||
console.log("boolTouch");
|
||||
this.gameEnd();
|
||||
}
|
||||
/** 初始化游戏 */
|
||||
initGame() {
|
||||
GameModel._ins.gameScore = 0;
|
||||
GameCtrl._ins.initGame();
|
||||
GameCtrl._ins.boolTouch = true;
|
||||
}
|
||||
/** 开始游戏 */
|
||||
startGame() {
|
||||
}
|
||||
/** 游戏结束 */
|
||||
gameEnd() {
|
||||
if (GameCtrl._ins.gameState == GameState.Over) { return; }
|
||||
GameCtrl._ins.overGame();
|
||||
|
||||
weiSan.log("游戏结束");
|
||||
this.scheduleOnce(() => {
|
||||
UIManager.OpenUI("OverUI");
|
||||
}, 0.5);
|
||||
};
|
||||
|
||||
|
||||
/** 事件 监听 */
|
||||
addInitListener() {
|
||||
EventManager.addListener(EventData.START_GAME, this.startGame.bind(this), this.node);
|
||||
|
||||
}
|
||||
onDestroy() {
|
||||
EventManager.removeListenerForTarget(this.node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
9
assets/script/game/MainGame.ts.meta
Normal file
9
assets/script/game/MainGame.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "874b2f98-0ca1-4cc7-a253-8f1f379936be",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
61
assets/script/game/initGame.ts
Normal file
61
assets/script/game/initGame.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
import { _decorator, Component, Node, Prefab, Enum, instantiate, sys, view, ResolutionPolicy, screen } from 'cc';
|
||||
import { AdManager } from '../ads/AdManager';
|
||||
import { weiSan } from '../common/weiSanTools';
|
||||
import { PlatformManager, releaseType } from '../manager/PlatformManager';
|
||||
import { PoolManager } from '../manager/PoolManager';
|
||||
import { ResArr } from '../item/ResArr';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('initGame')
|
||||
export class initGame extends Component {
|
||||
@property([Prefab])
|
||||
resNodeArr: Array<Prefab> = [];
|
||||
@property({ type: Enum(releaseType) })
|
||||
rType: number = releaseType.test_TEST;
|
||||
@property
|
||||
storageKey: string = "demo_Game"
|
||||
|
||||
@property
|
||||
fitWidth: number = 720;
|
||||
@property
|
||||
fitHeight: number = 1280;
|
||||
|
||||
|
||||
onLoad() {
|
||||
if (this.rType == releaseType.h5_weiSan) {
|
||||
this.rType = releaseType.h5_common;
|
||||
}
|
||||
PlatformManager.releaseType = this.rType;
|
||||
PlatformManager.storageKey = this.storageKey;
|
||||
PlatformManager.initPlatform();
|
||||
// AdManager.loadAds();
|
||||
|
||||
this.initResNode();
|
||||
this.initScreen();
|
||||
weiSan.initLog();
|
||||
}
|
||||
/** 初始化 resNode */
|
||||
initResNode() {
|
||||
for (let i = 0; i < this.resNodeArr.length; i++) {
|
||||
let resNode = instantiate(this.resNodeArr[i]);
|
||||
this.node.addChild(resNode);
|
||||
PoolManager._ins.init(resNode.getComponent(ResArr).PrefabArr);
|
||||
}
|
||||
}
|
||||
/** 电脑端 按宽高一起适配 */
|
||||
initScreen() {
|
||||
if (this.rType != releaseType.h5_weiSan && this.rType != releaseType.h5_common) { return; }
|
||||
weiSan.log("系统OS: " + sys.os);
|
||||
// view.enableAutoFullScreen(false);
|
||||
// if( screen.fullScreen() ){
|
||||
// screen.exitFullScreen();
|
||||
// }
|
||||
// view.setResolutionPolicy(ResolutionPolicy.FIXED_WIDTH);
|
||||
if (sys.os == sys.OS.WINDOWS) {
|
||||
view.setRealPixelResolution(this.fitWidth, this.fitHeight, ResolutionPolicy.SHOW_ALL);
|
||||
}
|
||||
}
|
||||
// start() {
|
||||
// }
|
||||
}
|
||||
9
assets/script/game/initGame.ts.meta
Normal file
9
assets/script/game/initGame.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e60100f4-853c-4d81-aa19-d9bbb181c875",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/item.meta
Normal file
12
assets/script/item.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "098f74e7-3d20-4a12-98b7-892d9c489859",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
74
assets/script/item/ResArr.ts
Normal file
74
assets/script/item/ResArr.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
import { _decorator, Component, SpriteFrame, Prefab, AudioClip, Texture2D, Material, assertID, assetManager, Asset, Sprite } from 'cc';
|
||||
import { Tools } from '../common/Tools';
|
||||
import { ResModel } from '../model/ResModel';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('ResArr')
|
||||
export class ResArr extends Component {
|
||||
@property([SpriteFrame])
|
||||
public SpriteFrameArr: Array<SpriteFrame> = [];
|
||||
@property([Prefab])
|
||||
public PrefabArr: Array<Prefab> = [];
|
||||
@property([AudioClip])
|
||||
public audiosArr: Array<AudioClip> = [];
|
||||
|
||||
@property([Material])
|
||||
public MaterialArr: Array<Material> = [];
|
||||
@property([SpriteFrame])
|
||||
public Texture2DArr: Array<SpriteFrame> = [];
|
||||
|
||||
onLoad() {
|
||||
this.addAudio();
|
||||
this.addPrefabs();
|
||||
this.addSpriteFrame();
|
||||
this.addMaterial();
|
||||
|
||||
this.addTexture();
|
||||
}
|
||||
/** 添加音效文件 到Tools字典里面 */
|
||||
addAudio() {
|
||||
for (let i = 0; i < this.audiosArr.length; i++) {
|
||||
if (this.audiosArr[i]) {
|
||||
const element = this.audiosArr[i];
|
||||
ResModel._ins.AudioClipDic.set(element.name, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 添加图片文件 到Tools字典里面 */
|
||||
addSpriteFrame() {
|
||||
for (let i = 0; i < this.SpriteFrameArr.length; i++) {
|
||||
if (this.SpriteFrameArr[i]) {
|
||||
const element = this.SpriteFrameArr[i];
|
||||
ResModel._ins.SpriteFrameDic.set(element.name, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 添加预制体文件 到Tools字典里面 */
|
||||
addPrefabs() {
|
||||
for (let i = 0; i < this.PrefabArr.length; i++) {
|
||||
if (this.PrefabArr[i]) {
|
||||
const element = this.PrefabArr[i];
|
||||
ResModel._ins.PrefabDic.set(element.data.name, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 添加材质文件 到Tools字典里面 */
|
||||
addMaterial() {
|
||||
for (let i = 0; i < this.MaterialArr.length; i++) {
|
||||
if (this.MaterialArr[i]) {
|
||||
const element = this.MaterialArr[i];
|
||||
ResModel._ins.MaterialDic.set(element.name, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 添加Texture文件 到Tools字典里面 */
|
||||
addTexture() {
|
||||
for (let i = 0; i < this.Texture2DArr.length; i++) {
|
||||
if (this.Texture2DArr[i]) {
|
||||
const element = this.Texture2DArr[i];
|
||||
ResModel._ins.TextureDic.set(element.name, element.texture as Texture2D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/script/item/ResArr.ts.meta
Normal file
9
assets/script/item/ResArr.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "f5f4439e-1136-4841-b704-e1f74bf499a1",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/manager.meta
Normal file
12
assets/script/manager.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "b9102174-9f9c-46af-91b1-0eda31236428",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
57
assets/script/manager/EventManager.ts
Normal file
57
assets/script/manager/EventManager.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { director } from "cc";
|
||||
|
||||
export class EventManager {
|
||||
/**添加一个全局监听
|
||||
* @param eventName 事件名
|
||||
* @param event 事件Function
|
||||
* @param target 添加监听事件的脚本this
|
||||
*/
|
||||
public static addListener(eventName: string, event: any, target: any) {
|
||||
director.on(eventName, event, target);
|
||||
};
|
||||
/**
|
||||
* 移除一个监听事件
|
||||
* @param {*} eventName 事件名
|
||||
* @param {*} event 事件Function
|
||||
* @param {*} target 添加监听事件的Node
|
||||
*/
|
||||
public static removeListener(eventName: string, event: any, target: any) {
|
||||
director.off(eventName, event, target);
|
||||
};
|
||||
/**
|
||||
* 派发一个事件 令所有监听此事件的Node执行事件
|
||||
* @param {*} eventName 事件名
|
||||
* @param {*} arg1 传递的参数1
|
||||
* @param {*} arg2 传递的参数2
|
||||
* @param {*} arg3 传递的参数3
|
||||
* @param {*} arg4 传递的参数4
|
||||
* @param {*} arg5 传递的参数5
|
||||
*/
|
||||
public static dispatchEvent(eventName: string, arg1?: any, arg2?: any, arg3?: any, arg4?: any, arg5?: any) {
|
||||
director.emit(eventName, arg1, arg2, arg3, arg4, arg5);
|
||||
};
|
||||
/**
|
||||
* 移除 Node 上的所有事件
|
||||
* @param {*} target 需要移除事件的Node
|
||||
*/
|
||||
public static removeListenerForTarget(target: any) {
|
||||
director.targetOff(target);
|
||||
};
|
||||
};
|
||||
|
||||
export enum EventData {
|
||||
/** 开始游戏 */
|
||||
START_GAME = "START_GAME",
|
||||
/** 复活 */
|
||||
REIVE_GAME = "REIVE_GAME",
|
||||
/**加金币 */
|
||||
AddCoin = "AddCoin",
|
||||
/**加生命 */
|
||||
AddLife = "AddLife",
|
||||
/** 预制体分帧加载开始 */
|
||||
PREFAB_LOAD_START = "PREFAB_LOAD_START",
|
||||
/** 预制体分帧加载进度更新 */
|
||||
PREFAB_LOAD_PROGRESS = "PREFAB_LOAD_PROGRESS",
|
||||
/** 预制体分帧加载完成 */
|
||||
PREFAB_LOAD_COMPLETE = "PREFAB_LOAD_COMPLETE",
|
||||
}
|
||||
9
assets/script/manager/EventManager.ts.meta
Normal file
9
assets/script/manager/EventManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "1dddfca2-37e3-4421-9802-d1ed36cd6abf",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
123
assets/script/manager/NetworkManager.ts
Normal file
123
assets/script/manager/NetworkManager.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { loader } from "cc";
|
||||
import { weiSan } from "../common/weiSanTools";
|
||||
import { PlatformManager, releaseType } from "./PlatformManager";
|
||||
|
||||
/** 网络相关 管理类 */
|
||||
export class NetworkManager {
|
||||
/** 游戏ID */
|
||||
public static gameHttpId: number = 0;
|
||||
/** 更多游戏 链接 */
|
||||
public static moreGameUrl: string;
|
||||
|
||||
/** 初始化 网络相关 */
|
||||
public static initNetwork() {
|
||||
if (PlatformManager.releaseType == releaseType.h5_common || PlatformManager.releaseType == releaseType.h5_weiSan) {
|
||||
this.initNet_H5()
|
||||
} else if (PlatformManager.releaseType == releaseType.test_TEST) {
|
||||
this.moreGameUrl = "http://m.wesane.com/";
|
||||
weiSan.log("发送:---游戏加载成功!");
|
||||
}
|
||||
}
|
||||
/** 初始化 H5 网络请求 */
|
||||
private static initNet_H5() {
|
||||
this.getHttpGameId();
|
||||
this.sendLoadGame();
|
||||
}
|
||||
/** 通过url 获取gameID */
|
||||
private static getHttpGameId() {
|
||||
var url = document.URL;
|
||||
var game_id = 0;
|
||||
|
||||
if (PlatformManager.releaseType == releaseType.h5_common) {
|
||||
var httpUrl = window.location.href;
|
||||
var httpHead = httpUrl.substring(0, httpUrl.lastIndexOf("//") + 2);
|
||||
var httpMid = window.location.host;
|
||||
var httpAll = httpHead + httpMid + "/Service/Share/index";
|
||||
|
||||
var url = document.URL;
|
||||
var index = url.lastIndexOf("\/");
|
||||
var str = url.substring(0, index);
|
||||
var index = str.lastIndexOf("/");
|
||||
game_id = parseInt(str.substring(index + 1, str.length));
|
||||
this.gameHttpId = game_id;
|
||||
// console.log("gameIdNew", game_id);
|
||||
var endHttp = httpUrl.substring(httpUrl.lastIndexOf("//") + 4, httpUrl.lastIndexOf("com") + 3);
|
||||
var curWebMoreGame = httpHead + httpMid
|
||||
// console.log("moreGame", curWebMoreGame);
|
||||
|
||||
var urlIndex = curWebMoreGame.lastIndexOf('//')
|
||||
var urlG = curWebMoreGame.substring(urlIndex + 2, curWebMoreGame.indexOf("//") + 4);
|
||||
if (urlG == 'g.') {
|
||||
var newMoreUrl = curWebMoreGame.replace(urlG, "");
|
||||
// console.log("chagee", newMoreUrl);
|
||||
curWebMoreGame = newMoreUrl;
|
||||
} else {
|
||||
console.log("noChange");
|
||||
}
|
||||
this.moreGameUrl = curWebMoreGame;
|
||||
|
||||
msgHttpUrl.gamePv_commonH5 = httpHead + httpMid + "/Service/GamePv/index";
|
||||
msgHttpUrl.score_commonH5 = httpHead + httpMid + "/Service/Score/index";
|
||||
} else {
|
||||
var para = url.substring(url.lastIndexOf("/game/") + 1, url.length);
|
||||
var arr = para.split("/");
|
||||
if (arr.length >= 2) {
|
||||
game_id = parseInt(arr[1]);
|
||||
}
|
||||
this.moreGameUrl = "http://m.wesane.com/"; // this.httpHead + this.endHttp;
|
||||
}
|
||||
this.gameHttpId = game_id;
|
||||
weiSan.log("gameId:", game_id , this.moreGameUrl );
|
||||
};
|
||||
/** 向服务器 发送 加载游戏成功 */
|
||||
private static sendLoadGame() {
|
||||
if (PlatformManager.releaseType == releaseType.h5_weiSan) {
|
||||
this.sendMsg(msgHttpUrl.gamePv_weiSanH5, "gameID=" + this.gameHttpId.toString(), this.loadGameBack);
|
||||
} else if (PlatformManager.releaseType == releaseType.h5_common) {
|
||||
this.sendMsg(msgHttpUrl.gamePv_commonH5, "gameId=" + this.gameHttpId.toString(), this.loadGameBack);
|
||||
}
|
||||
};
|
||||
/** 发送加载游戏成功回调 */
|
||||
private static loadGameBack() {
|
||||
weiSan.log("gamePv加载成功");
|
||||
}
|
||||
/** 向服务器 提交分数 */
|
||||
public static sendGameScore(Score: number, gameType: any) {
|
||||
if (PlatformManager.releaseType == releaseType.h5_weiSan) {
|
||||
this.sendMsg(msgHttpUrl.score_weiSanH5, "gameScore=" + Score + "&gameId=" + this.gameHttpId + "&gameType=" + gameType, this.sendScoreBack);
|
||||
} else if (PlatformManager.releaseType == releaseType.h5_common) {
|
||||
this.sendMsg(msgHttpUrl.score_commonH5, "gameScore=" + Score + "&gameId=" + this.gameHttpId + "&gameType=" + gameType, this.sendScoreBack);
|
||||
}
|
||||
};
|
||||
/** 向服务器 提交分数回调 */
|
||||
private static sendScoreBack(Event: any) {
|
||||
weiSan.log("---提交分数成功!" + Event);
|
||||
if (Event.currentTarget.response != null && Event.currentTarget.response != "") {
|
||||
var endShowText = JSON.parse(Event.currentTarget.response);
|
||||
// weiSan.log("sendScoreBack:",endShowText.content);
|
||||
}
|
||||
}
|
||||
|
||||
/** 向服务器 POST请求 http */
|
||||
public static sendMsg(url: string, postData: any, callback?: any) {
|
||||
// var request = loader.getXMLHttpRequest();
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = callback;
|
||||
request.open("POST", url);
|
||||
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
request.send(postData);
|
||||
};
|
||||
}
|
||||
window.NetworkManager = NetworkManager;
|
||||
|
||||
/** 网络 消息号数据 */
|
||||
export var msgHttpUrl = {
|
||||
/** 微伞游戏H5 加载成功 */
|
||||
gamePv_weiSanH5: "http://www.wesane.com/admin.php/Activityshow/gamelogo",
|
||||
/** 微伞游戏H5 提交分数 */
|
||||
score_weiSanH5: "http://www.wesane.com/admin.php/Gamescore/saveGamescore",
|
||||
/** 通用H5游戏 加载成功 */
|
||||
gamePv_commonH5: "",
|
||||
/** 通用H5游戏 提交分数 */
|
||||
score_commonH5: "",
|
||||
}
|
||||
9
assets/script/manager/NetworkManager.ts.meta
Normal file
9
assets/script/manager/NetworkManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "700c5a3f-bf5b-4302-96ab-e576d03dccc1",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
115
assets/script/manager/PlatformManager.ts
Normal file
115
assets/script/manager/PlatformManager.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { Enum, game, view , screen, sys } from "cc";
|
||||
import { AdManager } from "../ads/AdManager";
|
||||
import { Tools } from "../common/Tools";
|
||||
import { NetworkManager } from "./NetworkManager";
|
||||
|
||||
/** 游戏管理类 */
|
||||
export class PlatformManager {
|
||||
/** 发布平台类型 */
|
||||
public static releaseType: number;
|
||||
/** 发布类型 h5 安卓 IOS 小程序 */
|
||||
public static osType:number;
|
||||
/** 存储本地数据 key的前标 */
|
||||
public static storageKey: string = "demo_Game_";
|
||||
/** 游戏是否 加载成功 */
|
||||
public static loadGameBool:boolean = false;
|
||||
|
||||
/** 初始化平台 相关 */
|
||||
public static initPlatform(){
|
||||
if(this.loadGameBool) { return; } //第一次加载成功后 不加载第二次
|
||||
this.initOsType();
|
||||
NetworkManager.initNetwork();
|
||||
|
||||
if(PlatformManager.releaseType == releaseType.h5_weiSan || PlatformManager.releaseType == releaseType.h5_common){
|
||||
if(NetworkManager.gameHttpId.toString() == "NaN"){
|
||||
if(PlatformManager.releaseType == releaseType.h5_weiSan){
|
||||
window.location.href = NetworkManager.moreGameUrl;
|
||||
}else{
|
||||
window.location.href = "http://www.vsane.com/";
|
||||
}
|
||||
}
|
||||
loadInScene();
|
||||
}
|
||||
if(PlatformManager.releaseType != releaseType.applet_ziJie){
|
||||
window.AdManager = AdManager;
|
||||
}
|
||||
this.loadGameBool = true;
|
||||
};
|
||||
/** 初始化 发布类型 */
|
||||
private static initOsType(){
|
||||
if( this.releaseType == releaseType.APP_google ){
|
||||
this.osType = osType.android;
|
||||
}else if( this.releaseType == releaseType.APP_ios ){
|
||||
this.osType = osType.ios;
|
||||
}else if(this.releaseType == releaseType.applet_wechat ||
|
||||
this.releaseType == releaseType.applet_ziJie ){
|
||||
this.osType = osType.applet;
|
||||
}else{
|
||||
this.osType = osType.h5;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 存储本地数据
|
||||
* @param {*} isObject 是否是一个对象或者数组
|
||||
*/
|
||||
public static setStorage(key: string, value: any, isObject = false) {
|
||||
key = this.storageKey + key;
|
||||
if (PlatformManager.releaseType === releaseType.applet_ziJie) {
|
||||
return tt.setStorageSync(key, value);
|
||||
}
|
||||
if (isObject) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
/** 默认cocos 存储数据方法 */
|
||||
sys.localStorage.setItem(key, value);
|
||||
}
|
||||
/**
|
||||
* 获取存储数据
|
||||
* @param {*} isObject 是否是一个对象或者数组
|
||||
*/
|
||||
public static getStorage(key: string, isObject = false) {
|
||||
key = this.storageKey + key;
|
||||
let temp = null;
|
||||
if (PlatformManager.releaseType === releaseType.applet_ziJie) {
|
||||
temp = <any>tt.getStorageSync(key);
|
||||
}else{
|
||||
temp = <any>sys.localStorage.getItem(key);
|
||||
if (!temp || temp.toString() == "NaN" || temp.toString() == "null") {
|
||||
temp = null;
|
||||
}else if( isObject ){
|
||||
temp = JSON.parse(temp);
|
||||
}else if ( !isNaN(temp) ) {
|
||||
temp = parseInt(temp);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
};
|
||||
};
|
||||
window.PlatformManager = PlatformManager;
|
||||
/** 发布平台类型 */
|
||||
export var releaseType = Enum({
|
||||
/** 测试 */
|
||||
test_TEST: 1,
|
||||
|
||||
/** 微伞 h5 */
|
||||
h5_weiSan: 2,
|
||||
/** 通用 h5 */
|
||||
h5_common: 3,
|
||||
|
||||
/** 字节跳动 小程序*/
|
||||
applet_ziJie: 4,
|
||||
applet_wechat: 5 ,
|
||||
|
||||
/** 谷歌 AppPlay*/
|
||||
APP_google: 10,
|
||||
/** IOS appStore */
|
||||
APP_ios: 11,
|
||||
});
|
||||
|
||||
/** 发布类型 h5 安卓 IOS 小程序 */
|
||||
export enum osType{
|
||||
h5 = 1,
|
||||
android = 2,
|
||||
ios = 3,
|
||||
applet = 4,
|
||||
}
|
||||
9
assets/script/manager/PlatformManager.ts.meta
Normal file
9
assets/script/manager/PlatformManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "4369c8b0-61d8-446e-bb87-570f94477bf4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
126
assets/script/manager/PoolManager.ts
Normal file
126
assets/script/manager/PoolManager.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { _decorator, Director, director, instantiate, Node, NodePool, Prefab } from 'cc';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
export class PoolManager {
|
||||
private static _instance: PoolManager = new PoolManager();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private prefabMap: Map<string, Prefab> = new Map();
|
||||
|
||||
private poolDic: Map<string, NodePool> = new Map();
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param resArr 预制体数组
|
||||
* 如无出现BUG无须主动调用
|
||||
*/
|
||||
init(prefabs: Prefab[]) {
|
||||
if (!prefabs || prefabs.length === 0) return;
|
||||
|
||||
// 清空之前的记录
|
||||
this.prefabMap.clear();
|
||||
|
||||
// 使用 Map 存储,提高查询效率
|
||||
prefabs.forEach(prefab => {
|
||||
if (prefab && prefab.name) {
|
||||
this.prefabMap.set(prefab.name, prefab);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取预制体
|
||||
* @param url 预制体的res/Prefab/的路径 或者 resArr拖动的名字
|
||||
*/
|
||||
getNode(url: string) {
|
||||
let prefab: Prefab = null;
|
||||
if (this.prefabMap.has(url)) {
|
||||
prefab = this.prefabMap.get(url);
|
||||
}
|
||||
|
||||
if (!prefab) {
|
||||
if (this.poolDic.has(url)) {
|
||||
if (this.poolDic.get(url).size() > 0) {
|
||||
const node = this.poolDic.get(url).get();
|
||||
return node;
|
||||
} else {
|
||||
const node = new Node(url);
|
||||
return node;
|
||||
}
|
||||
} else {
|
||||
this.poolDic.set(url, new NodePool(url));
|
||||
const node = new Node(url);
|
||||
return node;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!this.poolDic.has(url)) {
|
||||
const node = instantiate(prefab);
|
||||
this.poolDic.set(url, new NodePool(url));
|
||||
console.warn("First Init Pool: " + url);
|
||||
return node;
|
||||
} else {
|
||||
const Pool = this.poolDic.get(url);
|
||||
if (Pool.size() > 0) {
|
||||
const node = Pool.get();
|
||||
return node;
|
||||
} else {
|
||||
const node = instantiate(prefab);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收节点
|
||||
* @param node 节点
|
||||
* @param isRigiBody 是否是刚体
|
||||
*/
|
||||
recycleNode(node: Node, isRigiBody: boolean = false) {
|
||||
const url = node.name;
|
||||
if (isRigiBody) {
|
||||
if (this.poolDic.has(url)) {
|
||||
director.once(Director.EVENT_AFTER_PHYSICS, () => {
|
||||
this.poolDic.get(url).put(node);
|
||||
})
|
||||
} else {
|
||||
this.poolDic.set(url, new NodePool(url));
|
||||
director.once(Director.EVENT_AFTER_PHYSICS, () => {
|
||||
this.poolDic.get(url).put(node);
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (this.poolDic.has(url)) {
|
||||
this.poolDic.get(url).put(node);
|
||||
} else {
|
||||
this.poolDic.set(url, new NodePool(url));
|
||||
this.poolDic.get(url).put(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 清空所有节点池
|
||||
*/
|
||||
clearAllPool() {
|
||||
for (let pool of this.poolDic.values()) {
|
||||
pool.clear();
|
||||
}
|
||||
this.poolDic.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点池字典
|
||||
*/
|
||||
getPoolDic() {
|
||||
return this.poolDic;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
9
assets/script/manager/PoolManager.ts.meta
Normal file
9
assets/script/manager/PoolManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ea012293-8105-4f8a-a2f4-2be50875c717",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
123
assets/script/manager/UIManager.ts
Normal file
123
assets/script/manager/UIManager.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { Component, director , find, Node} from "cc";
|
||||
import { Tools } from "../common/Tools";
|
||||
import { weiSan } from "../common/weiSanTools";
|
||||
|
||||
export abstract class UIManager extends Component {
|
||||
/** 存放UI的字典 */
|
||||
public static UIDic: Map<string, any> = new Map();
|
||||
/**
|
||||
* 打开一个UI页面
|
||||
* @param panelName UIConfig配置里面的名字
|
||||
* @param param 打开UI时传递的参数
|
||||
* @param isRemoveOther 是否删除所有的UI
|
||||
* @returns
|
||||
*/
|
||||
public static OpenUI(panelName: string, isRemoveOther: boolean = false, ...param: any): void {
|
||||
let config;
|
||||
if (UIConfig[panelName]) {
|
||||
config = UIConfig[panelName];
|
||||
}
|
||||
if (config == null) {
|
||||
weiSan.error("未找到该UI的配置信息:" + panelName);
|
||||
return null;
|
||||
}
|
||||
if (!this.UIDic.has(panelName)) {
|
||||
if (isRemoveOther == true) {
|
||||
this.removeAllUI();
|
||||
}
|
||||
this.CreateUI(config, ...param);
|
||||
} else {
|
||||
weiSan.warn("已经打开过UI:" + panelName);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 关闭一个UI页面
|
||||
* @param panelName UIConfig配置里面的名字
|
||||
* @param param 关闭UI时传递的参数
|
||||
*/
|
||||
public static CloseUI(panelName: string, ...param: any): void {
|
||||
let panel;
|
||||
panel = this.UIDic.get(panelName);
|
||||
|
||||
if (panel) {
|
||||
this.UIDic.delete(panelName);
|
||||
if(panel.name == ""){ return; }
|
||||
let component = panel.getComponent(panel.config.com);
|
||||
if (component && component.closeUI) {
|
||||
component.closeUI(...param);
|
||||
}
|
||||
} else {
|
||||
weiSan.warn("已经关闭过UI:" + panelName);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 获取UI的Node
|
||||
* @param {*} panelName UI配置里面的名字
|
||||
*/
|
||||
public static GetUI(panelName): Node {
|
||||
let panel = this.UIDic.get(panelName);
|
||||
if (panel != null) {
|
||||
return panel;
|
||||
} else {
|
||||
weiSan.log("没有打开UI:" + panelName);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 获取UI上的脚本
|
||||
* @param {*} panelName UI的名字
|
||||
*/
|
||||
public static GetUIForComponent(panelName) {
|
||||
let panel = this.UIDic.get(panelName);
|
||||
if (panel != null) {
|
||||
return panel.getComponent(panel.config.com);
|
||||
} else {
|
||||
weiSan.warn("没有打开UI:" + panelName);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 创建一个UI
|
||||
* @param config UI配置config
|
||||
* @param param 传递参数
|
||||
* @returns
|
||||
*/
|
||||
public static CreateUI(config: any, ...param: any): void {
|
||||
if (this.UIDic.get(config.name) != null) { return; }
|
||||
// let parent = director.getScene().getChildByName();
|
||||
let parent = find("Canvas");
|
||||
Tools.newPrefab(config.resUrl, parent , null, (node: any) => {
|
||||
node.config = config;
|
||||
let component = node.getComponent(config.com);
|
||||
if (component && component.openUI) {
|
||||
component.openUI(...param);
|
||||
component.uiName = config.name;
|
||||
}
|
||||
// this.UIDic[config.name] = node;
|
||||
this.UIDic.set(config.name, node);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 移除所有存放在字典里的UI
|
||||
*/
|
||||
public static removeAllUI(): void {
|
||||
this.UIDic.forEach( (value:any,key:any) => {
|
||||
this.CloseUI( key.toString() );
|
||||
} );
|
||||
};
|
||||
/** 从字典中移除所有UI */
|
||||
public static removeUIDic() {
|
||||
this.UIDic.clear();
|
||||
};
|
||||
|
||||
public abstract openUI(...data: any);
|
||||
public abstract closeUI(...data: any);
|
||||
public abstract uiName:string;
|
||||
protected onDestroy(): void {
|
||||
UIManager.UIDic.delete(this.uiName);
|
||||
}
|
||||
}
|
||||
/** name UI的名字 resUrl预制体加载路径或者名字 com绑定脚本的名字 */
|
||||
var UIConfig = <any>{
|
||||
OverUI: { name: "OverUI", resUrl: "OverUI", com: "OverUI", zIndex: 99 },
|
||||
}
|
||||
9
assets/script/manager/UIManager.ts.meta
Normal file
9
assets/script/manager/UIManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "fcdeb5f9-1b46-4a66-9692-5b16e61da895",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/model.meta
Normal file
12
assets/script/model.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "1b9de719-371a-4e6f-bb55-1e990eb77cac",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
24
assets/script/model/GameModel.ts
Normal file
24
assets/script/model/GameModel.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Sprite, SpriteFrame, resources } from "cc";
|
||||
import { MainGame } from "../game/MainGame";
|
||||
|
||||
/** 游戏数据相关 */
|
||||
export class GameModel {
|
||||
/** 单例模式 */
|
||||
private static _instance: GameModel = new GameModel();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
/** 主场景 名字 */
|
||||
mainScene: string = "MainGame";
|
||||
|
||||
/** MainGame脚本 */
|
||||
mainGame: MainGame = null;
|
||||
/** 游戏分数 */
|
||||
gameScore: number = 1;
|
||||
/** 平均分 用来计算超越了多少玩家 */
|
||||
standScore: number = 80;
|
||||
/** 最高分 用来计算超越了多少玩家 */
|
||||
gameMaxScore: number = 200;
|
||||
|
||||
}
|
||||
9
assets/script/model/GameModel.ts.meta
Normal file
9
assets/script/model/GameModel.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "f69a5547-feea-4fbd-ad4d-f04735df5a8b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
50
assets/script/model/ResModel.ts
Normal file
50
assets/script/model/ResModel.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { AudioClip, Material, Prefab, SpriteFrame, Texture2D } from "cc";
|
||||
import { LoadTools } from "../common/LoadTools";
|
||||
|
||||
/** 资源存放的数据类 */
|
||||
export class ResModel {
|
||||
/** 单例模式 */
|
||||
private static _instance: ResModel = new ResModel();
|
||||
private constructor() { }
|
||||
public static get _ins() {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 存储resArr脚本拖动的图片字典 */
|
||||
public SpriteFrameDic: Map<string, SpriteFrame> = new Map();
|
||||
/** 存储resArr脚本拖动的预制体字典 */
|
||||
public PrefabDic: Map<string, Prefab> = new Map();
|
||||
/** 存储resArr脚本拖动的音效字典 */
|
||||
public AudioClipDic: Map<string, AudioClip> = new Map();
|
||||
/** 存储resArr脚本拖动的材质字典 */
|
||||
public MaterialDic: Map<string, Material> = new Map();
|
||||
/** 存储resArr脚本拖动的Texture字典 */
|
||||
public TextureDic: Map<string, Texture2D> = new Map();
|
||||
|
||||
/** resArr清理字典 */
|
||||
public clearResDic() {
|
||||
this.AudioClipDic.clear();
|
||||
this.SpriteFrameDic.clear();
|
||||
this.PrefabDic.clear();
|
||||
this.MaterialDic.clear();
|
||||
this.TextureDic.clear();
|
||||
}
|
||||
|
||||
|
||||
/** 获取拖动到res 里面的 Texture 资源 */
|
||||
getTexture(key: string, callFunc?: (age: Texture2D) => {}): Texture2D {
|
||||
if (this.TextureDic[key]) {
|
||||
return this.TextureDic[key];
|
||||
} else {
|
||||
LoadTools._ins.loadResAny(key + "/texture", Texture2D, callFunc);
|
||||
}
|
||||
}
|
||||
/** 获取拖动到res 里面的 材质资源 */
|
||||
getMaterial(key: string, callFunc?: (age: Material) => {}) {
|
||||
if (this.MaterialDic[key]) {
|
||||
return this.MaterialDic[key];
|
||||
} else {
|
||||
LoadTools._ins.loadResAny(key, Material, callFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/script/model/ResModel.ts.meta
Normal file
9
assets/script/model/ResModel.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "90f35c76-cc50-4872-bd99-7af2500bfdf2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
39
assets/script/model/WordsModel.ts
Normal file
39
assets/script/model/WordsModel.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tools } from "../common/Tools";
|
||||
import { weiSan } from "../common/weiSanTools";
|
||||
|
||||
/** 游戏内 文字翻译相关数据 */
|
||||
export var WordsModel = {
|
||||
gameName:{
|
||||
CN: "", //中文
|
||||
CHT: "", //繁体
|
||||
EN: "", //英文
|
||||
KOR: "", //韩文
|
||||
JP: "", //日文
|
||||
TH: "" //泰语
|
||||
},
|
||||
overScoreInfo_0: { CN:"只得0分,全球独一个!",CHT:"只得0分,全球獨一個!",
|
||||
EN:"Only 0, the only one in the world!", KOR:"0점밖에 안 돼, 전 세계에서 하나야!"
|
||||
, JP:"0点しか取れません。世界で唯一です", TH:"มีเพียง <NU>0 จุดหนึ่งในโลก" },
|
||||
|
||||
overScoreInfo_1: { CN:"击败了全球",CHT:"擊敗了全球", EN:"Beat ", KOR:"격파", JP:"打ち負かす", TH:"ทำให้พ่ายแพ้" },
|
||||
overScoreInfo_2: { CN:"的玩家!",CHT:"的玩家!", EN:" of the players!", KOR:"유저!", JP:"のプレイヤー!", TH:"ผู้เล่นของ" },
|
||||
overTitle_1:{
|
||||
CN:"我真是太厉害了,我在",CHT:"我真是太厲害了,我在",EN:"I'm really great. I'm in ",
|
||||
},
|
||||
overTitle_2:{
|
||||
CN:"中,",CHT:"中,",EN:". "
|
||||
},
|
||||
|
||||
/** 通过语言 获得文字翻译 */
|
||||
getStrForLanguage( modelKey:string , languageType?:string){
|
||||
languageType = languageType || Tools.getLanguageType();
|
||||
if(this[modelKey] ){
|
||||
if( this[modelKey][languageType] ){
|
||||
return this[modelKey][languageType];
|
||||
}
|
||||
return this[modelKey]["EN"];
|
||||
}else{
|
||||
weiSan.log("没有翻译:" + modelKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/script/model/WordsModel.ts.meta
Normal file
9
assets/script/model/WordsModel.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "77968eaa-9734-4273-85e4-209355aa1cf5",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/script/uiPanel.meta
Normal file
12
assets/script/uiPanel.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "720bc2a0-db9f-49d1-b0cf-a8558640f42f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
164
assets/script/uiPanel/OverUI.ts
Normal file
164
assets/script/uiPanel/OverUI.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import { _decorator, Component, Node, Label, UIOpacity, v3, director, tween } from 'cc';
|
||||
import { AdManager } from '../ads/AdManager';
|
||||
import { Tools } from '../common/Tools';
|
||||
import { weiSan } from '../common/weiSanTools';
|
||||
import { NetworkManager } from '../manager/NetworkManager';
|
||||
import { osType, PlatformManager, releaseType } from '../manager/PlatformManager';
|
||||
import { UIManager } from '../manager/UIManager';
|
||||
import { GameModel } from '../model/GameModel';
|
||||
import { WordsModel } from '../model/WordsModel';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
|
||||
@ccclass('OverUI')
|
||||
export class OverUI extends UIManager {
|
||||
@property(Node)
|
||||
bgSpr!: Node;
|
||||
|
||||
@property(Node)
|
||||
viewNode!: Node;
|
||||
@property(Label)
|
||||
scoreLab!: Label;
|
||||
@property(Label)
|
||||
maxScoreLab!: Label;
|
||||
@property(Label)
|
||||
infoText!: Label;
|
||||
|
||||
@property(Node)
|
||||
moreBtn!: Node;
|
||||
@property(Node)
|
||||
againBtn!: Node;
|
||||
|
||||
/** 是否可点击 按钮 */
|
||||
isClick: boolean = false;
|
||||
onLoad() {
|
||||
this.bgSpr.getComponent(UIOpacity).opacity = 0;
|
||||
this.viewNode.position.add(v3(0, 1000, 0));
|
||||
this.againBtn.scale = v3(0, 0, 0);
|
||||
this.moreBtn.position.add(v3(-2000, 0, 0));
|
||||
|
||||
// GameModel._ins.gameScore = Tools.random(100,200);
|
||||
this.initShowInfo();
|
||||
this.addBtnEvent();
|
||||
// 提交分数 和 显示插屏广告
|
||||
NetworkManager.sendGameScore(GameModel._ins.gameScore, 1);
|
||||
AdManager.showIntersAd();
|
||||
|
||||
if (PlatformManager.osType != osType.h5) { //非H5平台 隐藏更多游戏按钮
|
||||
this.moreBtn.active = false;
|
||||
}
|
||||
}
|
||||
// start() {
|
||||
// }
|
||||
/** 显示结束页 信息 */
|
||||
initShowInfo() {
|
||||
this.scoreLab.string = GameModel._ins.gameScore.toString();
|
||||
|
||||
let tempNum = this.getBeatItScore(GameModel._ins.gameScore, GameModel._ins.standScore, GameModel._ins.gameMaxScore);
|
||||
this.infoText.string = this.getBeatItStr(GameModel._ins.gameScore, tempNum, true);
|
||||
|
||||
let maxScore = Tools.getStorage("gameOverMaxScore");
|
||||
if (!maxScore || maxScore <= GameModel._ins.gameScore) {
|
||||
maxScore = GameModel._ins.gameScore;
|
||||
Tools.setStorage("gameOverMaxScore", GameModel._ins.gameScore);
|
||||
}
|
||||
this.maxScoreLab.string = maxScore.toString();
|
||||
|
||||
if (PlatformManager.osType != osType.h5) { return; }
|
||||
if (Tools.getLanguageType() == "CN" || Tools.getLanguageType() == "CHT") {
|
||||
document.title = WordsModel.getStrForLanguage("overTitle_1", "CN") + "<" + WordsModel.getStrForLanguage("gameName", "CN")
|
||||
+ ">" + WordsModel.getStrForLanguage("overTitle_2", "CN") + this.getBeatItStr(GameModel._ins.gameScore, tempNum, false);
|
||||
} else {
|
||||
document.title = WordsModel.getStrForLanguage("overTitle_1", "EN") + "<" + WordsModel.getStrForLanguage("gameName", "EN")
|
||||
+ ">" + WordsModel.getStrForLanguage("overTitle_2", "EN") + this.getBeatItStr(GameModel._ins.gameScore, tempNum, false);
|
||||
}
|
||||
console.log(document.title);
|
||||
}
|
||||
|
||||
addBtnEvent() {
|
||||
this.againBtn.on("click", () => {
|
||||
if (!this.isClick) { return; }
|
||||
this.aginGame();
|
||||
});
|
||||
this.moreBtn.on("click", () => {
|
||||
if (!this.isClick) { return; }
|
||||
if (PlatformManager.releaseType == releaseType.test_TEST) {
|
||||
weiSan.log("测试模式 更多游戏Url: " + NetworkManager.moreGameUrl);
|
||||
return;
|
||||
}
|
||||
this.isClick = false;
|
||||
window.location.href = NetworkManager.moreGameUrl;
|
||||
});
|
||||
}
|
||||
/** 再玩一次 */
|
||||
aginGame() {
|
||||
this.isClick = false;
|
||||
// AdManager.showIntersAd();
|
||||
UIManager.CloseUI("OverUI");
|
||||
this.scheduleOnce(() => {
|
||||
director.preloadScene(GameModel._ins.mainScene, () => {
|
||||
director.loadScene(GameModel._ins.mainScene);
|
||||
});
|
||||
}, 0.2);
|
||||
}
|
||||
/**
|
||||
* 获取击败了 全球多少玩家
|
||||
* @param gameScore 分数
|
||||
* @param standScore 平均分
|
||||
* @param maxScore 最高分
|
||||
*/
|
||||
getBeatItScore(gameScore: number, standScore: number, maxScore: number) {
|
||||
if (gameScore >= maxScore) {
|
||||
return 100;
|
||||
}
|
||||
if (gameScore <= standScore) {
|
||||
let temp = (gameScore / standScore) * 80 + Tools.random(-3, 3);
|
||||
return Math.max(Math.floor(temp), 5);
|
||||
} else {
|
||||
let temp = 80 + ((gameScore - standScore) / (maxScore - standScore)) * 20 + Tools.random(-3, 3);
|
||||
return Math.min(Math.floor(temp), 99);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 获取击败了 全球多少玩家 文字 tempNum:百分之多少 是否是richText
|
||||
*/
|
||||
getBeatItStr(score: number, tempNum: number, isRichText = true): string {
|
||||
var share_title = WordsModel.getStrForLanguage("overScoreInfo_0");
|
||||
if (score > 0) {
|
||||
if (isRichText) {
|
||||
share_title = WordsModel.getStrForLanguage("overScoreInfo_1") +
|
||||
tempNum + "%" + WordsModel.getStrForLanguage("overScoreInfo_2");
|
||||
} else {
|
||||
share_title = WordsModel.getStrForLanguage("overScoreInfo_1") + tempNum + "%" + WordsModel.getStrForLanguage("overScoreInfo_2");
|
||||
}
|
||||
}
|
||||
return share_title;
|
||||
};
|
||||
// update (deltaTime: number) {
|
||||
// }
|
||||
public openUI() {
|
||||
this.bgSpr.getComponent(UIOpacity)!.opacity = 0;
|
||||
|
||||
tween(this.bgSpr.getComponent(UIOpacity)).to(0.3, { opacity: 100 }).start();
|
||||
tween(this.moreBtn).by(0.3, { position: v3(2000, 0, 0) }, { easing: "backOut" }).start();
|
||||
|
||||
tween(this.viewNode)
|
||||
.by(0.3, { position: v3(0, -1000, 0) }, { easing: "backOut" })
|
||||
.call(() => {
|
||||
this.isClick = true;
|
||||
tween(this.againBtn).to(0.3, { scale: v3(1, 1, 1) }, { easing: "backOut" }).start();
|
||||
}).start();
|
||||
}
|
||||
public closeUI() {
|
||||
tween(this.bgSpr.getComponent(UIOpacity)).to(0.2, { opacity: 0 }).start();
|
||||
|
||||
tween(this.viewNode)
|
||||
.by(0.3, { position: v3(0, 100, 0) }, { easing: "backIn" })
|
||||
.call(() => {
|
||||
this.node.destroy();
|
||||
}).start();
|
||||
|
||||
tween(this.moreBtn).by(0.2, { position: v3(-2000, 0, 0) }, { easing: "backIn" }).start();
|
||||
}
|
||||
public uiName: string;
|
||||
}
|
||||
9
assets/script/uiPanel/OverUI.ts.meta
Normal file
9
assets/script/uiPanel/OverUI.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "37f4898e-a6c6-4320-aba4-e4dd276e959c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
12
assets/texture.meta
Normal file
12
assets/texture.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "7c328e08-8fda-40bf-8feb-2dfce6ba3b88",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
12
assets/texture/overUI.meta
Normal file
12
assets/texture/overUI.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "0e76ff52-c7fc-44fe-88a9-89099cbb6e88",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
||||
BIN
assets/texture/overUI/maxIcon.png
Normal file
BIN
assets/texture/overUI/maxIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
134
assets/texture/overUI/maxIcon.png.meta
Normal file
134
assets/texture/overUI/maxIcon.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "9b914cf0-224a-4a7a-93cc-4ab3906fbeec",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "9b914cf0-224a-4a7a-93cc-4ab3906fbeec@6c48a",
|
||||
"displayName": "maxIcon",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "9b914cf0-224a-4a7a-93cc-4ab3906fbeec",
|
||||
"visible": false
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "9b914cf0-224a-4a7a-93cc-4ab3906fbeec@f9941",
|
||||
"displayName": "maxIcon",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 46,
|
||||
"height": 43,
|
||||
"rawWidth": 46,
|
||||
"rawHeight": 43,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "9b914cf0-224a-4a7a-93cc-4ab3906fbeec@6c48a",
|
||||
"atlasUuid": "",
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-23,
|
||||
-21.5,
|
||||
0,
|
||||
23,
|
||||
-21.5,
|
||||
0,
|
||||
-23,
|
||||
21.5,
|
||||
0,
|
||||
23,
|
||||
21.5,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
43,
|
||||
46,
|
||||
43,
|
||||
0,
|
||||
0,
|
||||
46,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-23,
|
||||
-21.5,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
23,
|
||||
21.5,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"hasAlpha": true,
|
||||
"type": "sprite-frame",
|
||||
"redirect": "9b914cf0-224a-4a7a-93cc-4ab3906fbeec@6c48a",
|
||||
"fixAlphaTransparencyArtifacts": false
|
||||
}
|
||||
}
|
||||
BIN
assets/texture/overUI/moreBtn.png
Normal file
BIN
assets/texture/overUI/moreBtn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
134
assets/texture/overUI/moreBtn.png.meta
Normal file
134
assets/texture/overUI/moreBtn.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "34ced794-7ae5-40da-b5aa-d6a8fbd39a38",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "34ced794-7ae5-40da-b5aa-d6a8fbd39a38@6c48a",
|
||||
"displayName": "moreBtn",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "34ced794-7ae5-40da-b5aa-d6a8fbd39a38",
|
||||
"visible": false
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "34ced794-7ae5-40da-b5aa-d6a8fbd39a38@f9941",
|
||||
"displayName": "moreBtn",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 80,
|
||||
"height": 81,
|
||||
"rawWidth": 80,
|
||||
"rawHeight": 81,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "34ced794-7ae5-40da-b5aa-d6a8fbd39a38@6c48a",
|
||||
"atlasUuid": "",
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-40,
|
||||
-40.5,
|
||||
0,
|
||||
40,
|
||||
-40.5,
|
||||
0,
|
||||
-40,
|
||||
40.5,
|
||||
0,
|
||||
40,
|
||||
40.5,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
81,
|
||||
80,
|
||||
81,
|
||||
0,
|
||||
0,
|
||||
80,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-40,
|
||||
-40.5,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
40,
|
||||
40.5,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"hasAlpha": true,
|
||||
"type": "sprite-frame",
|
||||
"redirect": "34ced794-7ae5-40da-b5aa-d6a8fbd39a38@6c48a",
|
||||
"fixAlphaTransparencyArtifacts": false
|
||||
}
|
||||
}
|
||||
BIN
assets/texture/overUI/startBtn.png
Normal file
BIN
assets/texture/overUI/startBtn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
134
assets/texture/overUI/startBtn.png.meta
Normal file
134
assets/texture/overUI/startBtn.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "73b3655a-f0d7-4f43-b215-efb04b1633be",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "73b3655a-f0d7-4f43-b215-efb04b1633be@6c48a",
|
||||
"displayName": "startBtn",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "73b3655a-f0d7-4f43-b215-efb04b1633be",
|
||||
"visible": false
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "73b3655a-f0d7-4f43-b215-efb04b1633be@f9941",
|
||||
"displayName": "startBtn",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 175,
|
||||
"height": 175,
|
||||
"rawWidth": 175,
|
||||
"rawHeight": 175,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "73b3655a-f0d7-4f43-b215-efb04b1633be@6c48a",
|
||||
"atlasUuid": "",
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-87.5,
|
||||
-87.5,
|
||||
0,
|
||||
87.5,
|
||||
-87.5,
|
||||
0,
|
||||
-87.5,
|
||||
87.5,
|
||||
0,
|
||||
87.5,
|
||||
87.5,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
175,
|
||||
175,
|
||||
175,
|
||||
0,
|
||||
0,
|
||||
175,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-87.5,
|
||||
-87.5,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
87.5,
|
||||
87.5,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"hasAlpha": true,
|
||||
"type": "sprite-frame",
|
||||
"redirect": "73b3655a-f0d7-4f43-b215-efb04b1633be@6c48a",
|
||||
"fixAlphaTransparencyArtifacts": false
|
||||
}
|
||||
}
|
||||
BIN
assets/texture/singleColor.png
Normal file
BIN
assets/texture/singleColor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
138
assets/texture/singleColor.png.meta
Normal file
138
assets/texture/singleColor.png.meta
Normal file
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a@6c48a",
|
||||
"displayName": "singleColor",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"minfilter": "linear",
|
||||
"magfilter": "linear",
|
||||
"mipfilter": "none",
|
||||
"anisotropy": 0,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a",
|
||||
"visible": false
|
||||
},
|
||||
"ver": "1.0.22",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"f9941": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a@f9941",
|
||||
"displayName": "singleColor",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 2,
|
||||
"height": 2,
|
||||
"rawWidth": 2,
|
||||
"rawHeight": 2,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a@6c48a",
|
||||
"atlasUuid": "",
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-1,
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
-1,
|
||||
0,
|
||||
-1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-1,
|
||||
-1,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
1,
|
||||
1,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"hasAlpha": false,
|
||||
"type": "sprite-frame",
|
||||
"redirect": "56a35c4e-18ad-4795-86ad-f11bb3ebaa5a@6c48a",
|
||||
"compressSettings": {
|
||||
"useCompressTexture": false
|
||||
},
|
||||
"flipVertical": true,
|
||||
"fixAlphaTransparencyArtifacts": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user