javascript 小遊戲小技巧教學6(物品欄教學1)

遊戲中的物品欄教學,以2x3為例。點擊後選取,再點擊取消。

今天要教的是物品欄~
目前的目標是點擊東西得到物品,並且可以在物品欄點擊選擇物品、再點擊一次則取消選擇物品。
這次的範例為了模擬遊戲情境,還做了小變化~(也就是不是一點擊就得到物品喔)
情境是:
在地上發現有一個痕跡,
點擊痕跡後露出紙張的一小角,
再點擊取得紙張(出現在物品欄)。
點擊紙張選擇紙張(外框變紅色),再點擊一次紙張,回復到還沒選擇紙張的樣子。
先看範例網址(注意,因為是雲端網頁,圖片會比較慢顯示):

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

那麼第一步,一樣先顯示背景和物品(可互動的部分):

<!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 6</title>
<style type="text/css">
#scene{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 300px;
	height: 232px;
	background: url("bg.png");
}
#ground{
	position: absolute;
	left: 130px;
	top: 165px;
	background: url("ground.png");
	width: 29px;
	height: 23px;
	cursor: pointer;
	z-index:1000;
}
#show{
	position: absolute;
	left: 140px;
	top: 170px;
	background: url("show.png");
	width: 12px;
	height: 15px;
	cursor: pointer;
	z-index:1000;
}
.hide{
	display: none;
}
</style>
</head>

<body>
<div id="show" class="hide"></div>
<div id="ground"></div>
<div id="scene"></div>
</body>
</html>

一樣是用position:absolute設定位置的方法,用left和top抓物品的位置。
再來,就是顯示物品欄的格子。
這邊要先圖解一下。
原本,我們要的格子是80x80px大小的圖:
而選擇後的圖片是紅色框的:
然而,要是真的就用這樣的圖,中間的部分會變得很粗(因為是兩倍的粗度),
因此,這2x3的圖片其實是長這樣:

由第一個物品為例,
假如第一個物品還沒得到東西,就是長這樣:
當你得到物品(紙條)時長這樣:
當你選取物品(紙條)時長這樣:
由此可知,物品欄難不在做法,難在準備圖片Orz
我這邊因為是範例,所以只有1個物品要準備,你的話就要依照物品來設計。
畢竟!不是所有格子都要用完的!
你可以自己設計物品欄的長相,
有的人會用叉叉來表示其餘格子是沒有用到的(只是為了排版美觀),
1x6(直排)或6x1(橫排)也是一樣的道理。
總之就是以2x3舉例囉。
接著,
如果像以前一樣一個一個排div會排到瘋掉@@
因此我直接上用javascript幫你排的方法了:
 

<!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 6</title>
<style type="text/css">
#scene{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 300px;
	height: 232px;
	background: url("bg.png");
}
#ground{
	position: absolute;
	left: 130px;
	top: 165px;
	background: url("ground.png");
	width: 29px;
	height: 23px;
	cursor: pointer;
	z-index:1000;
}
#show{
	position: absolute;
	left: 140px;
	top: 170px;
	background: url("show.png");
	width: 12px;
	height: 15px;
	cursor: pointer;
	z-index:1000;
}
.hide{
	display: none;
}
</style>
</head>

<body>
<div id="show" class="hide"></div>
<div id="ground"></div>
<div id="scene"></div>
</body>
<script type="text/javascript">
var ground=getById("ground"), showpaper=getById("show"), selected=null;	//其中,selected代表你目前選擇了什麼物品?null代表什麼都沒有選
// itemBar的部分
//itemBar各個欄位寬度(依據圖片大小)
var barWid=new Array(78,78,78,78,78,78);
//itemBar各個欄位高度(依據圖片大小)
var barHei=new Array(78,78,76,76,78,78);
//itemBar無道具時的圖檔名稱(假設都是png檔)
var barPan=new Array("panel1","panel2","panel3","panel4","panel5","panel6");
//itemBar有道具時的圖檔名稱(假設都是png檔)
var barIte=new Array("item1","item2","item3","item4","item5","item6");
//itemBar選擇道具時的圖檔名稱(假設都是png檔)
var barSel=new Array("select1","select2","select3","select4","select5","select6");
//各個item取得的狀態(預設是false,表示還沒得到任何東西)
var barGet=new Array(false,false,false,false,false,false);
//接著產生itemBar(還沒有任何東西時)
for(var i=0;i<barWid.length;i++){	//因為各個item對應一樣,所以用哪個陣列都可以,這邊是用barWid
	var itm=document.createElement('div');	//產生各個item的div
	//item的寬度
	itm.style["width"] = barWid[i]+"px";
	//item的高度
	itm.style["height"] = barHei[i]+"px";
	itm.style["position"]="absolute";
	//item一開始的樣子(還無道具時)
	itm.style["background"]='url("'+barPan[i]+'.png")';	//檔名直接加在這邊
	//先處理left的部分
	//itemBar最左邊是從scene的最右邊開始排,
	//而雙數個item的左邊則是要加入奇數個item的寬度也就是說item2的left要加入item1的寬度
	if(i%2==0)				//因為從0開始,所以0,2,4,....是奇數位item,因此只要從主畫面(scene)的最右邊開始排
		itm.style["left"]=(getById("scene").clientLeft + getById("scene").clientWidth)+"px";
	else
		itm.style["left"]=(getById("scene").clientLeft + getById("scene").clientWidth + barWid[(i-1)]) + "px";
	//再來處理top的部分
	//itemBar的最上方是從scene的最上方開始排,
	//而item1、2高度一樣,3、4高度一樣....因此就是雙數個item會跟前一個高度一樣。而每組要加上前一個的高度
	if(i==0||i==1)		//若是第一或第二個item,則是和scene的最上方對齊
		itm.style["top"]= (getById("scene").clientTop) + "px";
	else
		itm.style["top"]= (getById("scene").clientTop) + itemHeight(i) + "px";
	//接著設定item的各個id
	itm.setAttribute('id','item'+(i+1));	//因為i從0開始,加1後才是item1~6
	//最後把設定好的item顯示出來
	document.body.appendChild(itm);
}
function itemHeight(index){
	var ind=index;
	if(index%2!=0) ind--;	//確保同一組高度一樣(同一行)
	//累加的觀念
	var heights=0;
	for(var d in barHei){
		if(d<ind){
			if(d%2==0){
				heights+=parseInt(barHei[d]);		//確保取得的值是整數所以用parseInt
			}
		}else break;
	}
	return heights;
}
function getById(id){
	return document.getElementById(id);
}
</script>
</html>

那麼, 一開始,你的網頁就會把空白物品欄以及第一個場景顯示出來。
接著就是互動的部分:
 

<!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 6</title>
<style type="text/css">
#scene{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 300px;
	height: 232px;
	background: url("bg.png");
}
#ground{
	position: absolute;
	left: 130px;
	top: 165px;
	background: url("ground.png");
	width: 29px;
	height: 23px;
	cursor: pointer;
	z-index:1000;
}
#show{
	position: absolute;
	left: 140px;
	top: 170px;
	background: url("show.png");
	width: 12px;
	height: 15px;
	cursor: pointer;
	z-index:1000;
}
.hide{
	display: none;
}
</style>
</head>

<body>
<div id="show" class="hide"></div>
<div id="ground"></div>
<div id="scene"></div>
</body>
<script type="text/javascript">
var ground=getById("ground"), showpaper=getById("show"), selected=null;	//其中,selected代表你目前選擇了什麼物品?null代表什麼都沒有選
// itemBar的部分
//itemBar各個欄位寬度(依據圖片大小)
var barWid=new Array(78,78,78,78,78,78);
//itemBar各個欄位高度(依據圖片大小)
var barHei=new Array(78,78,76,76,78,78);
//itemBar無道具時的圖檔名稱(假設都是png檔)
var barPan=new Array("panel1","panel2","panel3","panel4","panel5","panel6");
//itemBar有道具時的圖檔名稱(假設都是png檔)
var barIte=new Array("item1","item2","item3","item4","item5","item6");
//itemBar選擇道具時的圖檔名稱(假設都是png檔)
var barSel=new Array("select1","select2","select3","select4","select5","select6");
//各個item取得的狀態(預設是false,表示還沒得到任何東西)
var barGet=new Array(false,false,false,false,false,false);
//接著產生itemBar(還沒有任何東西時)
for(var i=0;i<barWid.length;i++){	//因為各個item對應一樣,所以用哪個陣列都可以,這邊是用barWid
	var itm=document.createElement('div');	//產生各個item的div
	//item的寬度
	itm.style["width"] = barWid[i]+"px";
	//item的高度
	itm.style["height"] = barHei[i]+"px";
	itm.style["position"]="absolute";
	//item一開始的樣子(還無道具時)
	itm.style["background"]='url("'+barPan[i]+'.png")';	//檔名直接加在這邊
	//先處理left的部分
	//itemBar最左邊是從scene的最右邊開始排,
	//而雙數個item的左邊則是要加入奇數個item的寬度也就是說item2的left要加入item1的寬度
	if(i%2==0)				//因為從0開始,所以0,2,4,....是奇數位item,因此只要從主畫面(scene)的最右邊開始排
		itm.style["left"]=(getById("scene").clientLeft + getById("scene").clientWidth)+"px";
	else
		itm.style["left"]=(getById("scene").clientLeft + getById("scene").clientWidth + barWid[(i-1)]) + "px";
	//再來處理top的部分
	//itemBar的最上方是從scene的最上方開始排,
	//而item1、2高度一樣,3、4高度一樣....因此就是雙數個item會跟前一個高度一樣。而每組要加上前一個的高度
	if(i==0||i==1)		//若是第一或第二個item,則是和scene的最上方對齊
		itm.style["top"]= (getById("scene").clientTop) + "px";
	else
		itm.style["top"]= (getById("scene").clientTop) + itemHeight(i) + "px";
	//接著設定item的各個id
	itm.setAttribute('id','item'+(i+1));	//因為i從0開始,加1後才是item1~6
	//最後把設定好的item顯示出來
	document.body.appendChild(itm);
	//接著要設定item的操作方式(選擇)
	getById("item"+(i+1)).onclick=function(){
		var num=parseInt(this.id.substr(4))-1;	//item1等於陣列索引值的第0個,substr是字串從第幾個字切,因為item是4個字,所以這樣就能得到item1的1了
		if(barGet[num]){	//要取得了該item才能起作用
			if(selected!=num){	//如果原本選擇的不是這個item,則現在選擇了這個item,要將這個item改成選到了的樣子,且將selected改成現在選擇的這個item
				getById("item"+(num+1)).style.background="url("+barSel[num]+".png)";
				selected=num;
			}else{				//如果原本已經選擇這個item,則要將這個item的狀態還原成還沒選擇的樣子,且將selected還原成null狀態。
				getById("item"+(num+1)).style.background="url("+barIte[num]+".png)";
				selected=null;
			}
		}
	}
}
function itemHeight(index){
	var ind=index;
	if(index%2!=0) ind--;	//確保同一組高度一樣(同一行)
	//累加的觀念
	var heights=0;
	for(var d in barHei){
		if(d<ind){
			if(d%2==0){
				heights+=parseInt(barHei[d]);		//確保取得的值是整數所以用parseInt
			}
		}else break;
	}
	return heights;
}
ground.onclick=function(){
	hide(ground);
	show(showpaper);
}
showpaper.onclick=function(){
	hide(showpaper);
	//得到紙片(item1)
	//將紙片所在的item改變背景,並且讓這個item可以選擇(改變鼠標)
	getById("item1").style.background="url(item1.png)";
	getById("item1").style.cursor="pointer";
	//將item1的取得值設為true
	barGet[0]=true;
}
function getById(id){
	return document.getElementById(id);
}
function hide(elem){
	elem.style.display="none";
}
function show(elem){
	elem.style.display="block";
}
</script>
</html>

可以先從簡單的地方開始看,
當我們執行網頁,直覺是看到地上有玄機,
所以處理地上的部分(ground):

ground.onclick=function(){
	hide(ground);
	show(showpaper);
}
showpaper.onclick=function(){
	hide(showpaper);
	//得到紙片(item1)
	//將紙片所在的item改變背景,並且讓這個item可以選擇(改變鼠標)
	getById("item1").style.background="url(item1.png)";
	getById("item1").style.cursor="pointer";
	//將item1的取得值設為true
	barGet[0]=true;
}
function hide(elem){
	elem.style.display="none";
}
function show(elem){
	elem.style.display="block";
}

這裡其實跟之前教的沒什麼部分,
只是你要先把show(露出一小角的圖)的位置抓好,接著就用show與hide的方法將你要的東西顯示或隱藏。
而showpaper部分則是做如果點擊一小角,可以得到紙張的動作。
不過這邊其實也有個小缺點,那就是我為了讓你知道那個是什麼,所以變數取了通俗的id。
正確應該叫做show1,
所以就可以變成這樣:

show1.onclick=function(){
	hide(this);			//在onclick中直接用this,則this就是觸發點擊的這個元件,就是show1(此處是getById("show1"))
	var num=parseInt(this.id.substr(4));	//substr是切字串,因為show是4個字,所以就得到show1的1
	//得到紙片(item1)
	//將紙片所在的item改變背景,並且讓這個item可以選擇(改變鼠標)
	getById("item"+num).style.background="url(item"+num+".png)";
	getById("item"+num).style.cursor="pointer";
	//將item1的取得值設為true
	barGet[(num-1)]=true;	//第1個物品在陣列的索引值是0,所以減一
}

如此一來,你可以在一個場景設很多個物品來取得~(我設一個是因為場景太小~)
只要點擊就可以取得的div都用show開頭。因此有10個物品可以使用就用show1~show10

接著,既然得到東西了,就要可以點擊、選取呀!
這部分回到一開始產生物品欄的部分,看到下面有註解的地方:
 

getById("item"+(i+1)).onclick=function(){
		var num=parseInt(this.id.substr(4))-1;	//item1等於陣列索引值的第0個,substr是字串從第幾個字切,因為item是4個字,所以這樣就能得到item1的1了
		if(barGet[num]){	//要取得了該item才能起作用
			if(selected!=num){	//如果原本選擇的不是這個item,則現在選擇了這個item,要將這個item改成選到了的樣子,且將selected改成現在選擇的這個item
				getById("item"+(num+1)).style.background="url("+barSel[num]+".png)";
				selected=num;
			}else{				//如果原本已經選擇這個item,則要將這個item的狀態還原成還沒選擇的樣子,且將selected還原成null狀態。
				getById("item"+(num+1)).style.background="url("+barIte[num]+".png)";
				selected=null;
			}
		}
	}

因為每個物品的id都有規則(以item開頭),所以就可以直接這樣使用了。

那麼,假如你要修改範例成為你的背景和物品呢?
請看到上方變數的部分(雖然都有註解):
 

var ground=getById("ground"), showpaper=getById("show"), selected=null;	//其中,selected代表你目前選擇了什麼物品?null代表什麼都沒有選
// itemBar的部分
//itemBar各個欄位寬度(依據圖片大小)
var barWid=new Array(78,78,78,78,78,78);
//itemBar各個欄位高度(依據圖片大小)
var barHei=new Array(78,78,76,76,78,78);
//itemBar無道具時的圖檔名稱(假設都是png檔)
var barPan=new Array("panel1","panel2","panel3","panel4","panel5","panel6");
//itemBar有道具時的圖檔名稱(假設都是png檔)
var barIte=new Array("item1","item2","item3","item4","item5","item6");
//itemBar選擇道具時的圖檔名稱(假設都是png檔)
var barSel=new Array("select1","select2","select3","select4","select5","select6");
//各個item取得的狀態(預設是false,表示還沒得到任何東西)
var barGet=new Array(false,false,false,false,false,false);

其中,除了ground和showpaper是依據場景改變的(而其中showpaper應該改成show1對應得到的第一個物品),
其他請根據你的物品欄做設計。
要注意的是,因為範例的物品欄是2x3,所以共有6個物品要設定,
假如你的物品有10個,就要將陣列改成你的數量。
由於barPan、barIte、barSel以及barGet陣列都有規律,
因此還可以簡寫成這樣:
 

var barPan=[],barIte=[],barSel=[],barGet=[];
for(var s=0;s<6;s++){
	barPan[s]="panel"+(s+1);
	barIte[s]="item"+(s+1);
	barSel[s]="select"+(s+1);
	barGet[s]=false;
}

那麼你就可以依據你的物品欄格數改變6那個值囉~
記得,物品欄最好用偶數個來排版!
此範例是以2xn排版。
再來就是背景和互動物品的部分:
 

#scene{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 300px;
	height: 232px;
	background: url("bg.png");
}
#ground{
	position: absolute;
	left: 130px;
	top: 165px;
	background: url("ground.png");
	width: 29px;
	height: 23px;
	cursor: pointer;
	z-index:1000;
}
#show{
	position: absolute;
	left: 140px;
	top: 170px;
	background: url("show.png");
	width: 12px;
	height: 15px;
	cursor: pointer;
	z-index:1000;
}

也請依照自己的背景大小以及互動物品的大小來修改位置和寬與高囉~

不過呢,
這只是物品欄的第一種方法,
後面還會教物品欄的第二種方法,
也就是循序得到物品的方法(不是我得到第1個就顯示第1個,如果先得到第5個物品則將第5個物品排到第1個位置)。

先消化一下囉~