Skip to content

Instantly share code, notes, and snippets.

@samfromcadott
Created June 6, 2023 15:09
Show Gist options
  • Save samfromcadott/9cbf4781a19ad89d2b2f8edf616e8479 to your computer and use it in GitHub Desktop.
Save samfromcadott/9cbf4781a19ad89d2b2f8edf616e8479 to your computer and use it in GitHub Desktop.
Boids swarm AI using pyglet
import pyglet
from pyglet import shapes
from pyglet.math import Vec2
from random import random
window_width = 800
window_height = 600
mouse_position = Vec2(0, 0)
window = pyglet.window.Window(window_width, window_height)
pyglet.gl.glClearColor(0.95, 0.95, 0.95, 1.0)
label = pyglet.text.Label(
'0, 0',
font_name='Courier New',
font_size=12,
x=12, y=window.height-12,
color=(0, 0, 0, 255),
anchor_x='left', anchor_y='top'
)
batch = pyglet.graphics.Batch() # Batch used for drawing the boids
class Boid:
"""An agent in the swarm"""
speed = 4.0
def __init__(self, id, x, y):
self.id = id
self.position = Vec2(x, y)
self.velocity = Vec2()
self.shape = shapes.Circle(
x, y,
radius=10,
color=(
int(random()*200),
int(random()*200),
int(random()*200),
128
),
batch=batch
)
def update(self):
# Move towards mouse
d = mouse_position - self.position
self.velocity = d.normalize() * self.speed
# Add boid rules
self.velocity = self.velocity + self.center_of_mass() + self.keep_distance() + self.match_velocity()
# Move the boid
self.position += self.velocity
# Update shape
self.shape.x = self.position.x
self.shape.y = self.position.y
def center_of_mass(self):
c = Vec2()
# Average position of all other boids
for b in boids:
if b.id == self.id: # Skip self
continue
c += b.position
c / ( len(boids)-1 )
return (c - self.position).normalize() / 25.0
def keep_distance(self):
min_dist = 25.0
v = Vec2()
for b in boids:
if b.id == self.id: # Skip self
continue
dist = self.position.distance( b.position )
if dist < min_dist:
v -= b.position - self.position
return v / 30.0
def match_velocity(self):
v = Vec2()
# Average velocity of other boids
for b in boids:
if b.id == self.id: # Skip self
continue
v += b.velocity
v / ( len(boids)-1 )
return (v - self.velocity).normalize() / 2.0
@window.event
def on_draw():
# Update the boids
for b in boids:
b.update()
# Rendering
window.clear()
batch.draw()
label.draw()
@window.event
def on_mouse_motion(x, y, dx, dy):
mouse_position.x = x
mouse_position.y = y
label.text = f"{mouse_position.x}, {mouse_position.y}"
boids = []
for i in range(80):
boids.append(
Boid( i, random()*window_width, random()*window_height )
)
pyglet.app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment