2003/12/26

聖誔遊戲

這次macromedia網站上的site of the Day是遊戲。
大家看看吧
Merry Christmas Games
我覺得做得不錯,shockwave game

2003/12/12

碰撞反應

同樣是FLASH MX Game Design Demystified這本書的筆記,今天終於搞定第六章 碰撞反應,這裏牽扯到一些物理知識,有興趣的同好可以參考看看,並歡迎共同討論。

Chapter 6. Collision Reactions
.所有範例檔下載
*這裏分的節次,並不是書中的節次。只是方便我自己整理書中重點及個人心得而分的。(所以說是筆記嘛)

第一節 點跟矩形
範例檔:collisionReaction_1.fla

這節算是我自己加的,書中並沒有此節
為了循序漸進,所以我先用上一章第八節來改。在ch5筆記的第八節中,其碰撞偵測非常簡單
//以比大小方式,判斷點是否在矩形裏
if (x>x1 and x< x2 and y>y1 and y< y2 ) {
trace("碰到了!!");
}

而我們要做碰撞反應的話,最簡單的方式就是:
當 點碰到上邊界時 --> y位移量 乘以 -1 (就是往反方向彈的意思)
當 點碰到下邊界時 --> y位移量 乘以 -1
當 點碰到左邊界時 --> x位移量 乘以 -1
當 點碰到右邊界時 --> x位移量 乘以 -1
所以上述的函式我們必需拆開變四部份才行:
if (x < x1 ) {
point.xmov *= -1;
point.tempx = x1;
}
if (x>x2) {
point.xmov *= -1;
point.tempx = x2;
}
//碰到上下邊界
if (y < y1 ) {
point.ymov *= -1;
point.tempy = y1;
}
if (y>y2) {
point.ymov *= -1;
point.tempy = y2;
}

原則大概就這樣吧


第二節 pong試做
範例檔:collisionReaction_2.fla

pong是一套經典且古老的電玩(關於它的歷史可能要另外寫一篇),應該很多人看過,如下圖

左右各一個上下移動的板子,碰到球就反彈,利用之前學過的技巧,這種遊戲是能夠很簡單地做出來的。
這部份我是以延用上一節的檔案來改的,跟原書中的寫法不太一樣,不過原理大致相同。

1.球跟周圍場景的互動跟上一節一樣,只是當碰到左邊界時,右方得一分,碰到右邊界時,左方得一分,並讓球回到場地中央重新開始。
2.球跟板子的互動,其實跟場景的互動原理類似,只是場景是把球框在裏面,而板子是把球彈在外面,因此將碰撞偵測的寫法修改一下:當發現球跟板子重疊時,就是碰到了。且碰到後,馬上將球的x位移量* -1。
3.玩家是操縱左邊板子,左板主要是跟隨滑鼠的y位置而定,另外加上"別讓板子超出場景"的預防措施
4.右板是代表電腦,電腦就直接跟隨球的y值,以範例中的ai設定,電腦幾乎是不會輸球的。不過沒差,這章不是要講ai,所以不用計較太多。

第三節 自由落體小球collisionReaction_3.fla

這節只是要做一個自由落體小球,落到地面上,又彈起,又落下,且速度一直衰減到靜止狀態
其實這個範例在前幾章就提過了(如果你也有看這本書的話就知)
不過這裏再複習一下而已。
我想這個練習的重點在於,位移量(速度)的動態變化吧

先做好球跟地板,再寫好球跟地板的碰撞,因為只有y值的變化,所以很簡單。
之後只要在ymov時,隨著時間累加一個g值(重力),
並在碰到地時,多乘一個衰減值。(否則球彈起高度跟落下高度太相近,感覺像在太空中)
如此而已。

由於這個範例在前面的章節就教過了,所以我就直接自己寫了,因此會跟書中內容不太一樣,不過原理是相同的。


第四節 球與線的碰撞反應
範例檔:collisionReaction_4.fla

前幾節討論的,都是水平、垂直的線條,我們只要比比xy值的大小就行了,但並不能應用於斜線上,這節的重點就是這個。
如果我的理解沒錯,我想原則在於:
先把球的前進向量拆解成兩個相互垂直的向量,其中一個向量與碰撞目標線平行,另一條則與它垂直。當發生碰撞後,垂直那條將會反轉。
圖解會是這樣吧

上圖是當球與線發生碰撞的瞬間,綠色線的方向及長度,代表球的前進向量。

上圖是表示,我們可以將綠色那條向量拆解成藍色那兩條相互垂直的向量,並注意一點,其中一條與碰撞目標線(粗黑)是平行的。

上圖,當發生碰撞後,與目標線垂直的那條向量會變反相,而平行的不變。反應後,可組成一條新的向量,即是球碰撞後的反射軌跡。

所以這部份的解題步驟應該是:
球的前進向量-->拆成與目標線平行、垂直兩部份-->將垂直那條反向-->組成新的前進向量
但是由於我們目前在as中,位移的方式是以xmov、ymov這種方式,而不是直接用向量的方式,所以這部份就變得更麻煩些:
球原本的xy位移量-->各別拆成與目標線平行、垂直兩部份-->將垂直那部份反向-->組成新的x y位移量
//函式:反應
function ballLineReaction(tempLine, point, x, y) {
//起始設定
var lineDecay = tempLine.lineDecay;
var alpha = tempLine.radian;
var cosAlpha = Math.cos(alpha);
var sinAlpha = Math.sin(alpha);
//取得球的x向量及y向量
var vyi = point.ymov;
var vxi = point.xmov;
//轉換為與目標線垂直之向量
var vVp = vyi*cosAlpha-vxi*sinAlpha;
//轉換為與目標線平行之向量
var vHp = vxi*cosAlpha+vyi*sinAlpha;
//反轉垂直向量
var vVfp = -vVp*lineDecay;
var vHfp = vHp;
//將之轉換回xy位移量
var vVf = vVfp*cosAlpha+vHfp*sinAlpha;
var vHf = vHfp*cosAlpha-vVfp*sinAlpha;
//將結果傳回給point
point.xmov = vHf;
point.ymov = vVf;
point.tempx = point.x+point.xmov;
point.tempy = point.y+point.ymov;
}

*這部份的as code,原書中的變數名稱與我的並不相同,原因是原書中都是用x y來取名,但我在看的時候卻常跟x y位移量搞混,所以都改成v(垂直)跟h(水平)


第五節 Conservation of Momentum and Energy(應該是動量及動能守恆吧?)
*這部份的概念還要多參考一些物理書才行…先挑範例來練習吧
*我的物理知識有限,如有錯,請務必告知

列出會用到的公式
p = mass*v; //動量公式
kinetic energy = (?)*mass*speed*speed //動能公式

假如做兩物體的碰撞
p1i = m1*v1i ; //物體1動量,碰撞前(i代表碰撞前)
p2i = m2*v2i //物體2
Pi = p1i+p2i //碰前動量總和

ke1i = (1/2)*m1*v1i*v1i //物體1碰撞前動能
ke2i = (1/2)*m2*v2i*v2i //物體2
KEi = ke1i+ke2i //碰撞前動能總和

////以下為碰撞後(f代表碰撞後)
p1f = m1*v1f
p2f = m2*v2f
Pf = p1f+p2f

ke1f = (1/2)*m1*v1f*v1f
ke2f = (1/2)*m2*v2f*v2f
KEf = ke1f+ke2f

///由於動量動能守恆
Pi = Pf = P
m1*v1i+m2*v2i = m1*v1f+m2*v2f
KEi = Kef
(1/2)*m1*v1i*v1i+(1/2)*m2*v2i*v2i = (1/2)*m1*v1f*v1f+(1/2)*m2*v2f*v2f

///整理後可導出
//**這個整理過程需要用到 (A*A-B*B)=(A-B)*(A+B)
v1i-v2i = v2f-v1f
V = v1i-v2i

//所以

v1f = v2f-V

//而我們最後需要的是

v2f = (P+V*m1)/(m1+m2)
v1f = v2f-v1i+v2i


(天啊,自己都快不知道自己在寫啥了,還是快找範例來練吧)


第六節 兩方塊的水平碰撞反應
範例檔:collisionReaction_5.fla

如果不計較物理理論的話,就直接引用上面的公式,放到as code中使用吧
在碰撞上,直接引用上一章的筆記中的矩形碰撞,而在偵測到碰撞後,呼叫這個函式就行了
//函式:碰撞反應
function reaction(a, b) {
var m1 = a.mass;
var m2 = b.mass;
var v1i = a.xmov;
var v2i = b.xmov;
var V = v1i-v2i;
var P = m1*v1i+m2*v2i;
//求碰撞後,物體b之速度
var v2f = (P+m1*V)/(m1+m2);
//求碰撞後,物體a之速度
var v1f = v2f-v1i+v2i;
//將答案傳回給各obj
a.xmov = v1f;
b.xmov = v2f;
//更新各obj之temp位移值
a.tempx = a.x+a.xmov;
b.tempx = b.x+b.xmov;
}

只看程式的話,好像滿簡單的。但背後的理論,還是不懂
(問了一些朋友,發現還會扯出一些"功"、"力"之類的,愈聽愈模糊-_-")


第七節 多個方塊的水平碰撞反應
範例檔:collisionReaction_6.fla

承接前一節範例,做成四個方塊的碰撞,並將四個方塊的質量設成不同的,可得到不同的碰撞反應速度
基本上,上一節的會寫的話,這節就沒什麼問題了,只是為了方便撰寫,用了一些回圈。
這個範例跟書中所附的不太一樣,因為我照書裏的寫(看懂別人寫的,比自己寫,來得更花時間)
不過原書的範例只花了七十多行,我倒寫了100行整-_-"。有書的人可對照參考看看…

第八節 球-球的碰撞反應
範例檔:collisionReaction_7.fla

用簡單點的方式來做筆記好了
1.球的碰撞偵測引用之前做的"不受限制的球球碰撞偵測"
2.碰撞反應則用類似之前做的"球與線的碰撞反應",將球與球的碰撞面當成之前的碰撞線,就差不多了:
將前進向量轉換為與碰撞面平行及垂直兩種。
將兩球的垂直的向量,以之前的一維碰撞的方式去解。平行的先不管。
垂直的算出結果後,再回來跟平行的結合並轉換回新的 x y 向量。


第九節 重力模擬
範例檔:collisionReaction_8.fla

照理說,碰撞反應教到這裏就差不多了,但書中最後還加了一個重力模擬的練習,拿來練練也不錯

我再次以自己的方法改寫,直接引用上一節的檔案,加了兩個東西
*因為要加很多球,所以先把大部份函式改以迴圈來跑
1.加上球跟四周的碰撞,這部份很簡單,當發現球超出場景時,反轉他碰到牆的那個向量
2.加上引力公式(又開始物理課了)
萬有引力公式: F=G*m1*m2/(d平方) F:引力,G:萬有引力常數,m1m2:兩物各別質量,d:兩物體距離
加速度公式:F=m*a ,所以 a1=F/m1 a2=F/m2 a:加速度
所以引力的函式會變這樣
//引力
function gravitation() {
for (var i = 1; i< =game.numBalls; i++) {
for (var j = i+1; j<=game.numBalls; j++) {
var ballA = eval("game.ball"+i);
var ballB = eval("game.ball"+j);
var dx = ballA.xpos-ballB.xpos;
var dy = ballA.ypos-ballB.ypos;
var d = dx*dx+dy*dy;
var F = G*ballA.mass*ballB.mass/d;
ballA.amov = F/ballA.mass;
ballB.amov = F/ballB.mass;
var angle = Math.atan2(dy, dx);
var sinAng = Math.sin(angle);
var cosAng = Math.cos(angle);
ballA.xmov -= ballA.amov*cosAng;
ballA.ymov -= ballA.amov*sinAng;
ballB.xmov += ballB.amov*cosAng;
ballB.ymov += ballB.amov*sinAng;
}
}
}

另一點特別要注意的是,由於這個範例又有引力又有碰撞等等因素,所以要特別注意資料更新的順序,否則會出現球跟球疊在一起,或是球卡在牆壁等靈異現象

後來回去看書中範例,發現它反而是用較簡便的寫法,就是沒有用 "不受frame限制"的那種…(被騙了)

另一個未解決的疑點,就是我寫的這個範例,必需以player6 做publish才能正常,若以player7做publish會在球碰到球後當住,語法都檢查過了,但還是不知原因…希望有人能給予指點…

讀後心得
這裏算是我個人的心得,與各位同好分享之
看到這邊總算看完這兩章了,我想這裏教的碰撞偵測及反應已可應付許多需要碰撞功能的遊戲了。
不過理論歸理論,真的用起來的實用性如何,倒還沒試過,(我指真的用在要開發的遊戲上)
例如一些動作遊戲在執行時,不會是只有一、兩個或三、四個物件要測碰撞的,可能是數十個或以上。
那麼跑起來的速率如何呢?跟最簡單的hitTest比呢?
我希望在下一個遊戲作品中確實用進去看看。
下個章節是要教tile-based的遊戲製作,很想繼續看下去,但最近要趕論文,只好暫時作罷 (-_-")

*關於物理方面的知識,個人推薦兩本書:

針對開發電玩程式會用到的物理知識做講解,天瓏有賣,600多。

.一生受用的公式
應該可以當方便的小手冊,天下網站賣144。

2003/12/8

FLASH的碰撞偵測

最近讀完FLASH MX Game Design Demystified這本書的Chapter 5. Collision Detection,這章節主要是介紹一些hitTest()所做不到,或有限制的碰撞。以下是我的筆記,有興趣的朋友可以參考看看。
.所有範例檔下載

前言
經常使用hitTest()的人應該都知道,hitTest有著一些限制,例如矩形範圍限制,即使hitTest(x,y,true)也只是解決一半的問題;還有frame by frame的限制,例如當位移量大於被偵測物時,那碰撞事件就會被忽略了。
總之這個章節是讓我們練習不用hitTest,自己手工打造碰撞偵測的方法。

第一節 點對圓的碰撞
範例檔:collision.fla

點對圓的碰撞是相當簡單的,因為你只要知道點跟圓的距離,及圓本身的半徑就能測到兩者是否碰撞了。
只要 點跟圓的距離 小於 圓的半徑 那麼就表示有碰到,反之則否。
這個範例中,如上圖的描述,我們放了兩個點,一個在圓內,一個在圓外,各別計算他們離圓心的距離,再跟圓的半徑比大小,就能知道是否碰撞了。

//碰撞函式
function collision(pointMc, cycleMc) {
var dx = cycleMc.x-pointMc.x;
var dy = cycleMc.y-pointMc.y;
var distance = Math.sqrt(dx*dx+dy*dy);
trace(pointMc.name+"離圓心的距離為:"+distance);
if (distance>cyc.radius) {
trace(pointMc.name+"沒碰到圓。");
} else {
trace(pointMc.name+"碰到圓了!");
}
}

第二節 圓對圓的碰撞
範例檔:collision2.fla

這節除了判斷碰撞外,還加上了圓的運動狀態。
圓跟圓的碰撞原理也是相當容易的。
同樣先取得兩圓心間的距離,再來只要比對兩圓半徑的和。
當 兩圓心間距離 小於 兩圓半徑的和 則表示有碰到。

//碰撞函式
function collision(obj1, obj2) {
var dx = obj1.x-obj2.x;
var dy = obj1.y-obj2.y;
var distance = Math.sqrt(dx*dx+dy*dy);
if (distance>(obj1.radius+obj2.radius)) {
trace("沒事");
//cFlag = false;
} else {
trace("啊!!!!!!!!!!!撞到了!");
//cFlag = true;
}
}

第三節 圓對圓-不受frame限制
範例檔:collision3.fla

我所謂的frame限制,是指在flash中的移動,是一個個frame來動的,例如你設的位移量可能是10,那麼在flash中,就是一次10px地跳躍式前進。但真實世界中可不是這樣的,真實世界中的移動是連續性的,而不是一秒跳多少公分這樣算的。但這種限制是無可避免的,因為flash就是這樣一套建立於frame基礎上的軟體。我們只能儘量地擺脫並模擬真實世界,但其最根源還是frame by frame的。

前兩節都有受限於這樣的frame限制,下面這個範例就是要來嘗試擺脫它了
它大概的原理是,在畫面上的圓要移到下一個位置時,事先算好是否會碰撞
也因此程式會比上述的麻煩些。它把時間因素加進去算,然後用一元二次方程式的公式去解。

//預先測碰撞
function collision(obj1, obj2) {
//設解答變數,若無解則為1
collisionTime = 1;
//設定位移變數
var xmov1 = obj1.xmov;
var ymov1 = obj1.ymov;
var xmov2 = obj2.xmov;
var ymov2 = obj2.ymov;
//設舊的位置變數
var xold1 = obj1.xpos;
var yold1 = obj1.ypos;
var xold2 = obj2.xpos;
var yold2 = obj2.ypos;
//定義公式所需之各小變數
var R = obj1.r+obj2.r;
var a = -2*xmov1*xmov2+xmov1*xmov1+xmov2*xmov2;
var b =-2*xold1*xmov2-2*xold2*xmov1+2*xold1*xmov1+2*xold2*xmov2;
var c =-2*xold1*xold2+xold1*xold1+xold2*xold2;
var d =-2*ymov1*ymov2+ymov1*ymov1+ymov2*ymov2;
var e =-2*yold1*ymov2-2*yold2*ymov1+2*yold1*ymov1+2*yold2*ymov2;
var f =-2*yold1*yold2+yold1*yold1+yold2*yold2;
var g = a+d;
var h = b+e;
var k = c+f-R*R;
//計算公式
var sqRoot = Math.sqrt(h*h-4*g*k);
var t1 = (-h+sqRoot)/(2*g);
var t2 = (-h-sqRoot)/(2*g);
//若第一個根小於1且大於0
if (t1>0 && t1< =1) {
collisionTime = t1;
cycleCollided = true;
}
//若第二根小於1且大於0
if (t2>0 && t2< =1) {
//且第二根小於第一根或是無第一根,則以第二根為解
if (collisionTime == null || t2<=t1) {
collisionTime = t2;
cycleCollided = true;
}
}
if (cycleCollided) {
//發出碰撞訊號
trace("碰到了!!");
}
}
二元二次就是像: aX平方+bX+c=0這種的 而解法是: 2a分之 -b 加減 根號 b平方-4ac (因為不會打數學符號,其實看圖比較清楚) 前面AS碼中,t1及t2代表兩個根 若這個根大於0且小於1的話,就代表他們有碰到了。 若兩個根都符合條件,那就取小的為答案。 照書中的範例弄出來的結果會像下圖 但我個人認為有個小缺失,就是它雖然脫離了frame的限制,抓到了碰撞訊號,但畫面中的球仍是疊在一起。也就是雖然抓到了訊號,也抓到了正確的碰撞時間,但最後沒有畫出正確的碰撞位置。 因此我加了小小的改進。把算出的碰撞時間,乘以其位移量,畫出正確的碰撞位置。 結果變成下圖 我想該書作者不是不知道啦… 也許是有別的考量,因此沒有在這?討論這個問題。 第四節 線與斜率 範例檔:collision4_drawLine.fla 這一節也是相當簡單,就是從已知的y軸截點b,及斜率m,畫出一條線。 斜率的公式我想大概是高中的吧 (沒讀過高中…這部份如果講錯,請指正) 斜率公式:斜率(m)=直邊(y)/橫邊(x) 斜率公式2:y=m*x+b (b為線與y軸之交界點y值) 然後用
_root.createEmptyMovieClip("clip", 1);
clip.lineStyle(0, 0x000000, 100);
line1 = {};
line1.m = 1;
line1.b = 100;
function findY(line, x) {
var y = line.m*x+line.b;
return y;
}
function drawLine(line) {
//決定一個 x
var x = 200;
//求得y
var y = findY(line, x);
//線的起點
clip.moveTo(x, y);
//決定另一個x
var x = 100;
//求另一個y
var y = findY(line, x);
//畫出線
clip.lineTo(x, y);
}
drawLine(line1);
可畫出來 相當容易的一個練習 第五節 線與線的交叉 範例檔:collision5_drawLine2.fla 當兩條的斜率不同,則此兩線將會交叉 這一節就是要做這個練習,先在場景中畫出兩斜率不同的線, 並求出其交叉點的位置 畫線的部份就如同上一節 求交叉點的部份原理如下 已知:y=m1*x+b1 y=m2*x+b2 所以:m1*x+b1=m2*x+b2 m1*x-m2*x=b2-b1 x=(b2-b1)/(m1-m2) 改寫成as code就是:
function findIntersection(line_a, line_b) {
var x = (line_b.b-line_a.b)/(line_a.m-line_b.m);
var y = line_a.m*x+line_a.b;
dot._x = x;
dot._y = y;
}
第六節 判斷碰撞是否發生 範例檔:collision6_drawLine3.fla 這一節仍是上一節的延伸, 上一次知道當斜率不同時,此兩線將會交叉,但不能得知這個交叉是否發生了。 一切也是延用上一節的做法,只是最後再判斷一下交叉點有沒有在線上。 而這個判斷法也只是用x、y值比比大小而已,所以不會太複雜。 所謂 兩線將會交叉,但目前未發生,就像 而目前已交叉會像 這樣應該很清楚了 重點如下
//判斷目前是否發生交叉
function collision(lineA, lineB) {
if ((dot._x>=lineA.x1 and dot._x< =lineA.x2) ||
(dot._x<=lineA.x1 and dot._x>=lineA.x2) || 
(dot._y>=lineA.y1 and dot._y< =lineA.y2) ||
(dot._y<=lineA.y1 and dot._y>=lineA.y2)) {
lineA.collision = true;
}
if ((dot._x>=lineB.x1 and dot._x< =lineB.x2) ||
(dot._x<=lineB.x1 and dot._x>=lineB.x2) ||
(dot._y>=lineB.y1 and dot._y< =lineB.y2) ||
(dot._y<=lineB.y1 and dot._y>=lineB.y2)) {
lineB.collision = true;
}
if (lineA.collision and lineB.collision) {
trace("目前發生碰撞了!!!!");
} else {
trace("目前沒事。");
}
}
第七節 球與線的碰撞 範例檔:collision7_cycleLine.fla 這節的主旨是偵測移動中的球與線之間的碰撞,書中提出四個步驟: step1.找出球的運動路徑與線的交叉點 step2.運用三角函數,找出球碰到線時的位置 step3.同上,找出球跟線碰到的接觸點 step4.計算從目前位置到碰觸位置所需的frame數(時間),若大於0小於等於1,則表示碰撞發生。 配合下圖解釋: 重點如下:
function getFrames(tempLine, point) {
//========Step 1============
//球路徑斜率
var slope2 = point.ymov/point.xmov;
//預防斜率無限大(垂直線)或無限小(水平線)狀況
if (slope2 == Number.POSITIVE_INFINITY) {
var slope2 = 1000000;
} else if (slope2 == Number.NEGATIVE_INFINITY) {
var slope2 = -1000000;
}
//球路徑的y軸截點b2
var b2 = point.y-slope2*point.x;
//求出球路徑與線的交叉點
var x = (b2-tempLine.b)/(tempLine.slope-slope2);
var y = tempLine.slope*x+tempLine.b;
//===========Step 2===============
//球路徑的角度
var theta = Math.atan2(point.ymov, point.xmov);
//球路徑與線之夾角
var gamma = theta-tempLine.angle;
//碰觸時,"球圓心"與"球路徑及線交叉點"之距離
var sinGamma = Math.sin(gamma);
var r = point.radius/sinGamma;
//求出碰觸時圓心座標 x, y
var x = x-r*Math.cos(theta);
var y = y-r*Math.sin(theta);
//==================Step 4================
//求出碰觸所需之frame數
var dis =Math.sqrt((x-point.x)*(x-point.x)+(y-point.y)*(y-point.y));
var vel =Math.sqrt(point.xmov*point.xmov+point.ymov*point.ymov);
var frames = dis/vel;
//======================Step 3=================
//找出碰觸點
//求tempLine.slope的垂直線=slope2a
var slope2a = -1/tempLine.slope;
var b2a = y-slope2a*x;
//碰觸點座標xa,ya
var xa = (tempLine.b-b2a)/(slope2a-tempLine.slope);
var ya = slope2a*xa+b2a;
//檢查碰觸點是否在線段上
if ((xa>tempLine.x1 && xa< templine .x2) ||(xa< tempLine.x1 && xa>tempLine.x2) ||((ya>tempLine.y1 && ya<templine .y2) ||(ya<tempLine.y1 && ya>tempLine.y2))) {
//是
} else {
//否
//讓frame數到1000
var frames = 1000;
}
return frames;
}
function getTempPositions() {
ball.tempx = ball.x+ball.xmov;
ball.tempy = ball.y+ball.ymov;
}
function bankCollisionDetect() {
for (var i = 0; i< linearray .length; ++i) {
var frame = getFrames(lineArray[i], ball);
if (frame<=1 && frame>0) {
//碰到了
trace("撞到了!!");
}
}
}
Step1就像之前介紹過的求兩線交叉點的方法。 Step2之所以會寫成這樣,可能就要看一下圖了
var theta = Math.atan2(point.ymov, point.xmov); //先求得theta角
var gamma = theta-tempLine.angle; //進而求得gamma角
var sinGamma = Math.sin(gamma);
var r = point.radius/sinGamma; //利用gamma角及圓半徑,取得r之長度
var x = x-r*Math.cos(theta); 
//利用r之長度,及之前找到的球路徑與線交叉點座標,來取得球碰撞時的圓心座標
var y = y-r*Math.sin(theta);
Step4 很簡單,只要知道目前離碰撞點的距離,除以每frame位移距離,就能得知目前到碰撞所需的frame數 Step3 要先知道,球跟線碰撞時,碰撞點跟圓心連成的那條半徑,必定是跟碰撞線形成垂直關係的。 所以我們把那條半徑算出來,再用之前介紹的線與線碰撞偵測,就能方便算出碰撞點的座標了。 最後再檢查這個點有沒有在碰撞線上,就大功告成了。 第八節 點跟矩形的碰撞偵測 範例檔:collision8_pointRectangle.fla 這節比上述幾節簡單許多,只用單純的比較x y大小而已 重點函式如下:
function pointRectangleDetection(point, rectangle) {
//點的位置
var x = point.x;
var y = point.y;
//矩形的左右邊界
var x1 = rectangle.x;
var x2 = x1+rectangle.width;
//上下邊界
var y1 = rectangle.y;
var y2 = y1+rectangle.height;
//以比大小方式,判斷點是否在矩形?
if (x>x1 && x< x2 && y>y1 && y< y2) {
trace("碰到了!!");
}
}
有一點值得討論一下 書中範例在最後執行的部份是這樣
EnterFrame = function() {
getTempPositions();
pointRectangleDetection(point1, rectangle1);
render();
};
所以當第一次發出碰撞訊號時,黑點其實已經畫到碰撞的下一格位置了。 要修正這點,我想可能要在render()之前做個判斷,或是乾脆把碰撞偵測跟render寫成一個function吧 不過這只是個範例,所以也不是那麼重要吧… 第九節 矩形跟矩形的碰撞偵測 範例檔:collision9_2rectangle.fla 矩形之所以簡單,是因為都是直角,也就是能夠直接用x y 值比一比就行了 (去年做的橫向捲軸demo,就是用這種方式) 這節也是用類似上一節的方式。比較兩矩形邊界的X Y值,來判斷是否碰撞。 後續討論 此章節主要內容大概就到這邊了,後面加了一些討論,順便記在這裏: 關於多邊形的碰撞呢?例如一個八角形跟一個球的碰撞該如何做? 用上述討論的球與線的碰撞,做八次就可以了 同理我們也可以做六角形、五角形、星形等複雜圖形的碰撞。 ch5總算k完了,接著ch6才是碰撞反應,趁這幾天有點空,一次把這兩章k完才算完整。

日本NBK株式會社社歌



這原本只是一家折屋公司的社歌,也許是太熱血了,於是便開始有人幫他畫人物設定op分鏡等等,最後還將它做成flash動畫,之後甚至還有英文版,更可怕的是還有"逆再生"版

滿搞笑的。

2003/12/1

3D FLASH WORLD競賽


由ElectricRain及thomasglyn合辦。

ElectricRain就是出swift3d及optimaze那家軟體公司。
thomasglyn(不知是一個人還是一個團體),專門製作具互動性的3d flash作品(用as去模擬)。

此比賽的目的,便是要結合上述兩單位的優點,希望參賽者能用render好的美美圖,加上flash的as程式去做控制,製作具互動性的3D FLASH作品。

Flash 3D Cheats Most Wanted

有興趣可以看看。
書本介紹範例觀看原始檔下載

感謝阿超介紹

Sound.ID3測試

所謂id3,各位聽過mp3的人都知,id3是儲存歌曲相關資訊的標籤格式,以winamp為例,在歌單上點選歌名,按右鍵選"檔案資訊",就可看到此歌的id3資訊。
在flash中也可調用id3資訊,透過下列方式:


就可得到歌名

*注意:中文不支援,即使用了System.useCodepage = true;也一樣。
*04/11/30追加:亂碼問題解決方案by云開

上面songname是一種屬性,其所有屬性如下

comment:註解
album:專輯
genre:類型
songname:歌名
artist:歌手
track:曲目
year:年份

以上是一個簡單的介紹,但若深入去研究它的help,會發現很多限制跟問題…
在Reading ID3 tags in MP3 files章節中提到:
Flash Player 7 supports version 1.0, 1.1, 2.3, and 2.4 tags; version 2.2 tags are not supported.

而取得id3資訊的指令也分兩種:大寫跟小寫,
例如:
my_sound.id3.comment

my_sound.ID3.COMM

其差別在於
小寫用於id3 version 1.0, 1.1 ,flash player6.0 r40後可用
大寫用於version 2.3 及2.4,flash player7後可用
小寫可用屬性如上述七種
大寫可用屬性有40種(真多啊~~)

所以請注意你的mp3的id3版本為何,有些是不支援的,像我的winamp是2.80中文版的,其ID3面板打開會分左右兩半,左半上面寫id3v1右半是id3v2,但測試結果,我用小寫的指令,卻抓到右半的id3v2,若我用大寫的指令,則抓不到東西。真是非常之奇怪

第二點很奇怪的
在help檔中,Sound.onID3單元中提到:
Description
Event handler; invoked each time new ID3 data is available for an MP3 file that you load using Sound.attachSound() or Sound.loadSound().
我想大概是說,這個onID3可用在以loadSound或attachSound載進的mp3檔案上,
但實驗結果是,只有loadSound的檔案叫得到id3,attachSound無效。

以上是我遇到的一些問題,如有人找出原因,麻煩指點一下。