python 物理模擬

最近心血來潮,想要自己實做一些物理方面的模擬,一般來講應該都是從2D方面開始,畢竟3D的世界有很多數學概念,相較起來2D的數學概念比較不吃重,話雖如此,只是果然天算不如人算阿 :(

一開始一路過關斬將,直到我開始寫碰撞的時候,一路上荊棘滿佈,頭一次寫程式寫到有種快要發飆的感覺 :) 我只能說我的數學,大學上學的我都忘了,剩下高中程度,若是一維碰撞那到是簡單的很,公式也能輕易推算出來,但是沒想到只是從1D轉到2D,整件事情就天差地遠阿,到目前為止,我也只是寫出個勉強貼近2D碰撞的模擬。
連結

上面這影片就是我目前寫出來的樣子,獻醜了 :) 這篇就來貼一下,我的2D運算基本工具,基本上我是自己實做了一個vector的class,讓它具有一些特性

  • normalize
  • reflect

等等。

class Vector:  

 def __init__(self, x=0.0, y=0.0):  
 self.x = x  
 self.y = y  

 def __neg__(self):  
 ''' ex. -Vector(2,2) -> Vector(-2,-2)'''  
 return Vector(-self.x, -self.y)  

 # def __del__(self):  
 # print('vector {} is delete'.format(self.point))  

 def __getitem__(self, value):  
 '''return a integer due to the coordinate in pygame is integer  
 '''  
 return int(self.__dict__[value])  

 def __setitem__(self, index, value):  
 self.__dict__[index] = value  

 def __add__(self, rhs):  
 return Vector(self.x+rhs.x, self.y+rhs.y)  

 def __truediv__(self, rhs):  
 if isinstance(rhs, Vector):  
 raise ValueError  
 return Vector(self.x/rhs, self.y/rhs)  

 def __mul__(self, rhs):  
 ''' rhs is a pure num '''  
 if isinstance(rhs, Vector):  
 raise ValueError  
 return Vector(self.x*rhs, self.y*rhs)  

 def __rmul__(self, lhs):  
 return Vector(self.x*lhs, self.y*lhs)  

 def __sub__(self, rhs):  
 return Vector(self.x-rhs.x, self.y-rhs.y)  

 def __imul__(self, rhs):  
 '''  
 *= equals to assign and inplace calculation  
 ex. a *= b --> a = operator.imul(a, b)  
 '''  
 if isinstance(rhs, Vector):  
 raise ValueError  
 self.x *= rhs  
 self.y *= rhs  
 return self  

 def __itruediv__(self, rhs):  
 if isinstance(rhs, Vector):  
 raise ValueError  
 self.x /= rhs  
 self.y /= rhs  
 return self  

 def __iadd__(self, rhs):  
 self.x += rhs.x  
 self.y += rhs.y  
 return self  

 def __isub__(self, rhs):  
 self.x -= rhs.x  
 self.y -= rhs.y  
 return self  

 def __str__(self):  
 return 'vector x ={} y={}'.format(self.x, self.y)  

 @property  
 def point(self):  
 return (int(self.x), int(self.y))  

 @point.setter  
 def point(self, value):  
 self.x = value[0]  
 self.y = value[1]  

 @property  
 def angle(self):  
 ''' return radian'''  
 return math.atan(self.y/self.x)  


 def reflect(self, normal):  
 '''  
 I < |---->normal  
 \ | /  
 ___\|/____  

 2*(-I.dot(normal)) -- scalar  
 '''  
 I = self  
 self = (2*(-I.dot(normal))*normal) + I  
 return self  

 def normalVector(self):  
 ''' return the normal vector of self'''  
 l = self.length()  
 angle = self.angle + math.pi/2  
 return Vector(l*math.cos(angle), l*math.sin(angle))  

 def normalize(self):  
 try:  
 length = self.length()  
 return Vector(self.x/length, self.y/length)  
 except:  
 return self  


 def rotate(self, radius):  
 newx = self.x*math.cos(radius) - self.y*math.sin(radius)  
 newy = self.x*math.sin(radius) + self.y*math.cos(radius)  
 return Vector(newx, newy)  

 def length(self):  
 return math.sqrt(self.x**2 + self.y**2)  

 def dot(self, v2):  
 if isinstance(v2, Vector):  
 return self.x*v2.x + self.y*v2.y  
 else:  
 raise ValueError  

關於python的operator我就不說明了,有興趣的就看看[這個吧][3]

裡面有些function的意思在這邊說明一下

  1. dot: return 兩向量 內積
  2. rotate: return 旋轉 XX radus後的向量
  3. normalize: 不知道怎翻耶,應該是單位向量這樣
  4. normalVector: return 相對於自己的法向量
  5. reflect: 給予法向量後,計算出反射後的向量

雖然看起來自己另外做一個vector好像有點多餘,只是我覺得這樣對於往後的coding會帶來一些方便性,另外比起用一些 list來代替vector,可讀性也比較高。

等我二維碰撞用出一個更加貼近真實的,我在PO心得,目前到這邊為止 :)