麻烦帮忙解读下示例代码(emample-cases)

creator v2.4.6

文件: assets/cases/Collider/Platform/HeroControl.js
疑问: 看不懂 onCollisionEnter里面的 2nd step 3rd step

示例运行界面:

cc.Class({
  extends: cc.Component,
 
  properties: {
    speed: cc.v2(0, 0),// 当前速度
    maxSpeed: cc.v2(2000, 2000),// 最大限速
    gravity: -1000,// 模拟重力加速度
    drag: 1000,// 模拟水平阻力加速度
    direction: 0,// 左右方向 -1 0 1
    jumpSpeed: 300,// 起跳速度
    _lastSpeedY: 0,//上一帧的速度
  },
 
  // use this for initialization
  onLoad: function () {
    //add keyboard input listener to call turnLeft and turnRight
    cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyPressed, this);
    cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyReleased, this);
 
    this.collisionX = 0;
    this.collisionY = 0;
    this.jumping = true;
 
    this.prePosition = cc.v2();
    this.preStep = cc.v2();
 
    this.touchingNumber = 0;
  },
 
  onEnable: function () {
    cc.director.getCollisionManager().enabled = true;
    cc.director.getCollisionManager().enabledDebugDraw = true;
  },
 
  onDisable: function () {
    cc.director.getCollisionManager().enabled = false;
    cc.director.getCollisionManager().enabledDebugDraw = false;
  },
 
  onKeyPressed: function (event) {
    let keyCode = event.keyCode;
    switch (keyCode) {
      case cc.macro.KEY.a:
      case cc.macro.KEY.left:
        this.direction = -1;
        break;
      case cc.macro.KEY.d:
      case cc.macro.KEY.right:
        this.direction = 1;
        break;
      case cc.macro.KEY.w:
      case cc.macro.KEY.up:
        if (!this.jumping) {
          this.jumping = true;
          this.speed.y = this.jumpSpeed > this.maxSpeed.y ? this.maxSpeed.y : this.jumpSpeed;
          this._lastSpeedY = this.jumpSpeed > this.maxSpeed.y ? this.maxSpeed.y : this.jumpSpeed;
        }
        break;
    }
  },
 
  onKeyReleased: function (event) {
    let keyCode = event.keyCode;
    switch (keyCode) {
      case cc.macro.KEY.a:
      case cc.macro.KEY.left:
      case cc.macro.KEY.d:
      case cc.macro.KEY.right:
        this.direction = 0;
        break;
    }
  },
 
  onCollisionEnter: function (other, self) {
    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
    // 正向x轴,检查x轴上是否有碰撞
    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
    // 正向y轴,检查y轴上是否有碰撞
    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;
      this._lastSpeedY = 0;
      other.touchingY = true;
    }
 
  },
 
  onCollisionStay: function (other, self) {
    if (this.collisionY === -1) {
      if (other.node.group === 'Platform') {
        var motion = other.node.getComponent('PlatformMotion');
        if (motion) {
          this.node.x += motion._movedDiff;// 跟移动的平台保持相对静止
        }
      }
 
      // this.node.y = other.world.aabb.yMax;
 
      // var offset = cc.v2(other.world.aabb.x - other.world.preAabb.x, 0);
 
      // var temp = cc.affineTransformClone(self.world.transform);
      // temp.tx = temp.ty = 0;
 
      // offset = cc.pointApplyAffineTransform(offset, temp);
      // this.node.x += offset.x;
    }
  },
 
  onCollisionExit: function (other) {
    this.touchingNumber--;
    if (this.touchingNumber === 0) {
      this.node.color = cc.Color.WHITE;
    }
 
    if (other.touchingX) {
      this.collisionX = 0;
      other.touchingX = false;
    }
    else if (other.touchingY) {
      other.touchingY = false;
      this.collisionY = 0;
      this.jumping = true;
    }
  },
 
  update: function (dt) {
    if (this.jumping) {
      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;
    if (this._lastSpeedY === 0 || this.speed.y === 0 || this._lastSpeedY / Math.abs(this._lastSpeedY) === this.speed.y / Math.abs(this.speed.y)) {
      // 起点、顶点、落点、同向
      this.node.y += (this._lastSpeedY + this.speed.y) * dt / 2;
      // s = (vt + v0) * t / 2
    }
    else {
      // 异向的
      this.node.y += - this._lastSpeedY / this.gravity / 2 * this._lastSpeedY + this.speed.y / this.gravity / 2 * this.speed.y;
 
      // s = (v1^2 - v0^2)/(2*a)
    }
 
    this._lastSpeedY = this.speed.y;
  },
});


这个够清晰吧

这我肯定看过了呀 :sweat_smile:,我是这个案例这块处理看不懂,不是不知道这个回调函数

…看注释写的挺明白的呀…

那请问下这段代码什么意思?

感谢楼主给了我一个规避方案 :joy:
这个是自己写的模拟物理碰撞吧。我是这么理解的:
collider检测到碰撞发生的时候,先对两个包围盒做碰撞检测cc.Intersection.rectRect(selfPreAabb, otherPreAabb),如果碰撞后,再根据自己的方向this.speed.x,小于0代表向左移动,大于0表示向右,然后判断自己的包围盒相对碰撞体的位置xMax表示包围盒最右边的点的x坐标,xMin表示最左边。第一个就是判断自己方向向左,并且自己在碰撞体的右边,然后禁止物体穿过,需要把物体位置设置到刚好碰撞的地方,然后collisionX标记为-1,在update中判断速度与标记相乘大于0就会停止移动,后续的判断大致意思都这样,不过是方向选取的问题

selfPreAabb.x = selfAabb.x;
otherPreAabb.x = otherAabb.x;
 
if (cc.Intersection.rectRect(selfPreAabb, otherPreAabb)) {}
selfPreAabb.y = selfAabb.y;
otherPreAabb.y = otherAabb.y;
 
if (cc.Intersection.rectRect(selfPreAabb, otherPreAabb)) {}

这两段我也不能理解,而且第二段是紧跟着第一段的,那不是相当于x,y都赋值给preAabb,就是当前的aabb了?

还有这一段里面的y轴方向上的移动,原谅我物理不好。明明都是求路径公式,if语句内

this.node.y += (this._lastSpeedY + this.speed.y) * dt / 2;

如果换成下面的公式

this.node.y += - this._lastSpeedY / this.gravity / 2 * this._lastSpeedY + this.speed.y / this.gravity / 2 * this.speed.y;

,star开始时(load,start后)掉落下来,不会正常掉落到平台,会停在空中

看这个帖子,跟你问题相同

1赞

别人有注释啊,上面一个公式是同向的,就是说加速度和速度方向相同或者其中某一个为0,下面的公式是方向相反的。
也就是说上面的公式是加速或匀速运动,下面的公式是减速运动,你拿减速的换到加速或匀速情况下肯定有问题啊,除非你改成通用的

那是我自己加的注释,我怕写错了,刚去掉了。。

感谢大大的解答!! !那个,enn,还有个问题。Rect是不是只能表示正放的矩形,倾斜的没法表示?我看一个物体旋转的时候,manager.enabledDrawBoundingBox = true,boundingBox会一直变,但一直是那种正向的矩形(长宽跟x,y轴平行)。

:joy:没写错啊,那就是判断方向的

该主题在最后一个回复创建后14天后自动关闭。不再允许新的回复。