Skip to content

Instantly share code, notes, and snippets.

@shifterbit
Last active February 4, 2025 15:59
Show Gist options
  • Select an option

  • Save shifterbit/b8a81c7ade9343b7786d68b76a682c8b to your computer and use it in GitHub Desktop.

Select an option

Save shifterbit/b8a81c7ade9343b7786d68b76a682c8b to your computer and use it in GitHub Desktop.

Predicting The Fatality of a Move in Fraymakers

Calculating distance from deathbounds

function distanceFromDeathBounds(entity: Entity, components: {x: Float, y: Float}) {
    var deathBounds = stage.getDeathBounds();
    var r = deathBounds.getRectangle();
    var width = r.width;
    var height = r.height;
    var top = deathBounds.getY(); // top
    var left = deathBounds.getX(); // left 
    var bottom = top + height; //  bottom
    var right = left + width; // right


    var entityX = entity.getX(); //
    var entityY = entity.getY(); //


    // Create points we can use to measure distance
    var topPoint = Point.create(0, top);
    var bottomPoint = Point.create(0, bottom);
    var leftPoint = Point.create(left, 0);
    var rightPoint = Point.create(right, 0);

    var entityXPoint = Point.create(entityX, 0);
    var entityYPoint = Point.create(0, entityY);

    var leftDistance = Math.abs(Math.getDistance(entityXPoint, leftPoint));
    var rightDistance = Math.abs(Math.getDistance(entityXPoint, rightPoint));
    var upDistance = Math.abs(Math.getDistance(entityYPoint, topPoint));
    var downDistance = Math.abs(Math.getDistance(entityYPoint, bottomPoint));

    var closestXBoundDistance = (if (components.x < 0) { leftDistance; } else { rightDistance; });
    var closestYBoundDistance = (if (components.y < 0) { upDistance; } else { downDistance; });
    return { x: closestXBoundDistance, y: closestYBoundDistance };

}

Finish Zoom Function

Code

function finishZoom(event: GameObjectEvent) {
    var victim: Character = event.data.self;
    if (!victim.hasBodyStatus(BodyStatus.INVINCIBLE) && event.data.hitboxStats.flinch) {
        var xVel = victim.getXKnockback();
        var yVel = victim.getYKnockback();

        var airTime = victim.getHitstun();
        // External Forces besides knockback
        var airFriction = victim.getGameObjectStat("aerialFriction");
        var gravity = victim.getGameObjectStat("gravity");


        var kbComponents = { x: xVel, y: yVel };
        var boundDistance: { x: Int, y: Int } = distanceFromDeathBounds(victim, kbComponents);
        var xDistance: Float = Math.abs(xVel * airTime) + 0.5 * (-airFriction * Math.pow(airTime, 2));
        var yDistance: Float =  if (kbComponents.y >= 0) {
            // "Calculating launch height using kinematic equations.");
            Math.abs((Math.abs(yVel) * airTime) + 0.5 * (gravity * Math.pow(airTime, 2)));
        } else {
            // "Calculating launch height using projectile motion formula.");
            Math.abs(Math.pow(yVel, 2) / (2.2 * (gravity)));
        };

        var distanceComponents = { x: xDistance, y: yDistance };
        var stats = event.data.hitboxStats;
        var angle = stats.angle;
        var autoLinkAngles = [SpecialAngle.AUTOLINK_STRONGER, SpecialAngle.AUTOLINK_STRONGEST, SpecialAngle.AUTOLINK_WEAK];
        if (autoLinkAngles.indexOf(stats.rawAngle) < 0 && (distanceComponents.x >= (boundDistance.x * 1.1) || distanceComponents.y > (boundDistance.y * 1.1))) { 

            // Generic Effects here
            

            // Training Mode or Last Stock
            if (match.getMatchSettingsConfig().matchRules[0].contentId == "infinitelives" || gameEndingStock(victim)) {
                // Effects exclusive to last/game ending stock here

            } else { // Regular Kills
                // Effects exclusive to everything else here

            }
        }
    }

}

Formulas Used/The Math

Calculating Horizontal Distance

Here is the code that calculates Horizontal Distance due to knockback

var xVel = victim.getXKnockback();

var airTime = victim.getHitstun();
// External Forces besides knockback
var airFriction = victim.getGameObjectStat("aerialFriction");

Math.abs(xVel * airTime) + 0.5 * (-airFriction * Math.pow(airTime, 2));

Derived from this formula

$$\Delta x = v_0 \cdot t + \frac{1}{2} \cdot (-a) \cdot t^{2}$$

And in terms of Fraymakers we have:

$$\text{Horizontal Distance Travelled} = \text{InitialVelocity} \times \text{Hitstun} + \frac{1}{2} \times (-\text{AirFrictionStat}) \cdot \text{Hitstun}^{2}$$

Calculating Vertical Distance

Calculating Vertical launch distance requires a bit more work

Downward Launching

For downward launching moves we use essentially the same formula as the first except we are adding distance caused by gravity

var yVel = victim.getYKnockback();

var airTime = victim.getHitstun();
var gravity = victim.getGameObjectStat("gravity");

Math.abs((Math.abs(yVel) * airTime) + 0.5 * (gravity * Math.pow(airTime, 2)));

Notice how this time there's no negative sign as gravity increases the distance

$$\Delta y = v_0 \cdot t + \frac{1}{2} \cdot (a) \cdot t^{2}$$

And in terms of Fraymakers we have:

$$\text{Vertical Distance Travelled Down} = \text{YKnockback} \times \text{Hitstun} + \frac{1}{2} \times (\text{GravityStat}) \times \text{Hitstun}^{2}$$

Upward Launching

This calculates the Vertical Distance upward if the move hits up

var yVel = victim.getYKnockback();
var gravity = victim.getGameObjectStat("gravity");

Math.abs(Math.pow(yVel, 2) / (2.2 * (gravity)));

Derived from the following formula:

$$h = \frac{v^2}{2.2 \cdot g}$$

And in terms of Fraymakers we have:

$$\text{Max Height} = \frac{(\text{YKnockback})^2}{2.2 \times \text{GravityStat} }$$
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment