# 【Cocos Creator实战教程(5)】——打砖块(物理引擎,碰撞检测)
# 1. 知识点
1. 物理引擎
2. 碰撞检测
# 2. 步骤
## 2.1 准备工作
搭一个游戏背景
## 2.2 小球运动
再建一个物理层,用来装游戏里的带有物理属性的东西,设置锚点为左下角
- wall:墙//小球碰到就会反弹的那种墙
- ground:地面//球碰到地面,这局游戏就结束了
- brick_layout:砖块布局//这个单词我们之前讲过了就不讲了
- ball:球//就是球
- paddle:桨//这里特指那个可以控制移动的白色长方形
![](http://www.writebug.com/myres/static/uploads/2021/10/19/b7493d8e2f6bd62990dff3ecb757228e.writebug)
这个wall肯定是要有碰撞属性的,在属性面板,添加一个物理组件 (物理->rigidbody)。
因为我们的墙有上,左,右三面,所以再添加三个碰撞组件(一个节点可以有多个碰撞组件)。
![](http://www.writebug.com/myres/static/uploads/2021/10/19/4b79294289794339e1b64a3b8ebdc24e.writebug)
编辑一下
![](http://www.writebug.com/myres/static/uploads/2021/10/19/a5a0a4e997912294075065606421b2b3.writebug)
地面同理,小球同理,托盘同理 。(这里把地面和墙分开是为了后面墙和地面可能有不同的逻辑)
现在已经编辑了几个物理节点的碰撞包围盒,但还没有编辑他们的物理属性(cc.RigidBody)
先从小球开始,点击ball节点,在属性检查器可以看到
![](http://www.writebug.com/myres/static/uploads/2021/10/19/7d304f97545bc72f4c841eaf57cb770b.writebug)
Cocos Creator从1.5版本开始支持Box2D物理游戏引擎,Box2D是一个优秀的刚体模拟框架,关于Box2D的知识可以去网络上自行了解。
把第一个参数勾选,代表启用碰撞回调,可以在脚本里写回调函数
Bullet:高速运动的物体(子弹)开启,避免穿透,这里不用勾选
type选择Dynamic,
- static:不会受到力的影响,不会受到速度影响,指的是物理引擎,我们依然可以通过移动节点来改变位置 。
- kinematic:不受力的影响,会受到速度影响 。
- dynamic:受力影响,受速度影响 。
- animated:和动画结合使用。
Gravity Scale设置为0(标准是1,数值代表比例),也就是没有重力。
设置线速度(1000,1000)
在下面的碰撞组件里,设置Friction (摩擦系数)等于0(没有摩擦力),Restitution(弹性系数)等于1(没有动量损耗)
![](http://www.writebug.com/myres/static/uploads/2021/10/19/2a09ceaf1d1dfa1ee993d82422cb2451.writebug)
因为小球是我们的主角,左右的碰撞都是对球来说的,所以碰撞属性都在小球这一方设置就可以了。
另外要设置wall,ground,paddle,brick的type为static
brick的tag为1,
ground的tag为2,
paddle的tag为3,
wall的tag位4
下面来看脚本
BrickLayout.js
```javascript
cc.Class({
extends: cc.Component,
properties: {
padding: 0,
spacing: 0,
cols: 0,
brickPrefab: cc.Prefab,
bricksNumber: 0,
},
init(bricksNumber) {
this.node.removeAllChildren();
this.bricksNumber = bricksNumber;
for (let i = 0; i < this.bricksNumber; i++) {
let brickNode = cc.instantiate(this.brickPrefab);
brickNode.parent = this.node;
brickNode.x = this.padding + (i % this.cols) * (brickNode.width + this.spacing) + brickNode.width / 2;
brickNode.y = -this.padding - Math.floor(i / this.cols) * (brickNode.height + this.spacing) - brickNode.height / 2;
}
}
});
```
## 2.3 添加砖块
自己写了一个动态添加砖块的布局脚本,传入需要添加的砖块数量就可以动态加入的布局节点中。
## 2.4 结束界面
完善好游戏逻辑,我使用了MVC模式编写脚本。
![](http://www.writebug.com/myres/static/uploads/2021/10/19/5575fcc51872ee173ebcfff8c3b7522f.writebug)
# 3. 总结
至此,我便给大家简要的介绍了一下物理引擎,更多的功能需要大家自己探索实践。
列出几个大家常问的问题:
## 3.1如何移动刚体?
当我们的一个节点上有一个刚体,我们要进行移动。一般我们都会通过节点的setPosition进行移动,但是刚体不会被影响,不管是Static、还是Dynamic还是Kinematic都不会被影响
我们可以通过
1、瞬时动作cc.place来进行移动而且不会影响刚体原本的运动轨迹
2、Action的所有动作。cc.moveBy;cc.moveTo;等等
## 3.2 碰撞组件和物理组件有什么不同?
碰撞组件没有类型之分,只要相交就会发生碰撞事件,如果不对碰撞进行处理,那就没有任何影响。物理碰撞组件分类型,因为他们先会绑定刚体。如果刚体类型不同则会有不同的效果。
和Dynamtic类型刚体绑定的PhysicsBoxCollider会受重力影响,可以设置速度
和Static类型刚体绑定的物理组件,不会受重力影响,不可以设置速度,可以通过设置位置让其移动
和Kinematic类型刚体绑定的物理组件,不受重力影响,可以设置速度
例如,本文中我们就是用了物理碰撞组件,所以刚体类型选择上要有一定技巧。
在现实开发情况下,拾取道具和横像动作例如进攻多用碰撞组件 ,而竖向动作例如弹跳多用物理碰撞组件。
## 3.3 三种物理组件有什么不同?
绑定了Dynamic(运动)类型的物理组件不能穿透绑定了Static(静态)类型的物理组件
绑定了Dynamic类型的物理组件不能穿透绑定了Kinematic类型的物理组件
Static和Kinematic不会触发碰撞事件,Static和Static;Kinematic和Kinematic不会触发碰撞事件;
所以,因为我们不能将ball选为kinematic,尽管此游戏我们忽略了重力。
# 3.4 物理组件如何进行碰撞回调?
首先RigidBody要开启碰撞监听
然后当前节点下有如下函数
```javascript
在函数碰撞体刚开始接触时调用一次
onBeginContatct:function(contact,selfCollider,otherCollider){}
在两个碰撞体结束接触时被调用一次
onEndContact:fucntion(contact,setCollider,otherCollider){}
每次要处理碰撞体接触逻辑是被调用
onPreSolve:function(contact,selfCollider,otherCollider){}
每次处理完碰撞体接触时被调用
onPostSolve:fucntion(contact,selfCollider,otherCollider){}
```
# 3.5 碰撞组件的回调
```javascript
var manager = cc.director.getCollisionManager();
manager.enabled = true;
脚本里面先开启碰撞监听,因为默认是关闭
然后有以下函数:
//当碰撞产生时调用
onCollisionEnter:function(other,self){
}
//在碰撞产生后,在碰撞结束前,每次计算完碰撞结果后调用
onCollisionStay:function(other,self){}
//当碰撞结束后调用
onCollisionExit;function(other,self){}
```
部分素材来源于网络,欢迎提问