大家好,欢迎来到IT知识分享网。
1.碰撞检测
(1)圆形和圆形的碰撞判断:计算两个圆心之间的距离是否小于两个圆的半径和
假设圆形1的左上角坐标是(x1,y1),半径是r1;圆形2的左上角坐标是(x2,y2),半径是r2;
用数学公式表达就是:(x1-x2)的平方+(y1-y2)的平方 < (r1+r2)的平方
//判断是否碰到道具 _proto.isHitProp = function (roleX, roleZ, roleSize) { //吃道具 var dx = Math.abs(roleX - this.x); //返回绝对值 var dy = Math.abs(roleZ - this.z); var dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); //pow(x,y) 方法可返回 x 的 y 次幂的值。//sqrt() 方法可返回一个数的平方根 var hitRadius = this.colliderSize + roleSize; if (dis <= hitRadius) { this.hitProp(); } };
(2)应用碰撞检测,做吸收金币的功能:
第一步:获取角色的位置和角色的半径大小:
var roleX = gameManager.player.getPos().x; var roleZ = gameManager.player.getPos().z; var roleY = gameManager.player.getPos().y; var roleSize = G.ROLE_SIZE;
第二步:计算角色距离金币的距离,以及计算角色和金币的半径之和:
var dx = Math.abs(roleX - this.x); var dy = Math.abs(roleZ - this.z); var dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); //计算角色距离金币的距离 var hitRadius = G.GOLD_SIZE + roleSize; //计算角色和金币的半径之和
第三步:做出碰撞检测的判断,移动金币到角色身上:
if (dis>hitRadius){ if(roleZ<this.z){ var disZ=this.z-roleZ; //角色的位置在金币的前边 var speed = (roleX - this.x) * G.PROP_GOLD_SPEED / disZ; this.x += speed; this.z -= G.PROP_GOLD_SPEED; //金币向前移动到角色身上 }else{ var disZ=roleZ-this.z; //角色的位置在金币的后边 var speed = (roleX - this.x) * G.PROP_GOLD_SPEED / disZ; this.x += speed; this.z += G.PROP_GOLD_SPEED; //金币向后移动到角色身上 }
2.通过半径之和以及中心点距离进行碰撞检测:
(1)主要检测函数:
/ * 检测碰撞 */ _proto.checkCollider = function (pos) { //参数是:战斗中手臂(this.battleUI.mainUI.image_collider)的中心点的全局坐标 if (this.isRemove) return; var dx = Math.abs(pos.x - this.mainUI.x); var dy = Math.abs(pos.y - this.mainUI.y); var hitRadius = this.radiuSize + this.handColliderSize; //this.radiuSize该物品的碰撞半径,物品的配表中获取该值 //this.handColliderSize 手臂碰撞区域大小 battleMgr.battleUI.getHandColliderSize函数获取==this.mainUI.image_collider.width / 2; var dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); //手臂中心点和掉落物品中心点之间的直线距离 if (dis < hitRadius) { //距离小于半径之和就判断发生了碰撞 if (this.money > 0 || this.goodItem.type == G.GOOD_TYPES.NEWJINZHIBI) { //吃到纸币手机发生震动 if (this.goodItem.type == G.GOOD_TYPES.ZHIBI) { utils.vibration(); //调用手机震动 } else if (this.goodItem.type == G.GOOD_TYPES.JINZHIBI) { utils.vibration(); } else if (this.goodItem.type == G.GOOD_TYPES.NEWJINZHIBI) { this.money = battleMgr.getRedBagValue(); utils.vibration(); } } //吃到炸弹死亡 if (this.goodItem.type == G.GOOD_TYPES.ZHADAN) { battleMgr.bombOver(); eventDispatcher.dispatchEvent(cc.Event.ON_GAMEOVER_CLEAR); } var score = this.goodScore; //发生碰撞触发事件 eventDispatcher.dispatchEvent(cc.Event.ON_EAT_GOOD, { score: score, money: this.money, itemType: this.goodItem.type, len: this.mainUI.x - pos.x }); // this.destroy(); this.isRemove = true; } };
(2)前提准备(对手臂进行全局坐标的转换):
//碰撞检测(主要在于battleGood的碰撞检测,这里只做坐标转化而已) _prop.checkCollider = function () { var playerHand = battleMgr.getPlayerHand(); //获取手臂碰撞点ui元素img var point = Laya.Point.TEMP; point.setTo(0, 0); playerHand.localToGlobal(point); //point的值变为,手臂的本地坐标转成的全局坐标 var pos = { x: point.x + playerHand.width / 2, y: point.y + playerHand.height / 2 }; //this.battleUI.mainUI.image_collider的中心点坐标 //物件逻辑更新 var count = this.allGoods.length; for (var i = 0; i < count; i++) { this.allGoods[i] && this.allGoods[i].checkCollider(pos); //掉落物品的碰撞检测,调用battleGood中定义的函数 } };
3.创建遮罩,屏蔽按钮事件:
(1)创建UI元素,平铺:
(2)如果是box组件,必须注册一个事件:
this.mainUI.box_wating.on(Laya.Event.MOUSE_DOWN,this,function(){});
(3)设置按钮点击后,打开遮罩:
//抽奖 _proto.onChouClick = function () { var totalScore = dataManager.getRoleScore(); var spend = dataManager.getRoleSpendScore(); if (spend > totalScore) { // utils.prompt("积分不足"); this.mainUI.ani1.play(0, false); return; } protocolReq.reqLuckDraw(); this.openWait(); }; _proto.monitorWaitTimeout = function(){ Laya.timer.once(5000,this, this.onWaitTimeOut); // 相当于注册了一个时间点事件(定时炸弹) } _proto.cancleWaitTimeOut = function(){ Laya.timer.clear(this, this.onWaitTimeOut); //取消定时事件的监听 }; _proto.openWait = function(){ this.mainUI.box_wating.visible = true; this.monitorWaitTimeout(); //注册定时事件的监听 } _proto.closeWait = function(){ this.cancleWaitTimeOut(); this.mainUI.box_wating.visible = false; }; _proto.onWaitTimeOut = function(){ if(this.mainUI.box_wating.visible) this.closeWait(); //时间点到了,如果遮罩还在我们就执行这个函数 }
4.毫秒倒计时:
/ * 倒计时刷新 */ refreshCd = function () { let times = this.SecondCountDown * 100; //5秒倒计时 this.countTime = window.setInterval(() => { times = --times < 0 ? 0 : times; var ms = Math.floor(times / 100).toString(); if (ms.length <= 1) { ms = "0" + ms; } var hm = Math.floor(times % 100).toString(); if (hm.length <= 1) { hm = "0" + hm; } if (times == 0) { // alert("游戏结束"); this.ani3.play(0, true); window.clearInterval(this.countTime); } // 获取分钟、毫秒数 this.ms_label.text = ms; this.hs_label.text = hm; }, 10); };
5.3D游戏子弹发射:
*基本原理:鼠标点击产生射线,射线与模型碰撞器相交,则获取碰撞点作为子弹发射方向;如果子弹未与3D模型相交,则直接使用射线作为发射方向
(1) 子弹获取和克隆
1. /场景中的初始子弹/ 2. public bullet: Laya.MeshSprite3D; 加载资源结束之后,获取场景中的子弹用于克隆: 1. //获取场景中的子弹用于克隆 2. this.bullet = this.scene.getChildByName("bullet") as Laya.MeshSprite3D; 3. //未产生子弹时移除克隆参考用子弹 4. this.bullet.removeSelf();
(2) 鼠标点击屏幕的位置,生成射线,射线与3D模型中的碰撞器进行碰撞检测
1. public ray: Laya.Ray = new Laya.Ray(new Laya.Vector3(), new Laya.Vector3()); 2. /鼠标坐标/ 3. public mousePos: Laya.Vector2 = new Laya.Vector2(); 4. /碰撞信息/ 5. public rayCastHit: Laya.RaycastHit = new Laya.RaycastHit(); //不存在的接口 public rayCastHit: Laya.HitResult = new Laya.HitResult(); //存在的接口 1. //鼠标点击屏幕的位置 2. this.mousePos = new Laya.Vector2(Laya.MouseManager.instance.mouseX, Laya.MouseManager.instance.mouseY); 3. //鼠标点击屏幕产生射线 4. this.camera.viewportPointToRay(this.mousePos, this.ray); 5. //射线与3D模型中的碰撞器进行碰撞检测 6. Laya.Physics.rayCast(this.ray, this.rayCastHit, 30, 0); //不存在的接口 this.scene.physicsSimulation.rayCast(this.ray, this.rayCastHit); //存在的解决
(3) 进行碰撞判定,进而,在子弹脚本中设置子弹发射的方向:
1. //射击的方向向量 2. var dirV3: Laya.Vector3 = new Laya.Vector3(); 3. //如果鼠标点击到模型上(射线与碰撞器发生碰撞) 4. if (this.rayCastHit.distance !== -1) { 5. //子弹射击方向向量 = 由鼠标点中的目标位置向量 —— 子弹起始位置向量 6. Laya.Vector3.subtract(this.rayCastHit.position, this.bullet.transform.position, dirV3); 7. //设置子弹控制脚本中发射方向 8. script.setShootDirection(dirV3); 9. } else { //如果鼠标未点击到模型上 10. / 11. *射线方向向量是归一化的单位向量,不能直接用于向量加减。需要根据射线产生的原理算 12. *出相当于有长短距离的方向向量用于计算,可以通过向量缩放方法实现。 13. *射线原理:原点是鼠标点击在近裁剪面上的点,方向是从摄像机位置到鼠标点击在远裁剪面 14. *上的点产生的归一化方向。因此可以用摄像机到远裁面的距离模拟原始方向向量 15. / 16. // console.log(Laya.Vector3.scalarLength(this.ray.direction)); 17. //摄像机到鼠标点击处的方向向量 18. var aV3: Laya.Vector3 = new Laya.Vector3(); 19. //根据射线方向向量、摄像机远裁剪值缩放为射线方向原始向量(使用远裁距会有一点误差,但不影响效果) 20. Laya.Vector3.scale(this.ray.direction, this.camera.farPlane, aV3); 21. //根据摄像机与子弹的位置求出子弹到摄像机的方向向量 22. var bV3: Laya.Vector3 = new Laya.Vector3(); 23. Laya.Vector3.subtract(this.camera.transform.position, this.bullet.transform.position, bV3); 24. //射击的方向向量 = 摄像机到鼠标点击处的方向向量 +子弹到摄像机的方向向量 25. Laya.Vector3.add(aV3, bV3, dirV3); 26. //设置子弹控制脚本中发射方向 27. script.setShootDirection(dirV3); 28. }
(4) 子弹控制脚本:
1. /被绑定的子弹对象/ 2. private bullet: Laya.MeshSprite3D; 3. /子弹生命周期/ 4. private life: number = 200; 5. /子弹发射的速度(方向)/ 6. public speedV3: Laya.Vector3 = new Laya.Vector3(); 1. / 2. * 设置子弹射击方向并计算速度 3. * @param directionV3 4. */ 5. public setShootDirection(directionV3: Laya.Vector3): void { 6. / 7. * 注: 8. * 三维向量即是位置、方向,也可以是速度,但速度需要一个统一的参考衡量标准,比如“N*标准速度值/帧”或 9. * “N*标准速度值/毫秒”,它类似于“N*米/帧”。 10. * 而我们得到的方向向量,它的大小不一,无法作为标准速度值使用,这个时候可用Vector3.normalize()方法 11. * 把任一向量归一化,产生单位为一的向量作为标准速度值,再把它进行缩放作为不同物体的速度来使用,比如 12. * 0.2倍标准速度值,1.5倍标准速度值等,可使用Vector3.scale()方法缩放。 13. / 14. //将方向向量归一成单位为一的方向速度向量(在LayaAir中相当于1米的长度) 15. Laya.Vector3.normalize(directionV3, this.speedV3); 16. console.log("\n子弹攻击速度(方向):", this.speedV3.elements) 17. //用缩放方法去调整发射速度,0.2倍标准速度(注:子弹速度过快,可能会越过场景中物品,不发生碰撞!) 18. // Vector3.scale(speedV3,0.2,speedV3); 19. } 20. / 21. * 脚本帧循环更新 22. */ 23. public _update(state: Laya.RenderState): void { 24. //子弹位置更新 25. this.bullet.transform.translate(this.speedV3, false); 26. //生命周期递减 27. this.life--; 28. //生命周期结束后,一帧后销毁子弹(目前脚本中直接销毁绑定对象会报错,后期版本解决此问题) 29. if (this.life < 0) { 30. Laya.timer.frameOnce(3, this, function () { this.bullet.destroy(); }); 31. } 32. }
(5) 被子弹攻击的盒子,产生击退效果,立方体控制脚本逻辑如下:
1. /被绑定的立方体对象/ 2. public cube: Laya.MeshSprite3D; 3. /是否被攻击/ 4. private isAttacked: Boolean = false; 5. /盒子被击退的标准速度(方向)/ 6. public repelledV3: Laya.Vector3 = new Laya.Vector3(); 7. /盒子生命周期/ 8. public life: number = 60; 1. / 2. * 当其他碰撞器进入绑定物体碰撞器时触发(子弹击中盒子时) 3. * 注:如相对移动速度过快,可能直接越过 4. */ 5. public onTriggerEnter(other: Laya.Collider): void { 6. //获取其他碰撞器绑定的模型 7. var sp3D: Laya.MeshSprite3D = other.owner as Laya.MeshSprite3D; 8. //获取子弹对象模型脚本 9. var script: BulletScript = sp3D.getComponentByType(BulletScript) as BulletScript; 10. //获取子弹速度为 11. this.repelledV3 = script.speedV3.clone(); 12. //被攻击速度归一化成单位一向量 13. Laya.Vector3.normalize(this.repelledV3, this.repelledV3); 14. //设置为被攻击状态 15. this.isAttacked = true; 16. console.log("\n1 子弹碰撞时位置(方向):", sp3D.transform.position.elements); 17. }
1. / 2. * 脚本的帧循环 3. */ 4. public _update(state: Laya.RenderState): void { 5. //被攻击状态下,盒子产生击退效果 6. if (this.isAttacked) { 7. //根据击退方向和速度移动 8. this.cube.transform.translate(this.repelledV3, false); 9. // console.log("击退位置变化:",(this.cube.transform.position.clone() as Laya.Vector3).elements); 10. //击退速度逐步减小 11. Laya.Vector3.scale(this.repelledV3, 0.3, this.repelledV3); 12. //当后退各方向速度小于0.01时,击退状态停止 13. if (Laya.Vector3.scalarLength(this.repelledV3) < 0.01) { 14. this.isAttacked = false; 15. } 16. } 17. }
6.U3D 和 Laya配合做碰撞检测,切记几点:
(1) 主动体 :空节点作为父节点的,模型作为子节点,
模型身上必须绑定 刚体和网格碰撞器,父节点不加任何物理组件
模型身上必须绑定 刚体和网格碰撞器,父节点不加任何物理组件
(2) 被动体: 空节点作为父节点,模型作为子节点,
模型身上必须不能带刚体,只需要加碰撞器,父节点不加任何物理组件
模型身上必须不能带刚体,只需要加碰撞器,父节点不加任何物理组件
7.2d精灵通过绳索骨骼链接起来,链接的部分需要依靠物理引擎来运动:
(1)创建 碰撞器:
/ 创建身体的2d碰撞器 */ createCollier2d$() { if (!this._headCtrl$) return; this._bodyCollider$ = new Laya.CircleCollider(); this._bodyCollider$.label = "wormBody"; this._bodyCollider$.radius = this._headCtrl$.headColliderRaduis$ * this._headCtrl$.lastBodyScale$; this._bodyCollider$.x = -this._bodyCollider$.radius + this.owner.x; this._bodyCollider$.y = -this._bodyCollider$.radius + this.owner.y; this.owner.addComponentIntance(this._bodyCollider$); }
(2)创建 刚体:
/ 创建身体的2d刚体 */ createRigidBody2d$() { this._bodyRigidBody$ = this.owner.addComponent(Laya.RigidBody); this._bodyRigidBody$.allowRotation = false; this._bodyRigidBody$.type = this.isSleep$ ? "static" : "dynamic"; this._bodyRigidBody$.body.SetGravityScale(0); }
(3)创建 绳索骨骼:
/ 创建骨骼点 */ createRopeJoint$() { this._bodyJoint$ = new Laya.RopeJoint(); this._bodyJoint$.otherBody = this._connectBody$; this._bodyJoint$.selfAnchor = [0, 0]; this._bodyJoint$.otherAnchor = [0, 0]; // this._bodyJoint$.maxLength = GameSetting$.BODY_MODEL_DIS$ * GameSetting$.UI_SCENE_RATE$; this._bodyJoint$.maxLength = GameSetting$.BODY_MODEL_DIS$; this.owner.addComponentIntance(this._bodyJoint$); this.updateConnectBody$(); }
(4)给链接的头部施加线速度或者方向力,只依靠移动 x,y 是没法真正实现物理上的移动的,只是UI表现上的瞬移罢了;
_wormMove$() { if (!this.isNeedMoved$) return; let deltX = this.curSpeedX$ * this._deltaTime$; let deltY = this.curSpeedY$ * this._deltaTime$; // this._targetX$ = playerStagePos.x + deltX; // this._targetY$ = playerStagePos.y + deltY; let direction = new Laya.Vector2(deltX, deltY); Laya.Vector2.normalize(direction, direction) this.force$.x = direction.x * this.power$; this.force$.y = direction.y * this.power$; // playerStagePos.x = this._targetX$; // playerStagePos.y = this._targetY$; // this._wormX$ = playerStagePos.x; // this._wormY$ = playerStagePos.y; // this.owner.pos(-this._wormX$, this._wormY$); this.setVelocity$(); }
(5)设置 物理线速度:
setVelocity$() { let v = this.headRigidbody$.linearVelocity; v.x = this.force$.x; v.y = this.force$.y; this.headRigidbody$.linearVelocity = v; this.headRigidbody$.applyForceToCenter(this.force$); //施加一个力到刚体上的质心上 }
8.坐标位置,转化方向向量,计算角度:
let otherPosX = this._bodyJoint$.otherBody.owner.x; //坐标 let otherPosY = this._bodyJoint$.otherBody.owner.y; let myPosX = this.owner.x; let myPosY = this.owner.y; let delX = (otherPosX - myPosX); let delY = (otherPosY - myPosY); let rad = Math.atan2(delY, delX); //弧度 this.owner.rotation = rad * GameSetting$.ANGLE_1_RAD$; //弧度转化为角度 GameSetting$.ANGLE_1_RAD$ = 180 / Math.PI; let dx = lastButOneBody.x - lastBody.x; let dy = lastButOneBody.y - lastBody.y; let direction = new Laya.Vector2(dx, dy); Laya.Vector2.normalize(direction, direction)
9.设置物体角速度使之物理系统发生旋转:
前提条件: this.sawRigidbody$.allowRotation = true; //设置可旋转 this.sawRigidbody$.type = "dynamic"; //刚体类型动态 //旋转速度 this.rollSpeed$ = 2; setRollVelocity$() { if (!this.woodenPlateRigidbody$ || !this.rollSpeed$) return; this.woodenPlateRigidbody$.angularVelocity = this.rollSpeed$; rollSpeed$ 负值:逆时针 正值:顺时针 }
10.即使是3D的也可以忽略Y轴,只考虑X轴和 Z轴上的碰撞检查:
(1)基本碰撞检测,用位置和半径判断:
/ * 行车与黑洞是否碰撞 * @param {} car * @param {*} dinosaur */ _isCarAndDinoCollision$(car, dinosaur) { let hPos = car.owner.transform.position; let dPos = dinosaur.owner.transform.position; let x = hPos.x - dPos.x; let z = hPos.z - dPos.z; if (x * x + z * z <= Math.pow(dinosaur.collisionRadius + car.collisionRadius, 2)) return true; return false; }
(2)从数组中取出需要进行碰撞判断的 对象,嵌套for循环进行实时检测:
/ * 检查车与黑洞碰撞 */ checkCarsAndDinoCollision$() { if (!this._init$()) return; if (!window.curScene || curScene.isPaused || !curScene._cars$ || !curScene.dinosaurs) return; let cars = curScene._cars$; let dinosaurs = curScene.dinosaurs; let car, dinosaur; for (let j = cars.length - 1; j >= 0; j--) { car = cars[j]; for (let i = dinosaurs.length - 1; i >= 0; i--) { dinosaur = dinosaurs[i]; if (this._isCarAndDinoCollision$(car, dinosaur)) { dinosaur.onCollision$(null, car); //触发碰撞结果 car.onKilled$(dinosaur); break;//一辆车只能被一只恐龙吃 } } } }
(3)注册帧循环,实时检测碰撞:
Laya.timer.loop(100, this, this.checkCarsAndDinoCollision$);
11.计算移动到目标点,需要旋转的角度:
/ 路段起始坐标 */ this._startPos$ = new Laya.Vector3(); / 路段结束坐标 */ this._endPos$ = new Laya.Vector3(); / 路线角度 */ this._roadAngle$ = undefined; let deltaX = this._endPos$.x - this._startPos$.x; let deltaZ = this._endPos$.z - this._startPos$.z; this._roadAngle$ = (Math.atan2(deltaX, deltaZ) * GameSetting$.ANGLE_1_RAD$) % 360; / 弧度转角度换算单位 */ GameSetting$.ANGLE_1_RAD$ = 180 / Math.PI; 发生旋转动画: _move$(){ let rot = this.owner.transform.rotationEuler; let deltaAngle = (this._roadAngle$ - rot.y) % 360; if(deltaAngle > 180) { deltaAngle -= 360; }else if(deltaAngle < -180) { deltaAngle += 360; } rot.y += deltaAngle * Math.min(0.02 * deltaT, 1); this.owner.transform.rotationEuler = rot; } onUpdate(){ this._move$(); }
12.玩家交互区域判定
(1)工具函数
/ * 获取二维距离平方 m^2 * @param {*} x1 * @param {*} y1 * @param {*} x2 * @param {*} y2 * @returns */ static getV2DisQ$(x1, y1, x2, y2) { return Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2); }
(2)玩家移动状态:
/ 是否鼠标按下状态 */ get isMouseDown$() { return this._isMouseDown$; } / 是否移动中 */ get isMoveing$() { return this._isMoveing$; } / 获取上次移动时刻 ms */ get lastMouseMoveT$() { return this._lastMouseMoveT$; } this.owner.on(Laya.Event.MOUSE_MOVE, this, (e: Laya.Event) => { if (!this.currentTouch) { this.currentTouch = e; stageX = e.stageX; stageY = e.stageY; } else { isMoved = true; this._lastMouseMoveT = Laya.timer.currTimer; this.angle = this.getAngle(new Laya.Vector2(stageX, stageY), new Laya.Vector2(e.stageX, e.stageY)); this._isMoving = true; } }) / 是否等待交互 */ isWaitInteract() { return Globals.moveCtr && !Globals.moveCtr.isMouseDown && Globals.moveCtr.lastMouseMoveT > 0 && Globals.moveCtr.lastMouseMoveT + 300 < Laya.timer.currTimer; }
(3)主逻辑代码
//交互距离平方 public interDisQ: number = 1.5 * 1.5; onUpdate() { this.checkInteract(); } checkInteract(): void { if (!this.playerMove) return; let playerPos = this.playerMove.position; let disQ = Utils.getV2DisQ$(playerPos.x, playerPos.z, this.boxAreaPos.x, this.boxAreaPos.z); (disQ > this.interDisQ || !this.playCtr.isWaitInteract()) ? this.onNoInter() : this.onInter(); //!this.playCtr.isWaitInteract()可注释 } onInter(): void { if (this._isInter) return; this._isInter = true; console.log("tcy 进去食品交互区域") } onNoInter(): void { if (!this._isInter) return; this._isInter = false; console.log("tcy 离开食品交互区域") }
13.是否在交互矩形范围内
/ * 点是否在矩形范围内(场景是平面(非球形),只取X和Z方向坐标) * @param {*} pV3 坐标点 * @param {*} tV3 目标坐标点 * @param {*} xR 目标x长度/2 * @param {*} zR 目标z长度/2 */ static isInRect$(pV3, tV3, xR, zR) { if (pV3.x > tV3.x - xR && pV3.x < tV3.x + xR && pV3.z > tV3.z - zR && pV3.z < tV3.z + zR) return true; return false; }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/139082.html