12.JavaScript實現拼圖游戲源碼

来源:https://www.cnblogs.com/lanshanxiao/archive/2020/04/25/12775195.html
-Advertisement-
Play Games

目前代碼沒有放到GitHub上,之後會放出鏈接 1.目錄結構: 2.index.html文件: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=de ...


目前代碼沒有放到GitHub上,之後會放出鏈接

1.目錄結構:

 

 2.index.html文件:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="clearfix">
        <!-- 拼圖游戲 -->
        <div style="float:left;" class="picture-puzzle">

        </div>
        <!-- 對比圖片 -->
        <div style="float:right;">
            <img src="./image/dog.jpg" alt="">
        </div>
    </div>
    <script src="./js/index.js"></script>
</body>
</html>
index.html

3.index.js文件:

// 游戲參數
var gameConfig = {
    width: 589, //整張圖片的寬度
    height: 416, //整張圖片的高度
    row: 3, //小方塊的行數
    cols: 3, //小方塊的列數
    imageurl: "./image/dog.jpg", //圖片的路徑
    dom: document.getElementsByClassName("picture-puzzle")[0], //游戲容器的dom
    isOver: false, //游戲是否結束
    minStep: 30,//打亂拼圖的最小步數
    maxStep: 100//打亂拼圖的最大步數
    // isHaveSolution: false //游戲是否有解
}

gameConfig.pieceWidth = gameConfig.width / gameConfig.row; //每個小塊的寬度
gameConfig.pieceHeight = gameConfig.height / gameConfig.cols; //每個小塊的高度

var blocks = []; //存儲每個小塊的信息

//小方塊構造函數
function Block(row, cols) {
    // this.sequenceNumber; //方塊的編號從1到(row*cols)-1;空白格編號為0
    this.width = gameConfig.pieceWidth; //
    this.height = gameConfig.pieceHeight; //
    this.correctRow = row; //小方塊所在正確的行數,用來判斷方塊行數是否正確
    this.correctCols = cols; //小方塊所在正確的列數,用來判斷方塊列數是否正確
    this.row = row; //小方塊當前所在行數
    this.cols = cols; //小方塊當前所在列數
    this.isDisplay = false; //是否是空白塊:true.是;false:否;

    this.div = document.createElement("div");
    this.div.style.width = gameConfig.pieceWidth + "px";
    this.div.style.height = gameConfig.pieceHeight + "px";
    this.div.style.background = `url("${gameConfig.imageurl}") -${this.correctCols * this.width}px -${this.correctRow * this.height}px`;
    this.div.style.border = "1px solid #fff";
    this.div.style['box-sizing'] = "border-box";
    this.div.style.position = "absolute";

    this.show = function () { //展示小方塊顯示的位置
        this.div.style.left = this.cols * gameConfig.pieceWidth + "px";
        this.div.style.top = this.row * gameConfig.pieceHeight + "px";

    }
    this.show();

    if (row === gameConfig.row - 1 && cols === gameConfig.cols - 1) { //最後一方塊隱藏
        this.div.style.display = "none";
        this.isDisplay = true; //是否是空白塊:true.是;false:否;
    }
    gameConfig.dom.appendChild(this.div);

    this.isCorrect = function () { //判斷方塊當前位置的行列是否等於正確位置的行列
        if (this.row === this.correctRow && this.cols === this.correctCols) {
            return true;
        }
        return false;
    }
}

//初始化游戲
function init() {
    //1.初始化游戲容器寬度
    initGameDom();
    //2.初始化每個小方塊基本信息
    initBlocksArray();
    //3.亂序拼圖可解的演算法沒有看懂,只能程式自動走100步
    // while (!gameConfig.isHaveSolution) {
    randomSort();
    // }
    //4.註冊點擊事件
    registerEvent();

    //初始化游戲容器
    function initGameDom() {
        gameConfig.dom.style.width = gameConfig.width + "px";
        gameConfig.dom.style.height = gameConfig.height + "px";
        gameConfig.dom.style.border = "2px solid #ccc";
        gameConfig.dom.style.position = "relative";
    }

    //初始化小方塊數組信息
    function initBlocksArray() {
        for (var i = 0; i < gameConfig.row; i++) {
            for (var j = 0; j < gameConfig.cols; j++) {
                // 每個小塊的基本信息
                var block = new Block(i, j);
                blocks.push(block);
            }
        }
        // blocks.forEach(function (item, index) {
        //     item.sequenceNumber = index + 1;
        // });
        // blocks[gameConfig.row * gameConfig.cols - 1].sequenceNumber = 0; //最後一個空白塊編號為0
    }

    //把小方塊打亂順序
    function randomSort() {
        var step = getRandom(gameConfig.minStep, gameConfig.maxStep);//隨機在[30,100)區間里取出一個數,作為打亂拼圖的步數
        console.log(step);
        //程式自走step步,將拼圖順序打亂
        for (var i = 0; i < step; i++) {
            // 找到空白塊所在的行和列
            var blankBlock = blocks.filter(function (item) {
                return item.isDisplay;
            });

            for (var j = 0; j < blocks.length; j++) {
                //判斷是否可以交換,橫坐標相同則縱坐標相差1||縱坐標相同則橫坐標相差為1
                if (blocks[j].row === blankBlock[0].row && Math.abs(blocks[j].cols - blankBlock[0].cols) === 1 ||
                    blocks[j].cols === blankBlock[0].cols && Math.abs(blocks[j].row - blankBlock[0].row) === 1) {
                    exchangeBlocks(blocks[j], blankBlock[0]);
                    continue; //交換一次後進入下個迴圈,保障交換次數為step次
                }
            }
        }
        // for (var i = 0; i < (gameConfig.row * gameConfig.cols - 1); i++) {
        //     //1.產生一個隨機數
        //     //2.將當前小方塊信息和隨機選中的小方塊信息互換,最後一個空白塊位置不變
        //     var index = getRandom(0, blocks.length - 2);
        //     //交換數據
        //     exchangeBlocks(blocks[i], blocks[index]);
        // }

        blocks.forEach(function (item) {
            item.show();
        });
        //判斷拼圖是否有解
        // haveSolution();
    }

    //判斷亂序的拼圖是否有解
    // function haveSolution() {
    //     var count = 0;
    //     //計算逆序列個數,逆序數:前面的編號大於後面的編號的個數
    //     for (var i = 0; i < blocks.length; i++) {
    //         for (var j = i + 1; j < (blocks.length - 1 - i); j++) {
    //             console.log(i, j, blocks[i].sequenceNumber);
    //             if (blocks[i].sequenceNumber > blocks[j].sequenceNumber) {
    //                 count++;
    //             }
    //         }
    //     }
    //     console.log(count);

    //     //計算空白塊編號為0所在的位置
    //     var blankBlock = gameConfig.row * gameConfig.cols - 1;

    //     //奇偶性不同則無解
    //     gameConfig.isHaveSolution = (count % 2 != blankBlock % 2) ? false : true;
    //     console.log(gameConfig.isHaveSolution);
    // }

    //為方塊註冊事件
    function registerEvent() {
        //找到空白塊
        var isDisplayBlock = blocks.find(function (item) {
            return item.isDisplay;
        });
        blocks.forEach(function (item) {
            item.div.onclick = function () {
                if (gameConfig.isOver) { //游戲結束,則不在繼續以下操作
                    return;
                }
                //判斷是否可以交換,橫坐標相同則縱坐標相差1||縱坐標相同則橫坐標相差為1
                if (item.row === isDisplayBlock.row && Math.abs(item.cols - isDisplayBlock.cols) === 1 ||
                    item.cols === isDisplayBlock.cols && Math.abs(item.row - isDisplayBlock.row) === 1) {
                    exchangeBlocks(item, isDisplayBlock);
                }
                //游戲結束
                isWin();
            }
        });
    }

    //交換兩個方塊的位置
    function exchangeBlocks(b1, b2) {
        var temp = b1.row;
        b1.row = b2.row;
        b2.row = temp;

        var temp = b1.cols;
        b1.cols = b2.cols;
        b2.cols = temp;

        // var temp = b1.sequenceNumber;
        // b1.sequenceNumber = b2.sequenceNumber;
        // b2.sequenceNumber = temp;

        b1.show();
        b2.show();
    }

    //游戲結束
    function isWin() {
        var wrongBlocks = blocks.filter(function (item) { //篩選出位置錯誤的方塊
            return !item.isCorrect();
        });
        if (wrongBlocks.length === 0) { //所有方塊都在正確位置
            gameConfig.isOver = true; //游戲結束
            blocks.forEach(function (item) {
                item.div.style.display = "block";
                item.div.style.border = "none";
            });
        }
    }
    //-------------通用函數----begin-----------//

    //返回一個[min,max)區間的隨機數
    function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min)) + min;
    }

    //-------------通用函數----end-----------//
}

init();
index.js

代碼中都有簡單註釋,有什麼問題請在評論中提出,這裡只講解拼圖初始化時打亂拼圖順序所用的方法。

在網上找了好多拼圖的可解演算法,都沒有看太懂,若讀者知道或有實現方法,請賜教。

我這裡使用randomSort()方法,讓正確的順序自動走一定的步數去打亂拼圖的順序。

4.圖片文件

可以從網上隨意找一張圖片放到1中的image文件夾下,記得更改圖片名稱和路徑(imageurl),和圖片的width和height

 

 上圖中是游戲的參數配置,可以自己修改下row,cols,minStep,maxStep看下效果

 

 

效果展示:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 日常運維中的坑真是防不勝防,不一小心就遇到別人給你挖的坑。最近又遇到經驗不足的DBA不知道從哪拷貝的配置文件(據說是當時參加某培訓機構視頻培訓是資料里的模板,真的是誤人子弟呀),其中把max_binlog_cache_size設置的只有2G,而MySQL早已將此參數的預設值調整的很大了(184467 ...
  • https://www.cnblogs.com/chenshishuo/p/5030029.html 本文從如何建立mysql索引以及介紹mysql的索引類型,再講mysql索引的利與弊,以及建立索引時需要註意的地方 首先:先假設有一張表,表的數據有10W條數據,其中有一條數據是nickname=' ...
  • 一.創建spring boot項目 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <depe ...
  • 一、SQLite安裝包准備 本文章主要是針對安裝了Android Studio 3.6.3 版本(Android Studio以下簡稱為AS)所做的SQLite教程, 博主這邊安裝的是, 由於SQL語言基本大同小異,僅僅是管理資料庫的軟體不大相同,所以說資料庫使用方法類似,具體安裝流程參考網路上其他 ...
  • 目錄:andorid jar/庫源碼解析 Okhttp3: 作用: 用於網路編程(http,https)的快速開發。 慄子: // okHttpClient定義成全局靜態,或者單例,不然重覆new可能導致連接數耗盡 OkHttpClient okHttpClient = new OkHttpClie ...
  • 事件綁定 版 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> ...
  • join(): 將數組的元素組起一個字元串,以 separator 為分隔符,省略的話則用預設用逗號為分隔符,該方法只接收一個參數:即分隔符。 push()和pop(): push() 可以接收任意數量的參數,把它們逐個添加到數組末尾,並返回修改後數組的長度。 pop() 數組末尾移除最後一項,減少 ...
  • 隨著Jquery知識點的結束,我也開始接觸到框架來了。 開始的時候,總是聽到插件和框架等詞,我疑惑框架和插件是啥有啥區別?? 插件可以說有無數種,在網頁中任何一種功能都可以被叫做插件,單獨提取出來,可以供別人使用,而框架是一個超大號的的插件,它將各種方法融合成一體,使用者可以使用它來構造不同的功能。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...