一 項目簡介html
主要知識點:JavaScript、HTML、CSS
這是一個主要用JS實現的網頁版小遊戲,遊戲規則很簡單,經過點擊不斷下落的黑塊來消滅它並獲取分數,若是不幸黑塊掉落下來或點到了白色區域那麼遊戲就會終止。
遊戲截圖以下:
web
二 遊戲框架
數組
整個遊戲可分爲如下幾個步驟實現:
1. HTML和CSS畫出靜態的遊戲框架;
2. DOM結構說明:
遊戲元素使用嵌套的div元素來實現,是一個4*4的方格地圖:最外層容器main(一個) > 次外層容器container(一個) > 行容器row(四行) > 方塊cell(每行4塊)
3. JS邏輯:
1)圖形的繪製:用js來動態建立div元素,並逐級添加到上層節點當中;
2)實現下落:經過動態增長包裹全部方塊的container容器的top的值來實現下落效果;
3)持續下落:動態在最上層建立一行方塊,同時刪除最下層一行方塊;隔一段時間調用一次;
4)用戶交互:用戶經過點擊事件,綁定到整個動畫中,經過改變屬性名來使黑塊轉變爲白塊,實現視覺上的「消滅黑塊」;
5)加分規則:用戶成功點擊黑塊,則調用一次加分函數,並將分數實時寫入頁面中;
6)犯規處理:A. 經過判斷方塊元素屬性名來判斷用戶是否點擊白塊從而終止遊戲;B. 經過判斷最後下落的一行是否含有黑塊從而判斷是否應該終止遊戲;
7)遊戲加成:當分數達到某個階段可經過增長下落的像素值的大小來加快下落速度從而增長遊戲難度,增長趣味性;
8)結束遊戲:犯規後,清除調用函數,來終止遊戲運行。瀏覽器
三 完整代碼app
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>別踩白塊</title>
<style>
#main{ /*遊戲背景板的樣式*/
width:400px;
height:400px;
background:white;
border:1px solid green;
margin:0 auto;
position:relative; /*position 屬性規定元素的定位類型。relative:生成相對定位的元素,相對於其正常位置進行定位。*/
overflow:hidden;
} /*overflow屬性規定當內容溢出元素框時發生的事情。hidden::內容會被修剪,而且其他內容是不可見的。*/
#container{ /*下落方塊所在的容器樣式*/
width:100%;
height:400px;
position:relative;
top:-100px; /*黑塊最開始不能出如今最下面,不然遊戲直接結束,所以容器總體上移100px*/
}
.row{ /*一行容器的樣式*/
height:100px;
width:100%;
}
.cell{ /*單個方塊的樣式*/
height:100px;
width:100px;
float:left; /*float 屬性定義元素在哪一個方向浮動*/
}
.black{ /*黑塊的樣式*/
background:black;
}
h1{
text-align:center;
}
p{
display:inline-block; /*display 屬性規定元素應該生成的框的類型,inline-block爲行內塊元素。*/
}
</style>
</head>
<body>
<h1>Score: <p id="score">0</p></h1>
<div id="main">
<div id="container"></div>
</div>
<script>
var clock=null; //定時器操做句柄
var state=0; //定義遊戲當前狀態:0初始化,1進行中,2暫停,3失敗
var speed=2; //方塊下落的速度,初始值爲2像素框架
//初始化
function init(){
for(var i=0; i<4; i++){ //建立4行row
crow();
}
$('main').onclick=function(ev){ //向main添加點擊事件
judge(ev); //調用判斷函數來判斷用戶的點擊行爲是否合規,參數爲事件對象
}
}dom
//start()啓動
function start(){
clock=window.setInterval('move()',30); //每30毫秒調用一次移動函數函數
//下落動畫
function move(){
var con=$('container'); //經過自定義函數$()找到container
var top=parseInt(window.getComputedStyle(con,null)['top']); //window.getComputedStyle(element, [pseudoElt]);方法給出應用活動樣式表後的元素的全部CSS屬性的值,並解析這些值可能包含的任何基本計算。element用於獲取計算樣式的Element,pseudoElt(可選)指定一個要匹配的僞元素的字符串。必須對普通元素省略(或null)。返回的樣式是一個實時的 CSSStyleDeclaration
對象,當元素的樣式更改時,它會自動更新自己。CSSStyleDeclaration 表示一個CSS屬性鍵值對的集合。此處初始值爲-100
if(speed + top >0){ //當最上面一行row走過頭了,沒法與main上邊緣重合時
top=0; //直接將row的座標置爲0
}else{
top += speed;//調節每次降低的像素,必須是100的約數,這樣才能移動若干次後恰好爲100px,由於一個方塊爲100px*100px,恰好可以與main上下兩邊重合
}
con.style.top=top + 'px';
if(top==0){ //當最上面一行row恰好落進main內
crow(); //調用函數在最上方插入一行row
con.style.top='-100px'; //並使其位於main上面隱藏的部分
drow(); //當上下中間共有6行row時調用函數,刪除最下面一行row,避免遊戲過程當中堆積太多元素,給瀏覽器增長負擔
}else if(top==(-100+speed)){ //一輪恰好進行第一次下落,此時最下面一行row恰好準備和main的下邊緣觸碰
var rows=con.children; //ParentNode.children
是一個只讀屬性,返回 一個Node的子elements
,是一個動態更新的 HTMLCollection
。
if((rows.length==5) && (rows[rows.length-1].pass !==1)){ //若是此時有5行row,而且最後一行未成功點擊黑塊
fail(); //遊戲失敗
}
}
}學習
//加速
function speedup(){
speed +=2;
if(speed==20){
alert('Excellent!');
}
}優化
//遊戲失敗
function fail(){
clearInterval(clock); //clearInterval() 方法可取消由 setInterval() 函數設定的定時執行操做。
state=3; //另遊戲狀態等於3,最開始定義的3爲失敗
alert('Game Over!');
}
//計分
function score(){
var newscore=parseInt($('score').innerHTML)+1; //獲取score的innerHTML值並轉化爲整數,再加一分
$('score').innerHTML=newscore; //增長後的分數寫入score
if(newscore % 10 == 0){ //分數每增長10分
speedup(); //遊戲加速
}
}
//判斷玩家點擊事件是否需合規
function judge(ev){
if(state==3){ //上文設定遊戲失敗時state爲3,此處判斷遊戲是否已經結束
return;
}
if(ev.target.className.indexOf('black')==-1){ //若是點擊的元素的屬性名不含black,也就是點中了白塊
fail();
}else{
ev.target.className='cell'; //不然點中了黑塊,重寫屬性名,將其改成白塊
ev.target.parentNode.pass=1;//用js獲取DOM節點對象後,能夠增長一個自定義屬性,這裏的pass是自定義的,也就是說:當點中黑塊的時候,黑塊所在的row的pass屬性值是1
score(); //加分
}
}
//建立行row
function crow(){
var con=$('container');
var row=cdiv('row'); //建立屬性名爲row的div
var classes=createSn(); //一個row下面的屬性的數組
for(var i=0; i<4; i++){
row.appendChild(cdiv(classes[i])); //建立4個div添加給row,4個div的屬性名中隨機產生一個cell black,獲得一個含有隨機位置黑塊的row
}
if(con.firstChild==null){ //若是con沒有子元素
con.appendChild(row); //那就添加row
}else{
con.insertBefore(row,con.firstChild); //不然將這個row插入到子元素前面
}
}
//刪除最後一行
function drow(){
var con=$('container');
if(con.childNodes.length==6){
con.removeChild(con.lastChild); //當有6行row時刪除最後一行
}
}
//建立一個div,className是其類名
function cdiv(className){
var div=document.createElement('div');
div.className=className;
return div;
}
//返回一個數組,隨機其中一個單元,值爲'cell black',其他皆爲'cell'
function createSn(){
var arr=['cell','cell','cell','cell'];
var i=Math.floor(Math.random()*4); //Math.random()隨機產生範圍爲[0,1)之間的小數,Math.floor()向下取整,此處爲0,1,2,3,
arr[i]='cell black';
return arr;
}
//按照id獲取對象,取代反覆用到的document.getElementById()
function $(id){
return document.getElementById(id);
}
init();
start();
</script>
</body>
</html>
四 知識點整理
1. CSS:
-position:relative:position 屬性規定元素的定位類型。relative:生成相對定位的元素,相對於其正常位置進行定位。
-overflow:hidden:overflow屬性規定當內容溢出元素框時發生的事情。hidden::內容會被修剪,而且其他內容是不可見的。
-float:left:float屬性定義元素在哪一個方向浮動。
-display:inline-block:display屬性規定元素應該生成的框的類型,inline-block爲行內塊元素。
2. JS:
-window.setInterval('move()',30);setInterval()方法可按照指定的週期(以毫秒計)來調用函數或計算表達式。setInterval() 方法會不停地調用函數,直到 clearInterval() 被調用或窗口被關閉。
-parseInt(window.getComputedStyle(con,null)['top']):window.getComputedStyle(element, [pseudoElt])方法給出應用活動樣式表後的元素的全部CSS屬性的值,並解析這些值可能包含的任何基本計算。element用於獲取計算樣式的Element,pseudoElt(可選)指定一個要匹配的僞元素的字符串。必須對普通元素省略(或null)。返回的樣式是一個實時的 CSSStyleDeclaration對象,當元素的樣式更改時,它會自動更新自己。CSSStyleDeclaration表示一個CSS屬性鍵值對的集合。
-con.children:ParentNode.children 是一個只讀屬性,返回 一個Node的子elements,是一個動態更新的 HTMLCollection。
-ev.target.parentNode.pass=1:用js獲取DOM節點對象後,能夠增長一個自定義屬性,這裏的pass是自定義的,也就是說:當點中黑塊的時候,黑塊所在的row的pass屬性值是1。
-Math.random():隨機產生範圍爲[0,1)之間的小數。
-Math.floor():向下取整。
五 相關資源
剛開始是在實驗樓找的項目,看完以後有的地方不是很明白,百度的時候發現網易雲課堂恰好有現成的課,就跟着老師看完敲了一邊,收穫仍是蠻大的,畢竟以前學習方式基本是「光看不練」,這算是第一個完整敲完整理完的項目。
其實這個遊戲還有很大的優化空間,好比實驗樓提出的那幾個問題都挺有價值的,以後若是有空了會嘗試一下吧:)
1. 給這個遊戲增長開始/暫停按鈕;
2. 用JQuery重寫一遍;
3. 最佳分數記錄(可能須要用到H5新增的web存儲)
最後貼一下連接:實驗樓:https://www.shiyanlou.com/courses/306網易雲課堂:http://study.163.com/course/courseMain.htm?courseId=652005