如果你想制作一款酷炫的動畫效果或者做一款h5的小遊戲,但又不知道如何入手?計算機動畫怎麼知道一個物體放到何處的?它又是怎麼讓物體移動的?等等類似的問題,解決這些問題,都少不了數學與物理的基礎知識,從本系列文章起,筆者将介紹一些基礎的數學與物理知識,希望對你有所幫助。
本篇文章先從最基礎的點和直線開始介紹,主要涉及以下内容:
坐标系和點
讓我們先來思考一個問題,計算機是怎麼将我們指定的物體放置到對應的位置?一般來說,我們開發人員是通過使用笛卡爾坐标系确定物體的具體位置,笛卡爾坐标系由一個水平軸x和一個垂直軸y組成,每個點都可以寫成類似(x,y),其中x和y分别為該點在x軸和y軸上的坐标值。坐标系的原點(0,0)是量軸相交的地方。從原點出發,向右是x軸的正方向,向左是x軸的負方向;同樣,y軸的正方向向上,y軸的負方向向下。
在二維坐标系裡表示點
例1: 現在有個需求在屏幕上放置6個物體A-F,并在笛卡爾坐标系進行表示。
A(0,0)、B(1,2)、C(4,3)、D(-1,2),E(-2,-1)和 F(3,-2)。
在三維坐标系裡表示點
所謂的三維坐标,就是在二維的基礎上,添加第三個坐标軸——Z軸而已。z軸的具體方向在哪,目前還沒有統一的标準。目前有兩個标準:左手系統和右手系統。
伸出你的右手,彎曲你的無名指和小拇指,讓大拇指指向右方(X軸的正方向),并且讓食指指向上方(Y軸的正方向),那你會發現中指指向屏幕的外部(Z軸的正方向)。如果用左手做同樣的事情,讓左大拇指指向右方(X軸的正方向),食指向上(Y軸的正方向),那麼你的中指指向屏幕的内部(左手系統中Z軸的正方向)。本系列文章會選擇y軸向上的右手系統,原因有以下幾點:
在這種坐标系中,我們可以用(x,y,z)來表示三維空間的任意一個位置。
例2: 如圖所示,給出P點的坐标:
如圖所示,我們做了黃色的輔助線,可以清楚看出p的坐标,其實p點沿着原點右移了2個單位,然後向上移了4個單位,再沿着z軸移動了5個單位,因此p點的坐标為(2,4,5)
屏幕中的坐标系
前面我們講過,在笛卡爾坐标系中y軸正方向是向上的,然而顯示器則是被設置成從上往下讀,因此屏幕坐标系使用向下作為y軸的正方向。如下圖示意:
直線及計算直線的斜率
直線的定義
我們都知道兩點确定一條直線,在數學中我們一般用類似y=2x這樣的函數方程表示直線,而方程的全解則是滿足該方程的點。
如何根據一個函數方程畫一條直線呢?
例3: 畫出方程3x-2y=8表示的直線。
1、首先變換方程将y移動到方程的一邊。
y=(3/2)x-4
2、在畫點時,使用整數坐标比較容易些,因此x取值0,2,4。将這3個值帶入方程後,将會得到以下三個點:
(0,4)、(2,-1)、(4,2)。
3、在坐标系裡畫出這3個點,并用線将它們連接起來如圖所示:
斜率
斜率是直線的一個重要屬性,如圖所示展示了一個斜面(直線),一個物體以速度50m/s沿垂直方向上升,以速度100m/s沿水平方向運動,該斜面的斜率是通過垂直上升的速度與水平運動的速度比率來确定的,在該圖的比率就是50/100,或50%。如果用函數方程表示這條斜線:1/2x-y=c。
1、兩點之間的斜率
接下來讓我們來看坐标系中的P點(x1,y1)和Q點(x2,y2),用m來表示斜率,其對應的計算斜率公式如下:
斜率=m=△y/△x=(y2-y1)/(x2-x1)
例4: 計算點(1,5)和(-2,0)之間的斜率
斜率=m=△y/△x=(y2-y1)/(x2-x1)=(0-5)/(-2-1)=5/3
2、計算直線的斜率
對于标準的直線方程形如Ax By=C這樣的方程,其斜率為m=-A/B。
例5: 計算直線2x y=5的斜率。
如果y前沒數字,這意味着B=1,如果沒有y項,則B=0,帶入斜率公式:
斜率=m=-A/B=-2/1=-2
除了Ax By=C這種标準的直線函數方程,我們還會見到如下的表示形式:
斜截式:y=mx b
點斜式:(y-y1)=m(x-x1),其中(x1,y1)是直線上任一點。
3、斜率的一些重要屬性
4、有趣的練習
例6: 假如人物角色在遊戲中的位置為(50,200),當玩家在點(150,400)點擊了鼠标,這說明它想要此位置,那麼就需要找到一條到達目的直線的路徑,請計算出該直線方程。
解答思路:
1、首先我們需要通過兩點之間的斜率公式,計算出直線斜率:
斜率=m=(400-200)/(150-50)=200/100=2
2、然後将其中一點和斜率m帶入點斜式方程:
(y-y1)=m(x-x1)
(y-200)=2(x-50)
如果你不習慣點斜式的表述方式,你可以改成斜截式,隻需要多幾部運算而已:
y=2x 100
有了直線方程,現在我們可以讓人物角色按照直線路徑動起來了。
例7: 在你的遊戲中角色正沿着直線y=(2/3)x 20移動,當它到達位置(30,40)時玩家按了下方向按鈕,命令它向左轉90。然後繼續沿着直線前進,請計算出新的路徑直線方程。
解答思路:
1、根據斜率的屬性我們得知,兩條直線垂直,其斜率相乘等于-1,由此我們可以得出另一條直線方程的斜率為-3/2。
2、然後我們把斜率和點帶入點斜式方程中:
(y-40)=(-2/3)(x-30)
如果你不習慣點斜式的表述方式,你可以改成斜截式,隻需要多幾步運算而已:
y=(-3/2)x 85
檢測直線是否相交及計算交點
在遊戲和動畫編程中,我們經常要判斷兩條直線是否相交,如果相交的話交點在哪裡?直線在遊戲或動畫裡可以代表建築的邊界、地面或者物體路徑,因此需要思考如何判斷兩直線是否相交以及直線在哪裡。其實計算交點,就相當兩個方程組求解,計算出滿足兩個方程中的(x,y)的點而已。
如果同一平面的兩條直線,其解的情況如下:
方程組的求解方法一般分為兩種——消元法和帶入法:
消元法的步驟:
帶入法的步驟:
接下來讓我們來看一個例子,加深下對消元法和代入法的理解,示例如下:
例8: 假如在你的遊戲中,一輛汽車沿着直線3x 5y=8的方向行駛,而一堵牆被放置在直線x 3y=4處,如果汽車沿着原來的路線前進,它是否會撞到牆上?如果發生碰撞,那麼碰撞點是多少?
解題思路:
消元法求解
1、是否會碰到牆上,我們需要确認兩條直線的斜率,第一條直線為 -3/5,第二條直線為 -1/3,因此必相交。
2、利用消元法求解直線方程組
3x 5y=8
x 3y=4
3、選擇你将要消去的變量,假如我們在這裡要消去x。
4、我們在第二個方程的兩邊同時乘以3,從而得到下面方程組:
3x 5y=8
3x 9y=12
5、用上面的方程減去下面的方程,可以得到0x-4y=-4,y=1。
6、将y值帶入任意一個方程,我們帶入下面一個方程,得到x=1,因此方程組求解就是(1,1)
帶入法求解:
1、從下面的一個方程中,我們得出x=4-3y
2、把x=4-3y,帶入第一個方程中,得出-4y=-4,然後得出y=1
3、然後把y=1,帶入任意一方程進行求解,得出x=1,因此方程組求解就是(1,1)
網頁上繪制直線和箭頭
了解了點和直線的基礎知識後,我們開始在電腦上進行實踐,這裡需要用到html5的canvas,通過這個技術我們可以畫圖以及進行更加靈活的的高級動畫設計,甚至可以進行3D繪圖,今天我們先利用其實現簡單的直線和箭頭的繪制。
關于線條的繪制主要包含以下幾個常用方法:
context.moveTo(x,y):把畫筆移動到(x,y)坐标,建立新的子路徑。
context.lineTo(x,y):用于建立上一個點到(x,y)坐标的直線,如果沒有上一個點,則等同moveTo(x,y),把(x,y)點添加到子路徑中。
context.stroke():使用lineWidth、lineCap、lineJoin及strokeStyle對所有子路徑進行描邊。
context.closePath():如果當前路子路徑是打開的,則關閉它。
給畫布繪制一條對角線
假如我們從畫布左上角的點(0,0)畫一條對角線,我們需要知道右下角點的坐标,其實右下角的坐标即為畫布的(寬,高),因此我們的代碼部分如下:
<body> <h2>畫線例子</h2> <canvas id="can" width="300" height="300" ></canvas> </body> <script> //獲取2d上下文 var ctx = can.getContext("2d"); var width = can.width, height = can.height; ctx.moveTo(0,0); ctx.lineTo(width,height); ctx.lineWidth = 6; ctx.strokeStyle = "red"; //開始畫線 ctx.stroke(); </script>
效果如下圖:
繪制箭頭
如果我們需要繪制一個箭頭,如下圖所示,我們需要知道其對應關鍵點的集合,如下圖所示,然後不斷的使用lineTo方法進行各個關鍵點的連接:
<body> <canvas id="can" width="400" height="300" ></canvas> </body> <script> //獲取2d上下文 var ctx = can.getContext("2d"); var width = can.width, height = can.height; var pts=[[30,100],[300,100],[300,50],[350,130],[300,210],[300,160],[30,160]] ctx.strokeStyle="red"; ctx.lineWidth = 2; ctx.moveTo(pts[0][0],pts[0][1]); for(var i=1;i<pts.length;i ) { ctx.lineTo(pts[i][0],pts[i][1]); } ctx.closePath(); ctx.stroke(); </script>
今天的文章就到這裡,接下來的文章将會介紹幾何相關的基礎知識,敬請期待。
更多精彩内容請關注“前端達人”公衆号!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!