前提・実現したいこと
Pythonを使ってBOIDモデルを実装しています.
発生している問題・エラーメッセージ
Python標準のtkinterを使っているのですが,birdが複数いる時の跳ね返りの処理が上手く動作せず,右下の角に収束してしまいます.
該当のソースコード
Python
1import math 2import random 3from statistics import mean 4from tkinter import * 5 6 7class Coordinate(): 8 def __init__(self): 9 self.x = 0 10 self.y = 0 11 12 def reset(self): 13 self.x = 0 14 self.y = 0 15 16 17class Bird(): 18 """ 19 Bird Class 20 """ 21 def __init__(self, x, y, vx, vy, identifier, field_info, others, view): 22 """Bird Class Constructor 23 24 BOID用のエージェントです 25 :param x: x coordinate 26 :param y: y coordinate 27 :param vx: x方向の移動量 28 :param vy: y方向の移動量 29 :param id: 識別用id 30 :param field_info: (field_width, field_height, fish_radius, fish_speed) 31 :param others: other fish 32 :param view: 視野の広さ(半径) 33 """ 34 self.x = x 35 self.y = y 36 self.vx = vx 37 self.vy = vy 38 self.identifier = identifier 39 self.others = others 40 self.view = view 41 self.field_info = field_info 42 self.inverse_x = self.field_info[0] - self.x 43 self.inverse_y = self.field_info[1] - self.y 44 self.r1 = 2.0 # cohesion coefficient 45 self.r2 = 0.5 # separation coefficient 46 self.r3 = 1.0 # alignment coefficient 47 self.neighbors = [] # 近くにいるエージェント 48 49 self.v1 = Coordinate() 50 self.v2 = Coordinate() 51 self.v3 = Coordinate() 52 53 def set_others(self, others): 54 self.others = others 55 self.find_neighbors() 56 57 # 結合 58 def cohesion(self): 59 center_pull_coeff = 10 60 if len(self.neighbors) == 0: 61 return 62 self.v1.x = mean([agent.x for agent in self.neighbors if not agent.identifier == self.identifier]) 63 self.v1.y = mean([agent.y for agent in self.neighbors if not agent.identifier == self.identifier]) 64 self.v1.x = (self.v1.x - self.x) / center_pull_coeff 65 self.v1.y = (self.v1.y - self.y) / center_pull_coeff 66 67 # 離脱 68 def separation(self): 69 personal_space = 50 70 for agent in self.neighbors: 71 if self.identifier == agent.identifier: 72 continue 73 74 dist = self.calc_distance(agent, self) 75 if dist <= personal_space: 76 self.v2.x -= (agent.x - self.x) / dist 77 self.v2.y -= (agent.y - self.y) / dist 78 79 def _separation(self): 80 if len(self.neighbors) == 0: 81 return 82 self.v2.x = mean([agent.x for agent in self.neighbors if not agent.identifier == self.identifier]) - self.x 83 self.v2.y = mean([agent.y for agent in self.neighbors if not agent.identifier == self.identifier]) - self.y 84 85 # 距離の計算 86 def calc_distance(self, a, b): 87 return min(math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2), 88 math.sqrt((a.inverse_x - b.x) ** 2 + (a.inverse_y - b.y) ** 2)) 89 90 # 整列 91 def alignment(self): 92 if len(self.neighbors) == 0: 93 return 94 self.v3.x = mean([agent.x for agent in self.neighbors if not self.identifier == agent.identifier]) 95 self.v3.y = mean([agent.y for agent in self.neighbors if not self.identifier == agent.identifier]) 96 self.v3.x = (self.v3.x - self.vx) / 2 97 self.v3.y = (self.v3.y - self.vy) / 2 98 99 def _collision_detection(self): 100 if self.x - self.field_info[2] <= 0: 101 self.vx *= -1 102 self.x = self.field_info[2] 103 if self.x + self.field_info[2] >= self.field_info[0]: 104 self.vx *= -1 105 self.x = self.field_info[0] - self.field_info[2] 106 107 if self.y - self.field_info[2] <= 0: 108 self.vy *= -1 109 self.y = self.field_info[2] 110 if self.y + self.field_info[2] >= self.field_info[1]: 111 self.vy *= -1 112 self.y = self.field_info[1] - self.field_info[2] 113 114 def step(self): 115 self.cohesion() 116 self.separation() 117 self.alignment() 118 119 def find_neighbors(self): 120 self.neighbors = [neighbor for neighbor in self.others 121 if self.calc_distance(self, neighbor) <= self.view and 122 not self.identifier == neighbor.identifier] 123 124 def update(self): 125 self.vx += self.r1 * self.v1.x + self.r2 * self.v2.x + self.r3 * self.v3.x 126 self.vy += self.r1 * self.v1.y + self.r2 * self.v2.y + self.r3 * self.v3.y 127 128 distance = math.sqrt(self.vx ** 2 + self.vy ** 2) 129 if distance > self.field_info[3]: 130 self.vx = (self.vx / distance) * self.field_info[3] 131 self.vy = (self.vy / distance) * self.field_info[3] 132 133 self.x += int(self.vx) 134 self.y += int(self.vy) 135 136 self._collision_detection() 137 print(self.vx, self.vy) 138 139 self.inverse_x = self.field_info[0] - self.x 140 self.inverse_y = self.field_info[1] - self.y 141 142 def clear_movement(self): 143 self.v1.reset() 144 self.v2.reset() 145 self.v3.reset() 146 147 def draw(self): 148 self.clear_movement() 149 self.step() 150 self.update() 151 return self.x, self.y, self.vx, self.vy 152 153root = Tk() 154 155WIDTH = 1000 156HEIGHT = 1000 157 158fish_radian = 10 159bird_num = 3 160SPEED = 5 161VIEW = 50 162 163c = Canvas(root, width=WIDTH, height=HEIGHT) 164c.pack() 165 166 167fish_list = [Bird(random.randint(0, WIDTH), random.randint(0, HEIGHT), random.randint(-SPEED, SPEED), 168 random.randint(-SPEED, SPEED), i, (WIDTH, HEIGHT, fish_radian, SPEED), [], VIEW) for i in range(bird_num)] 169[fish.set_others(fish_list) for fish in fish_list] 170 171 172def animate(): 173 c.delete("all") 174 for fish in fish_list: 175 fish.draw() 176 c.create_oval(fish.x - fish_radian, fish.y - fish_radian, fish.x+fish_radian, fish.y+fish_radian) 177 c.create_line(fish.x, fish.y, fish.x + fish.vx * 3, fish.y + fish.vy * 3) 178 [fish.set_others(fish_list) for fish in fish_list] 179 root.after(20, animate) 180 181animate() 182root.mainloop() 183 184
試したこと
条件式を色々変えて試しました.
ほぼ全ての条件で同様にウィンドウの右下に収束してしまいました.
補足情報(FW/ツールのバージョンなど)
MacOS Catalina
Python 3.6.8
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/12/01 12:47
2019/12/01 13:18
2019/12/01 13:37