//判断是否碰到道具
_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();
}
};
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
/**
* 检测碰撞
*/
_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;
}
};
//碰撞检测(主要在于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中定义的函数
}
};
this.mainUI.box_wating.on(Laya.Event.MOUSE_DOWN,this,function(){});
//抽奖
_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(); //时间点到了,如果遮罩还在我们就执行这个函数
}
/**
* 倒计时刷新
*/
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);
};
1. /**场景中的初始子弹**/
2. public bullet: Laya.MeshSprite3D;
加载资源结束之后,获取场景中的子弹用于克隆:
1. //获取场景中的子弹用于克隆
2. this.bullet = this.scene.getChildByName("bullet") as Laya.MeshSprite3D;
3. //未产生子弹时移除克隆参考用子弹
4. this.bullet.removeSelf();
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); //存在的解决
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. }
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. }
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. }
/** 创建身体的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$);
}
/** 创建身体的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);
}
/** 创建骨骼点 */
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$();
}
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$); //施加一个力到刚体上的质心上
}
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)
前提条件:
this.sawRigidbody$.allowRotation = true; //设置可旋转
this.sawRigidbody$.type = "dynamic"; //刚体类型动态
//旋转速度
this.rollSpeed$ = 2;
setRollVelocity$() {
if (!this.woodenPlateRigidbody$ || !this.rollSpeed$) return;
this.woodenPlateRigidbody$.angularVelocity = this.rollSpeed$; rollSpeed$ 负值:逆时针 正值:顺时针
}
(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;
}
/**
* 检查车与黑洞碰撞
*/
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;//一辆车只能被一只恐龙吃
}
}
}
}
Laya.timer.loop(100, this, this.checkCarsAndDinoCollision$);
/** 路段起始坐标 */
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$();
}
(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);
}
/** 是否鼠标按下状态 */
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;
}
//交互距离平方
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;
}