Polygon Collision Detection

Collision Detect with Polygon & Rect

The blue polygon can be moved and transformed by using the following keys below. Red shapes are can be solid and cannot be passed. Yellow shapes are opaque.

  • ArrowKeys - Moves the polygon
  • Q - Rotates the polygon
  • R - Increases the polygon size
  • F - Decreases the polygon size
  • C - Resets the polygon

Canvas tag not supported

Creating the PolygonObject

constructor(options={}) {
    options.isMovable = true;
    options.movementRate = 0.25,
    super(options);

    this._shape = new hamonengine.geometry.polygon();
    this._shape.addVertex(0, 0);
    this._shape.addVertex(75, 0);
    this._shape.addVertex(100, 75/2);
    this._shape.addVertex(75, 75);
    this._shape.addVertex(0, 75);

    this._polygonRotation = 0;
    this._polygonScale = 1.0;

    this._rotateHold = 0;
    this._scaleDirection = 0;
    this._scaleHoldDown = 0;

    this._transformedShape = this._shape;
}
                            

Creating the Polygons

constructor(options={}) {
    super(options);

    //Our main, movable shape.
    this._object = new hamonengine.demos.actors.polygonObject();

    //Create the shape and add the vertices.
    this._shape3 = new hamonengine.geometry.polygon();
    this._shape3.addVertex(0, 0);
    this._shape3.addVertex(75, 75);
    this._shape3.addVertex(0, 75);

    //Create the shape and add the vertices.
    this._shape2Position = new hamonengine.math.vector2(160, 150);
    this._shape2 = this._shape3.translate(this._shape2Position);

    this._rectPosition = new hamonengine.math.vector2(400, 100);
    this._rect = new hamonengine.geometry.rect(400, 100, 100, 100);
}
                            

Rendering the Polygons

renderBasics1(screen, elapsedTimeInMilliseconds) {
    screen.beginPainting();

    screen.drawPolygon(this._shape2, 0, 0, {lineWidth: 1, color: 'red'});
    screen.drawPolygon(this._shape3, 300, 25, {lineWidth: 1, color: 'yellow', fill: true, fillColor: 'yellow'});
    screen.drawRect(this._rect, 0, 0, {lineWidth: 1, color: 'red'});

    this._object.process(screen, elapsedTimeInMilliseconds, [
        {
            shape: this._rect,
            position: this._rectPosition
        }, 
        {
            shape: this._shape2,
            position: this._shape2Position
        }
    ]);

    //Render the polygon at the specific position that has a line width of 3px and the color is blue with no normals drawn.
    //The final parameter determines if normals are drawn.
    this._object.render(screen, elapsedTimeInMilliseconds);

    screen.endPainting();
}
                            

Collision Detection Logic

process(screen, elapsedTimeInMilliseconds, otherShapes) {
    //Handle rotation & scale.
    this._polygonRotation = ((this._polygonRotation + (this._rotateHold * elapsedTimeInMilliseconds / 1000 * Math.PI / 4)) % Math.PI2);
    this._polygonScale = (this._polygonScale + (this._scaleDirection * elapsedTimeInMilliseconds / 1000 * 0.10));

    //Precalculate the movement vector and update it with any collision information.
    let movementVector = this.calcMove(elapsedTimeInMilliseconds);

    //Perform the actual rotation & scaling and cache it for rendering.
    this._transformedShape = this._shape.scale(new hamonengine.math.vector2(this._polygonScale, this._polygonScale))
        .rotateAtCenter(this._polygonRotation)
        .translate(this.position.add(movementVector));

    //Handle collisions detection with otherShapes.
    let hasCollisions = false;
    let collisionCount = 0;
    do {
        //Make note if we have a collision.
        hasCollisions = false;
        for (let i = 0; i < otherShapes.length; i++) {
            //Determine if this shape has collided with another.
            const mtv = this._transformedShape.isCollision(otherShapes[i].shape);
            if (mtv.length > 0) {
                //Determine the position of the two shapes and correct the direction of the MTV based on the position of the two shapes.
                let distance = otherShapes[i].position.subtract(this.position);
                if (mtv.dot(distance) >= 0) {
                    mtv = mtv.invert();
                }
                
                //Adjust the movement vector and shape.
                movementVector = movementVector.add(mtv);
                this._transformedShape = this._transformedShape.translate(mtv);
                hasCollisions = true;
            }
        }
    //If a collision has occurred then we need to recalculate the collision detection again between the shapes.
    //The MTV generated by one object may force one object to clip into another one, so another round of collision detection is needed.
    } while (hasCollisions && collisionCount++ <= hamonengine.core.collisionDetection.limit);

    this.move(elapsedTimeInMilliseconds, movementVector);
}