■
衝突シミュレーション。
左クリックでボール生成、ボールを右ドラッグアンドドロップで動かせる。
ボールがぶつかるとその時のスピードで動き出す。
…計算式が適当なので真面目に勉強しようと思ったが挫折した。
#!/usr/bin/env python import Tkinter from math import * class boundBall: def __init__(self): self.width = 800 self.height = 600 self.window = Tkinter.Tk() self.canvas = Tkinter.Canvas(self.window,bg='white', width=self.width,height=self.height) self.canvas.bind("<ButtonPress-1>",self.press1Canvas) self.canvas.bind('<ButtonPress-3>',self.press3Canvas) self.canvas.bind('<ButtonRelease-3>',self.releas3Canvas) self.canvas.bind('<Button3-Motion>',self.motion3Canvas) self.canvas.pack() self.circleR = 10 self.objects = [] self.dragObject = None self.window.mainloop() def press3Canvas(self,event): object = self.findObject(event.x,event.y) if object==None: return self.dragObject = object def releas3Canvas(self,event): self.dragObject['vector'] = [0,0] self.dragObject = None def motion3Canvas(self,event): if self.dragObject==None: return x,y = event.x,event.y circleR = self.circleR self.canvas.coords(self.dragObject['id'],x-circleR,y-circleR,x+circleR,y+circleR) self.dragObject['vector'] = [x-self.dragObject['center']['x'], y-self.dragObject['center']['y']] self.dragObject['center']['x'] = x self.dragObject['center']['y'] = y for obj in self.findConflictObjects(self.dragObject): self.conflictObject(obj,self.dragObject) def press1Canvas(self,event): object = self.findObject(event.x,event.y) if object==None: circleR = self.circleR obj = {'id':self.canvas.create_oval(event.x-circleR,event.y-circleR, event.x+circleR,event.y+circleR, fill='red',outline='red'), 'center':{'x':event.x,'y':event.y}, 'vector':[0,0]} self.moveObject(obj) self.objects.append(obj) else: return def calcInterval(self,x1,y1,x2,y2): return pow(pow(x1-x2,2)+pow(y1-y2,2),0.5) def calcAngle(self,x1,y1,x2,y2): return atan2(y2-y1,x2-x1) def findObject(self,x,y): for object in self.objects: d = self.calcInterval(x,y,object['center']['x'],object['center']['y']) if d<=self.circleR: return object def calcObjectInterval(self,objA,objB): return self.calcInterval(objA['center']['x'],objA['center']['y'], objB['center']['x'],objB['center']['y']) def findConflictObjects(self,object): return [o for o in self.objects if self.calcObjectInterval(o,object) <= self.circleR*2 and o['id']!=object['id']] def conflictObject(self,objA,objB): vbx,vby = objB['vector'] rad1 = atan2(vby,vbx) vs = pow(pow(vbx,2)+pow(vby,2),0.5) rad2 = self.calcAngle(objB['center']['x'],objB['center']['y'], objA['center']['x'],objA['center']['y']) rad3 = rad1-rad2 vcos = pow(cos(rad3),2) vx,vy = cos(rad2)*vcos,sin(rad2)*vcos objA['vector'] = self.addVector(objA['vector'],[vx,vy]) objB['vector'] = self.addVector(objB['vector'],self.multiplyVector([vx,vy],-1)) def multiplyVector(self,v,n): return [i*n for i in v] def addVector(self,v1,v2): v = [] for ii in range(len(v1)): v.append(v1[ii]+v2[ii]) return v def afterImageEffect(self,id,color): if color<=0: self.canvas.delete(id) return c = '#%02x%02x%02x'%(255,255-color,255-color) self.canvas.itemconfigure(id,fill=c,outline=c) self.window.after(100,self.afterImageEffect,id,color-64) def moveObject(self,obj): id,x,y,[vx,vy] = obj['id'],obj['center']['x'],obj['center']['y'],obj['vector'] if self.dragObject!=None and self.dragObject['id']==id: return circleR = self.circleR color = '#%02x%02x%02x'%(255,0,0) afterImageId = self.canvas.create_oval(x-circleR,y-circleR,x+circleR,y+circleR, fill=color, outline=color) self.afterImageEffect(afterImageId,255) obj['vector'] = [vx,vy] x,y = x+vx,y+vy self.canvas.coords(id,x-circleR,y-circleR,x+circleR,y+circleR) obj['center']['x'],obj['center']['y'] = x,y for o in self.findConflictObjects(obj): self.conflictObject(o,obj) if x < 0 or x > self.width: obj['vector'] = -vx,vy if y < 0 or y > self.height: obj['vector'] = vx,-vy self.window.after(100,self.moveObject,obj) if __name__ == '__main__': boundBall()