Skip to content

Instantly share code, notes, and snippets.

@fogleman
Last active September 11, 2024 07:27
Show Gist options
  • Save fogleman/436e19a22f570f1cce2f to your computer and use it in GitHub Desktop.
Save fogleman/436e19a22f570f1cce2f to your computer and use it in GitHub Desktop.

Revisions

  1. fogleman revised this gist Jul 8, 2014. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,7 @@ def __init__(self, position, target):
    self.position = position
    self.target = target
    self.speed = random.random() + 0.5
    self.padding = random.random() * 8 + 16
    self.history = deque(maxlen=64)
    def get_position(self, offset):
    px, py = self.position
    @@ -35,7 +36,7 @@ def update(self, bots):
    continue
    x, y = bot.position
    d = hypot(px - x, py - y) ** 2
    p = 20 ** 2
    p = bot.padding ** 2
    angle = atan2(py - y, px - x)
    dx += cos(angle) / d * p
    dy += sin(angle) / d * p
    @@ -77,7 +78,7 @@ def select_point(self):
    def update(self, dt):
    data = [bot.update(self.bots) for bot in self.bots]
    for bot, (angle, magnitude) in zip(self.bots, data):
    speed = min(1, 0.1 + magnitude * 0.9)
    speed = min(1, 0.2 + magnitude * 0.8)
    dx = cos(angle) * dt * SPEED * bot.speed * speed
    dy = sin(angle) * dt * SPEED * bot.speed * speed
    px, py = bot.position
    @@ -86,7 +87,7 @@ def update(self, dt):
    if hypot(px - tx, py - ty) < 10:
    bot.target = self.select_point()
    for bot in self.bots[-FOLLOWERS:]:
    bot.target = self.bots[0].get_position(12)
    bot.target = self.bots[0].get_position(10)

    class Panel(wx.Panel):
    def __init__(self, parent):
  2. fogleman revised this gist Jul 8, 2014. 1 changed file with 11 additions and 4 deletions.
    15 changes: 11 additions & 4 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -7,12 +7,10 @@
    SIZE = 600
    COUNT = 64
    SPEED = 100
    FOLLOWERS = 5
    FOLLOWERS = 4

    COLORS = [
    wx.RED,
    # wx.BLUE,
    # wx.GREEN,
    ]

    class Bot(object):
    @@ -21,6 +19,11 @@ def __init__(self, position, target):
    self.target = target
    self.speed = random.random() + 0.5
    self.history = deque(maxlen=64)
    def get_position(self, offset):
    px, py = self.position
    tx, ty = self.target
    angle = atan2(ty - py, tx - px)
    return (px + cos(angle) * offset, py + sin(angle) * offset)
    def update(self, bots):
    px, py = self.position
    tx, ty = self.target
    @@ -83,7 +86,7 @@ def update(self, dt):
    if hypot(px - tx, py - ty) < 10:
    bot.target = self.select_point()
    for bot in self.bots[-FOLLOWERS:]:
    bot.target = self.bots[0].position
    bot.target = self.bots[0].get_position(12)

    class Panel(wx.Panel):
    def __init__(self, parent):
    @@ -93,6 +96,7 @@ def __init__(self, parent):
    self.Bind(wx.EVT_SIZE, self.on_size)
    self.Bind(wx.EVT_PAINT, self.on_paint)
    self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
    self.Bind(wx.EVT_RIGHT_DOWN, self.on_right_down)
    self.timestamp = time.time()
    self.on_timer()
    def on_timer(self):
    @@ -104,6 +108,9 @@ def on_timer(self):
    wx.CallLater(10, self.on_timer)
    def on_left_down(self, event):
    self.model.bots[0].target = event.GetPosition()
    def on_right_down(self, event):
    width, height = self.GetClientSize()
    self.model = Model(width, height, COUNT)
    def on_size(self, event):
    width, height = self.GetClientSize()
    self.model = Model(width, height, COUNT)
  3. fogleman revised this gist Jul 8, 2014. 1 changed file with 6 additions and 5 deletions.
    11 changes: 6 additions & 5 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,7 @@
    SIZE = 600
    COUNT = 64
    SPEED = 100
    FOLLOWERS = 5

    COLORS = [
    wx.RED,
    @@ -81,7 +82,7 @@ def update(self, dt):
    bot.set_position((px + dx, py + dy))
    if hypot(px - tx, py - ty) < 10:
    bot.target = self.select_point()
    for bot in self.bots[-3:]:
    for bot in self.bots[-FOLLOWERS:]:
    bot.target = self.bots[0].position

    class Panel(wx.Panel):
    @@ -123,15 +124,15 @@ def on_paint(self, event):
    dc.SetPen(wx.Pen(COLORS[index]))
    x, y = bot.target
    dc.DrawCircle(x, y, 6)
    dc.SetPen(wx.BLACK_PEN)
    for index, bot in enumerate(self.model.bots):
    dc.SetPen(wx.BLACK_PEN)
    if index < n:
    dc.SetBrush(wx.Brush(COLORS[index]))
    else:
    dc.SetBrush(wx.WHITE_BRUSH)
    if index >= COUNT - 3:
    elif index >= COUNT - FOLLOWERS:
    dc.SetBrush(wx.BLACK_BRUSH)
    dc.SetPen(wx.WHITE_PEN)
    else:
    dc.SetBrush(wx.WHITE_BRUSH)
    x, y = bot.position
    dc.DrawCircle(x, y, 6)

  4. fogleman revised this gist Jul 8, 2014. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -81,6 +81,8 @@ def update(self, dt):
    bot.set_position((px + dx, py + dy))
    if hypot(px - tx, py - ty) < 10:
    bot.target = self.select_point()
    for bot in self.bots[-3:]:
    bot.target = self.bots[0].position

    class Panel(wx.Panel):
    def __init__(self, parent):
    @@ -127,6 +129,9 @@ def on_paint(self, event):
    dc.SetBrush(wx.Brush(COLORS[index]))
    else:
    dc.SetBrush(wx.WHITE_BRUSH)
    if index >= COUNT - 3:
    dc.SetBrush(wx.BLACK_BRUSH)
    dc.SetPen(wx.WHITE_PEN)
    x, y = bot.position
    dc.DrawCircle(x, y, 6)

  5. fogleman revised this gist Jul 8, 2014. 1 changed file with 45 additions and 16 deletions.
    61 changes: 45 additions & 16 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,25 @@
    from collections import deque
    from math import sin, cos, pi, atan2, hypot
    import random
    import time
    import wx

    SIZE = 600
    COUNT = 100
    SPEED = 80
    COUNT = 64
    SPEED = 100

    COLORS = [
    wx.RED,
    # wx.BLUE,
    # wx.GREEN,
    ]

    class Bot(object):
    def __init__(self, position, target):
    self.position = position
    self.target = target
    self.speed = random.random() + 0.5
    self.history = deque(maxlen=64)
    def update(self, bots):
    px, py = self.position
    tx, ty = self.target
    @@ -22,12 +30,24 @@ def update(self, bots):
    if bot == self:
    continue
    x, y = bot.position
    m = hypot(px - x, py - y) ** 2
    d = hypot(px - x, py - y) ** 2
    p = 20 ** 2
    angle = atan2(py - y, px - x)
    dx += cos(angle) / m * 300
    dy += sin(angle) / m * 300
    dx += cos(angle) / d * p
    dy += sin(angle) / d * p
    angle = atan2(dy, dx)
    return angle
    magnitude = hypot(dx, dy)
    return angle, magnitude
    def set_position(self, position):
    self.position = position
    if not self.history:
    self.history.append(self.position)
    return
    x, y = self.position
    px, py = self.history[-1]
    d = hypot(px - x, py - y)
    if d >= 10:
    self.history.append(self.position)

    class Model(object):
    def __init__(self, width, height, count):
    @@ -51,13 +71,14 @@ def select_point(self):
    y = cy + sin(angle) * radius
    return (x, y)
    def update(self, dt):
    angles = [bot.update(self.bots) for bot in self.bots]
    for bot, angle in zip(self.bots, angles):
    dx = cos(angle) * dt * SPEED * bot.speed
    dy = sin(angle) * dt * SPEED * bot.speed
    data = [bot.update(self.bots) for bot in self.bots]
    for bot, (angle, magnitude) in zip(self.bots, data):
    speed = min(1, 0.1 + magnitude * 0.9)
    dx = cos(angle) * dt * SPEED * bot.speed * speed
    dy = sin(angle) * dt * SPEED * bot.speed * speed
    px, py = bot.position
    tx, ty = bot.target
    bot.position = (px + dx, py + dy)
    bot.set_position((px + dx, py + dy))
    if hypot(px - tx, py - ty) < 10:
    bot.target = self.select_point()

    @@ -68,6 +89,7 @@ def __init__(self, parent):
    self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
    self.Bind(wx.EVT_SIZE, self.on_size)
    self.Bind(wx.EVT_PAINT, self.on_paint)
    self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
    self.timestamp = time.time()
    self.on_timer()
    def on_timer(self):
    @@ -77,25 +99,32 @@ def on_timer(self):
    self.model.update(dt)
    self.Refresh()
    wx.CallLater(10, self.on_timer)
    def on_left_down(self, event):
    self.model.bots[0].target = event.GetPosition()
    def on_size(self, event):
    width, height = self.GetClientSize()
    self.model = Model(width, height, COUNT)
    event.Skip()
    self.Refresh()
    def on_paint(self, event):
    n = len(COLORS)
    dc = wx.AutoBufferedPaintDC(self)
    dc.SetBackground(wx.BLACK_BRUSH)
    dc.Clear()
    dc.SetPen(wx.RED_PEN)
    dc.SetPen(wx.BLACK_PEN)
    for index, bot in enumerate(self.model.bots[:n]):
    dc.SetBrush(wx.Brush(COLORS[index]))
    for x, y in bot.history:
    dc.DrawCircle(x, y, 3)
    dc.SetBrush(wx.BLACK_BRUSH)
    for bot in self.model.bots:
    for index, bot in enumerate(self.model.bots[:n]):
    dc.SetPen(wx.Pen(COLORS[index]))
    x, y = bot.target
    dc.DrawCircle(x, y, 6)
    break
    dc.SetPen(wx.BLACK_PEN)
    for index, bot in enumerate(self.model.bots):
    if index == 0:
    dc.SetBrush(wx.RED_BRUSH)
    if index < n:
    dc.SetBrush(wx.Brush(COLORS[index]))
    else:
    dc.SetBrush(wx.WHITE_BRUSH)
    x, y = bot.position
  6. fogleman created this gist Jul 8, 2014.
    119 changes: 119 additions & 0 deletions main.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,119 @@
    from math import sin, cos, pi, atan2, hypot
    import random
    import time
    import wx

    SIZE = 600
    COUNT = 100
    SPEED = 80

    class Bot(object):
    def __init__(self, position, target):
    self.position = position
    self.target = target
    self.speed = random.random() + 0.5
    def update(self, bots):
    px, py = self.position
    tx, ty = self.target
    angle = atan2(ty - py, tx - px)
    dx = cos(angle)
    dy = sin(angle)
    for bot in bots:
    if bot == self:
    continue
    x, y = bot.position
    m = hypot(px - x, py - y) ** 2
    angle = atan2(py - y, px - x)
    dx += cos(angle) / m * 300
    dy += sin(angle) / m * 300
    angle = atan2(dy, dx)
    return angle

    class Model(object):
    def __init__(self, width, height, count):
    self.width = width
    self.height = height
    self.bots = self.create_bots(count)
    def create_bots(self, count):
    result = []
    for i in range(count):
    position = self.select_point()
    target = self.select_point()
    bot = Bot(position, target)
    result.append(bot)
    return result
    def select_point(self):
    cx = self.width / 2.0
    cy = self.height / 2.0
    radius = min(self.width, self.height) * 0.4
    angle = random.random() * 2 * pi
    x = cx + cos(angle) * radius
    y = cy + sin(angle) * radius
    return (x, y)
    def update(self, dt):
    angles = [bot.update(self.bots) for bot in self.bots]
    for bot, angle in zip(self.bots, angles):
    dx = cos(angle) * dt * SPEED * bot.speed
    dy = sin(angle) * dt * SPEED * bot.speed
    px, py = bot.position
    tx, ty = bot.target
    bot.position = (px + dx, py + dy)
    if hypot(px - tx, py - ty) < 10:
    bot.target = self.select_point()

    class Panel(wx.Panel):
    def __init__(self, parent):
    super(Panel, self).__init__(parent)
    self.model = Model(SIZE, SIZE, COUNT)
    self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
    self.Bind(wx.EVT_SIZE, self.on_size)
    self.Bind(wx.EVT_PAINT, self.on_paint)
    self.timestamp = time.time()
    self.on_timer()
    def on_timer(self):
    now = time.time()
    dt = now - self.timestamp
    self.timestamp = now
    self.model.update(dt)
    self.Refresh()
    wx.CallLater(10, self.on_timer)
    def on_size(self, event):
    width, height = self.GetClientSize()
    self.model = Model(width, height, COUNT)
    event.Skip()
    self.Refresh()
    def on_paint(self, event):
    dc = wx.AutoBufferedPaintDC(self)
    dc.SetBackground(wx.BLACK_BRUSH)
    dc.Clear()
    dc.SetPen(wx.RED_PEN)
    dc.SetBrush(wx.BLACK_BRUSH)
    for bot in self.model.bots:
    x, y = bot.target
    dc.DrawCircle(x, y, 6)
    break
    dc.SetPen(wx.BLACK_PEN)
    for index, bot in enumerate(self.model.bots):
    if index == 0:
    dc.SetBrush(wx.RED_BRUSH)
    else:
    dc.SetBrush(wx.WHITE_BRUSH)
    x, y = bot.position
    dc.DrawCircle(x, y, 6)

    class Frame(wx.Frame):
    def __init__(self):
    super(Frame, self).__init__(None)
    self.SetTitle('Motion')
    self.SetClientSize((SIZE, SIZE))
    Panel(self)

    def main():
    app = wx.App()
    frame = Frame()
    frame.Center()
    frame.Show()
    app.MainLoop()

    if __name__ == '__main__':
    main()