skip to Main Content

I am trying to create little top view game with a character that moves around an open world. The world is filled with obstacles. I cannot figure out to handle my character position when he collides with corners of obstacles. I have the following onCollision method implemented, which ofcourse works just fine when the player hits a wall vertically or horizontally.

  @override
  void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
    if (other is Wall) {
      if (intersectionPoints.length == 2) {
        var pointA = intersectionPoints.elementAt(0);
        var pointB = intersectionPoints.elementAt(1);
        final mid = (pointA + pointB) / 2;
        final collisionVector = absoluteCenter - mid;
        double penetrationDepth = (size.x / 2) - collisionVector.length;
        collisionVector.normalize();
        position += collisionVector.scaled(penetrationDepth);
      }
    }
    super.onCollision(intersectionPoints, other);
  }

However, when the character hits a corner, the way the penetration depth is calculated does not make sense, and therefor he gets stuck.

enter image description here

Any help on how to approach this problem would be greatly appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    I solved it by figuring out how the intersection points work and determining the quadrant of the collision vector's direction. The smallest absolute displacement in either x or y direction determines from which side the player bumps into the corner. It works, so I am happy :). Still very curious if a math wizz could do this without all these assumptions, and use some clever vector tricks.

      @override
      void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
        if (other is Wall) {
          if (intersectionPoints.length == 2) {
            var pointA = intersectionPoints.elementAt(0);
            var pointB = intersectionPoints.elementAt(1);
            final mid = (pointA + pointB) / 2;
            final collisionVector = absoluteCenter - mid;
            if (pointA.x == pointB.x || pointA.y == pointB.y) {
              // Hitting a side without touching a corner
              double penetrationDepth = (size.x / 2) - collisionVector.length;
              collisionVector.normalize();
              position += collisionVector.scaled(penetrationDepth);
            } else {
              position += _cornerBumpDistance(collisionVector, pointA, pointB);
            }
          }
        }
        super.onCollision(intersectionPoints, other);
      }
    
      Vector2 _cornerBumpDistance(
          Vector2 directionVector, Vector2 pointA, Vector2 pointB) {
        var dX = pointA.x - pointB.x;
        var dY = pointA.y - pointB.y;
        // The order of the two intersection points differs per corner
        // The following if statements negates the necessary values to make the 
        // player move back to the right position
        if (directionVector.x > 0 && directionVector.y < 0) {
          // Top right corner
          dX = -dX;
        } else if (directionVector.x > 0 && directionVector.y > 0) {
          // Bottom right corner 
          dX = -dX;
        } else if (directionVector.x < 0 && directionVector.y > 0) {
          // Bottom left corner
          dY = -dY;
        } else if (directionVector.x < 0 && directionVector.y < 0) {
          // Top left corner
          dY = -dY;
        }
        // The absolute smallest of both values determines from which side the player bumps
        // and therefor determines the needed displacement
        if (dX.abs() < dY.abs()) {
          return Vector2(dX, 0);
        } else {
          return Vector2(0, dY);
        }
      }
    

  2. First time I try something for the game in Flutter. Could you please try this code for your need?

    @override
    void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
      if (other is Wall) {
        if (intersectionPoints.length == 2) {
          final wallCorner = intersectionPoints.elementAt(0);
          final collisionVector = position - wallCorner;
          final penetrationDepth = size.x / 2 - collisionVector.length;
          collisionVector.normalize();
          position += collisionVector * penetrationDepth;
        }
      }
      super.onCollision(intersectionPoints, other);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search