顯示具有 95360334 許達易 標籤的文章。 顯示所有文章
顯示具有 95360334 許達易 標籤的文章。 顯示所有文章

2009年6月25日 星期四

期末專案 - 串丸子



遊戲操作:
開啟遊戲後,點選左上角視訊裝置->連線
物件偵測->建立背景
物件偵測->偵測on
當竹籤漂到螢幕最上方後,先伸出手測試竹籤會不會移動
然後再按Start即可開始遊戲
要結束遊戲,按 Stop
把手放在左下角,過一段時間後,遊戲會重新開始

參數設定:
將遊戲畫面切換到 test分頁
Down Speed: 貢丸Image降下的周期
Add Speed: 新增一個貢丸Image的週期
Distance: 貢丸Image下降移動的距離, 遊戲等級增加後,貢丸Image下降距離的增加量
Lv up:經過多久等級才會上升
Game Over:經過多久遊戲會自動結束
Game Win:獲得多少分才會贏
Game Restart: 手放在左下角多久才會重新開始


遊戲實作過程敘述:
1. 竹籤的移動
當決定要做「串丸子」這個遊戲後
第一個想到的就是用竹籤去串
所以首先要做的就是竹籤的移動
因為遊戲中,只有7排的貢丸會掉下來
所以將二元圖劃分成8個區塊


當某個區塊的白點累積到一定的數量後,竹籤就移動過去

如圖中,竹籤應該移動到D區的位子(C區白點太少)

但是 E,F,G,H 這四區也是有一堆白點
總不能讓竹籤在這五個區塊中亂跳
所以採用多層 if else 當作優先權判定
先判斷最左邊區塊的白點是否累積到指定數量
如果有,竹籤移動到該區,後面的就不理
如果沒有,就再判斷下一區塊的白點數量

2. 落下的貢丸
竹籤會動之後,再來要弄的是往下掉的貢丸


如圖,一共有7排的貢丸在起始的位子上
每一排各有兩顆疊在一起
總計有14個
原本以為很簡單的,就是讓Image往下移動嘛
改一下每個Image的Top,讓Image會往下移動
然後當Image超出視窗後就消失、回到起始點上就好啦
但是並非如此 ...

首先,用一個Timer元件 (Name:Down)
讓Image在每過一段時間就往下移動一次
接著,正常的遊戲中
貢丸不可能全部一起出現一起掉
所以一定要安排先後出現的順序
而且總計只有14個有貢丸Image
資源有限,所以只好自己想一個演算法來解決這個問題
( 要放5、600個貢丸Image來弄也是可以
但是我覺得這樣很蠢,同樣的東西放這麼多 ... 不僅浪費空間,做的時候也浪費時間 )


3. 串貢丸
竹籤和貢丸都會動之後,再來要想的就是竹籤串貢丸
原本要做的功能是,竹籤要從右邊移動到左邊,"串"到貢丸才會消失、計分
利用一個 Bamboo_mark 儲存竹籤出現的上一個位置
如果竹籤現在的位置小於Bamboo_mark
在此條件成立下,表示竹籤是從右邊串過來的
這樣竹籤碰到貢丸Image才會得分

但是程式寫好後,並沒有達到預期的效果
現在還沒想到合適的演算法去操作,所以還是只能維持原樣
竹籤一"碰"到貢丸就消失 ...

以上三個為最主要的部分
其他的就是debug和一堆拉哩拉雜的 ...


心得:

這學期印象最深的應該就是callback function吧
老師跟同學們討論了很久

再來是操作視訊的code
雖然大二時已經有學過
雖然講義一模一樣
但是這學期老師教的是另外一種方式

大二時用的是使用Timer元件
每隔一段時間就取一張圖

而這學期學到的是利用callback function
每當視訊有擷取新的資料傳入,視窗裡的畫面就會即時更新

二元圖也是
之前學的就是直接劃分黑色白色
而這次老師教的是將畫面切分為一格一格的小方塊再分黑白兩色
一格一格的其實還挺有趣的
對 有趣


最後的暑期夏令營
很集中的煎熬
感覺像是放暑假前的熱身(?)

CAM Game Show 2009 照片 (26 June 2009):


許達易展示成果! (25 June 2009)


串丸子之執行畫面! (26 June 2009)
 

2009年5月15日 星期五

期末專案構想

1. 塗鴉大師



以手掌當畫筆,照指示將指定區域內著色

依照完成時間的長短和符合度給予分數


2. 消除方塊



==>

感應手掌停留的位置,按住相同的方塊即消除

3. 電流急急棒




4. 高爾夫球

以球竿(掃把)揮動的情況計算白球飛出的角度和速度

5. 串丸子




6. 競速規避賽

模擬戰機or賽車遊戲

在畫面中央有一台賽車/飛機

跟著賽道奔跑的同時,也會有障礙物出現

躲避障礙物才不會落後

操作方式:

飛機:兩手打直張開,以左右反向傾斜的方式表示往左/右
   以傾斜的角度表示過彎角度

賽車:以身體左右傾斜表示左/右轉,可以給玩的人一個方向盤
   往左上/右上表示大幅度過彎

校準:因玩的人體型、身高不同,所以需要校準對應人影


7. Halli Galli 水果心臟病

遊戲畫面:

1.先選擇使用人數 2-6 後,程式自行切換不同的人數使用介面

2.介面改成固定六人遊戲模式,但是依使用者數量開放手印區
 比誰的手先蓋滿手印區得勝

3.中央一個固定的服務鈴,以手伸進去的方向 & 速度判斷是誰搶到



程式:

依順序翻牌,遊戲中需要一直截取影像,因為會有人拍錯

每X秒擷取一次畫面,計算手印區(1,2)/各方向(3)的白點數量

同時伸進的話,以白點數量多的為勝

判斷有手伸進時,螢幕上會同步顯示一隻卡通手掌


優化:

scan一整張圖片尋找白點可能會太耗時間

改為每個方向都有一條固定的,接往服務鈴的直線

當有手伸進去時,判斷某一方向的直線上是否佈滿白點

且直線上的白點分佈率即為卡通手掌伸出的比率


Problem:如果兩人同時且差異不大,無法判斷是誰的手壓在下面

2009年3月5日 星期四

我對 Scanline

一點點看法 看過就好

首先要說明的是,在講義 1.2.2 儲存影像陣列裡的
第一部分程式碼 (page.14)

 TCanvas *csBuf=new TCanvas;
 HDC hDC=GetDC(Panel->Handle);
 csBuf->Handle=hDC;

 Graphics::TBitmap*Source=new Graphics::TBitmap();

 Source->Width=Panel->Width;

 Source->Height=Panel->Height;

 Source->Canvas->CopyRect(Rect(0, 0, Source->Width, Source->Height),

              csBuf,
              Rect(0, 0, Panel->Width, Panel->Height));
 Image->Picture->Bitmap->Assign(Source);


 for(i=0;i<BitmapInfoHead.biHeight;i++)
 {
  ptr=(Byte *) Image->Picture->Bitmap->ScanLine[i];
  for(k=0,j=0;j<BitmapInfoHead.biWidth;j++)
  {
   background[i][j][0] =ptr[k+2];
   background[i][j][1]= ptr[k+1];
   background[i][j][2] =ptr[k];
   k+=3;
  }
 }
只要key in藍色部分,就會顯示出來一張圖了!!
顯示圖片靠 Image->Picture->Bitmap->Assign(Source);裡的Assign( )函數
(我覺得這範例寫得不好,傳回給source會影響截圖計算,
可能會給初學者錯誤的觀點,所以我改成background

而且範例需要修改正確 ... 講義上都是不完整的code)

至於使用Scanline的部分正如敘述所說,是將像素值輸入到陣列中
是給後續使用的,跟顯示影像無關
如果你只是想顯示一張擷取的影像,請不要理後續Scanline的部分

這樣瞭解了吧?
anyway, 下面接著講 Scanline


=========================================

 ptr=(Byte*) Image->Picture->Bitmap->ScanLine[i];


就是這條混蛋指令讓人死一堆腦細胞
ptr是什麼? 為什麼可以這樣做?? Scanline的功能???

首先,對於這條指令,還必須得宣告 Byte *ptr;才能使用
也就是如下:
 Byte *ptr;
 ptr=(Byte *) Image->Picture->Bitmap->ScanLine[i];

ptr是個Byte型態的變數,加個星號就是指標嘛
所以 *ptr儲存的是Byte型態的記憶體位址

(Byte *)Image->Picture->Bitmap->ScanLine[i];
是該Image,第 i行(height)的起始位置


以此3x3的圖為例,
 (Byte*)Image->Picture->Bitmap->ScanLine[0]; 回傳的就是0xA0
 (Byte*)Image->Picture->Bitmap->ScanLine[1]; 回傳的就是0xB0
 (Byte*)Image->Picture->Bitmap->ScanLine[2]; 回傳的就是0xC0

用很白話的講,Scanline就是掃瞄一條線,

他指向某條水平線第一個點的位子

如果你要問我為什麼要加
(Byte*) ?
別傻了,單純用Image->Picture->Bitmap->ScanLine[i];
跑出來的應該是RGB的值吧
我猜的

想多認識(Byte*)可以參考此網誌
http://www.wretch.cc/blog/hhmmjj/9594208




這樣應該懂Scanline是做什麼的了吧?
所以,
 for(i=0;i<BitmapInfoHead.biHeight;i++)
 {
  ptr=(Byte *) Image->Picture->Bitmap->ScanLine[i];
  for(k=0,j=0;j<BitmapInfoHead.biWidth;j++)
  {
   background[i][j][0] =ptr[k+2];
   background[i][j][1]= ptr[k+1];
   background[i][j][2] =ptr[k];
   k+=3;
  }
 }
這段,其實就是將Image裡每個pixel的RGB值傳給background
讓你可以將background的值累加起來後取平均,
然後把background顯示出來,就可以得到視訊的背景圖了



再囉嗦一點

上一篇文章作者提到因不懂Scanline
所以改用GetRValue()、GetGValue()、GetBValue()
去擷取Image的RGB值

這兩者有什麼差異?
最大的差異就是在執行速度吧

上禮拜在作業系統的課上老師有提到,
以前ANSI C用來寫OS的武器之一就是指標 => *

用指標直接存取記憶體的速度本來就較快,
更何況用了三個函數才能去得RGB值

假設
ptr[k]    取出R值的速度是0.01秒
GetRValue() 取出R值的速度是0.1秒
相差10倍

每一個pixel有RGB三個值,等於需要花 0.03 : 0.3
一張800x600的圖片有480000個pixel
這樣用函數取RGB所花的時間會比用指標多花上10x480000倍 ...
應該是這樣算吧,我只是舉例有錯不能怪我



還有一張圖畫了沒用到,不管,我還是要放上來



p.s.
在blogspot可以利用修改css,讓文章內可以有個物件包住程式碼
  看起來也比較美觀 ...
  可以參考這篇文章修改:【Blog】文章中引用程式碼的作法

=================================================

附錄: i++ v.s. ++i

老師說這個不會也不影響寫程式是沒錯
但是多瞭解一些還是可以幫助釐清觀念
尤其是上arping的課如果有要寫程式時,沒分清楚可能就哉了
雖然我也沒很懂,簡易的描述使用上的差異應該還是ok的

把寫好的程式進行編譯時,
編譯器也是從上到下,由左至右讀取文字判斷要編譯成什麼樣的低階語言
所以
 i++; 編譯器先讀到 i 再讀到++,所以把 i 加1
 ++i; 編譯器先讀到++,再讀到 i ,接著把 i 加1
看起來意思都相同,但這是因為這兩句語法都是獨立使用

如果程式碼長這樣呢?
 int a[3]={0,0,0};
 i=0;
 a[i++]=1;
 i=0;
 a[++i]=1;
看起來似乎都是把a[1]的值變成1,輸出就會是 {0,1,0} 對吧?
其實執行結果陣列a的內容會是這樣 => {1,1,0}

 i=0;
 a[i++]=1;
編譯器會先把 i 提出來,並把 i 的值,0給a[]使用
然後才做 i++
所以這裡其實是 a[0]=1; i 的值為1

 i=0;
 a[++i]=1;
編譯器會先執行 ++ 的動作,也就是把 i 加1之後,
才把 i 的值,1給a[]使用
也就是這裡其實是 a[1]=1; i 的值為1

所以真正的執行結果陣列a的內容會是 {1,1,0}

就我的印象,arping好像還講過 i++ 和 ++i 在執行上還有別的差異
那時他沒多講我也沒多問就 .... 現在就不會了


 i=0;
 a[(i++)]=2;
你覺得陣列a之中哪個位置會變成2?

 i=1;
 c = (i++)+(++i)+(i++)+(++i)+i+(i++)+(++i);
最後c的值會是多少?

我用手算是29,用Dev-C++執行結果卻是19
怎麼會這樣 ... ??? (使用不同的IDE可能會有不同的執行結果)

試試看吧 很好玩的 :D