108 lines
2.5 KiB
Lua
108 lines
2.5 KiB
Lua
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 = {}
|
|
|
|
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
|
|
|
|
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)
|
|
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
|
|
-- print("duck " .. self.index .. " starting chase")
|
|
self.state = States.CHASE
|
|
self.target = feed
|
|
feed.occupied = true
|
|
end
|
|
|
|
return Duck |