Just a little project I made while testing AI that I thought was fun to play around with and decided to share.
https://www.youtube.com/watch?v=FezouyXIpjo
--# Bot
Bot = class()
function Bot:init()
self.pos = vec2(WIDTH / 4, HEIGHT / 4)
self.target = target
self.size = 50
end
function Bot:draw()
local mot = (self.target - self.pos):normalize() * 200 * DeltaTime
local angle = math.atan2(mot.y, mot.x)
local next = self.pos + mot
local move = true
local i = math.random() * 45 - 22.5
while i <= 180 do
for k, v in ipairs(bots) do
if v ~= self then
if v.pos:dist(next) < (v.size + self.size) / 2 and v.pos:dist(v.target) < self.pos:dist(self.target) then
next = self.pos + vec2(math.cos(angle + math.rad(i)), math.sin(angle + math.rad(i))) * 200 * DeltaTime
end
end
end
for k, v in ipairs(obstacles) do
if math.abs(v.x - self.pos.x) < (v.size + self.size) / 2 and math.abs(v.y - self.pos.y) < (v.size + self.size) / 2 then
next = self.pos + vec2(math.cos(angle + math.rad(i)), math.sin(angle + math.rad(i))) * 200 * DeltaTime
end
end
i = -i
local sign = i / math.abs(i)
if sign ~= 1 and sign ~= -1 then
sign = 1
end
if sign == 1 then
i = i + sign * 22.5
end
end
if move then
self.pos = next
end
noStroke()
fill(0)
ellipse(self.pos.x, self.pos.y, self.size)
end
--# Main
-- Bot Swarm
function setup()
tool = "target"
parameter.watch("tool")
parameter.action("Find Tool", function()
tool = "find"
end)
parameter.action("Target Tool", function()
tool = "target"
end)
parameter.action("Obstacle Tool", function()
tool = "obstacle"
end)
parameter.action("Army Tool", function()
tool = "army"
end)
parameter.boolean("Autospawn", true)
parameter.action("Clear Bots", function()
bots = {}
end)
parameter.action("Clear Obstacles", function()
obstacles = {}
end)
parameter.action("Clear All", function()
bots = {}
obstacles = {}
end)
target = vec2(WIDTH / 1.5, HEIGHT / 1.5)
bots = {}
loop()
obstacles = {}
new = image(WIDTH, HEIGHT)
old = image(WIDTH, HEIGHT)
end
function loop()
if Autospawn then
table.insert(bots, Bot())
end
tween.delay(1, loop)
end
function draw()
rectMode(CENTER)
background(255)
noStroke()
setContext(old, false)
background(0, 0)
sprite(new, old.width / 2, old.height / 2, old.width, old.height)
setContext()
setContext(new, false)
background(0, 0)
for k, v in ipairs(obstacles) do
rect(v.x, v.y, v.size, v.size)
end
for k, v in ipairs(bots) do
v:draw()
end
setContext()
noTint()
sprite(new, WIDTH / 2, HEIGHT / 2, WIDTH, HEIGHT)
tint(255, 127)
sprite(old, WIDTH / 2, HEIGHT / 2, WIDTH, HEIGHT)
collectgarbage()
end
function touched(touch)
if tool == "find" then
local closest = 1
local tvec = vec2(touch.x, touch.y)
for k, v in ipairs(bots) do
if v.pos:dist(tvec) < bots[closest].pos:dist(tvec) then
closest = k
end
end
local null = {pos = vec2(0, 0)}
local cbot = bots[closest] or null
if cbot == null then
closest = 0
end
print("Closest is bot #" .. closest)
print("X: " .. cbot.pos.x .. "\
Y: " .. cbot.pos.y)
elseif tool == "target" then
target = vec2(touch.x, touch.y)
for k, v in ipairs(bots) do
v.target = target
end
elseif tool == "obstacle" then
if touch.state == BEGAN then
table.insert(obstacles, {x = touch.x, y = touch.y, size = math.random(50, 150)})
end
elseif tool == "army" then
local gridx = 10
local gridy = 10
if touch.state == BEGAN or math.floor(touch.x / WIDTH * gridx + 0.5) ~= math.floor(touch.prevX / WIDTH * gridx + 0.5) or math.floor(touch.y / HEIGHT * gridy + 0.5) ~= math.floor(touch.prevY / HEIGHT * gridy + 0.5) then
table.insert(bots, Bot())
bots[#bots].target = vec2(math.floor(touch.x / WIDTH * gridx + 0.5) / gridx * WIDTH, math.floor(touch.y / HEIGHT * gridy + 0.5) / gridy * HEIGHT)
end
end
end