1
votes

I am currently playing with crafty js and have created 2D top-down world with solid objects.

When a collision event occurs with any solid object, I want my player to no longer be able to move in the direction of said object (as there is a solid object blocking its path).

I have found a few tutorials online which cover this topic, however the methods and functions they are calling are depricated.

    .onHit("solid", function(from) {
        console.log("ouch");
     }

I can register the collision when my player hits a solid, but I do not know how to stop the movement.

I know that I can setup specific solutions per collision (for example, a top border can update y to move off the specific top collision), however I want a generic approach so colliding with any solid results in my character not being able to move.

When I try to call from.x I receive that the element is undefined, while other elements such as from.length do work, which does not make sense to me.

Or offer some demo-code which is compatible with the latesty crafty?

1

1 Answers

2
votes

Collision data

When I try to call from.x I receive that the element is undefined, while other elements such as from.length do work, which does not make sense to me.

The onHit callback provides you with the same collision data as the hit function - an array of collision results. That's why you are able to access the length property.

From the hit apidocs:

The returned collision data will be an Array of Objects with the type of collision used, the object collided and if the type used was SAT (a polygon was used as the hitbox) then an amount of overlap.


MBR collision

I know that I can setup specific solutions per collision (for example, a top border can update y to move off the specific top collision), however I want a generic approach so colliding with any solid results in my character not being able to move.

Colliding horizontally and/or vertically are the only two cases I know for a collision between two axis-aligned bounding boxes. AABBs are used as a default in Crafty's collision detection (and can be accessed via .mbr()).
The solution you propose is actually what's commonly used to resolve such AABB collisions.

Use arrow keys or WASD to move the green player. Notice how movement is limited by the black walls.

Crafty.init();

Crafty.e("2D, DOM, Color, Fourway, Collision, player")
      .attr({x: 32, y: 32, w: 32, h: 32})
      .color('green')
      .fourway()
      .bind('Moved', function(evt){
        if (this.hit('solid'))
          this[evt.axis] = evt.oldValue;
      });

Crafty.e("2D, DOM, Color, solid, top")
      .attr({x: 0, y: 0, w: 128, h: 1})
      .color('black');
Crafty.e("2D, DOM, Color, solid, bottom")
      .attr({x: 0, y: 127, w: 128, h: 1})
      .color('black');
Crafty.e("2D, DOM, Color, solid, left")
      .attr({x: 0, y: 0, w: 1, h: 128})
      .color('black');
Crafty.e("2D, DOM, Color, solid, right")
      .attr({x: 127, y: 0, w: 1, h: 128})
      .color('black');
<script src="https://github.com/craftyjs/Crafty/releases/download/0.7.1/crafty-min.js"></script>

SAT collision

There is a more complex and precise collision detection variant in Crafty using the seperate axis theorem, which works between any two convex polygons. A custom polygon hitbox can be specified via .collision().
A similar solution is used to resolve the SAT collision - move the colliding object back using the information from the collision results.

Use arrow keys or WASD to move the green player. Notice how movement is limited along the red lines, which represent the convex polygon hitboxes.

Crafty.init();

Crafty.e("2D, Fourway, Collision, DOM, Color, WiredHitBox, player")
      .attr({x: 32, y: 32, w: 32, h: 32})
      .collision([0, 16, 16, 0, 32, 16, 16, 32])
      .color('green')
      .fourway()
      .bind('Moved', function(evt) {
        var hitDatas, hitData;
        if ((hitDatas = this.hit('solid'))) {
          // resolving collision for just one collider here and assuming SAT collision
          hitData = hitDatas[0];
          this.x -= hitData.overlap * hitData.normal.x;
          this.y -= hitData.overlap * hitData.normal.y;
        }
      });


Crafty.e("2D, Collision, DOM, Color, WiredHitBox, solid")
      .attr({x: 64, y: 64, w: 64, h: 64})
      .collision([0, 32, 32, 0, 64, 32, 32, 64])
      .color('black');
<script src="https://github.com/craftyjs/Crafty/releases/download/0.7.1/crafty-min.js"></script>

Be sure to read up on the apidocs for additional information about the components and events used.