All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almasb.fxgl.physics.SAT Maven / Gradle / Ivy

There is a newer version: 21.1
Show newest version
/*
 * FXGL - JavaFX Game Library. The MIT License (MIT).
 * Copyright (c) AlmasB ([email protected]).
 * See LICENSE for details.
 */

package com.almasb.fxgl.physics;

import com.almasb.fxgl.core.math.Vec2;
import com.almasb.fxgl.entity.components.TransformComponent;

/**
 * Separating Axis Theorem based check for collision.
 *
 * @author Almas Baimagambetov ([email protected])
 */
public final class SAT {

    private SAT() {}

    private static final MinMax box2axis1 = new MinMax();
    private static final MinMax box2axis2 = new MinMax();
    private static final MinMax box1axis3 = new MinMax();
    private static final MinMax box1axis4 = new MinMax();

    /**
     * Note: NOT thread-safe but GC-friendly.
     *
     * @param box1 hit box 1
     * @param box2 hit box 2
     * @param angle1 angle of hit box 1
     * @param angle2 angle of hit box 2
     * @param t1 transform of hit box 1
     * @param t2 transform of hit box 2
     * @return true if two hit boxes are colliding
     */
    public static boolean isColliding(HitBox box1, HitBox box2, double angle1, double angle2,
                                      TransformComponent t1, TransformComponent t2) {

        Vec2 axis1 = box1.axes[0];
        Vec2 axis2 = box1.axes[1];
        Vec2 axis3 = box2.axes[0];
        Vec2 axis4 = box2.axes[1];

        computeMinMax(box2.corners, axis1, box2axis1);

        if (box1.axis1MinMax.isSeparated(box2axis1))
            return false;

        computeMinMax(box2.corners, axis2, box2axis2);

        if (box1.axis2MinMax.isSeparated(box2axis2))
            return false;

        computeMinMax(box1.corners, axis3, box1axis3);

        if (box2.axis1MinMax.isSeparated(box1axis3))
            return false;

        computeMinMax(box1.corners, axis4, box1axis4);

        if (box2.axis2MinMax.isSeparated(box1axis4))
            return false;

        return true;
    }

    /**
     * Calculate a projection of corners to an axis and populate the minMax object.
     *
     * @param corners a 4-value array defining corner points
     * @param axis the axis on which to project corners
     * @param minMax the storage object
     */
    static void computeMinMax(Vec2[] corners, Vec2 axis, MinMax minMax) {
        float value = Vec2.dot(corners[0], axis);

        float min = value;
        float max = value;

        for (int i = 1; i < 4; i++) {
            value = Vec2.dot(corners[i], axis);

            min = Math.min(min, value);
            max = Math.max(max, value);
        }

        minMax.min = min;
        minMax.max = max;
    }

    /**
     * Data structure for min-max values on an axis.
     */
    public static class MinMax {
        private float min = 0;
        private float max = 0;

        /**
         * @param other another min-max (assumed on the same axis)
         * @return true if this min-max is separated from other
         */
        private boolean isSeparated(MinMax other) {
            return max < other.min || other.max < min;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy