Transcript 下載/瀏覽
第3章
基本遊戲架構:配對遊戲
南台科技大學
多媒體與電腦娛樂科學系
本章目的
第3章開始,每章都是遊戲範例
藉由“配對遊戲”了解如何規劃Flash遊
戲
應用第2章有學到的一些程式用法
練習規劃自己的遊戲
配對遊戲的概念
配對遊戲是網頁上常見的小遊戲
遊戲玩法如下…
使用卡片顯示兩張一對的圖片
一開始全部蓋牌
玩家翻到一樣的圖片就現牌
考驗記憶力
每次遊戲進行前進行亂數洗牌
製作配對遊戲的流程
首先要在畫面上排列卡片
每次玩之前要將卡片洗牌
再來偵測玩家的輸入
一次顯示兩張卡片
比較這兩張圖片是否相同
如果相同,將兩張卡片現牌
不果不同,將兩張卡片蓋回去
檢查是否所有成對的牌都可以找完
全部找完則結束遊戲
章節大綱
放置互動元素
遊戲進行方式
把遊戲封裝起來
增加得分和時鐘
增加遊戲特效
修改遊戲
放置互動元素
(page-84)
我們需要先產生一系列的卡片
因為卡片是成對的
看現在畫面上有幾張卡片
產生卡片數一半的圖片
例如:遊戲中有36張卡片,需要18張圖片
第一種方法:使用多個元件
在元件庫裡面準備18個不同的元件
每個元件代表一種牌
每個元件的背景都相同,放入不同的圖片
這種方法的缺點
需要修改卡片的美工圖形時,每個元件都要
修改
美工和程式人員配合時比較麻煩
第二種方法:使用一個元件
使用一份元件,在不同影格顯示不同圖片
相同的背景圖形可以放在獨立的圖層,每
個影格都看到到
方便修改元件內的美工圖形
設定Flash影片
MatchingGame1.fla
在元件庫內準備好Card影片片段
設定連結類別名稱Card,讓程式可以存取
元件的第一個是卡片背面(黑色)
Flash原始檔文件類別設定為MatchingGame1
(圖3.1) Card卡片元件
產生基本的ActionScript類別
MatchingGame1.as
// 先引入Flash內建類別
package
{
import flash.display.*;
// 宣告Flash放映檔的類別
// 類別名稱和放映檔名稱要相同, 都是“MatchingGame1”
public class MatchingGame1 extends MovieClip
{
//接下來在螢幕上產生36張卡片
// 先宣告MatchingGame1的建構函式
// 建構函式不需要回傳值,函式名稱和類別名稱要相同
public function MatchingGame1():void
{
// 建構函式內使用雙層迴圈產生卡片
// 產生6x6張卡片,每張間隔6像素
for(var x:uint=0;x<6;x++)
{
for(var y:uint=0;y<6;y++)
{
// 新增卡片物件
var thisCard:Card = new Card();
// 卡片先停在第一個影格
thisCard.stop();
// 設定卡片位置
thisCard.x = x*52+120;
thisCard.y = y*52+45;
// 把影片片段加入場景
addChild(thisCard);
} // End of second loop
} // End of first loop
} // End of 建構子
} // End of MatchGame1類別
} // End of package
執行結果
(圖3.4) 畫面上顯示36張卡片
使用常數宣告改進程式碼
使用範例:MatchingGame2.fla,MatchingGame2.as
注意事項
文件類別名稱記得設為MatchingGame2
類別宣告和建構函式宣告名稱都設為MatchingGame2
如果想要改變卡片數量(原本為6x6)
原本的寫法要修改迴圈參數
更好的方法是宣告常數來設定卡片數量
需要使用的遊戲常數
水平列數 = 6
垂直列數 = 6
水平間距 = 52
垂直間距 = 52
螢幕水平位移 = 120
螢幕垂直位移 = 45
public class MatchingGame2 extends MovieClip
{
// 所有遊戲常數
// private私有型態只能在類別內存取
// const常數型態代表遊戲內不能更改
// static靜態型態代表所有實體使用同樣的變數
private static const boardWidth:uint = 6; // 使用正整數unit儲存
private static const boardHeight:uint = 6; // 使用正整數unit儲存
private static const cardHorizontalSpacing:Number = 52; // 使用小數Number儲存
private static const cardVerticalSpacing:Number = 52; // 使用小數Number儲存
private static const boardOffsetX:Number = 120; // 使用小數Number儲存
private static const boardOffsetY:Number = 45; // 使用小數Number儲存
public function MatchingGame2():void
{
for(var x:uint=0;x<boardWidth;x++)
{
for(var y:uint=0;y<boardHeight;y++)
{
var thisCard:Card = new Card();
thisCard.stop();
thisCard.x = x*cardHorizontalSpacing + boardOffsetX;
thisCard.y = y*cardVerticalSpacing + boardOffsetY;
addChild(thisCard);
}
}
} // End of MatchingGame2建構函式
} // End of MatchingGame2
測試一下不同的數值有什麼不同…
洗牌和指定卡片
使用範例:MatchingGame3.fla,MatchingGame3.as
畫面上有36張牌,總共要有18對圖片
第2章的內容有提到如何使用亂數
洗牌機制
產生一個陣列,列出每一張牌
從陣列當中亂數挑選一張牌
實作
陣列長度36,列出兩張一組的18種卡片
畫面上產生6x6的牌型
從陣列內移除卡片,排到畫面上
排列完畢後,陣列是空的,所有卡片都在畫面上
洗牌程式碼
// 宣告一個陣列cardlist
var cardlist:Array = new Array();
// 依照牌型數目把數字存入陣列
for(var i:uint=0;i<boardWidth*boardHeight/2;i++)
{
// 一個迴圈參數存入兩次
cardlist.push(i);
cardlist.push(i);
}
試著把cardlist內容,看看是否像下面這樣
0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,
12,12,13,13,14,14,15,15,16,16,17,17
以下程式碼把卡片加入場景,並且將cardlist亂數指定給卡片
// 雙層迴圈
for(var x:uint=0;x<boardWidth;x++)
{
for(var y:uint=0;y<boardHeight;y++)
{
var c:Card = new Card(); // 新增一張卡片
c.stop(); // 卡片影片片段停在第一個影格
c.x = x*cardHorizontalSpacing+boardOffsetX; // 設定位置
c.y = y*cardVerticalSpacing+boardOffsetY;
// 依照陣列長度產生亂數, 長度36的話, 亂數在1~36之間
// 數學函式floor和random詳細用法查一下說明手冊
var r:uint = Math.floor(Math.random()*cardlist.length);
c.cardface = cardlist[r]; // 依照產生的亂數r設定使用哪個元件
cardlist.splice(r,1); // 把第r個單元從陣列內移除
c.gotoAndStop(c.cardface+2); // 依照使用第r個播放對應的影格
addChild(c); // 把卡片加入場景當中
}
}
MatchGame3的洗牌效果
回家練習題3-1
修改MatchGame3
產生一個環狀的牌型(一樣36張)
使用類似的亂數機制
將兩張一對的卡片加入環狀牌型
下週上課前上傳FTP繳交
遊戲進行
(page-95)
遊戲牌型設定完成
玩家用滑鼠點擊,找尋成對的卡片
必須追蹤遊戲狀態
檢查玩家點擊的是第一張還是第二張牌
檢查玩家是否檢查完所有卡片
增加滑鼠事件監聽器
使用範例:MatchingGame4.fla,MatchingGame4.as
第一步要讓卡片對滑鼠點擊有反應
針對畫面上每個物件都要加入事件監聽器
使用addEventListener函式
讓滑鼠點擊事件MouseEvent.CLICK發生時,呼叫
clickCard()函式,程式碼像這樣…
c.addEventListener(MouseEvent.CLICK,clickCard);
使用import輸入需要的類別,像這樣…
import flash.events.*;
以下是clickCard函式最簡單的寫法
public function clickCard(event:MouseEvent)
{
var thisCard:Card = (event.currentTarget as Card); // 點擊到哪一張牌
trace(thisCard.cardface);
}
參數event是關鍵,因為我們需要知道玩家點擊
的是36張牌的哪一張?
參數event是一個有很多屬性的物件,我們只需
要知道是哪個Card物件被點擊
被點擊的目標(target),是事件的currentTarget
被點擊的卡片存到thisCard,把cardFace屬性用
trace()印出來
★設定遊戲邏輯
(本單元比較複雜,也很重要…)
使用範例:MatchingGame5.fla,MatchingGame5.as
當玩家點擊一張牌,我們需要根據他們的選擇和遊
戲的狀態,來決定下一個步驟
遊戲狀態總共有三種
狀態1:還未選取任何卡片,玩家選取第一張牌準備配對
狀態2:已經選取一張牌,玩家選了第2張,必須比較兩張
是否相同,來決定採取什麼動作
狀態3:兩張牌已經被選取,但是兩張配對失敗。在選下
一張牌之前,兩張都先現牌。如果有選取新的牌,兩張再
蓋牌。
遊戲三個狀態示意圖
(圖3.6) 遊戲狀態1
(圖3.7) 遊戲狀態2
(圖3.8) 遊戲狀態3
還有一些其他考量
如果玩家選了一張牌,又再點選同一張
代表玩家想要收回第一張牌,我們應該把這張牌蓋回
去,並回到原本的狀態
我們需要追蹤選的是第一張或是第二張牌
宣告類別內的變數(型態都是Card)
private var firstCard:Card;
private var secondCard:Card;
這兩個變數預設值都是null,表示尚未被選取
判斷這兩個變數是否為null,來決定遊戲狀態
如果firstCard和secondCard都是null
代表目前在狀態1,玩家準備選取第一張牌
如果firstCard不是null,secondCard是null
代表目前在狀態2,玩家準備選取下一張牌,來配對
第一張牌
如果firstCard和secondCard都不是null
代表目前在狀態3
我們會使用firstCard和secondCard裡面儲存的數值,
來決定玩家選取下一張牌時,哪兩張牌要重新蓋牌。
看一下程式碼…
public function clickCard(event:MouseEvent)
{
// 儲存點擊的是哪張牌
var thisCard:Card = (event.target as Card);
// 如果第一張牌還未被選取
if (firstCard == null)
{
// 把這次點擊的卡片儲存到第一張牌
firstCard = thisCard;
// 把這張卡片翻開,卡片類型編號儲存在cardface變數
firstCard.gotoAndStop(thisCard.cardface+2);
回想一下,36張牌共有18種牌,編號0~17,放置在第
2~19個影格(看一下元件庫內的Card影片片段)
接下來的程式碼處理,玩家又點擊到第一張牌
}
// 如果又是按到第一張牌
else if (firstCard == thisCard)
{
firstCard.gotoAndStop(1); // 把這張牌翻回去
firstCard = null; // 清除第一張牌儲存的卡片
如果玩家第二張牌是選到不同的牌,需要比較兩張牌
直接使用cardface屬性來比較,如果兩張牌相同,則配對
成功
}
// 如果第二張牌尚未選取
else if (secondCard == null)
{
secondCard = thisCard; // 把點擊的牌儲存為第二張牌
// 把點擊的第二張牌掀開
secondCard.gotoAndStop(thisCard.cardface+2);
// 比較兩張牌是否相同
if (firstCard.cardface == secondCard.cardface)
{
有配對成功的話…
需要移除卡片 -> 使用removeChild(和addChild相反)
重設firstCard和secondCard變數值(設回null)
// 把兩張牌從場景上移除
removeChild(firstCard);
removeChild(secondCard);
// 重設紀錄兩張牌的變數值
firstCard = null;
secondCard = null;
}
最後一種狀況
玩家選了第一張牌,又選了第二張,但是兩張配對失敗,
尚未點擊新的牌
必須把兩張牌蓋回去(也就是播放的Card影片片段第1個影
格)
}
// 準備選取另一張牌
else
{
// 把前兩張牌蓋回去(播放第1個影格)
firstCard.gotoAndStop(1);
secondCard.gotoAndStop(1);
secondCard = null; // 重設第二張牌
firstCard = thisCard; // 第一張牌設為現在選取的牌
// 第一張牌掀開, 依照卡片編號cardface播放影格
firstCard.gotoAndStop(thisCard.cardface+2);
}
}
回家練習題3-2
替本學期進行的Flash遊戲規劃遊戲邏輯
確定自己遊戲的完整玩法
討論各種可能的遊戲狀態
繪製簡易的流程圖
撰寫Pseudo-code
使用判斷式加上文字描述
整理成簡報檔
下週上課時發表簡報,與老師討論後修改,繳交
簡報檔
檢查遊戲是否結束
使用範例:MatchingGame6.fla,MatchingGame6.as
所有卡片都被移除代表遊戲結束
有一些做法來處理
方法1:使用一個變數來儲存已經找到幾對卡片,找到一
對變數值增加1
方法2:檢查MatchingGame物件的numChildren屬性,新
增36張牌,代表numChildren為36。所有卡片被移除,代
表numChild為0
方法1可以,方法2會有問題
場景中若有其他物件,numChildren數量也會算進去
最後採用方法1,稍微修改想法…
計算已經翻開的卡片數
新增一個類別變數
private var cardsLeft:uint;
用迴圈新增卡片之前,先把cardLeft設為0
每新增一張卡片,cardLeft增加1
cardsLeft = 0; // 剩餘卡片初始值設為0
for(var x:uint=0;x<boardWidth;x++)
{
for(var y:uint=0;y<boardHeight;y++)
{
var c:Card = new Card(); // 新增卡片
c.stop(); // 卡片停在第一個影格
c.x = x*cardHorizontalSpacing+boardOffsetX; // 設定位置
c.y = y*cardVerticalSpacing+boardOffsetY;
var r:uint = Math.floor(Math.random()*cardlist.length);
c.cardface = cardlist[r]; // 設定卡片編號
cardlist.splice(r,1); // 把卡片編號從陣列中移除
c.addEventListener(MouseEvent.CLICK,clickCard);
addChild(c); // 卡片加入場景當中
cardsLeft++; // 累加剩餘卡片數目
}
}
clickCard函式內,卡片配對成功,卡片從場景內移除
cardsLeft -= 2; // 每次配對成功剩餘卡片數累減2
if (cardsLeft == 0) // 當已經沒有剩下卡片
{
gotoAndStop(“gameover”); // 播放gameover影格標籤
}
(圖3.9) 遊戲結束畫面
把遊戲封裝起來
(page-102)
使用範例:MatchingGame7.fla,MatchingGame7.as
產生遊戲影片片段
加入介紹畫面
加入“再玩一次”按鈕
加入得分和時鐘
(page-106)
使用範例:MatchingGame8.fla,MatchingGame8.as
加入時鐘
顯示時間
遊戲結束時顯示得分與時間
使用範例:MatchingGame8.fla,MatchingGame8.as
增加遊戲特效
(page-113)
卡片翻面動畫
限制卡片觀看時間
聲音效果
修改遊戲
(page-119)