Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

188 lines (159 sloc) 6.144 kb
require 'vector.lua'
Boid = {
identity = "Boid class",
radius = 15
}
Boid.MAX_SPEED = 175
Boid.MIN_SPEED = 100
Boid.ATTRACTION_RADIUS = Boid.radius * 8
Boid.ATTRACTION_DAMPER = 10
Boid.AVOID_RADIUS = Boid.radius * 3
Boid.AVOID_AMPLIFIER = 6
Boid.ALIGNMENT_RADIUS = Boid.radius * 3
Boid.ALIGNMENT_DAMPER = 8
Boid.HUNTING_RADIUS = Boid.radius * 10
Boid.HUNTING_DAMPER = 5
Boid.STAY_VISIBLE_DAMPER = 40
function Boid:new(x, y, vx, vy)
local instance = {}
setmetatable(instance, self)
self.__index = self
instance.velocity = Vector:new(vx, vy)
instance.position = Vector:new(x, y)
instance.velocity_delta = Vector:new(0, 0)
instance.left_sprite = love.graphics.newImage("images/left_chicken.png")
instance.right_sprite = love.graphics.newImage("images/right_chicken.png")
instance.left_anim = love.graphics.newAnimation(instance.left_sprite, 18, 18,
instance:flap_rate())
instance.right_anim = love.graphics.newAnimation(instance.right_sprite, 18, 18,
instance:flap_rate())
instance.anim = left_anim
return instance
end
function Boid:flap_rate()
return 0.1--self.velocity:r() / Boid.MAX_SPEED / 4
end
function Boid:calculate_avoidance_delta(boids)
for _, other in ipairs(boids) do
if self.position:isNearby(Boid.AVOID_RADIUS, other.position) then
local avoid_vector = (self.position - other.position)
local unit_avoid_accel = avoid_vector:norm()
local avoid_multiplier = Boid.AVOID_RADIUS * Boid.AVOID_AMPLIFIER / avoid_vector:r()
local avoid_accel = unit_avoid_accel * avoid_multiplier
self.velocity_delta = self.velocity_delta + avoid_accel
end
end
end
function Boid:calculate_attraction_delta(boids)
local average_position = Vector:new(0, 0)
local visible_boids = 0
for _, other in ipairs(boids) do
if self.position:isNearby(Boid.ATTRACTION_RADIUS, other.position) then
average_position = average_position + other.position
visible_boids = visible_boids + 1
end
end
average_position = average_position / visible_boids
self.velocity_delta = self.velocity_delta +
((average_position - self.position) / Boid.ATTRACTION_DAMPER)
end
function Boid:calculate_alignment_delta(boids)
local alignment_delta = Vector:new(0, 0)
local visible_boids = 0
for _, other in ipairs(boids) do
if self.position:isNearby(Boid.ALIGNMENT_RADIUS, other.position) then
alignment_delta = alignment_delta + other.velocity
visible_boids = visible_boids + 1
end
end
alignment_delta = alignment_delta / visible_boids
self.velocity_delta = self.velocity_delta +
((alignment_delta / Boid.ALIGNMENT_DAMPER))
end
function Boid:calculate_hunting_delta(foodstuffs)
for _, food in ipairs(foodstuffs) do
if self.position:isNearby(Boid.HUNTING_RADIUS, food.position) then
self.velocity_delta = self.velocity_delta +
((food.position - self.position) / Boid.HUNTING_DAMPER)
end
end
end
function Boid:calculate_stay_visible_delta(boids)
local mid_x = love.graphics.getWidth() / 2
local mid_y = love.graphics.getHeight() / 2
local center_vector = Vector:new(mid_x, mid_y)
self.velocity_delta = self.velocity_delta -
((self.position - center_vector) / Boid.STAY_VISIBLE_DAMPER)
end
function Boid:apply_deltas()
self.velocity = self.velocity + self.velocity_delta
self.velocity_delta = Vector:new(0, 0)
end
function Boid:limit_speed()
if self.velocity:r() > Boid.MAX_SPEED then
self.velocity = self.velocity / self.velocity:r() * Boid.MAX_SPEED
end
if self.velocity:r() < Boid.MIN_SPEED then
self.velocity = self.velocity / self.velocity:r() * Boid.MIN_SPEED
end
end
function Boid:navigate(boids, foodstuffs)
self:calculate_avoidance_delta(boids)
self:calculate_attraction_delta(boids)
self:calculate_alignment_delta(boids)
self:calculate_hunting_delta(foodstuffs)
-- self:calculate_stay_visible_delta(boids)
end
function Boid:move(dt)
self:apply_deltas()
self:limit_speed()
self.position = self.position + self.velocity * dt
end
function Boid:animate(dt)
if self.velocity.x <= 0 then
self.anim = self.left_anim
else
self.anim = self.right_anim
end
self.anim:update(dt)
end
function Boid:draw()
love.graphics.draw(self.anim, self.position.x, self.position.y,
math.deg(self.velocity:ang()), 1.5)
end
function Boid:draw_debug()
love.graphics.setColor(255, 165, 0)
love.graphics.circle(love.draw_line, self.position.x, self.position.y, 10)
love.graphics.draw("("..math.floor(self.position.x)..", "..math.floor(self.position.y)..")", self.position.x + 5, self.position.y)
love.graphics.setColor(255, 255, 255)
end
-- draw the physical radius
function Boid:draw_physical()
love.graphics.setColor(255, 255, 255, 128)
love.graphics.circle(love.draw_line, self.position.x, self.position.y, Boid.radius, 10)
love.graphics.setColor(255, 255, 255, 255)
end
-- draw the attraction radius
function Boid:draw_attraction()
love.graphics.setColor(255, 0, 0, 128)
love.graphics.circle(love.draw_line, self.position.x, self.position.y, Boid.ATTRACTION_RADIUS, 10)
love.graphics.setColor(255, 255, 255, 255)
end
-- draw the avoidance radius
function Boid:draw_avoidance()
love.graphics.setColor(0, 255, 0, 128)
love.graphics.circle(love.draw_line, self.position.x, self.position.y, Boid.AVOID_RADIUS, 10)
love.graphics.setColor(255, 255, 255, 255)
end
-- draw the alignment radius
function Boid:draw_alignment()
love.graphics.setColor(0, 0, 255, 128)
love.graphics.circle(love.draw_line, self.position.x, self.position.y, Boid.ALIGNMENT_RADIUS, 10)
love.graphics.setColor(255, 255, 255, 255)
end
-- draw the hunting radius
function Boid:draw_hunting()
love.graphics.setColor(255, 225, 132, 128)
love.graphics.circle(love.draw_line, self.position.x, self.position.y, Boid.HUNTING_RADIUS, 10)
love.graphics.setColor(255, 255, 255, 255)
end
Jump to Line
Something went wrong with that request. Please try again.