2025-08-09 18:18:23 +03:00

112 lines
3.9 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 }