112 lines
3.9 KiB
Lua
112 lines
3.9 KiB
Lua
local anim8 = require "lib/anim8"
|
||
require 'lib/vec3'
|
||
|
||
--- Скорость между кадрами в анимации
|
||
local ANIMATION_SPEED = 0.1
|
||
|
||
local characterId = 1
|
||
|
||
--- @todo Композиция лучше наследования, но не до такой же степени! Надо отрефакторить и избавиться от сотни полей в таблице
|
||
--- @class Character
|
||
--- @field id integer
|
||
--- @field animationTable table<string, table>
|
||
--- @field state "idle"|"run"|"attack"|"hurt"
|
||
--- @field info Info
|
||
--- @field player table
|
||
--- @field position Vec3
|
||
--- @field latestPosition Vec3 позиция, где character был один тик назад
|
||
--- @field runTarget Vec3 точка, в которую в данный момент бежит персонаж
|
||
--- @field size Vec3
|
||
local character = {}
|
||
character.__index = character
|
||
|
||
--- Создаёт персонажа, которым будет управлять или игрок или компьютер
|
||
--- @param name string
|
||
--- @param template ClassTemplate
|
||
--- @param spriteDir table
|
||
--- @param level? integer
|
||
local function spawn(name, template, spriteDir, level)
|
||
local animationGrid = {}
|
||
-- n: name; i: image
|
||
for n, i in pairs(spriteDir) do
|
||
local aGrid = anim8.newGrid(96, 64, i:getWidth(), i:getHeight())
|
||
local tiles = '1-' .. math.ceil(i:getWidth() / 96)
|
||
animationGrid[n] = aGrid(tiles, 1)
|
||
end
|
||
|
||
local char = {
|
||
animationTable = {}
|
||
}
|
||
|
||
char.id = characterId
|
||
characterId = characterId + 1
|
||
|
||
char.position = Vec3({})
|
||
char.size = Vec3({ 1, 1 })
|
||
|
||
char.state = "idle"
|
||
|
||
char.animationTable.idle = anim8.newAnimation(animationGrid["idle"], ANIMATION_SPEED)
|
||
char.animationTable.run = anim8.newAnimation(animationGrid["run"], ANIMATION_SPEED)
|
||
char.animationTable.attack = anim8.newAnimation(animationGrid["attack"], ANIMATION_SPEED, function()
|
||
char.state = "idle"
|
||
end)
|
||
char.animationTable.hurt = anim8.newAnimation(animationGrid["hurt"], ANIMATION_SPEED, function()
|
||
char.state = "idle"
|
||
end)
|
||
|
||
char.info = (require "lib/character/info").new(name, template)
|
||
|
||
char = setmetatable(char, character)
|
||
Tree.level.characters[char.id] = char
|
||
Tree.level.positionGrid:add(char)
|
||
return char
|
||
end
|
||
|
||
--- @param target Vec3
|
||
function character:runTo(target)
|
||
self.state = "run"
|
||
self.runTarget = target
|
||
end
|
||
|
||
function character:update(dt)
|
||
if self.state == "run" and self.runTarget then
|
||
if self.position:floor() == self.runTarget:floor() then -- мы добежали до цели и сейчас в целевой клетке
|
||
self.state = "idle"
|
||
self.runTarget = nil
|
||
else -- мы не добежали до цели
|
||
local vel = (self.runTarget:subtract(self.position):normalize() --[[@as Vec3]]
|
||
):scale(2 * dt) -- бежим 2 условных метра в секунду
|
||
self.position = self.position:add(vel)
|
||
end
|
||
end
|
||
|
||
if self.position ~= self.latestPosition then
|
||
-- типа уведомление о том, что положение (на уровне клеток) изменилось
|
||
Tree.level.positionGrid:remove(self)
|
||
Tree.level.positionGrid:add(self)
|
||
end
|
||
|
||
if love.keyboard.isDown("r") then
|
||
self.state = "run"
|
||
end
|
||
if love.keyboard.isDown("i") then
|
||
self.state = "idle"
|
||
end
|
||
if love.keyboard.isDown("u") then
|
||
self.state = "attack"
|
||
end
|
||
if love.keyboard.isDown("h") then
|
||
self.state = "hurt"
|
||
end
|
||
self.animationTable[self.state]:update(dt)
|
||
end
|
||
|
||
function character:draw()
|
||
local ppm = Tree.level.camera.pixelsPerMeter
|
||
self.animationTable[self.state]:draw(Tree.assets.files.sprites.character[self.state], self.position.x,
|
||
self.position.y, nil, 1 / ppm, 1 / ppm, 38, 47)
|
||
end
|
||
|
||
return { spawn = spawn }
|