下載/瀏覽

Download Report

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)