Commit ad003d7c authored by Delisa Mason's avatar Delisa Mason

Create DSL for generating animations

parent 58b8535b
load_resources {
map_add("level01", "game/assets/maps/level01/init.lua"),
sprite_add("player", "game/assets/images/player.png", 0, 0, 16, 16),
--image_add("name", "image.png"),
--anim_add("name", "image.png", w, h, num_frames, duration),
}
group {
map_draw("level01"),
sprite_draw("player", 300, 0, 10, 10),
map_follow("level01", "player"),
sprite_move("player", 210, 110, 8),
--sprite_rotate("player", 2.1, 10),
}
group {
map_draw("level01"),
sprite_draw("player", 210, 110, 10, 10),
sprite_scale("player", 1, 1, 8),
wait(2)
}
--[[group {
sprite_draw("name", x, y),
image_draw("name", x, y),
map_follow("sprite name"),
dialog(x, y, "hello there"),
wait(10),
anim_draw("name", x, y)
}]]
local sti = require 'lib.sti'
local anim8 = require 'lib.anim8'
local Camera = require 'lib.camera'
local SceneDSL = function()
local scene = {
done = false,
assets = {},
groups = {},
groupindex = 1,
}
local function apply_xy_transform(dt, context, transform, xprop, yprop, dxprop, dyprop)
transform.elapsed = transform.elapsed + dt
if transform.elapsed <= transform.duration then
context[xprop] = context[xprop] + (transform[dxprop] * dt/transform.duration)
context[yprop] = context[yprop] + (transform[dyprop] * dt/transform.duration)
end
end
-- Cache resources for later use
function scene.load_resources(items)
for _, asset in ipairs(items) do
scene.assets[asset.id] = asset
end
end
function scene.map_add(id, map_path)
local camera = Camera()
camera:setFollowStyle('TOPDOWN')
return {id=id, data={map=sti(map_path), camera=camera}}
end
function scene.map_follow(map_id, other_id)
local target = scene.assets[other_id]
return {asset_id=map_id, transform={
apply=function(self, asset, _, dt)
asset.data.camera:follow(target.x, target.y)
end
}}
end
function scene.map_draw(id)
return {
asset_id=id,
context={x=0, y=0},
draw=function(asset, ctx)
asset.data.map:draw(-ctx.x, -ctx.y, 1, 1)
end,
transform={
apply=function(self, asset, ctx, dt)
local windowWidth = love.graphics.getWidth()
local windowHeight = love.graphics.getHeight()
local mapMaxWidth = asset.data.map.width * asset.data.map.tilewidth
local mapMaxHeight = asset.data.map.height * asset.data.map.tileheight
ctx.x = math.min(math.max(0, asset.data.camera.x - windowWidth/2), mapMaxWidth - windowWidth)
ctx.y = math.min(math.max(0, asset.data.camera.y - windowHeight/2), mapMaxHeight - windowHeight)
asset.data.map:update(dt)
asset.data.camera:update(dt)
end
}
}
end
function scene.sprite_add(id, path, x, y, w, h)
local image = love.graphics.newImage(path)
local quad = love.graphics.newQuad(x, y, w, h, image:getWidth(), image:getHeight())
return {id=id, data={quad=quad, image=image}}
end
function scene.sprite_draw(id, x, y, sx, sy)
return {
asset_id=id,
context={x=x, y=y, sx=sx or 1, sy=sy or 1, radians=0},
draw=function(asset, ctx)
love.graphics.draw(asset.data.image, asset.data.quad, ctx.x,
ctx.y, ctx.radians, ctx.sx, ctx.sy)
end
}
end
function scene.sprite_move(id, target_x, target_y, duration)
return {
asset_id=id,
transform={
elapsed=0,
duration=duration,
init=function(self, ctx)
self.dx = target_x - ctx.x
self.dy = target_y - ctx.y
end,
apply=function(self, _, ctx, dt)
apply_xy_transform(dt, ctx, self, "x", "y", "dx", "dy")
end
}
}
end
function scene.sprite_scale(id, target_sx, target_sy, duration)
return {
asset_id=id,
transform={
elapsed=0,
duration=duration,
init=function(self, ctx)
self.dsx = target_sx - ctx.sx
self.dsy = target_sy - ctx.sy
end,
apply=function(self, _, ctx, dt)
apply_xy_transform(dt, ctx, self, "sx", "sy", "dsx", "dsy")
end
}
}
end
function scene.sprite_rotate(id, radians, duration)
return {
asset_id=id,
transform={
elapsed=0,
duration=duration,
init=function(self, ctx)
self.dradians = radians - ctx.radians
end,
apply=function(self, _, ctx, dt)
self.elapsed = self.elapsed + dt
if self.elapsed <= self.duration then
ctx.radians = ctx.radians + self.dradians * (dt/self.duration)
end
end,
}
}
end
function scene.image_add(id, path)
return {id=id, data={image=love.graphics.newImage(path)}}
end
function scene.image_draw(id, x, y)
return {
asset_id=id,
context={x=x, y=y},
draw=function(asset, ctx)
love.graphics.draw(asset.data.image, ctx.x, ctx.y)
end
}
end
function scene.anim_add(id, path, w, h, frame_count, frame_duration)
local image = love.graphics.newImage(path)
local g = anim8.newGrid(w, h, image:getWidth(), image:getHeight())
local animation = anim8.newAnimation(g('1-'..frame_count,1), frame_duration)
return {id=id, data={animation=animation, image=image}}
end
function scene.anim_draw(id, x, y)
return {
asset_id=id,
context={x=x, y=y},
draw=function(asset, ctx)
asset.data.animation:draw(asset.data.image, ctx.x, ctx.y)
end,
transform={
apply=function(self, asset, _, dt)
asset.data.animation:update(dt)
end
}
}
end
function scene.group(items)
local group = {loaded=false, duration=0, elapsed=0, directives={}, renderers={}}
for _, item in pairs(items) do
if item.asset_id ~= nil then
if group.directives[item.asset_id] == nil then
group.directives[item.asset_id] = {transforms={}, context={}}
end
if item.context ~= nil then
group.directives[item.asset_id].context = item.context
end
if item.transform ~= nil then
table.insert(group.directives[item.asset_id].transforms, item.transform)
if item.transform.duration ~= nil and item.transform.duration > group.duration then
group.duration = item.transform.duration
end
end
if item.draw ~= nil then
table.insert(group.renderers, {asset_id=item.asset_id, draw=item.draw})
end
end
if item.duration ~= nil then
if item.duration ~= nil and item.duration > group.duration then
group.duration = item.duration
end
end
if item.await_dialog == true then
group.await_dialog = true
end
end
table.insert(scene.groups, group)
end
function scene.wait(duration)
return {duration=duration}
end
function scene.dialog(x, y, text)
-- TODO: figure out what goes here
local directive = {await_dialog=true}
function directive:draw()
love.graphics.print(text, x, y)
end
return directive
end
-- Callbacks
function scene.dialogkeyreleased()
local group = scene.groups[scene.groupindex]
group.await_dialog = false
end
function scene.update(dt)
local group = scene.groups[scene.groupindex]
if not group.loaded then
for _, directive in pairs(group.directives) do
for _, transform in ipairs(directive.transforms) do
if transform.init ~= nil then
transform:init(directive.context)
end
end
end
group.loaded = true
end
for asset_id, directive in pairs(group.directives) do
local asset = scene.assets[asset_id]
for _, transform in ipairs(directive.transforms) do
transform:apply(asset, directive.context, dt)
end
end
group.elapsed = group.elapsed + dt
if group.elapsed >= group.duration and group.await_dialog ~= true then
if scene.groupindex == #scene.groups then
scene.done = true
else
scene.groupindex = scene.groupindex + 1
end
end
end
function scene.draw()
local group = scene.groups[scene.groupindex]
for _, renderer in ipairs(group.renderers) do
local asset = scene.assets[renderer.asset_id]
local context = group.directives[renderer.asset_id].context
renderer.draw(asset, context)
end
end
function scene.END()
return scene
end
return scene
end
local function readfile(path)
local file = io.open(path, "rb")
local content = file:read("*a")
file:close()
return content
end
return function(scene_file_path)
local content = readfile(scene_file_path)
content = content .. "\nreturn END()"
local scene = load(content, nil, nil, SceneDSL())
-- TODO: return sensible error state if loading fails
return scene()
end
local Gamestate = require 'lib.gamestate'
local RenderMapSystem = require 'game.systems.render_map'
local PlayerInputSystem = require 'game.systems.player_input'
local MovementSystem = require 'game.systems.movement'
local TriggerSystem = require 'game.systems.trigger'
local MapLoader = require 'game.map_loader'
local HooksLoader = require 'game.hooks_loader'
local SceneState = require 'game.states.scene'
local state = {}
function state:enter(_, level_index)
self.level_index = level_index
local map_path = string.format("game/assets/maps/level%02d/init.lua", level_index)
self.levelstate = MapLoader(map_path)
self.hooks_loader = HooksLoader(level_index, self.levelstate.map)
self.systems = require 'game.systems'
self.systems.add(PlayerInputSystem())
self.systems.add(RenderMapSystem())
self.systems.add(MovementSystem(self.levelstate.player, self.levelstate.map))
self.systems.add(TriggerSystem(self.hooks_loader))
Gamestate.push(SceneState, "game/assets/scenes/intro.scene")
end
function state:resume(prev)
if prev.__animation == true then
local map_path = string.format("game/assets/maps/level%02d/init.lua", self.level_index)
self.levelstate = MapLoader(map_path)
self.hooks_loader = HooksLoader(self.level_index, self.levelstate.map)
self.systems = require 'game.systems'
self.systems.add(PlayerInputSystem())
self.systems.add(RenderMapSystem())
self.systems.add(MovementSystem(self.levelstate.player, self.levelstate.map))
self.systems.add(TriggerSystem(self.hooks_loader))
end
end
function state:draw()
......
local Gamestate = require 'lib.gamestate'
local SceneLoader = require 'game.scene_loader'
local state = {__animation = true}
function state:enter(_, scene_file_path)
self.scene = SceneLoader(scene_file_path)
end
function state:draw()
self.scene.draw()
end
function state:update(dt)
self.scene.update(dt)
if self.scene.done == true then
Gamestate.pop()
end
end
function state:keydown(key, code)
end
function state:keyreleased(key, code)
end
return state
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment