javascrip 小遊戲小技巧教學7(簡易對話框教學)

這次範例演練的是:
填寫人名,按下開始進行劇情。
當劇情中有選擇時,
依照不同的選擇做安排。

 

其實是心血來潮,
所以將教學6後面的跳過,先教7的~
總之,
第7章教學的目標就是將我的遊戲"獨二無三"從C#遊戲轉變成網頁版~(儲存功能則交由cookie)
有空也會改成flash版。

為了循序漸進的教學,
這次範例演練的是:
填寫人名,按下開始進行劇情。
當劇情中有選擇時,
依照不同的選擇做安排。

先上網址:

http://www.googledrive.com/host/0B7hg_8WvMyfJV0JFM3RHRGNvMGM

強烈建議將範例下載下來,在你電腦跑跑看(也比較流暢)。
也可以注意到這次將圖檔都放在images資料夾中,
比較好做管理。

因為有上註解了,

就直接貼程式碼再進行補充:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Lesson 7</title>
</head>
<style type="text/css">
.bg{
	position: absolute;
	left:0px;
	top:0px;
	width: 454px;
	height: 340px;
	z-index: -1000;
}
#scene_init{
	background:url(images/intro.jpg);
}
#lbName{
	position: absolute;
	left:70px;
	top:120px;
	font-size: 24px;
	font-weight:bold;
}
#txName{
	position: absolute;
	left:160px;
	top:120px;
	font-size: 24px;
	width:200px;
}
#btnStart{
	position: absolute;
	left:100px;
	top:180px;
	width: 250px;
	height: 40px;
	font-size:21px;
	cursor:pointer;
}
div{
	font-size: 48px;
	-webkit-touch-callout: none; /* iOS Safari */
	-webkit-user-select: none;   /* Chrome/Safari/Opera */
	-khtml-user-select: none;    /* Konqueror */
	-moz-user-select: none;      /* Firefox */
	-ms-user-select: none;       /* IE/Edge */
	user-select: none;           /* non-prefixed version, currently
				  					not supported by any browser */
	cursor:default;
}
#scene_plot{
	background:url(images/school.jpg);
}
#character{
	position: absolute;
	left:10px;
	top:220px;
	width: 108px;
	height: 110px;
	background:url(images/IConfuse.jpg);
}
#convers{
	position: absolute;
	left:130px;
	top:220px;
	width: 290px;
	height: 90px;
	background:#FFFFFF;
	padding:10px;
	font-size:18px;
}
#sensor{
	z-index:1000;	/* sensor類似於背景,但是變成全景點選,因此要改在最前面 */
}
#select1,#select2{ cursor: pointer; font-size:24px; position:absolute; left: 150px; z-index: 1500; }
#select1{
	top: 240px;
}
#select2{
	top: 280px;
}
</style>
<body>
<!-- choice part -->
<div id="select2">456</div>
<div id="select1">123</div>
<!-- plot part -->
<div id="sensor" class="bg"></div>
<div id="convers">終於下課了......</div>
<div id="character"></div>
<div id="scene_plot" class="bg"></div>
<!-- end plot -->
<!-- init start -->
<div id="lbName">主角名:</div><input type="text" id="txName" autofocus value="永馨">
<input type="button" id="btnStart" value="開始">
<div id="scene_init" class="bg"></div>
<!-- end init -->
</body>
<script type="text/javascript">
var roleplayer=getById("txName").value;			//若使用者沒修改,就是預設的名稱:永馨
var initArr=new Array("lbName","txName","btnStart","scene_init");
var plotArr=new Array("character","convers","sensor","scene_plot");
var scene=0;									//現在是哪個場景
//這個陣列是用來對應每個角色的不同個性的圖檔,就不用記檔名了
var player=[];
player["I"]={normal: "I",happy: "IHappy",sad: "ISad",confused: "IConfuse", urgent: "IUrgent", end: "IEnd"};
player["Jen"]={normal: "Jen",happy: "JenHappy",sad: "JenSad", end: "JenEnd"};
player["her"]={normal: "her",happy: "herHappy",sad: "herSad", end: "herEnd"};
//這個陣列儲存每個場景的人物是哪個圖檔(統一jpg檔所以只要存檔名不用附檔名)
var charArr=new Array(player["I"].confused,player["Jen"].normal,player["I"].normal,player["Jen"].normal,player["I"].normal,player["Jen"].happy,player["Jen"].sad);
//這個陣列儲存每個場景是否可以按下一頁(換到下個對話或動作),若是數字則跳到抉擇陣列的部分
var cntiArr=new Array(true,true,true,false,0,true,true);
//這個陣列儲存每個場景的背景
var bgArr=new Array("school","school","school","school","school","school","school");
//這個陣列是儲存抉擇的部分
var choice=[];
choice[0]=new Array("嗯!","我有事......");
//這個陣列儲存每個場景人物的對話
var convArr=[];
//簡寫各個元件
var character=getById("character"), plot=getById("scene_plot"), conv=getById("convers"), sensor=getById("sensor"), select1=getById("select1"), select2=getById("select2");
//一開始將其他場景隱藏
hideArr(plotArr);
//一開始將抉擇隱藏
hideChoice();

/*******************************初始畫面(輸入主角按名並開始)******************************/
getById("btnStart").onclick=function(){
	roleplayer=getById("txName").value;			//假如使用者修改過名字,這個值就不會是預設的"永馨"
	//接著將場景切換到一開始的劇情(可按跳過!)
	//場景是由背景圖、人物框、對話框組成
	hideArr(initArr);		//先關閉按下開始的畫面
	showArr(plotArr);
}
/*************************************這邊處理劇情部分***********************************/
sensor.onclick=function(){
	//這個陣列比較特別,因為我們的roleplayer會隨著使用者輸入後修改,因此要放在這邊設定
	//若原本的部分是抉擇,就將對話統一改成false,讓陣列與陣列對齊
	convArr=new Array("終於下課了......","任同學:"+roleplayer+",妳有空嗎?",roleplayer+":有呀,怎麼了?","任同學:妳願意來我家玩嗎?",false,"任同學:真高興!","任同學:這樣呀......好吧......");
	if(cntiArr[scene]){
		if((scene+1)<charArr.length){			//以防練習時出錯(超出陣列範圍)
			scene++;
			character.style.background="url(images/"+charArr[scene]+".jpg)";
			conv.innerHTML=convArr[scene];
			plot.style.background="url(images/"+bgArr[scene]+".jpg)";
		}
	}else{
		//會需要抉擇的場景
		if((scene+1)<charArr.length){			//以防練習時出錯(超出陣列範圍)
			scene++;
			character.style.background="url(images/"+charArr[scene]+".jpg)";
			//將對話與切換下個場景的sensor隱藏
			hideConv();
			//接著顯示抉擇選項(此處只有兩種選擇
			//這邊顯示抉擇的選項有點複雜,
			//根據上面的cntiArr陣列,我們的第一個抉擇(其實是陣列的第一個索引,也就是從0開始)是0
			//而對應到了choice陣列,choice陣列的第一個(索引從0開始)抉擇選項是一個陣列
			//而這個陣列的第一個選項是"嗯!"、第二個選項是"我有事......"
			//因此遇到抉擇時就這樣以此類推。
			select1.innerHTML=choice[parseInt(cntiArr[scene])][0];
			select2.innerHTML=choice[parseInt(cntiArr[scene])][1];
			show(select1);
			show(select2);
			//這邊處理使用者點擊選項後的結果
			//使用者選擇的結果只有兩種:
			//1:繼續下一個對話(可能是下一段劇情,或者詢問者給予你的抉擇做感想)
			//2:切換畫面為位置選單(也就是可以到其他地點)
			select1.onclick=function(){
				if(parseInt(cntiArr[scene])==0){
					scene++;
					character.style.background="url(images/"+charArr[scene]+".jpg)";
					conv.innerHTML=convArr[scene];
					plot.style.background="url(images/"+bgArr[scene]+".jpg)";
					hideChoice();
				}
			}
			select2.onclick=function(){
				if(parseInt(cntiArr[scene])==0){
					scene++;
					character.style.background="url(images/"+charArr[scene]+".jpg)";
					conv.innerHTML=convArr[scene];
					plot.style.background="url(images/"+bgArr[scene]+".jpg)";
					hideChoice();
					show(sensor);
					fireClick(sensor);
				}
			}
			plot.style.background="url(images/"+bgArr[scene]+".jpg)";
		}
	}
}
/******************這個部分是給你測試不同的劇情畫面的切換******************/
/*hideArr(initArr);
scene=2;
fireClick(sensor);
*/
function getById(id){
	return document.getElementById(id);
}
function hideArr(arr){
	for(var i in arr){
		getById(arr[i]).style.display="none";
	}
}
function showArr(arr){
	for(var i in arr){
		getById(arr[i]).style.display="block";
	}
}
function hide(elem){
	elem.style.display="none";
}
function show(elem){
	elem.style.display="block";
}
function hideConv(){
	conv.innerHTML="";
	hide(sensor);
}
function hideChoice(){
	hide(select1);
	hide(select2);
}
//觸發點擊事件的方法
function fireClick(node){
	// 不同瀏覽器有不同的寫法
	if ( document.createEvent ) {
		var evt = document.createEvent('MouseEvents');
		evt.initEvent('click', true, false);
		node.dispatchEvent(evt);	
	} else if( document.createEventObject ) {
		node.fireEvent('onclick') ;	
	} else if (typeof node.onclick == 'function' ) {
		node.onclick();	
	}
}
</script>
</html>

我在html(DOM)裡有用<!-- -->作註解,
所以就可以看出這個部分是用來做什麼的。

從最上面的css部份看到#select1,#select2這裡,
這表示如果有兩個以上元件需要設定一樣的數值時,就用這樣的方式一起設定,
而有個別的差異時,
才用#select1設定各自的。

而select1與select2的div中間的123和456,則是讓你在畫面切換時,更好對準位置。
在該顯示的時候會將123和456改成我們要的值。

這邊陣列的處理相當重要!
以前我是用var i去記錄使用者點到哪個狀態了,然後再用if..else..去做處理......當然就是耗時,且很容易牽一髮動全身Orz
簡單來說就是用陣列去跑劇情。
我把陣列分成幾個:
人物頭像、是否可到下個畫面(按感應區域跳到下一個情境)、背景畫面、人物對話。

除了人物對話陣列,都可以直接在變數編寫內容。
而人物對話的部分,則是改到sensor部分做修改,
這是因為我們可以改主角的名字,
因此要隨時取得修改後的名字。

由於抉擇跟跑劇情是不同的處理方式,所以我在cntiArr陣列約法三章,
若此時的值是false,表示他的下一個畫面是抉擇,而再下一個則是抉擇的對話選項,
因此false後面接0,
這0是對應對話選項的陣列choice,
而select1與select2也依據目前的抉擇是第幾個(雖然目前只有一個),
才做if...else...的處理。
這樣的話,原本才4格的劇情要用到4個if...else....,
現在就直接跑陣列就能解決問題,
而抉擇對話部分也交由choice陣列幫我們顯示選項,
其他就在select1與select2各自分析即可。
因此比較麻煩、還需要人工的就是select1與select2了。

最後,
後面的fireClick是上網找的,
也就是利用程式模擬按下(click)的動作。

而這邊也有一個區域是可以讓你瞬間跳到第n個畫面(雖然這個n一定要小於陣列長度),
找錯誤時就會比較好找了。(不用每次都從按開始那頁做測試)

而圖片切換部分,也演示了將路徑加入檔名的方式。
也希望能把圖片分另外資料夾的習慣學起來喔!

有空的話就是把itemBar教完還有進入到跑文字地圖切換場景的教學囉~