最近心血來潮,想要自己實做一些物理方面的模擬,一般來講應該都是從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)
def point(self):
return (int(self.x), int(self.y))
def point(self, value):
self.x = value[0]
self.y = value[1]
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的意思在這邊說明一下
- dot: return 兩向量 內積
- rotate: return 旋轉 XX radus後的向量
- normalize: 不知道怎翻耶,應該是單位向量這樣
- normalVector: return 相對於自己的法向量
- reflect: 給予法向量後,計算出反射後的向量
雖然看起來自己另外做一個vector好像有點多餘,只是我覺得這樣對於往後的coding會帶來一些方便性,另外比起用一些 list來代替vector,可讀性也比較高。
等我二維碰撞用出一個更加貼近真實的,我在PO心得,目前到這邊為止 :)