summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-04-29 19:26:18 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2026-04-29 19:26:18 -0700
commit48491750e4ece19d2252592850b75d100afc2455 (patch)
tree54a1edb6f390053c0ecee47da7e6121a9a387839
parent42aeb43e2c8a959f5ea1f9a33cfe63d667321c56 (diff)
downloaddyl8-48491750e4ece19d2252592850b75d100afc2455.tar.gz
dyl8-48491750e4ece19d2252592850b75d100afc2455.zip
The refactor from HELL
-rw-r--r--dyl.lua349
-rw-r--r--entity.lua170
-rw-r--r--math.lua2
-rw-r--r--ui.lua0
-rw-r--r--util.lua20
-rw-r--r--world.lua21
6 files changed, 315 insertions, 247 deletions
diff --git a/dyl.lua b/dyl.lua
index bd024ef..1517438 100644
--- a/dyl.lua
+++ b/dyl.lua
@@ -1,18 +1,13 @@
-_slashing_timer_sec = 0.12
-function spawn_slashing_particle(e)
- slash_animation = entity()
- _slash_animation_distance = 3
- function slash_animation:transition_state()
- -- TODO: Find a better place to put this lol. This has nothing to do with state
- -- transitions
- slash_animation:equipped_from(e, _slash_animation_distance)
- end
- return slash_animation:b_type(Entities.Particle)
- :b_line_of_sight(e.line_of_sight)
- :b_position(vec2(e.position))
- :b_sprite_position(vec2(position))
+_slashing_timer_sec = .12
+_slash_animation_distance = 3
+function slashing_particle(following)
+ SlashingParticleBuilder = EntityBuilder:new(World)
+ :b_type(Entities.Particle)
:b_render_order(-1)
:b_live_for(_slashing_timer_sec)
+ :b_position(vec2(following.position))
+ :b_sprite_position(vec2(following.sprite_position))
+ :b_line_of_sight(vec2(following.line_of_sight))
:b_add_state(
States.Active, {
animation = {
@@ -24,161 +19,200 @@ function spawn_slashing_particle(e)
}
)
:b_state(States.Active)
- :build()
-end
+ function SlashingParticleBuilder:transition_state()
+ end
-enemy = entity()
-function enemy:transition_state()
+ return SlashingParticleBuilder:build()
end
-enemy:b_type(Entities.Enemy)
- :b_health(100)
- :b_position(vec2(30, 40))
- :b_sprite_position(vec2(30, 30))
- :b_line_of_sight(vec2(1, 0))
- :b_render_order(1)
- :b_collidable()
- :b_add_state(
- States.Idle, {
- animation = {
- pos_y = { sequence = { 32, 33 }, dt = 1 },
- neg_y = { sequence = { 32, 33 }, dt = 1 },
- pos_x = { sequence = { 32, 33 }, dt = 1 },
- neg_x = { sequence = { 32, 33 }, dt = 1, reflect = vec2(true, false) }
+
+function enemy()
+ EnemyBuilder = EntityBuilder:new(World)
+ function EnemyBuilder:transition_state()
+ end
+ EnemyBuilder:b_type(Entities.Enemy)
+ :b_health(100)
+ :b_position(vec2(30, 40))
+ :b_sprite_position(vec2(30, 40))
+ :b_line_of_sight(vec2(1, 0))
+ :b_render_order(1)
+ :b_collidable()
+ :b_add_state(
+ States.Idle, {
+ animation = {
+ pos_y = { sequence = { 32, 33 }, dt = 1 },
+ neg_y = { sequence = { 32, 33 }, dt = 1 },
+ pos_x = { sequence = { 32, 33 }, dt = 1 },
+ neg_x = { sequence = { 32, 33 }, dt = 1, reflect = vec2(true, false) }
+ }
}
- }
- )
- :b_add_state(
- States.Walk, {
- animation = {
- pos_x = { sequence = { 32, 34 }, dt = 0.20 },
- neg_x = { sequence = { 32, 34 }, dt = 0.20, reflect = vec2(true, false) },
- pos_y = { sequence = { 32, 34 }, dt = 0.20 },
- neg_y = { sequence = { 32, 34 }, dt = 0.20 }
+ )
+ :b_add_state(
+ States.Walk, {
+ animation = {
+ pos_x = { sequence = { 32, 34 }, dt = 0.20 },
+ neg_x = { sequence = { 32, 34 }, dt = 0.20, reflect = vec2(true, false) },
+ pos_y = { sequence = { 32, 34 }, dt = 0.20 },
+ neg_y = { sequence = { 32, 34 }, dt = 0.20 }
+ }
}
- }
- )
- :b_state(States.Walk)
- :b_equipped({ sword })
- :build()
-
+ )
+ :b_state(States.Walk)
+ return EnemyBuilder:build()
+end
-bow = entity()
-function bow:transition_state()
+function wife()
+ WifeBuilder = EntityBuilder:new(World)
+ function WifeBuilder:transition_state()
+ end
+ WifeBuilder:b_type(Entities.Wife)
+ :b_line_of_sight(vec2(1, 0))
+ :b_render_order(2)
+ :b_collidable()
+ :b_position(vec2(50, 50))
+ :b_sprite_position(vec2(30, 30))
+ :b_add_state(
+ States.Idle, {
+ animation = {
+ pos_y = { sequence = { 16, 17 }, dt = 1 },
+ neg_y = { sequence = { 16, 17 }, dt = 1 },
+ pos_x = { sequence = { 16, 17 }, dt = 1 },
+ neg_x = { sequence = { 16, 17 }, dt = 1, reflect = vec2(true, false) }
+ }
+ }
+ )
+ :b_state(States.Idle)
+ return WifeBuilder:build()
end
-bow:b_type(Entities.Bow)
- :b_position(vec2(0, 0))
- :b_sprite_position(vec2(0, 0))
- :b_line_of_sight(vec2(1, 0))
- :b_render_order(1)
- :b_collidable()
- :b_add_state(
- States.Equipped, {
- animation = {
- pos_y = { sequence = { 96 }, dt = 1, reflect = vec2(false, true) },
- neg_y = { sequence = { 96 }, dt = 1 },
- pos_x = { sequence = { 80 }, dt = 1 },
- neg_x = { sequence = { 80 }, dt = 1, reflect = vec2(true, false) }
+
+function bow()
+ BowBuilder = EntityBuilder:new(World)
+ function BowBuilder:transition_state()
+ end
+ BowBuilder:b_type(Entities.Bow)
+ :b_position(vec2(0, 0))
+ :b_sprite_position(vec2(0, 0))
+ :b_line_of_sight(vec2(1, 0))
+ :b_render_order(1)
+ :b_collidable()
+ :b_add_state(
+ States.Equipped, {
+ animation = {
+ pos_y = { sequence = { 96 }, dt = 1, reflect = vec2(false, true) },
+ neg_y = { sequence = { 96 }, dt = 1 },
+ pos_x = { sequence = { 80 }, dt = 1 },
+ neg_x = { sequence = { 80 }, dt = 1, reflect = vec2(true, false) }
+ }
+ }
+ )
+ :b_add_state(
+ States.Drawn, {
+ animation = {
+ pos_y = { sequence = { 81 }, dt = 1, reflect = vec2(false, true) },
+ neg_y = { sequence = { 81 }, dt = 1 },
+ pos_x = { sequence = { 81 }, dt = 1 },
+ neg_x = { sequence = { 81 }, dt = 1, reflect = vec2(true, false) }
+ }
}
- }
- )
- :b_add_state(
- States.Drawn, {
- animation = {
- pos_y = { sequence = { 81 }, dt = 1, reflect = vec2(false, true) },
- neg_y = { sequence = { 81 }, dt = 1 },
- pos_x = { sequence = { 81 }, dt = 1 },
- neg_x = { sequence = { 81 }, dt = 1, reflect = vec2(true, false) }
+ )
+ :b_add_state(
+ States.Drawing, {
+ animation = BowBuilder.states[States.Equipped]
}
- }
- )
- :b_add_state(
- States.Drawing, {
- animation = bow.states[States.Equipped]
- }
- )
- :b_state(States.Equipped)
- :build()
+ )
+ :b_state(States.Equipped)
+ return BowBuilder:build()
+end
-sword = entity()
-_attack_burst_sec = 0.200
-_sword_damage = { amount = 2, knockback = { magnitude = 200, time = 0.080 } }
-function sword:transition_state()
- if button_just_pressed(5) and self.state == States.Equipped and self.state_stopwatch > _attack_burst_sec then
- self:transition_to(States.Slashing)
- spawn_slashing_particle(self)
- self.damage = _sword_damage
- elseif self.state == States.Slashing and self.state_stopwatch > _slashing_timer_sec then
- self.damage = nil
- self:transition_to(States.Equipped)
+function sword()
+ _attack_burst_sec = 0.200
+ _sword_damage = { amount = 2, knockback = { magnitude = 200, time = 0.080 } }
+ SwordBuilder = EntityBuilder:new(World)
+ function SwordBuilder:transition_state()
+ if button_just_pressed(5) and self.state == States.Equipped and self.state_stopwatch > _attack_burst_sec then
+ self:transition_to(States.Slashing)
+ self:equip(slashing_particle(self))
+ self.damage = _sword_damage
+ elseif self.state == States.Slashing and self.state_stopwatch > _slashing_timer_sec then
+ self.damage = nil
+ self:transition_to(States.Equipped)
+ end
end
-end
-sword:b_type(Entities.Sword)
- :b_line_of_sight(vec2(1, 0))
- :b_position(vec2(0, 0))
- :b_sprite_position(vec2(0, 0))
- :b_render_order(0)
- :b_collidable()
- :b_add_state(
- States.Equipped, {
- animation = {
- pos_y = { sequence = { 99 }, dt = 1, reflect = vec2(false, true) },
- neg_y = { sequence = { 99 }, dt = 1, reflect = vec2(true, false) },
- pos_x = { sequence = { 98 }, dt = 1 },
- neg_x = { sequence = { 98 }, dt = 1, reflect = vec2(true, false) }
+ SwordBuilder:b_type(Entities.Sword)
+ :b_line_of_sight(vec2(1, 0))
+ :b_position(vec2(0, 0))
+ :b_sprite_position(vec2(0, 0))
+ :b_render_order(0)
+ :b_collidable()
+ :b_add_state(
+ States.Equipped, {
+ animation = {
+ pos_y = { sequence = { 99 }, dt = 1, reflect = vec2(false, true) },
+ neg_y = { sequence = { 99 }, dt = 1, reflect = vec2(true, false) },
+ pos_x = { sequence = { 98 }, dt = 1 },
+ neg_x = { sequence = { 98 }, dt = 1, reflect = vec2(true, false) }
+ }
}
- }
- )
- :b_add_state(
- States.Slashing, {
- animation = {
- pos_y = { sequence = { 82, 98 }, dt = _slashing_timer_sec / 2, reflect = vec2(false, true) },
- neg_y = { sequence = { 82, 98 }, dt = _slashing_timer_sec / 2, reflect = vec2(true, false) },
- pos_x = { sequence = { 82, 99 }, dt = _slashing_timer_sec / 2, reflect = vec2(false, false)},
- neg_x = { sequence = { 82, 99 }, dt = _slashing_timer_sec / 2, reflect = vec2(true, false) }
+ )
+ :b_add_state(
+ States.Slashing, {
+ animation = {
+ pos_y = { sequence = { 82, 98 }, dt = _slashing_timer_sec / 2, reflect = vec2(false, true) },
+ neg_y = { sequence = { 82, 98 }, dt = _slashing_timer_sec / 2, reflect = vec2(true, false) },
+ pos_x = { sequence = { 82, 99 }, dt = _slashing_timer_sec / 2, reflect = vec2(false, false)},
+ neg_x = { sequence = { 82, 99 }, dt = _slashing_timer_sec / 2, reflect = vec2(true, false) }
+ }
}
- }
- )
- :b_state(States.Equipped)
- :build()
+ )
+ :b_state(States.Equipped)
+ return SwordBuilder:build()
+end
+
+_enemy = enemy()
+_sword = sword()
+_wife = wife()
+_bow = bow()
-player = entity()
-function player:transition_state()
- if (self.velocity.x == 0 and self.velocity.y == 0) then
- self:transition_to(States.Idle)
- else
- self:transition_to(States.Walk)
+function player()
+ PlayerBuilder = EntityBuilder:new(World)
+ function PlayerBuilder:transition_state()
+ if (self.velocity.x == 0 and self.velocity.y == 0) then
+ self:transition_to(States.Idle)
+ else
+ self:transition_to(States.Walk)
+ end
end
-end
-player
- :b_type(Entities.Player)
- :b_line_of_sight(vec2(1, 0))
- :b_render_order(2)
- :b_collidable()
- :b_position(vec2(30, 30))
- :b_sprite_position(vec2(30, 30))
- :b_add_state(
- States.Idle, {
- animation = {
- pos_y = { sequence = { 3, 19 }, dt = 1 },
- neg_y = { sequence = { 6, 22 }, dt = 1 },
- pos_x = { sequence = { 0, 1 }, dt = 1 },
- neg_x = { sequence = { 0, 1 }, dt = 1, reflect = vec2(true, false) }
+ PlayerBuilder
+ :b_type(Entities.Player)
+ :b_line_of_sight(vec2(1, 0))
+ :b_render_order(2)
+ :b_collidable()
+ :b_position(vec2(30, 30))
+ :b_sprite_position(vec2(30, 30))
+ :b_add_state(
+ States.Idle, {
+ animation = {
+ pos_y = { sequence = { 3, 19 }, dt = 1 },
+ neg_y = { sequence = { 6, 22 }, dt = 1 },
+ pos_x = { sequence = { 0, 1 }, dt = 1 },
+ neg_x = { sequence = { 0, 1 }, dt = 1, reflect = vec2(true, false) }
+ }
}
- }
- )
- :b_add_state(
- States.Walk, {
- animation = {
- pos_x = { sequence = { 2, 0 }, dt = 0.20 },
- neg_x = { sequence = { 2, 0 }, dt = 0.20, reflect = vec2(true, false) },
- pos_y = { sequence = { 4, 5 }, dt = 0.20 },
- neg_y = { sequence = { 7, 8 }, dt = 0.20 }
+ )
+ :b_add_state(
+ States.Walk, {
+ animation = {
+ pos_x = { sequence = { 2, 0 }, dt = 0.20 },
+ neg_x = { sequence = { 2, 0 }, dt = 0.20, reflect = vec2(true, false) },
+ pos_y = { sequence = { 4, 5 }, dt = 0.20 },
+ neg_y = { sequence = { 7, 8 }, dt = 0.20 }
+ }
}
- }
- )
- :b_state(States.Idle)
- :b_equipped({ sword })
- :build()
+ )
+ :b_state(States.Idle)
+ return PlayerBuilder:build()
+end
+_player = player()
+_player:equip(_sword)
_walk_speed = 35 -- powerup increase?
function handle_input()
@@ -188,7 +222,7 @@ function handle_input()
if btn(3) then dpos.y += 1 end
if btn(2) then dpos.y -= 1 end
- player.velocity = dpos:normal() * _walk_speed
+ _player.velocity = dpos:normal() * _walk_speed
end
function _init()
@@ -206,8 +240,7 @@ function _update()
foreach(update_hooks, function(f) f(step_dt) end)
handle_input()
- World.foreach(function(e) if (not e.equipped) then e:update(step_dt) end end)
- World.foreach(function(e) if (e.equipped) then e:update(step_dt) end end)
+ World.foreach(function(e) e:update(step_dt) end)
run_collisions()
@@ -215,8 +248,8 @@ function _update()
end
function _draw()
- qsort(World, function(a, b) return b.render_order < a.render_order end)
- World.foreach(function(e)
- e:render()
+ World.sort(function(a, b)
+ return b.render_order < a.render_order
end)
+ World.foreach(function(e) e:render() end)
end \ No newline at end of file
diff --git a/entity.lua b/entity.lua
index 5cb52d8..449200e 100644
--- a/entity.lua
+++ b/entity.lua
@@ -3,7 +3,8 @@ Entities = {
Sword = 1,
Enemy = 2,
Bow = 3,
- Particle = 4
+ Particle = 4,
+ Wife = 5
}
States = {
Walk = "walk",
@@ -17,65 +18,6 @@ States = {
Entity = {}
Entity.__index = Entity
-function Entity:b_add_state(name, state)
- if self.states == nil then self.states = {} end
- self.states[name] = state
- if self.state == nil then self.state = name end
- return self
-end
-function Entity:b_state(name)
- assert(self.states[name] != nil)
- self.state = name
- self.state_stopwatch = 0
- return self
-end
-function Entity:b_health(health)
- self.health = health
- return self
-end
-function Entity:b_damage(damage_spec)
- self.damage = damage_spec
- return self
-end
-function Entity:b_render_order(ord)
- self.render_order = ord
- return self
-end
-function Entity:b_position(vec)
- self.position = vec2(vec)
- return self
-end
-function Entity:b_sprite_position(vec)
- self.sprite_position = vec2(vec)
- return self
-end
-function Entity:b_type(entity_type)
- self.entity_type = entity_type
- return self
-end
-function Entity:b_equipped(equipped)
- self.equipped = equipped
- return self
-end
-function Entity:b_collidable()
- self.collision = true
- return self
-end
-function Entity:b_live_for(t)
- self.life_time = t
- return self
-end
-function Entity:b_line_of_sight(vec)
- self.line_of_sight = vec2(vec)
- return self
-end
-function Entity:build()
- assert(self.transition_state)
-
- assert(self.position)
- assert(self.state)
- assert(self.state_stopwatch)
-end
function Entity:is_in_iframe()
return self.knockback ~= nil and self.knockback.time >= 0
@@ -102,7 +44,9 @@ function Entity:update(dt)
self:update_sprite_position()
if (self.equipped != nil) then
parent = self
- foreach(self.equipped, function (e) e:equipped_from(parent) end)
+ for id, entity in pairs(self.equipped) do
+ entity:equipped_from(parent)
+ end
end
assert(self.transition_state)
@@ -118,8 +62,11 @@ end
function Entity:update_line_of_sight()
nv = self.velocity:apply(normalize_scalar)
- if nv.y != 0 then self.line_of_sight = vec2(0, nv.y)
- elseif nv.x != 0 then self.line_of_sight = vec2(nv.x, 0) end
+ if nv.y != 0 then
+ self.line_of_sight = vec2(0, nv.y)
+ elseif nv.x != 0 then
+ self.line_of_sight = vec2(nv.x, 0)
+ end
end
-- prevent cobblestoning during non-manhattan movement by "lagging" the sprite
@@ -195,11 +142,15 @@ function Entity:integrate(dt)
end
end
- if self.velocity ~= nil then
+ if self.velocity ~= nil and self.position ~= nil then
self.position = self.position + (self.velocity * dt)
end
end
+function Entity:equip(that)
+ self.equipped[that.id] = that
+end
+
_equipped_item_distance = 6
function Entity:equipped_from(parent, dist)
dist = dist or _equipped_item_distance
@@ -212,7 +163,7 @@ function Entity:equipped_from(parent, dist)
end
-- -1 0 1
-_animation_keys = {"neg", "pos", "pos"}
+_animation_keys = { "neg", "pos", "pos" }
function _get_animation_key(line_of_sight)
n_line_of_sight = line_of_sight:apply(normalize_scalar)
if n_line_of_sight.y ~= 0 then
@@ -226,12 +177,14 @@ function Entity:render()
animation = self.states[self.state].animation
if (animation == nil) then return end
- key = _get_animation_key(self.line_of_sight)
- animation = animation[key] or animation
+ if (self.line_of_sight ~= nil) then
+ key = _get_animation_key(self.line_of_sight)
+ animation = animation[key] or animation
+ end
assert(animation)
frames_passed = flr(self.state_stopwatch / animation.dt)
- frame = animation.sequence[1 + (frames_passed % (#animation.sequence))]
+ frame = animation.sequence[1 + (frames_passed % #animation.sequence)]
assert(frame)
reflection = animation.reflect or vec2(false, false)
@@ -243,20 +196,73 @@ function Entity:render()
)
end
-_id = 1
-function _next_id()
- i = _id
- _id += 1
- return i
-end
-function entity()
- id = _next_id()
- World.add(setmetatable(
+EntityBuilder = {}
+EntityBuilder.__index = EntityBuilder
+function EntityBuilder:new(world)
+ return setmetatable(
{
- id = id,
- velocity = vec2(0,0),
+ build_context = {
+ world = world
+ },
+ velocity = vec2(0, 0),
collision = false
- }, Entity
- ))
- return World.get(id)
+ }, EntityBuilder
+ )
+end
+function EntityBuilder:b_add_state(name, state)
+ if self.states == nil then self.states = {} end
+ self.states[name] = state
+ if self.state == nil then self.state = name end
+ return self
+end
+function EntityBuilder:b_state(name)
+ assert(self.states[name] != nil)
+ self.state = name
+ self.state_stopwatch = 0
+ return self
+end
+function EntityBuilder:b_health(health)
+ self.health = health
+ return self
+end
+function EntityBuilder:b_damage(damage_spec)
+ self.damage = damage_spec
+ return self
+end
+function EntityBuilder:b_render_order(ord)
+ self.render_order = ord
+ return self
end
+function EntityBuilder:b_position(vec)
+ self.position = vec2(vec)
+ return self
+end
+function EntityBuilder:b_sprite_position(vec)
+ self.sprite_position = vec2(vec)
+ return self
+end
+function EntityBuilder:b_type(entity_type)
+ self.entity_type = entity_type
+ return self
+end
+function EntityBuilder:b_equipped(equipped)
+ self.equipped = equipped
+ return self
+end
+function EntityBuilder:b_collidable()
+ self.collision = true
+ return self
+end
+function EntityBuilder:b_live_for(t)
+ self.life_time = t
+ return self
+end
+function EntityBuilder:b_line_of_sight(vec)
+ self.line_of_sight = vec2(vec)
+ return self
+end
+function EntityBuilder:build()
+ self.equipped = {}
+
+ return self.build_context.world.add(setmetatable(self, Entity))
+end \ No newline at end of file
diff --git a/math.lua b/math.lua
index b543fa0..4a13517 100644
--- a/math.lua
+++ b/math.lua
@@ -4,7 +4,7 @@ Vec2.__add = function(a, b) return vec2(a.x + b.x, a.y + b.y) end
Vec2.__unm = function(a) return vec2(-a.x, -a.y) end
Vec2.__sub = function(a, b) return a + (-b) end
Vec2.__mul = function(a, b)
- if (type(b) == "number") then return vec2(a.x * b, a.y * b) end
+ if (type(b) == "number") then return vec2(a.x * b, a.y * b) end -- scalar mult
return a.x * b.x + a.y * b.y
end
Vec2.__div = function(a, b) return vec2(a.x / b.x, a.y / b.y) end
diff --git a/ui.lua b/ui.lua
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui.lua
diff --git a/util.lua b/util.lua
index 2b84d85..5d31a2a 100644
--- a/util.lua
+++ b/util.lua
@@ -53,12 +53,30 @@ function filter(a, pred)
return filtered
end
-function fmt(x)
+function fmt(x, depth)
+ depth = depth or 1
+ if (depth > 4) then return "STACK_OVERFLOW" end
+
+ if x == nil then
+ return "nil"
+ end
+
t = type(x)
if t == "number" then
return "" .. x
elseif t == "string" then
return x
+ elseif t == "table" then
+ s = "{"
+ i = 0
+ for k, v in pairs(x) do
+ if i ~= 0 then s = s .. ", " end
+ i += 1
+ s = s .. fmt(k, depth + 1) .. "=" .. fmt(v, depth + 1)
+ end
+ return s .. "}"
+ elseif t == "function" then
+ return "F()"
elseif t == "boolean" and x then
return "true"
elseif t == "boolean" and not x then
diff --git a/world.lua b/world.lua
index cb322df..122d60a 100644
--- a/world.lua
+++ b/world.lua
@@ -1,9 +1,24 @@
_World = {}
World = {}
+_id = 1
+function _next_id()
+ i = _id
+ _id += 1
+ return i
+end
+
+function World.sort(cmp)
+ -- qsort(_World, cmp)
+end
+
+function World.get(id)
+ return _World[id]
+end
function World.add(entity)
+ entity.id = _next_id()
_World[entity.id] = entity
- return World
+ return World.get(entity.id)
end
function World.foreach(f)
@@ -23,8 +38,4 @@ function World.cull_the_dead()
_World[id] = nil
end
return _World
-end
-
-function World.get(id)
- return _World[id]
end \ No newline at end of file