quack2/data/scripts/classes/duck.lua

108 lines
2.5 KiB
Lua
Raw Permalink Normal View History

2025-02-15 11:58:27 +00:00
local Vector3 = require "types.vector3"
local Signal = require "types.signal"
local TEXTURE = "images/duckie.png"
local States = {
IDLE = 1,
WANDER = 2,
CHASE = 3,
}
local WANDER_TIME = 1.0
local IDLE_TIME = 1.0
local Duck = {}
2025-02-15 11:58:27 +00:00
Duck.__index = Duck
function Duck.new(position)
-- 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
2025-02-15 11:58:27 +00:00
return setmetatable(d, Duck)
end
function Duck:tick(ctx)
if self.state == States.IDLE then
self:idle(ctx.frame_duration)
elseif self.state == States.WANDER then
self:wander(ctx.frame_duration)
elseif self.state == States.CHASE then
self:chase(ctx.frame_duration)
end
draw_billboard{position = self.position, size = {x = 0.4, y = 0.4}, texture = TEXTURE}
end
function Duck:idle(delta)
self.wander_timer = self.wander_timer + delta
if self.wander_timer >= IDLE_TIME then
self.state = States.WANDER
self.wander_timer = 0
self.direction = Vector3(0, 0, -1):rotated(Vector3.UP, math.random() * (math.pi * 2.0))
return
end
end
function Duck:wander(delta)
self.wander_timer = self.wander_timer + delta
if self.wander_timer >= WANDER_TIME then
self.state = States.IDLE
self.wander_timer = 0
self.SeekFeed:emit(self)
2025-02-15 11:58:27 +00:00
return
end
local target_vel = self.direction * self.speed
self.velocity = self.velocity:lerp(target_vel, self.accel)
self.position = self.position + self.velocity
end
function Duck:chase(delta)
local hpos = self.position:horizontal()
local fhpos = self.target.position:horizontal()
local dist = hpos:distance_to(fhpos)
if dist <= 0.1 then
self.AteFeed:emit(self.target)
self.wander_timer = 0
self.state = States.IDLE
self.target = nil
else
local dir = self.position:horizontal():direction_to(self.target.position:horizontal())
local target_vel = dir * self.chase_speed
self.velocity = self.velocity:lerp(target_vel, self.accel)
self.position = self.position + self.velocity
end
end
function Duck:start_chase(feed)
if self.state == States.CHASE then return end
2025-02-15 15:03:43 +00:00
-- print("duck " .. self.index .. " starting chase")
2025-02-15 11:58:27 +00:00
self.state = States.CHASE
self.target = feed
feed.occupied = true
end
return Duck