Last active
September 11, 2024 07:27
-
-
Save fogleman/436e19a22f570f1cce2f to your computer and use it in GitHub Desktop.
Revisions
-
fogleman revised this gist
Jul 8, 2014 . 1 changed file with 4 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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 = 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.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(10) class Panel(wx.Panel): def __init__(self, parent): -
fogleman revised this gist
Jul 8, 2014 . 1 changed file with 11 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,12 +7,10 @@ SIZE = 600 COUNT = 64 SPEED = 100 FOLLOWERS = 4 COLORS = [ wx.RED, ] 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].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) -
fogleman revised this gist
Jul 8, 2014 . 1 changed file with 6 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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[-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) for index, bot in enumerate(self.model.bots): dc.SetPen(wx.BLACK_PEN) if index < n: dc.SetBrush(wx.Brush(COLORS[index])) 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) -
fogleman revised this gist
Jul 8, 2014 . 1 changed file with 5 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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) -
fogleman revised this gist
Jul 8, 2014 . 1 changed file with 45 additions and 16 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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 = 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 d = hypot(px - x, py - y) ** 2 p = 20 ** 2 angle = atan2(py - y, px - x) dx += cos(angle) / d * p dy += sin(angle) / d * p angle = atan2(dy, dx) 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): 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.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.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 index, bot in enumerate(self.model.bots[:n]): 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): if index < n: dc.SetBrush(wx.Brush(COLORS[index])) else: dc.SetBrush(wx.WHITE_BRUSH) x, y = bot.position -
fogleman created this gist
Jul 8, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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()