Animated Sprite helpful class

If you're asking about complex animations, here's config for crab animations for my Cranner game:

ezgif.com-gif-maker

[
	{
		"name":"default",
		"tickStep": 3
	},
	{
		"name":"run",
		"firstFrameIndex":1,
		"framesCount":5,
		"yoyo": true
	},
	{
		"name":"jump",
		"firstFrameIndex": "run",
		"framesCount":6,
		"nextAnimation": "jump top"
	},
	{
		"name":"jump top",
		"firstFrameIndex":"jump",
		"framesCount":1
	},
	{
		"name":"fall",
		"firstFrameIndex":"jump top",
		"framesCount":5,
		"tickStep":2,
		"loop":false
	},
	{
		"name":"landing",
		"firstFrameIndex":"fall",
		"framesCount":2,
		"tickStep":4,
		"nextAnimation": "run"
	},
	{
		"name":"sit down",
		"firstFrameIndex":"landing",
		"framesCount":2,
		"tickStep": 2,
		"nextAnimation": "duck run"
	},
	{
		"name":"stand up",
		"firstFrameIndex":"landing",
		"framesCount":2,
		"reverse": true,
		"loop":false
	},
	{
		"name":"duck transition",
		"firstFrameIndex":"sit down",
		"framesCount":1,
		"nextAnimation": "duck run"
	},
	{
		"name":"duck run",
		"firstFrameIndex":"duck transition",
		"animationStartingFrame":3,
		"framesCount":3,
		"tickStep": 4,
		"yoyo":true
	},
	{
		"name":"fall idle",
		"firstFrameIndex":"jump top",
		"framesCount":2,
		"loop":false
	}
]

And here's crab controller lua class:

import 'libraries/AnimatedSprite/AnimatedSprite.lua'

class("Hero").extends(AnimatedSprite)

local xConst <const> = 121
local yConst <const> = 162
local zConst <const> = 10000

local mcPerFrame <const> = 25
local groundLevel <const> = 162
local gravity <const> = 0.3
local initialJumpVelocity <const> = -9
local dropVelocity <const> = -3
local minJumpHeight <const> = 110
local maxJumpHeight <const> = 50
local speedDropCoefficient <const> = 5

function Hero:init(imagetable, states, animate)
	Hero.super.init(self, imagetable, states, animate)

    self.states["stand up"].onAnimationEndEvent = function ()
		self:changeState(self.jumping and "fall idle" or "run")
	end
    self.alive = true
	self.velocity = 0
	self.reachedMinHeight = false
	self.speedDrop = false
	self.jumpVelocity = 0
	self.jumping = false
	self.ducking = false
	self.jumpEnded = false
	self.falling = false
	
	self:setCollideRect(0, 0, self:getSize())
	self:setCollidesWithGroups({1, 2})

	self:setCenter(0, 0)
	self:setZIndex(zConst)
	self:moveTo(xConst, yConst)

    table.insert(GameScene.sprites, self)
end

function Hero:update()
    if (not self.alive) then
        return
    end
    --#region jump
    if (self.jumping) then
        self:updateJump()
    end
    --#endregion
    --#region collisions
    local collisions = self:overlappingSprites()
    local amount = #collisions
    if (amount > 0) then
        for i = 1, amount do
            if (collisions[i]:getGroupMask() == 2) then
                GameScene.Slowdown()
                collisions[i]:setCollisionsEnabled(false)
                collisions[i].speed = GameScene.GetSpeed()
                goto continue
            end
            if (self:alphaCollision(collisions[i])) then
                GameScene.GameOver()
                --collisions[i]:moveTo(381, collisions[i].y)
            end
            ::continue::
        end
    end
    --#endregion
    self:updateAnimation()
end

function Hero:moveSideways(direction)
    newX = self.x + direction
    if (newX > 17 and newX < 335) then
        self:moveTo(newX, self.y)
    end
end

function Hero:startJump()
    if (not self.jumping) then
        GameScene.SpawnSandParticlesJump(self.x)
        self:changeState("jump")
        self.jumping = true
        self.jumpEnded = false
        self.velocity = initialJumpVelocity -- - (speed / 10)
        self.reachedMinHeight = false
        self.speedDrop = false
        self.falling = false
    end
end

function Hero:endJump()
    self.jumpEnded = true
    if (self.reachedMinHeight and (self.velocity < dropVelocity)) then
        self.velocity = dropVelocity
    end
end

function Hero:updateJump()
    if (not self.falling and self.velocity >= 0) then
        self.falling = true
        if (not self.speedDrop) then
            self:changeState("fall")
        end
    end
    local framesElapsed = deltaTime / mcPerFrame
    local newY = self.y
    if (self.speedDrop) then
        newY += self.velocity *	speedDropCoefficient * framesElapsed
    else
        newY += self.velocity * framesElapsed
    end		

    self.velocity += gravity * framesElapsed

    if ((newY < minJumpHeight) or self.speedDrop) then
        self.reachedMinHeight = true
    end

    if ((newY < maxJumpHeight) or self.speedDrop or self.jumpEnded) then
        self:endJump()
    end

    if (newY > groundLevel) then
        self:resetJump()
        return
    end

    self:moveTo(self.x, newY)
end

function Hero:resetJump()
    self:moveTo(self.x, groundLevel)
    GameScene.SpawnSandParticlesFall(self.x)
    self:changeState(self.speedDrop and "duck transition" or "landing")
    self.jumpVelocity = 0
    self.jumping = false
    self.jumpEnded = false
    self.speedDrop = false
end

function Hero:sitDown()
    self.ducking = true
    if (self.jumping) then
        self.speedDrop = true
        if (self.velocity < 1) then
            self.velocity = 1
        end
    end
    self:changeState("sit down")
end

function Hero:standUp()
    self.ducking = false
    if (self.jumping) then
        self.speedDrop = false
    end
    self:changeState("stand up")
end