craftyjs / Crafty

JavaScript Game Engine
http://craftyjs.com
MIT License
3.43k stars 555 forks source link

Colliding with an entity teleports the entity to the top #1184

Open ghost opened 6 years ago

ghost commented 6 years ago

I have an entity (we'll call it player) that, when colliding with another entity (platform), the player entity gets teleported to the top of the platform. My code is here https://repl.it/@j0rdancodes/Game-4

liamnajor commented 6 years ago

the Gravity component is completely separate from the Collision component. add this to your "player" component code: this.onHit("Platform", function() { var hitDatas, hitData; if ((hitDatas = this.hit('Platform'))) { var i = hitDatas.length while(i != 0){ hitData = hitDatas[i]; if (hitData.type === 'SAT') { this.x -= hitData.overlap hitData.nx; this.y -= hitData.overlap hitData.ny; } else { this.x = evt._x; this.y = evt._y; } } });); that way, it'll know what direction your player entity is hitting from, and move it back accordingly

ghost commented 6 years ago

@liamnajor That works for the bottom, but not the sides.

EDIT: Whoops, I put in an extra equals sign in the first if statement. I had to edit your code a little bit because I was getting errors. It works, but the whole game pauses when I hit an the side of an entity with the Platform component.

this.onHit("Platform", function() {
      var hitDatas, hitData;
      if (hitDatas = this.hit('Platform')) {
        var i = hitDatas.length;
        while(i != 0){
          hitData = hitDatas[i];
          if (hitData.type === 'SAT') {
            this.x -= hitData.overlap * hitData.nx;
            this.y -= hitData.overlap * hitData.ny;
          } else {
            this.x = evt._x;
            this.y = evt._y;
          }
        }
      }
    });

EDIT: After looking at the collision docs, I see the code. It still doesn't work and I get the same result.

this.onHit("Platform", function(evt) {
      var hitDatas, hitData;
      if ((hitDatas = this.hit('wall'))) { // check for collision with walls
        hitData = hitDatas[0]; // resolving collision for just one collider
        if (hitData.type === 'SAT') { // SAT, advanced collision resolution
          // move player back by amount of overlap
          this.x -= hitData.overlap * hitData.nx;
          this.y -= hitData.overlap * hitData.ny;
        } else { // MBR, simple collision resolution
          // move player to previous position
          this.x = evt._x;
          this.y = evt._y;
        }
      }
    });
liamnajor commented 6 years ago

Add i -= 1 to my code

this.onHit("Platform", function() {
      var hitDatas, hitData;
      if (hitDatas = this.hit('Platform')) {
        var i = hitDatas.length;
        while(i != 0){
          hitData = hitDatas[i];
          if (hitData.type === 'SAT') {
            this.x -= hitData.overlap * hitData.nx;
            this.y -= hitData.overlap * hitData.ny;
          } else {
            this.x = evt._x;
            this.y = evt._y;
          }
          i -= 1
        }
      }
    });

That way it'll use all the collision data, rather then just one collision callback. Sorry for the stupid error on my part. The reason the doc code didn't work is it uses only the first set of collision data, and my code did too (except trapped in a loop) until I added i -= 1

peetj commented 6 years ago

I'm having this problem too, my player entity passes right through to the top of the platform. Tried everything and nothing works. Tried every variation of the code above - doesn't work for me. It doesn't really seem like a robust solution in any case. I was thinking that a cancelJump() method would be more intuitive - however playing with vy, ay, _jumpSpeed yielded no positive result for me.

It was like the onHit event was just clobbering whatever I tried.

screen shot 2018-05-06 at 12 33 05 pm

For the moment, I am just going to use the UpdateFrame event and set my own flag/property on the Player entity with the onHit method which will tell me when collisions are occurring. I can then move the Player down and 'out of range' of the onHit() callback by setting this.y and vy = 0. Using the 'landedOnGround' event I then reset isColliding = false.

This works pretty well with just a couple of lines of code

player-crafty-entity