From 954277688f73e562b53fb3ff0de00812153ddfe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sat, 15 Feb 2025 17:25:27 +0300 Subject: [PATCH] don't rely on shallow copy to construct new classes. also multiple ducks --- data/scripts/classes/duck.lua | 48 +++++++++++++++++++---------------- data/scripts/classes/feed.lua | 24 ++++++++---------- data/scripts/game.lua | 33 +++++++++++++++++++----- data/scripts/types/list.lua | 39 +++++++++++++++++++++++++--- data/scripts/types/signal.lua | 25 +++++++++--------- 5 files changed, 110 insertions(+), 59 deletions(-) diff --git a/data/scripts/classes/duck.lua b/data/scripts/classes/duck.lua index 0b2cce9..7212d18 100644 --- a/data/scripts/classes/duck.lua +++ b/data/scripts/classes/duck.lua @@ -12,32 +12,34 @@ local States = { local WANDER_TIME = 1.0 local IDLE_TIME = 1.0 -local Duck = { - position = {}, - velocity = {}, - direction = {}, - - target = nil, - state = States.IDLE, - - wander_timer = 0, - - speed = 0.02, - chase_speed = 0.04, - accel = 0.5, - - STATES = States, - - AteFeed = Signal.new() -} +local Duck = {} Duck.__index = Duck function Duck.new(position) - local d = util.shallow_copy(Duck) - d.position = position - d.velocity = Vector3() - d.direction = Vector3(0, 0, -1):rotated(Vector3.UP, util.random_float(-math.pi, math.pi)) + -- local d = util.shallow_copy(Duck) + local d = { + position = position:copy(), + velocity = Vector3(), + direction = Vector3(0, 0, -1):rotated(Vector3.UP, util.random_float(-math.pi, math.pi)), + + target = nil, + state = States.IDLE, + + wander_timer = 0, + + speed = 0.02, + chase_speed = 0.04, + accel = 0.5, + + STATES = States, + + AteFeed = Signal.new(), + SeekFeed = Signal.new(), + + index = 1, + } + d.position.y = 0.4 return setmetatable(d, Duck) end @@ -68,6 +70,7 @@ function Duck:wander(delta) if self.wander_timer >= WANDER_TIME then self.state = States.IDLE self.wander_timer = 0 + self.SeekFeed:emit(self) return end @@ -96,6 +99,7 @@ end function Duck:start_chase(feed) if self.state == States.CHASE then return end + print("duck " .. self.index .. " starting chase") self.state = States.CHASE self.target = feed feed.occupied = true diff --git a/data/scripts/classes/feed.lua b/data/scripts/classes/feed.lua index 0a13428..c96250f 100644 --- a/data/scripts/classes/feed.lua +++ b/data/scripts/classes/feed.lua @@ -2,22 +2,20 @@ local Vector3 = require "types.vector3" local TEXTURE = "images/tongue.png" -local Feed = { - position = {}, - direction = {}, - velocity = {}, - landed = false, - occupied = false, - - speed = 0.15, -} +local Feed = {} Feed.__index = Feed -function Feed.new(p_position, p_direction) - local f = util.shallow_copy(Feed) - f.position = p_position:copy() - f.direction = p_direction:copy() +function Feed.new(position, direction) + local f = { + position = position:copy(), + direction = direction:copy(), + velocity = Vector3(), + landed = false, + occupied = false, + + speed = 0.15, + } f.velocity = f.direction * f.speed f.velocity.y = 0.1 diff --git a/data/scripts/game.lua b/data/scripts/game.lua index 2b38371..566b7f4 100644 --- a/data/scripts/game.lua +++ b/data/scripts/game.lua @@ -7,23 +7,33 @@ local Feed = require "classes.feed" local feed = List() local Duck = require "classes.duck" -local ducks = List{Duck.new(Vector3(0, 0.4, 3))} +local ducks = List() local function create_feed(position, direction) + print("?") local f = Feed.new(position, direction) feed:push(f) local eligible_ducks = ducks:filter( function (duck) - return duck.state ~= Duck.STATES.CHASE + return duck.state ~= duck.STATES.CHASE end ) - if #eligible_ducks == 0 then return end + if eligible_ducks:is_empty() then return end eligible_ducks[1]:start_chase(f) - f.occupied = true end local function delete_feed(f) - util.list_remove_value(feed, f) + feed:remove_value(f) +end + +local function duck_seek_feed(duck) + local eligible_feeds = feed:filter( + function (f) + return feed.occupied == false + end + ) + if eligible_feeds:is_empty() then return end + duck:start_chase(eligible_feeds[1]) end -- called every frame, with constant delta time @@ -35,9 +45,18 @@ function game_tick() capture = false, } player.ThrowPressed:connect(create_feed) - for _, v in ipairs(ducks) do - v.AteFeed:connect(delete_feed) + + -- spawn some ducks + for i = 1, 5 do + local duck = Duck.new(Vector3(0, 0, -math.random() * 10.0):rotated(Vector3.UP, util.random_float(-math.pi, math.pi))) + ducks:push(duck) + duck.AteFeed:connect(delete_feed) + duck.SeekFeed:connect(duck_seek_feed) + duck.index = i end + print(ducks[1].AteFeed._connections) + print(ducks[2].AteFeed._connections) + end ctx.mouse_capture = ctx.udata.capture diff --git a/data/scripts/types/list.lua b/data/scripts/types/list.lua index 219bb69..e58c97a 100644 --- a/data/scripts/types/list.lua +++ b/data/scripts/types/list.lua @@ -55,10 +55,11 @@ function List:__tostring() return s end ----Appends v to the end of the list. ----@param v any -function List:push(v) - table.insert(self, v) +---Appends value to the end of the list. +---@param value any +function List:push(value) + if self:has(value) then return end + table.insert(self, value) end ---Removes the last element in the list and returns it. @@ -82,6 +83,13 @@ function List:filter(predicate) return filter(self, predicate) end +---Removes the value at the given index. +---@param idx integer +---@return any +function List:remove_at(idx) + return table.remove(self, idx) +end + ---Returns the index of value, if it exists in the list, -1 otherwise. ---@param value any ---@return integer @@ -95,4 +103,27 @@ function List:find(value) end return idx end + +---Returns true if the value exists in the list. +---@param value any +---@return boolean +function List:has(value) + return self:find(value) ~= -1 +end + +---Removes the value from the list, if it exists. +---@param value any +function List:remove_value(value) + local idx = self:find(value) + if idx ~= -1 then + table.remove(self, idx) + end +end + +---Returns true if the list is empty. +---@return boolean +function List:is_empty() + return #self == 0 +end + return List \ No newline at end of file diff --git a/data/scripts/types/signal.lua b/data/scripts/types/signal.lua index ab2f077..379e869 100644 --- a/data/scripts/types/signal.lua +++ b/data/scripts/types/signal.lua @@ -1,10 +1,19 @@ ---@class Signal -local Signal = { - _connections = {} -} +---@field private _connections table +local Signal = {} Signal.__index = Signal +---Constructs a new signal. +---@return Signal +function Signal.new() + local s = { + _connections = {}, + } + + return setmetatable(s, Signal) +end + ---Connects f to this signal. When the signal is emmitted, this function will be called. ---@param f function function Signal:connect(f) @@ -26,14 +35,4 @@ function Signal:emit(...) end end ----Constructs a new signal. ----@return Signal -function Signal.new() - local s = { - _connections = {}, - } - - return setmetatable(s, Signal) -end - return Signal \ No newline at end of file