欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

使用javascript中canvas實現(xiàn)拼圖小游戲的方法

這篇文章主要介紹了使用javascript中canvas實現(xiàn)拼圖小游戲的方法,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

延壽網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),延壽網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為延壽數(shù)千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的延壽做網(wǎng)站的公司定做!

如果您想要綜合使用javascript中canvas、原生拖拽、本地存儲等多種技術(shù)完成一個有趣的項目,那么這篇文章將非常適合您

1 簡介和源碼

該項目中的拼圖小游戲使用javascript原創(chuàng),相比于網(wǎng)站上類似的功能,它使用到的技術(shù)點更先進豐富,功能更強大,還包含程序開發(fā)中更多先進的思想理念,從該項目中您將能學到:

  • FileReader、Image對象的配合canvas對圖片進行壓縮,切割的技巧。

  • 學習小游戲開發(fā)中最常用的碰撞檢測、狀態(tài)監(jiān)控、刷新保持狀態(tài)的處理方法。

  • 深入了解拖拽交換元素的細節(jié),學習到動態(tài)元素綁定事件、回調(diào)函數(shù)的處理方式。

項目源碼-github

下面是游戲界面的示例圖:

使用javascript中canvas實現(xiàn)拼圖小游戲的方法

2 實現(xiàn)思路

根據(jù)游戲界面圖我們可以將完成這么一個小游戲分為以下幾步來實現(xiàn):

  • 1.拖拽圖片到指定區(qū)域,使用FileReader對象讀取到圖片的base64內(nèi)容,然后添加到Image對象中

  • 2.當Image對象加載完成后,使用canvas對圖片進行等比縮放,然后取到縮略圖的base64內(nèi)容,添加到另外一個縮略圖Image對象中,并將該縮略圖base64的內(nèi)容保存到本地存儲(localStorage)中

  • 3.當縮略圖Image對象加載完成后,再次使用canvas對縮略圖進行切割,該游戲中將縮略圖切割成3*4一共12等份,使用本地存儲保存每份切割縮略圖base64內(nèi)容,將縮略圖順序打亂,使用img標簽顯示在web頁面上

  • 4.當縮略圖切片都添加到web界面上以后,為每一份縮略圖切片添加注冊拖拽事件,使得縮略圖切片可以相互交換,在這個過程當中,添加對縮略圖切片順序狀態(tài)的監(jiān)控,一旦完成拼圖,就直接展示完整的縮略圖,完成游戲

從以上對小游戲制作過程的分析來看,第4步是程序功能實現(xiàn)的重點和難點,在以上的每個步驟中都有很多小細節(jié)需要注意和探討,下面我就詳細分析一下每個步驟的實現(xiàn)細節(jié),說的不好的地方,歡迎大家留言指正。

3 開發(fā)細節(jié)詳解

3.1 圖片內(nèi)容讀取和加載

在游戲開發(fā)第1步中,我們將圖片拖拽到指定區(qū)域后,程序是怎樣得到圖片內(nèi)容信息的呢?fileReader對象又是怎樣將圖片信息轉(zhuǎn)化為base64字符串內(nèi)容的?Image對象拿到圖片的base64內(nèi)容之后,又是怎樣初始化加載的?帶著這些疑問,我們來研究一下實現(xiàn)項目中實現(xiàn)了第一步的關(guān)鍵代碼。

var droptarget = document.getElementById("droptarget"),
            output = document.getElementById("ul1"),
            thumbImg = document.getElementById("thumbimg");
            
 //此處省略相關(guān)代碼........
           
function handleEvent(event) {
                var info = "",
                    reader = new FileReader(),
                    files, i, len;

                EventUtil.preventDefault(event);
                localStorage.clear();

                if (event.type == "drop") {
                    files = event.dataTransfer.files;
                    len = files.length;
                    if (!/image/.test(files[0].type)) {
                        alert('請上傳圖片類型的文件');
                    }
                    if (len > 1) {
                        alert('上傳圖片數(shù)量不能大于1');
                    }

                    var canvas = document.createElement('canvas');
                    var context = canvas.getContext('2d');
                    var img = new Image(),          //原圖
                        thumbimg = new Image();     //等比縮放后的縮略圖

                    reader.readAsDataURL(files[0]);
                    reader.onload = function (e) {
                        img.src = e.target.result;
                    }

                    //圖片對象加載完畢后,對圖片進行等比縮放處理??s放后最大寬度為三百像素
                    img.onload = function () {
                        var targetWidth, targetHeight;
                        targetWidth = this.width > 300 ? 300 : this.width;
                        targetHeight = targetWidth / this.width * this.height;
                        canvas.width = targetWidth;
                        canvas.height = targetHeight;
                        context.clearRect(0, 0, targetWidth, targetHeight);
                        context.drawImage(img, 0, 0, targetWidth, targetHeight);
                        var tmpSrc = canvas.toDataURL("image/jpeg");
                        //在本地存儲完整的縮略圖源
                        localStorage.setItem('FullImage', tmpSrc);
                        thumbimg.src = tmpSrc;
                    }
                    
        //此處省略相關(guān)代碼......
        
         EventUtil.addHandler(droptarget, "dragenter", handleEvent);
         EventUtil.addHandler(droptarget, "dragover", handleEvent);
         EventUtil.addHandler(droptarget, "drop", handleEvent);            
}

這段代碼的思路就是首先獲得拖拽區(qū)域目標對象droptarget,為droptarget注冊拖拽監(jiān)聽事件。代碼中用到的EventUtil是我封裝的一個對元素添加事件、事件對象的兼容處理等常用功能的簡單對象,下面是其添加注冊事件的簡單簡單代碼,其中還有很多其他的封裝,讀者可自行查閱,功能比較簡單。

var EventUtil = {

    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent){
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    
    //此處省略代......
 }

當用戶將圖片文件拖放到區(qū)域目標對象droptarget時,droptarget的事件對象通過event.dataTransfer.files獲取到文件信息,對文件進行過濾(限制只能為圖片內(nèi)容,并且最多只能有一張圖片)。拿到文件內(nèi)容以后,使用FileReader對象reader讀取文件內(nèi)容,使用其readAsDataURL方法讀取到圖片的base64內(nèi)容,賦值給Image對象img的src屬性,就可以等到img對象初始化加載完畢,使canvas對img進行下一步的處理了。這里有一個重點的地方需要說明:一定要等img加載完成后,再使用canvas進行下一步的處理,不然可能會出現(xiàn)圖片損壞的情況。原因是:當img的src屬性讀取圖片文件的base64內(nèi)容時,可能還沒有將內(nèi)容加載到內(nèi)存中時,canvas就開始處理圖片(此時的圖片是不完整的)。所以我們可以看到canvas對圖片的處理是放在img.onload方法中進行的,程序后邊還會有這種情況,之后就不再贅述了。

3.2 圖片等比縮放和本地存儲

在第一步中我們完成了對拖拽文件的內(nèi)容讀取,并將其成功加載到了Image對象img中。接下來我們使用canvas對圖片進行等比縮放,對圖片進行等比縮放,我們采取的策略是限制圖片的最大寬度為300像素,我們再來看一下這部分代碼吧:

 img.onload = function () {
                        var targetWidth, targetHeight;
                        targetWidth = this.width > 300 ? 300 : this.width;
                        targetHeight = targetWidth / this.width * this.height;
                        canvas.width = targetWidth;
                        canvas.height = targetHeight;
                        context.clearRect(0, 0, targetWidth, targetHeight);
                        context.drawImage(img, 0, 0, targetWidth, targetHeight);
                        var tmpSrc = canvas.toDataURL("image/jpeg");
                        //在本地存儲完整的縮略圖源
                        localStorage.setItem('FullImage', tmpSrc);
                        thumbimg.src = tmpSrc;
                    }

確定了縮放后的寬度targetWidth和高度targetHeight之后,我們使用canvas的drawImage方法對圖像進行壓縮,在這之前我們最好先使用畫布的clearRect對畫布進行一次清理。對圖片等比縮放以后,使用canvas的toDataURL方法,獲取到縮放圖的base64內(nèi)容,賦給新的縮放圖Image對象thumbimg的src屬性,待縮放圖加載完畢,進行下一步的切割處理。縮放圖的base64內(nèi)容使用localStorage存儲,鍵名為"FullImage"。瀏覽器的本地存儲localStorage是硬存儲,在瀏覽器刷新之后內(nèi)容不會丟失,這樣我們就可以在游戲過程中保持數(shù)據(jù)狀態(tài),這點稍后再詳細講解,我們需要知道的是localStorage是有大小限制的,最大為5M。這也是為什么我們先對圖片進行壓縮,減少存儲數(shù)據(jù)大小,保存縮放圖base64內(nèi)容的原因。關(guān)于開發(fā)過程中存儲哪些內(nèi)容,下一小節(jié)會配有圖例詳細說明。

3.3 縮略圖切割

生成縮略圖之后要做的工作就是對縮略圖進行切割了,同樣的也是使用canvas的drawImage方法,而且相應(yīng)的處理必須放在縮略圖加載完成之后(即thumbimg.onload)進行處理,原因前面我們已經(jīng)說過。下面我們再來詳細分析一下源代碼吧:

thumbimg.onload = function () {
                        //每一個切片的寬高[切割成3*4格式]
                        var sliceWidth, sliceHeight, sliceBase64, n = 0, outputElement = '',
                            sliceWidth = this.width / 3,
                            sliceHeight = this.height / 4,
                            sliceElements = [];

                        canvas.width = sliceWidth;
                        canvas.height = sliceHeight;

                        for (var j = 0; j < 4; j++) {
                            for (var i = 0; i < 3; i++) {
                                context.clearRect(0, 0, sliceWidth, sliceHeight);
                                context.drawImage(thumbimg, sliceWidth * i, sliceHeight * j, sliceWidth, sliceHeight, 0, 0, sliceWidth, sliceHeight);
                                sliceBase64 = canvas.toDataURL("image/jpeg");
                                localStorage.setItem('slice' + n, sliceBase64);
                                //為了防止圖片三像素問題發(fā)生,請為圖片屬性添加 display:block
                                newElement = "<li name=\"" + n + "\" style=\"margin:3px;\"><img src=\"" + sliceBase64 + "\" style=\"display:block;\"></li>";
                                //根據(jù)隨機數(shù)打亂圖片順序
                                (Math.random() > 0.5) ? sliceElements.push(newElement) : sliceElements.unshift(newElement);
                                n++;
                            }
                        }

                        //拼接元素
                        for (var k = 0, len = sliceElements.length; k < len; k++) {
                            outputElement += sliceElements[k];
                        }

                        localStorage.setItem('imageWidth', this.width + 18);
                        localStorage.setItem('imageHeight', this.height + 18);
                        output.style.width = this.width + 18 + 'px';
                        output.style.height = this.height + 18 + 'px';
                        (output.innerHTML = outputElement) && beginGamesInit();

                        droptarget.remove();
                    }

上面的代碼對于大家來說不難理解,就是將縮略圖分割成12個切片,這里我給大家解釋一下幾個容易困惑的地方:

  • 1.為什么我們再切割圖片的時候,代碼如下,先從列開始循環(huán)?

 for (var j = 0; j < 4; j++) {
    for (var i = 0; i < 3; i++) {
        //此處省略邏輯代碼
    }
  }

這個問題大家仔細想一想就明白了,我們將圖片進行切割的時候,要記錄下來每一個圖片切片的原有順序。在程序中我們使用 n 來表示圖片切片的原有順序,而且這個n記錄在了每一個圖片切片的元素的name屬性中。在后續(xù)的游戲過程中我們可以使用元素的getAttribute('name')方法取出 n 的值,來判斷圖片切片是否都被拖動到了正確的位置,以此來判斷游戲是否結(jié)束,現(xiàn)在講起這個問題可能還會有些迷惑,我們后邊還會再詳細探討,我給出一張圖幫助大家理解圖片切片位置序號信息n:

使用javascript中canvas實現(xiàn)拼圖小游戲的方法

序號n從零開始是為了和javascript中的getElementsByTagName()選擇的子元素坐標保持一致。

  • 2 我們第3步實現(xiàn)的目的不僅是將縮略圖切割成小切片,還要將這些圖片切片打亂順序,代碼程序中這一點是怎樣實現(xiàn)的?
    閱讀代碼程序我們知道,我們每生成一個切片,就會構(gòu)造一個元素節(jié)點: newElement = "<li name=\"" + n + "\" style=\"margin:3px;\"><img src=\"" + sliceBase64 + "\" style=\"display:block;\"></li>"; 。我們在是在外部先聲明了一個放新節(jié)點的數(shù)組sliceElements,我們每生成一個新的元素節(jié)點,就會把它放到sliceElements數(shù)組中,但是我們向sliceElements頭部還是尾部添加這個新節(jié)點則是隨機的,代碼是這樣的:

(Math.random() > 0.5) ? sliceElements.push(newElement) : sliceElements.unshift(newElement);

我們知道Math.random()生成一個[0, 1)之間的數(shù),所以再canvas將縮略圖裁切成切片以后,根據(jù)這些切片生成的web節(jié)點順序是打亂的。打亂順序以后重新組裝節(jié)點:

//拼接元素
for (var k = 0, len = sliceElements.length; k < len; k++) {
    outputElement += sliceElements[k];
}

然后再將節(jié)點添加到web頁面中,也就自然而然出現(xiàn)了圖片切片被打亂的樣子了。

  • 3.我們根據(jù)縮略圖切片生成的DOM節(jié)點是動態(tài)添加的元素,怎樣給這樣動態(tài)元素綁定事件呢?我們的項目中為每個縮略圖切片DOM節(jié)點綁定的事件是“拖動交換”,和其他節(jié)點都有關(guān)系,我們要保證所有的節(jié)點都加載后再對事件進行綁定,我們又是怎樣做到的呢?

下面的一行代碼,雖然簡單,但是用的非常巧妙:

(output.innerHTML = outputElement) && beginGamesInit();

有開發(fā)經(jīng)驗的同學都知道 && 和 || 是短路運算符,代碼中的含義是:只有當切片元素節(jié)點都添加到
WEB頁面之后,才會初始化為這些節(jié)點綁定事件。

3.4 本地信息存儲

代碼中多次用到了本地存儲,下面我們來詳細解釋一下本游戲開發(fā)過程中都有哪些信息需要存儲,為什么要存儲?下面是我給出的需要存儲的信息圖示例(從瀏覽器控制臺獲取):

使用javascript中canvas實現(xiàn)拼圖小游戲的方法

瀏覽器本地存儲localStorage使用key:value形式存儲,從圖中我們看到我們本次存儲的內(nèi)容有:

  • FullImage:圖片縮略圖base64編碼。

  • imageWidth:拖拽區(qū)域圖片的寬度。

  • imageHeight:拖拽區(qū)域圖片的高度。

  • slice*:每一個縮略圖切片的base64內(nèi)容。

  • nodePos:保存的是當前縮略圖的位置坐標信息。

保存FullImage縮略圖的信息是當游戲結(jié)束后顯示源縮略圖時,根據(jù)FullImage中的內(nèi)容展示圖片。而imageWidth,imageHeight,slice*,nodePos是為了防止瀏覽器刷新導(dǎo)致數(shù)據(jù)丟失所做的存儲,當刷新頁面的時候,瀏覽器會根據(jù)本地存儲的數(shù)據(jù)加載沒有完成的游戲內(nèi)容。其中nodePos是在為縮略圖切片發(fā)生拖動時存入本地存儲的,并且它隨著切片位置的變化而變化,也就是它追蹤著游戲的狀態(tài),我們在接下來的代碼功能展示中會再次說到它。

3.5 拖拽事件注冊和監(jiān)控

接下來我們要做的事才是游戲中最重要的部分,還是先來分析一下代碼,首先是事件注冊前的初始化工作:

//游戲開始初始化
function beginGamesInit() {
    aLi = output.getElementsByTagName("li");
    for (var i = 0; i < aLi.length; i++) {
        var t = aLi[i].offsetTop;
        var l = aLi[i].offsetLeft;
        aLi[i].style.top = t + "px";
        aLi[i].style.left = l + "px";
        aPos[i] = {left: l, top: t};
        aLi[i].index = i;
        //將位置信息記錄下來
        nodePos.push(aLi[i].getAttribute('name'));
    }
    for (var i = 0; i < aLi.length; i++) {
        aLi[i].style.position = "absolute";
        aLi[i].style.margin = 0;
        setDrag(aLi[i]);
    }
}

可以看到這部分初始化綁定事件代碼所做的事情是:記錄每一個圖片切片對象的位置坐標相關(guān)信息記錄到對象屬性中,并為每一個對象都注冊拖拽事件,對象的集合由aLi數(shù)組統(tǒng)一管理。這里值得一提的是圖片切片的位置信息index記錄的是切片現(xiàn)在所處的位置,而我們前邊所提到的圖片切片name屬性所保存的信息n則是圖片切片原本應(yīng)該所處的位置,在游戲還沒有結(jié)束之前,它們不一定相等。待所有的圖片切片name屬性所保存的值和其屬性index都相等時,游戲才算結(jié)束(因為用戶已經(jīng)正確完成了圖片的拼接),下面的代碼就是用來判斷游戲狀態(tài)是否結(jié)束的,看起來更直觀一些:

//判斷游戲是否結(jié)束
function gameIsEnd() {
    for (var i = 0, len = aLi.length; i < len; i++) {
        if (aLi[i].getAttribute('name') != aLi[i].index) {
            return false;
        }
    }

    //后續(xù)處理代碼省略......
}

下面我們還是詳細說一說拖拽交換代碼相關(guān)邏輯吧,拖拽交換的代碼如下圖所示:

//拖拽
function setDrag(obj) {
    obj.onmouseover = function () {
        obj.style.cursor = "move";
        console.log(obj.index);
    }

    obj.onmousedown = function (event) {
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
        obj.style.zIndex = minZindex++;
        //當鼠標按下時計算鼠標與拖拽對象的距離
        disX = event.clientX + scrollLeft - obj.offsetLeft;
        disY = event.clientY + scrollTop - obj.offsetTop;
        document.onmousemove = function (event) {
            //當鼠標拖動時計算p的位置
            var l = event.clientX - disX + scrollLeft;
            var t = event.clientY - disY + scrollTop;
            obj.style.left = l + "px";
            obj.style.top = t + "px";

            for (var i = 0; i < aLi.length; i++) {
                aLi[i].className = "";
            }
            var oNear = findMin(obj);
            if (oNear) {
                oNear.className = "active";
            }
        }

        document.onmouseup = function () {
            document.onmousemove = null;       //當鼠標彈起時移出移動事件
            document.onmouseup = null;         //移出up事件,清空內(nèi)存
            //檢測是否普碰上,在交換位置
            var oNear = findMin(obj);
            if (oNear) {
                oNear.className = "";
                oNear.style.zIndex = minZindex++;
                obj.style.zIndex = minZindex++;

                startMove(oNear, aPos[obj.index]);
                startMove(obj, aPos[oNear.index], function () {
                    gameIsEnd();
                });

                //交換index
                var t = oNear.index;
                oNear.index = obj.index;
                obj.index = t;

                //交換本次存儲中的位置信息
                var tmp = nodePos[oNear.index];
                nodePos[oNear.index] = nodePos[obj.index];
                nodePos[obj.index] = tmp;
                localStorage.setItem('nodePos', nodePos);
            } else {
                startMove(obj, aPos[obj.index]);
            }
        }
        clearInterval(obj.timer);

        return false;//低版本出現(xiàn)禁止符號
    }
}

這段代碼所實現(xiàn)的功能是這樣子的:拖動一個圖片切片,當它與其它的圖片切片有碰撞重疊的時候,就和與其左上角距離最近的一個圖片切片交換位置,并交換其位置信息index,更新本地存儲信息中的nodePos。移動完成之后判斷游戲是否結(jié)束,若沒有,則期待下一次用戶的拖拽交換。
下面我來解釋一下這段代碼中比較難理解的幾個點:

  • 1.圖片切片在被拖動的過程中是怎樣判斷是否和其它圖片切片發(fā)生碰撞的?這就是典型的碰撞檢測問題。
    程序中實現(xiàn)碰撞檢測的代碼是這樣的:

//碰撞檢測
function colTest(obj1, obj2) {
    var t1 = obj1.offsetTop;
    var r1 = obj1.offsetWidth + obj1.offsetLeft;
    var b1 = obj1.offsetHeight + obj1.offsetTop;
    var l1 = obj1.offsetLeft;

    var t2 = obj2.offsetTop;
    var r2 = obj2.offsetWidth + obj2.offsetLeft;
    var b2 = obj2.offsetHeight + obj2.offsetTop;
    var l2 = obj2.offsetLeft;

    `if (t1 > b2 || r1 < l2 || b1 < t2 || l1 > r2)` {
        return false;
    } else {
        return true;
    }
}

這段代碼看似信息量很少,其實也很好理解,判斷兩個圖片切片是否發(fā)生碰撞,只要將它們沒有發(fā)生碰撞的情形排除掉就可以了。這有點類似與邏輯中的非是即否,兩個切片又確實只可能存在兩種情況:碰撞、不碰撞。圖中的這段代碼是判斷不碰撞的情況:if (t1 > b2 || r1 < l2 || b1 < t2 || l1 > r2),返回false, else 返回true。

2.碰撞檢測完成了之后,圖片切片之間又是怎樣尋找左上角定點距離最近的元素呢?

代碼是這個樣子的:

//勾股定理求距離(左上角的距離)
function getDis(obj1, obj2) {
    var a = obj1.offsetLeft - obj2.offsetLeft;
    var b = obj1.offsetTop - obj2.offsetTop;
    return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
}

//找到距離最近的
function findMin(obj) {
    var minDis = 999999999;
    var minIndex = -1;
    for (var i = 0; i < aLi.length; i++) {
        if (obj == aLi[i]) continue;
        if (colTest(obj, aLi[i])) {
            var dis = getDis(obj, aLi[i]);
            if (dis < minDis) {
                minDis = dis;
                minIndex = i;
            }
        }
    }
    if (minIndex == -1) {
        return null;
    } else {
        return aLi[minIndex];
    }
}

因為都是矩形區(qū)塊,所以計算左上角的距離使用勾股定理,這點相信大家都能明白。查找距離最近的元素原理也很簡單,就是遍歷所有已經(jīng)碰撞的元素,然后比較根據(jù)勾股定理計算出來的最小值,返回元素就可以了。代碼中也是使用了比較通用的方法,先聲明一個很大的值最為最小值,當有碰撞元素比其小時,再將更小的值最為最小值,遍歷完成后,返回最小值的元素就可以了。

  • 3.圖片區(qū)塊每次交換之后,是怎樣監(jiān)控判斷游戲是否已經(jīng)結(jié)束的呢?

答案是回調(diào)函數(shù),圖片切片交換函數(shù)通過回調(diào)函數(shù)來判斷游戲是否已經(jīng)結(jié)束,游戲是否結(jié)束的判斷函數(shù)前面我們已經(jīng)說過。圖片切片交換函數(shù)就是通過添加gameIsEnd作為回調(diào)函數(shù),這樣在每次圖片切片移動交換完成之后,就判斷一下游戲是否結(jié)束。圖片切片的交換函數(shù)還是比較復(fù)雜的,有興趣的同學可以研究一下,下面是其實現(xiàn)代碼,大家重點理解其中添加了回調(diào)函數(shù)監(jiān)控游戲是否結(jié)束就好了。

//通過class獲取元素
function getClass(cls){
    var ret = [];
    var els = document.getElementsByTagName("*");
    for (var i = 0; i < els.length; i++){
        //判斷els[i]中是否存在cls這個className;.indexOf("cls")判斷cls存在的下標,如果下標>=0則存在;
        if(els[i].className === cls || els[i].className.indexOf("cls")>=0 || els[i].className.indexOf(" cls")>=0 || els[i].className.indexOf(" cls ")>0){
            ret.push(els[i]);
        }
    }
    return ret;
}
function getStyle(obj,attr){//解決JS兼容問題獲取正確的屬性值
    return obj.currentStyle?obj.currentStyle[attr]:getComputedStyle(obj,false)[attr];
}

function gameEnd() {
    alert('游戲結(jié)束!');
}

function startMove(obj,json,fun){
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
        var isStop = true;
        for(var attr in json){
            var iCur = 0;
            //判斷運動的是不是透明度值
            if(attr=="opacity"){
                iCur = parseInt(parseFloat(getStyle(obj,attr))*100);
            }else{
                iCur = parseInt(getStyle(obj,attr));
            }
            var ispeed = (json[attr]-iCur)/8;
            //運動速度如果大于0則向下取整,如果小于0想上取整;
            ispeed = ispeed>0?Math.ceil(ispeed):Math.floor(ispeed);
            //判斷所有運動是否全部完成
            if(iCur!=json[attr]){
                isStop = false;
            }
            //運動開始
            if(attr=="opacity"){
                obj.style.filter = "alpha:(opacity:"+(json[attr]+ispeed)+")";
                obj.style.opacity = (json[attr]+ispeed)/100;
            }else{
                obj.style[attr] = iCur+ispeed+"px";
            }
        }
        //判斷是否全部完成
        if(isStop){
            clearInterval(obj.timer);
            if(fun){
                fun();
            }
        }
    },30);
}

4 補充和總結(jié)

4.1 游戲中值得完善的功能

我認為該游戲中值得優(yōu)化的地方有兩個:

  • 1.為拼圖小游戲添加縮略圖,因為縮略圖有利于為玩游戲的用戶提供思路。我們又在瀏覽器本地存儲中保存了縮略圖的base64內(nèi)容,所以實現(xiàn)起來也很容易。

  • 2.緩存有的時候也讓人很痛苦,就比如說在游戲中有些用戶就想要重新開始,而我們的小游戲只有在游戲完成之后才清空緩存,刷新頁面,游戲才能夠重新開始。這給用戶的體驗很不好,我們可以加一個重置游戲按鈕,清空緩存并優(yōu)化游戲結(jié)束后的一些邏輯。

這些功能感興趣的小伙伴可以嘗試一下。

感謝你能夠認真閱讀完這篇文章,希望小編分享使用javascript中canvas實現(xiàn)拼圖小游戲的方法內(nèi)容對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián),詳細的解決方法等著你來學習!

網(wǎng)站標題:使用javascript中canvas實現(xiàn)拼圖小游戲的方法
轉(zhuǎn)載注明:http://chinadenli.net/article24/gdoeje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、網(wǎng)站維護、Google、網(wǎng)站內(nèi)鏈、響應(yīng)式網(wǎng)站、網(wǎng)站排名

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護公司