diff options
| -rw-r--r-- | dyl.lua | 349 | ||||
| -rw-r--r-- | entity.lua | 170 | ||||
| -rw-r--r-- | math.lua | 2 | ||||
| -rw-r--r-- | ui.lua | 0 | ||||
| -rw-r--r-- | util.lua | 20 | ||||
| -rw-r--r-- | world.lua | 21 |
6 files changed, 315 insertions, 247 deletions
@@ -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 @@ -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 @@ -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 @@ -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 @@ -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 |
