cocos creator 中使用简单的碰撞系统实现物理引擎的效果

cocos creator 中使用简单的碰撞系统实现物理引擎的效果

最近在写一个帧同步的小游戏,  服务器用的pinus, 客户端就是cocos creator了

因为要实现玩家在物理环境的跳跃, 碰撞, 移动, 最开始准备使用cocos creator的物理引擎, 但是实际操作是发现并不可行

我的服务器接收和转发客户端的消息, 玩家移动位置使用过方向命令实现的, 并不是直接发位置信息, 这就导致由于客户端的差异而造成位置出现差异, 如此, 需要自己搭建一个物理环境

首先

我们为角色设置一些参数

speed: cc.v2(0, 0),            // 角色移动的速度
maxSpeed: cc.v2(2000, 2000),    // 角色移动的最大速度
gravity: -1000,                // 角色受到的重力
drag: 1000,                    
direction: 0,                  // 方向
jumpSpeed: 300                // 跳跃速度

通过gravity 我们可以模拟角色受到重力的效果

在update中

this.speed.y += this.gravity * dt;
if (Math.abs(this.speed.y) > this.maxSpeed.y) {
this.speed.y = this.speed.y > 0 ? this.maxSpeed.y : -this.maxSpeed.y;

这样 角色就会一直受到重力的影响向下运动

 

我们在做一个地面, 让角色可以站在上面

cocos creator 中使用简单的碰撞系统实现物理引擎的效果_第1张图片

大概这样, 记得要添加碰撞组件 , 然后分组, 当然也要开启物理引擎

在角色上添加好碰撞回调

onCollisionEnter(other, self);

onCollisionStay(other, self);

onCollisionExit(other, self);

 

那么重点来了, 就是如何让玩家站在地面上

代码如下, 讲解一下

首先添加属性 collisionX  表示横向碰撞, 即左右碰撞, -1表示左边发送碰撞, 1表示右边发生碰撞

collisionY 同理

var otherAabb = other.world.aabb;

var otherPreAabb = other.world.preAabb.clone();

var selfAabb = self.world.aabb;

var selfPreAabb = self.world.preAabb.clone();

获取自己和对方的包围盒, 以及上一帧的包围盒, 为什么要回去上一帧的包围盒呢, 因为当前帧以及发送碰撞, 即角色卡在地面了(有部分重合), 而上一帧就是角色站在地面上的感觉

还有一个点, 包围盒是世界坐标下的, 和触摸事件一样, 基于世界坐标

if (cc.Intersection.rectRect(selfPreAabb, otherPreAabb)) {

if (this.speed.x < 0 && (selfPreAabb.xMax > otherPreAabb.xMax)) {

this.node.x = otherPreAabb.xMax - this.node.parent.x;

this.collisionX = -1;

}

else if (this.speed.x > 0 && (selfPreAabb.xMin < otherPreAabb.xMin)) {

this.node.x = otherPreAabb.xMin - selfPreAabb.width - this.node.parent.x;

this.collisionX = 1;

}

 

this.speed.x = 0;

other.touchingX = true;

return;

}

首先判断是否相撞,  加粗的地方是关键, this.speed.x < 0 表示玩家是向左移动时发生的碰撞 在判断自己的包围盒右边是否在对方包围盒的右边, 如下图 即4是否在2右边, 

cocos creator 中使用简单的碰撞系统实现物理引擎的效果_第2张图片

如果判断语句正确, 碰撞发生了

this.node.x = otherPreAabb.xMax - this.node.parent.x;

这个时候, 设置玩家的位置 就是把黑方框, 放到红方框右边靠着, 靠多少可以自己调整

!!!重点 this.node.parent.x 必须是基于世界坐标的, 因为我这里刚好与世界坐标一样

这是我另一个项目中的

this.node.x = this.node.parent.convertToNodeSpaceAR(cc.v2(otherPreAabb.xMax+selfPreAabb.width/2, 0)).x;

 

this.node.color = cc.Color.RED;

        this.touchingNumber ++;
        
        // 1st step 
        // get pre aabb, go back before collision
        var otherAabb = other.world.aabb;
        var otherPreAabb = other.world.preAabb.clone();

        var selfAabb = self.world.aabb;
        var selfPreAabb = self.world.preAabb.clone();

        // 2nd step
        // forward x-axis, check whether collision on x-axis
        selfPreAabb.x = selfAabb.x;
        otherPreAabb.x = otherAabb.x;

        if (cc.Intersection.rectRect(selfPreAabb, otherPreAabb)) {
            if (this.speed.x < 0 && (selfPreAabb.xMax > otherPreAabb.xMax)) {
                this.node.x = otherPreAabb.xMax - this.node.parent.x;
                this.collisionX = -1;
            }
            else if (this.speed.x > 0 && (selfPreAabb.xMin < otherPreAabb.xMin)) {
                this.node.x = otherPreAabb.xMin - selfPreAabb.width - this.node.parent.x;
                this.collisionX = 1;
            }

            this.speed.x = 0;
            other.touchingX = true;
            return;
        }

        // 3rd step
        // forward y-axis, check whether collision on y-axis
        selfPreAabb.y = selfAabb.y;
        otherPreAabb.y = otherAabb.y;

        if (cc.Intersection.rectRect(selfPreAabb, otherPreAabb)) {
            if (this.speed.y < 0 && (selfPreAabb.yMax > otherPreAabb.yMax)) {
                this.node.y = otherPreAabb.yMax - this.node.parent.y;
                this.jumping = false;
                this.collisionY = -1;
            }
            else if (this.speed.y > 0 && (selfPreAabb.yMin < otherPreAabb.yMin)) {
                this.node.y = otherPreAabb.yMin - selfPreAabb.height - this.node.parent.y;
                this.collisionY = 1;
            }
            
            this.speed.y = 0;
            other.touchingY = true;
        }    

 

update(dt)

 if (this.collisionY === 0) {
            this.speed.y += this.gravity * dt;
            if (Math.abs(this.speed.y) > this.maxSpeed.y) {
                this.speed.y = this.speed.y > 0 ? this.maxSpeed.y : -this.maxSpeed.y;
            }
        }

        if (this.direction === 0) {
            if (this.speed.x > 0) {
                this.speed.x -= this.drag * dt;
                if (this.speed.x <= 0) this.speed.x = 0;
            }
            else if (this.speed.x < 0) {
                this.speed.x += this.drag * dt;
                if (this.speed.x >= 0) this.speed.x = 0;
            }
        }
        else {
            this.speed.x += (this.direction > 0 ? 1 : -1) * this.drag * dt;
            if (Math.abs(this.speed.x) > this.maxSpeed.x) {
                this.speed.x = this.speed.x > 0 ? this.maxSpeed.x : -this.maxSpeed.x;
            }
        }

        if (this.speed.x * this.collisionX > 0) {
            this.speed.x = 0;
        }
        
        this.prePosition.x = this.node.x;
        this.prePosition.y = this.node.y;

        this.preStep.x = this.speed.x * dt;
        this.preStep.y = this.speed.y * dt;
        
        this.node.x += this.speed.x * dt;
        this.node.y += this.speed.y * dt;
    },

 

你可能感兴趣的:(cocos,creator)