2013年8月9日 星期五

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我就不說明了,有興趣的就看看這個吧

裡面有些function的意思在這邊說明一下
  1. dot: return 兩向量 內積
  2. rotate: return 旋轉 XX radus後的向量
  3. normalize: 不知道怎翻耶,應該是單位向量這樣
  4. normalVector: return 相對於自己的法向量
  5. reflect: 給予法向量後,計算出反射後的向量
雖然看起來自己另外做一個vector好像有點多餘,只是我覺得這樣對於往後的coding會帶來一些方便性,另外比起用一些 list來代替vector,可讀性也比較高。


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

0 意見:

張貼留言