Исходник Гайд Плавненькооооо. Способ анимировать любые значения + примеры.

movebx

Известный
Автор темы
72
191
Всем хай, здрасьте, привет и здарова.
Пока я работаю над луа лаунчером под GTA SA: Definitive Edition, хочу запостить некоторый сниппет, который вы можете юзать везде, где сможете получить FPS.
Суть данного скрипта заключается в удобном использовании анимаций, которые смогут сделать ваш скрипт более красивым и плавным. Перейдем к делу.

В конструкторе объекта анимаций есть 2 параметра: длительность и тип анимации.
Длительность - скорость, с которой анимация завершит свой полный цикл. Стоит выставлять значение не больше единицы, т.к. она становится слишком долгой.
Тип анимации - говорит сам за себя.
Я сделал всего 3 типа анимаций:
ANIMATION_TYPE_DEFAULT - обычный тип анимаций.
ANIMATION_TYPE_ONCE - анимация проигрывается всего один раз после апдейта ( обновления ) объекта
ANIMATION_TYPE_STEP - тот же тип, что и ANIMATION_TYPE_DEFAULT, только при окончании цикла анимации он сбросится к нулю.

Создавать объект анимации нужно вне рендер-цикла. К примеру есть какой то эвент render, который вызывается каждый фрейм, делаем так:
Lua:
local my_superior_animation = animation( 0.1, animation.type.ANIMATION_TYPE_DEFAULT ) -- Объект анимации создан
Далее, в самом render эвенте вам нужно обновить эту анимацию, но только при условии, что второй параметр ( animation_type ) не равен animation.type.ANIMATION_TYPE_ONCE.
Как это делается, приведу простой пример:
Lua:
local my_superior_animation = animation( 0.1, animation.type.ANIMATION_TYPE_DEFAULT )

events.render( function( current_frame )
    local local_player = entity.get_local_player( )

    my_superior_animation:update( local_player:is_alive( ) )
    
    local rect_color = my_superior_animation:color( color( 0, 0, 0, 255 ), color( 255, 255, 255, 255 ) )
    render.filled_rect( vector( 250, 250 ), vector( 100, 100 ), rect_color )
end )
Теперь, когда локальный игрок жив, то цвет квадратика, располагающегося по координатам ( 250, 250 ) и с шириной ( 100, 100 ) будет белым, если же он умрет - цвет будет плавно изменяться на черный.
Теперь расскажу про ANIMATION_TYPE_ONCE
Lua:
local my_superior_animation = animation( 0.1, animation.type.ANIMATION_TYPE_ONCE )

events.render( function( current_frame )
    my_superior_animation:update( ) -- Обновление не требует параметра condition

    local rect_color = my_superior_animation:color( color( 0, 0, 0, 255 ), color( 255, 255, 255, 255 ) )
    render.rect( vector( 250, 250 ), vector( 100, 100 ), rect_color )
end )
Теперь же, при первом запуске скрипта цвет квадратика, расположенного по тем же координатам, будет плавно изменен на белый и останется таким до следующего перезапуска.
Анимировать можно абсолютно любые значения, для этого есть функция self:get(), которая возвращает текущую стадию анимации в границах [0, 1], а так же можете использовать любую функцию ease-ингов. Например я использовал easeOutQuint. Полный список можете найти тут: https://easings.net/

src:
Lua:
local animation = { } do

    animation.type = {
        ANIMATION_TYPE_ONCE = 1,
        ANIMATION_TYPE_DEFAULT = 2,
        ANIMATION_TYPE_STEP = 3
    }

    animation.ease = function( n )
        return 1 - math.pow( 1 - n, 5 );
    end

    animation.new = function( self, duration, animation_type )
        local animation = { }
            animation.duration = duration;
            animation.type = animation_type;
            animation.weight = 0.0;

        return setmetatable( animation, {
            __index = self,
            __call = self.update
        } );
    end

    animation.update = function( self, condition )
        local condition = condition or false;

        --frametime means 1 / fps
        local clock = ui.get_frametime( ) / self.duration;
        if ( self.animation_type == animation.type.ANIMATION_TYPE_ONCE ) then
            self.weight = self.weight + clock;
            self.weight = math.clamp( self.weight, 0, 1 );
            return;
        end

        self.weight = self.weight + ( condition and clock or -clock );
        if ( self.animation_type == animation.type.ANIMATION_TYPE_STEP ) then
            self.weight = math.clamp( self.weight, 0, 1 ) % 1;
            return;
        end

        self.weight = math.clamp( self.weight, 0, 1 );
    end

    animation.get = function( self )
        return self.weight * self.weight * self.weight;
    end

    animation.value = function( self, from, to )
        return from + ( to - from ) * animation.ease( self:get( ) )
    end

    animation.color = function( self, from, to )
        return color(
            from.r + ( to.r - from.r ) * animation.ease( self:get( ) ),
            from.g + ( to.g - from.g ) * animation.ease( self:get( ) ),
            from.b + ( to.b - from.b ) * animation.ease( self:get( ) ),
            from.a + ( to.a - from.a ) * animation.ease( self:get( ) )
        );
    end

    animation.vector = function( self, from, to )
        return vector(
            from.x + ( to.x - from.x ) * animation.ease( self:get( ) ),
            from.y + ( to.y - from.y ) * animation.ease( self:get( ) ),
            from.z + ( to.z - from.z ) * animation.ease( self:get( ) )
        )
    end

    setmetatable( animation, {
        __call = animation.new
    } );
    
end