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

com.almasb.fxgl.animation.Interpolators.kt Maven / Gradle / Ivy

The newest version!
/*
 * FXGL - JavaFX Game Library. The MIT License (MIT).
 * Copyright (c) AlmasB ([email protected]).
 * See LICENSE for details.
 */

package com.almasb.fxgl.animation

import com.almasb.fxgl.core.math.FXGLMath
import javafx.animation.Interpolator

/**
 * A collection of interpolators to be used with animations to control their progress rate.
 * Each interpolator returns 0 when input is 0 and returns 1 when input is 1.
 * When input is in (0, 1) the returned value is dependent on the interpolator behavior, but
 * typically stays within the (0, 1) range with a few exceptions, such as BACK interpolator,
 * which goes above 1.
 *
 * Adapted from https://github.com/grapefrukt/juicy-breakout/tree/master/lib/com/gskinner/motion/easing
 *
 * @author Almas Baimagambetov ([email protected])
 */
enum class Interpolators : EasingInterpolator {

    LINEAR {
        override fun easeIn(ratio: Double): Double {
            return ratio
        }

        override fun easeOut(ratio: Double): Double {
            return ratio
        }

        override fun easeInOut(ratio: Double): Double {
            return ratio
        }
    },

    QUADRATIC {
        override fun easeIn(ratio: Double): Double {
            return ratio*ratio
        }

        override fun easeOut(ratio: Double): Double {
            return -ratio*(ratio-2)
        }

        override fun easeInOut(ratio: Double): Double {
            return if (ratio < 0.5)
                2*ratio*ratio
            else
                -2*ratio*(ratio-2)-1
        }
    },

    CUBIC {
        override fun easeIn(ratio: Double): Double {
            return ratio*ratio*ratio
        }

        override fun easeOut(ratio: Double): Double {
            val r = ratio - 1
            return r*r*r+1
        }

        override fun easeInOut(ratio: Double): Double {
            val r = ratio - 1

            return if (ratio < 0.5)
                4*ratio*ratio*ratio
            else
                4*r*r*r+1
        }
    },

    QUARTIC {
        override fun easeIn(ratio: Double): Double {
            return ratio*ratio*ratio*ratio
        }

        override fun easeOut(ratio: Double): Double {
            val r = ratio - 1

            return 1-r*r*r*r
        }

        override fun easeInOut(ratio: Double): Double {
            val r = ratio - 1

            return if (ratio < 0.5)
                8*ratio*ratio*ratio*ratio
            else
                -8*r*r*r*r+1
        }
    },

    QUINTIC {
        override fun easeIn(ratio: Double): Double {
            return ratio*ratio*ratio*ratio*ratio
        }

        override fun easeOut(ratio: Double): Double {
            val r = ratio - 1

            return 1 + r*r*r*r*r
        }

        override fun easeInOut(ratio: Double): Double {
            val r = ratio - 1

            return if (ratio < 0.5)
                16*ratio*ratio*ratio*ratio*ratio
            else
                16 * r*r*r*r*r + 1
        }
    },

    EXPONENTIAL {
        override fun easeIn(ratio: Double): Double {
            return if (ratio == 0.0) 0.0 else Math.pow(2.0, 10 * (ratio - 1))
        }

        override fun easeOut(ratio: Double): Double {
            return if (ratio == 1.0) 1.0 else 1 - Math.pow(2.0, -10 * ratio)
        }

        override fun easeInOut(ratio: Double): Double {
            if (ratio == 0.0 || ratio == 1.0)
                return ratio

            val r = ratio * 2 - 1
            if (r < 0)
                return 0.5*Math.pow(2.0, 10*r)

            return 1 - 0.5*Math.pow(2.0, -10*r)
        }
    },

    SINE {
        override fun easeIn(ratio: Double): Double {
            if (ratio == 1.0)
                return 1.0

            return 1 - Math.cos(ratio * (Math.PI / 2))
        }

        override fun easeOut(ratio: Double): Double {
            return Math.sin(ratio * (Math.PI / 2))
        }

        override fun easeInOut(ratio: Double): Double {
            return -0.5 * (Math.cos(ratio * Math.PI) - 1)
        }
    },

    CIRCULAR {
        override fun easeIn(ratio: Double): Double {
            return -(Math.sqrt(1 - ratio*ratio) - 1)
        }

        override fun easeOut(ratio: Double): Double {
            return Math.sqrt(1 - (ratio - 1) * (ratio - 1))
        }

        override fun easeInOut(ratio: Double): Double {
            val r = ratio * 2
            val r2 = r - 2

            return if (r < 1)
                -0.5 * (Math.sqrt(1 - r * r) - 1)
            else
                0.5 * (Math.sqrt(1 - r2 * r2) + 1)
        }
    },

    SMOOTH {
        override fun easeIn(ratio: Double): Double {
            return Interpolator.EASE_IN.interpolate(0.0, 1.0, ratio)
        }

        override fun easeOut(ratio: Double): Double {
            return Interpolator.EASE_OUT.interpolate(0.0, 1.0, ratio)
        }

        override fun easeInOut(ratio: Double): Double {
            return Interpolator.EASE_BOTH.interpolate(0.0, 1.0, ratio)
        }
    },

    BOUNCE {
        override fun easeIn(ratio: Double): Double {
            return 1 - easeOut(1 - ratio)
        }

        override fun easeOut(ratio: Double): Double {
            if (ratio < 1/2.75) {
                return 7.5625*ratio*ratio
            } else if (ratio < 2/2.75) {
                val r = ratio - 1.5/2.75
                return 7.5625*r*r+0.75
            } else if (ratio < 2.5/2.75) {
                val r = ratio-2.25/2.75
                return 7.5625*r*r+0.9375
            } else {
                val r = ratio - 2.625/2.75
                return 7.5625*r*r+0.984375
            }
        }

        override fun easeInOut(ratio: Double): Double {
            val r = ratio * 2

            return if (r < 1)
                0.5 * easeIn(r)
            else
                0.5 * easeOut(r - 1) + 0.5
        }
    },

    ELASTIC {
        private val a = 1
        private val p = 0.3
        private val s = p / 4

        override fun easeIn(ratio: Double): Double {
            if (ratio == 0.0 || ratio == 1.0)
                return ratio

            val r = ratio - 1

            return -(a * Math.pow(2.0, 10 * r) * Math.sin((r - s) * (2 * Math.PI) / p))
        }

        override fun easeOut(ratio: Double): Double {
            if (ratio == 0.0 || ratio == 1.0)
                return ratio

            return a * Math.pow(2.0, -10 * ratio) *  Math.sin((ratio - s) * (2 * Math.PI) / p) + 1
        }

        override fun easeInOut(ratio: Double): Double {
            if (ratio == 0.0 || ratio == 1.0)
                return ratio

            val r = ratio*2 - 1

            if (r < 0) {
                return -0.5 * (a * Math.pow(2.0, 10 * r) * Math.sin((r - s*1.5) * (2 * Math.PI) /(p*1.5)))
            }

            return 0.5 * a * Math.pow(2.0, -10 * r) * Math.sin((r - s*1.5) * (2 * Math.PI) / (p*1.5)) + 1
        }
    },

    BACK {
        private val s = 1.70158

        override fun easeIn(ratio: Double): Double {
            if (ratio == 1.0)
                return 1.0

            return ratio * ratio * ((s+1) * ratio - s)
        }

        override fun easeOut(ratio: Double): Double {
            if (ratio == 0.0)
                return 0.0

            val r = ratio - 1

            return r * r * ((s+1) * r + s) + 1
        }

        override fun easeInOut(ratio: Double): Double {
            val r = ratio * 2
            val r2 = r - 2

            return if (r < 1)
                0.5*(r*r*((s*1.525+1)*r-s*1.525))
            else
                0.5*(r2 * r2 * ((s*1.525 + 1) * r2 + s*1.525)+2)
        }
    },

    RANDOM {
        override fun easeIn(ratio: Double) = random(ratio)

        override fun easeOut(ratio: Double) = random(ratio)

        override fun easeInOut(ratio: Double) = random(ratio)

        private fun random(ratio: Double): Double {
            if (ratio == 0.0 || ratio == 1.0)
                return ratio

            return FXGLMath.randomDouble()
        }
    },

    PERLIN {
        override fun easeIn(ratio: Double) = perlin(ratio)

        override fun easeOut(ratio: Double) = perlin(ratio)

        override fun easeInOut(ratio: Double) = perlin(ratio)

        private fun perlin(ratio: Double): Double {
            if (ratio == 0.0 || ratio == 1.0)
                return ratio

            return FXGLMath.noise1D(ratio * 2)
        }
    }
}

interface EasingInterpolator {

    fun EASE_IN(): Interpolator = object : Interpolator() {
        override fun curve(t: Double): Double {
            return easeIn(t)
        }
    }

    fun EASE_OUT(): Interpolator = object : Interpolator() {
        override fun curve(t: Double): Double {
            return easeOut(t)
        }
    }

    fun EASE_IN_OUT(): Interpolator = object : Interpolator() {
        override fun curve(t: Double): Double {
            return easeInOut(t)
        }
    }

    fun easeIn(ratio: Double): Double
    fun easeOut(ratio: Double): Double
    fun easeInOut(ratio: Double): Double
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy