本节目标:碰撞障碍物
laya商业级3d游戏开发
相交检测有很多方案,laya有内置的物理引擎,或者其他第三方类库
Laya内置物理引擎,刚体数量多时,苹果机上流畅度会比较低
性能和包体是非常重要的指标
分别决定了流畅度和加载速度,游戏包体越小,用户首次加载留存率就越高
考虑到性能和包体以及案例的实际需求原因
框架集成了最简单的3d碰撞模块
碰撞检测模块源码在3Dphysics目录下
给角色添加碰撞器
输出信息到黏贴版本
//center (0.0, 0.6, 0.0) size (0.6, 1.2, 0.3)
在onAwake给角色添加碰撞器
onAwake() {
super.onAwake();
this.animator = this.gameObject.getChildByName('CatBase').getComponent(Laya.Animator);
this.animator.play('Cat_RunLong');
//碰撞器章节讲解内容
let aabbshape: AABBShape = new AABBShape();
aabbshape.mask = CollisionMask.Character;
//位运算,表示碰撞器和 障碍物和鱼产生碰撞
aabbshape.collisionMask = 1 << CollisionMask.Obstacle | 1 << CollisionMask.Fish;
//center (0.0, 0.6, 0.0) size (0.6, 1.2, 0.3)
aabbshape.size = new Laya.Vector3(0.6, 1.2, 0.3)
aabbshape.center = new Laya.Vector3(0.0, 0.6, 0.0);
this.gameObject.addComponentIntance(aabbshape);
//考虑到性能原因,开启主动检测的对象才会进行遍历检测
//{a,b,c,......} a.ActiveDetec()
// detect(a ,b)
// detect(a ,c)
//........
//{a,b,c,......} a.ActiveDetec(); b.ActiveDetec()
// detect(a ,b)
// detect(a ,c)
//detect(b ,a)
//detect(b ,c)
aabbshape.ActiveDetec();
//碰撞进入
aabbshape.RegisetCollsionEnter(this, this.OnCollisionEnter)
//碰撞离开
// aabbshape.RegisetCollsionExit(this, this.OnCollisionExit)
}
OnCollisionEnter(source: AABBShape, target: AABBShape) {
console.log('OnCollisionEnter', target.mask);
if (target.mask == CollisionMask.Fish) {
target.gameObject.active = false;
GameSample.soundMgr.FishCollection.Play();
}
else if (target.mask == CollisionMask.Obstacle)//障碍物
{
this.Fail();
let obstalcle = Game.instance.obstacleSpawn.itemMap.getNumberKey(target.gameObject.id)
obstalcle.ani.play('death');
obstalcle.collider.enabled = false;
}
}
Fail() {
Game.instance.speed = 0
this.animator.play('Cat_Death')
}
Reborn(){}
鱼添加碰撞器和逻辑
FishSpwan.ts
添加
//碰撞器教程讲解
protected CreateSpwanItem(spwanItemData: SpwanItemData): SpawnItem {
let item = super.CreateSpwanItem(spwanItemData);
let newgo = item.gob;
let boxCollider = new AABBShape()
boxCollider.mask = CollisionMask.Fish;
boxCollider.collisionMask = 0;
boxCollider.size = new Laya.Vector3(1, 1, 0.34);
boxCollider.center = new Laya.Vector3(0, 0, 0);
newgo.addComponentIntance(boxCollider);
return item;
}
ObstacleSpawn.ts
//重载CreateSpwanItem
protected CreateSpwanItem(spwanItemData: SpwanItemData): SpawnItem {
let spwanitem = super.CreateSpwanItem(spwanItemData)
let newgo = spwanitem.gob;
//碰撞器的添加
let boxCollider = new AABBShape()
//center (0.0, 0.7, 0.0) size (1.5, 1.4, 0.6)
boxCollider.mask = CollisionMask.Obstacle;
boxCollider.collisionMask = 0;
boxCollider.center = new Laya.Vector3(0.0, 0.7, 0.0)
boxCollider.size = new Laya.Vector3(1.5, 1.4, 0.6)
let collidergob = newgo as Laya.Sprite3D;
collidergob.addComponentIntance(boxCollider);
let obstacle = new Obstacle();
obstacle.ani = newgo.getChildAt(0).getComponent(Laya.Animator) as Laya.Animator;
obstacle.collider = boxCollider;
this.itemMap.add(newgo.id, obstacle)
return spwanitem;
}
//障碍物模型
export class Obstacle {
ani: Laya.Animator;
//碰撞系统章节会用到
collider: AABBShape;
}
添加
protected onSpawn(newGo: Laya.Sprite3D, spwanItemData: SpwanItemData, z)
…
//重新激活碰撞器
obstacle.collider.enabled=true;
Game.ts
Onawake
… //碰撞检测模块
this.scene.addComponent(CollsionManagerThreeD);
// this.addfishCollider();
验证碰撞器是否成功添加
打开全局设定,开启显示碰撞器
角色碰撞到障碍物后睡觉
自定义碰撞模块哪些是需要知道的?
因为采用了位运算表示碰撞器之间的碰撞种类检测,
所以有新物体增加时CollisionMask会常常也需要同步增加
//因为考虑到性能原因,只有开启了自动检测的对象才会进行检测
//以下为表里有3个对象,1个对象开启检测,需要进行2此运算
//2个对象开启检测,需要进行4此运算
//{a,b,c,…} a.ActiveDetec()
// detect(a ,b)
// detect(a ,c)
//…
//{a,b,c,…} a.ActiveDetec(); b.ActiveDetec()
// detect(a ,b)
// detect(a ,c)
//detect(b ,a)
//detect(b ,c)
碰撞管理器CollsionManagerThreeD.ts
onLateUpdate() {
if (GameDesgin.enableCollsion) {
if (this.detectObjs.length >= 1) {
for (let i = 0; i < this.detectObjs.length; i++) {
let detectAABB = this.detectObjs[i] as AABBShape;
this.GetFilterZItems(this.detectObjs[i].transform.position.z, detectAABB);
this.Detect(detectAABB, detectAABB.moveSpeed);
}
}
}
}
//进行粗略检测
//结合案例,主角前面30米之内的对象才进行检测
//大多数物理引擎采用的是二叉树,,四叉树,八叉树,进行粗略检测
this.GetFilterZItems(this.detectObjs[i].transform.position.z, detectAABB);