HTML5+JavaScript實現連連看游戲之二
以前一篇,見 https://blog.csdn.net/cnds123/article/details/144220548
連連看游戲連接規則:
只能連接相同圖案(或圖標、字符)的方塊。
連線路徑必須是由直線段組成的,最多可以有兩個拐角。
連線路徑必須是空的,不能穿過其他方塊。
當兩個相同圖案的方塊被有效連接時,它們會從游戲板上消失。當所有方塊都被消除時,玩家獲勝。
現在再發布一個,可以自定義 行列數、可用圖片數(實際是使用Font Awesome圖標庫以便跨平臺兼容,通過CDN加載圖標庫)
同一局游戲中所有圖標使用相同顏色,不同局顏色會變化。
游戲就可以在行數和列數乘積為偶數時才允許開始,如果行數和列數的乘積為奇數,則不允許游戲開始,并且可以通過彈出提示信息來告知用戶。
點擊"開始"按鈕后立即生成布局并開始計時。
運行界面
下面代碼若要在手機上玩,可以在? <meta charset="UTF-8"> 之后添加一行
??? <meta name="viewport" content="width=device-width, initial-scale=1.0">
源碼如下:
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>連連看游戲(跨平臺版)</title><!-- 引入Font Awesome圖標庫 --><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"><style>body {font-family: Arial, sans-serif;display: flex;flex-direction: column;align-items: center;background-color: #f0f0f0;}#controls {margin: 20px 0;text-align: center;}input, button {margin: 0 10px;padding: 5px;}button {background-color: #4CAF50;color: white;border: none;cursor: pointer;transition: background-color 0.3s;}button:hover {background-color: #45a049;}#timebar {height: 30px;width: 600px;background-color: #ddd;margin-bottom: 20px;position: relative;}#timebar-inner {height: 100%;width: 100%;background-color: green;transition: width 1s linear;}#timeleft {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);color: white;font-weight: bold;z-index: 1;}#container {background-color: white;padding: 20px;border-radius: 10px;box-shadow: 0 0 10px rgba(0,0,0,0.1);display: flex;justify-content: center;align-items: center;}table {border-collapse: collapse;}td {border: 1px solid #ddd;text-align: center;vertical-align: middle;cursor: pointer;transition: background-color 0.3s;width: 40px;height: 40px;font-family: "Font Awesome 5 Free";font-weight: 900;}td:hover {background-color: #f5f5f5;}td i {font-size: 24px;}</style>
</head>
<body><div id="controls">行數<input id="setrow" type="number" value="9" min="2" max="20">列數<input id="setcol" type="number" value="16" min="2" max="40">圖片數<input id="setpic" type="number" value="12" min="1" max="26">時間<input id="settime" type="number" value="120" min="10" max="1200">秒<button onclick="SetupGame();">設置</button><button onclick="StartGame();" id="startButton">開始</button></div><div id="timebar"><div id="timebar-inner"></div><div id="timeleft"></div></div><div id="container"></div><script>// 圖標配置(擴展更多圖標請訪問:https://fontawesome.com/icons)const icons = ['fa-heart', 'fa-star', 'fa-circle', 'fa-square','fa-check', 'fa-times', 'fa-bell', 'fa-flag','fa-cloud', 'fa-sun', 'fa-moon', 'fa-leaf','fa-gem', 'fa-car', 'fa-tree', 'fa-coffee','fa-bolt', 'fa-rocket', 'fa-key', 'fa-bug','fa-cat', 'fa-dog', 'fa-fish', 'fa-horse'];// 圖標配置(僅定義類型)const iconClasses = ['fa-heart', 'fa-star', 'fa-circle', 'fa-square','fa-check', 'fa-times', 'fa-bell', 'fa-flag','fa-cloud', 'fa-sun', 'fa-moon', 'fa-leaf'];let currentColor = ""; // 全局當前顏色let RowMax = 11;let ColMax = 18;let PicMax = 12;let TimeMax = 120;let st;let TmpStr = "";let TmpObj = null;let TmpTime = 0;let TmpInt = 0;let gameMatrix;let gameStarted = false;let P = new Array(4);for(let i=0; i<4; i++) P[i] = {x:0, y:0};function SetupGame(){clearInterval(st);// 參數校驗const rowVal = Math.min(20, Math.max(2, parseInt(document.getElementById("setrow").value)));const colVal = Math.min(40, Math.max(2, parseInt(document.getElementById("setcol").value)));RowMax = rowVal + 2;ColMax = colVal + 2;// 檢查行數與列數的乘積是否為偶數if ((rowVal * colVal) % 2 !== 0) {alert("行數和列數的乘積必須為偶數,請調整行數或列數。");return; // 終止函數執行}PicMax = Math.min(icons.length, Math.max(1, parseInt(document.getElementById("setpic").value)));TimeMax = Math.min(1200, Math.max(10, parseInt(document.getElementById("settime").value)));generateNewGame();document.getElementById("timeleft").innerHTML = "點擊開始按鈕開始游戲";document.getElementById("timebar-inner").style.width = "100%";document.getElementById("timebar-inner").style.backgroundColor = "#4CAF50";document.getElementById("startButton").disabled = false;gameStarted = false;}function getRandomColor() {return `hsl(${Math.random() * 360}, 70%, 60%)`; // 隨機HSL顏色}function generateNewGame() {gameMatrix = Array(RowMax).fill().map(() => Array(ColMax).fill(0));// 生成全局統一顏色currentColor = `hsl(${Math.random()*360}, 70%, 60%)`; // 隨機HSL顏色// 生成配對邏輯(僅存儲圖標類型索引)const totalCells = (RowMax-2)*(ColMax-2);const pairs = [];for(let i=0; i<totalCells/2; i++){const type = i % PicMax; // 確保成對生成pairs.push(type, type);}// 洗牌算法for(let i = pairs.length -1; i > 0; i--){const j = Math.floor(Math.random() * (i+1));[pairs[i], pairs[j]] = [pairs[j], pairs[i]];}// 構建表格(所有圖標使用相同顏色)TmpStr = "<table>";let pairIndex = 0;for(let i=0; i<RowMax; i++){TmpStr += "<tr>";for(let j=0; j<ColMax; j++){TmpStr += `<td onclick="CheckP(this,${i},${j});">`;if(i === 0 || j === 0 || i === RowMax-1 || j === ColMax-1){gameMatrix[i][j] = null; // 邊界保持為空} else {const type = pairs[pairIndex++];gameMatrix[i][j] = type; // 存儲類型索引// 所有圖標使用同一顏色TmpStr += `<i class="fas ${iconClasses[type]}" style="color:${currentColor}"></i>`;}TmpStr += "</td>";}TmpStr += "</tr>";}TmpStr += "</table>";document.getElementById("container").innerHTML = TmpStr;TmpInt = totalCells/2;}// 開始游戲function StartGame(){gameStarted = true; // 標記游戲已開始TmpTime = TimeMax; // 重置時間document.getElementById("timeleft").innerHTML = TmpTime; // 顯示剩余時間document.getElementById("timebar-inner").style.width = "100%";document.getElementById("timebar-inner").style.backgroundColor = "green";st = setInterval(ShowTime, 1000); // 開始倒計時// 禁用"開始"按鈕document.getElementById("startButton").disabled = true;}// X方向連線。(有起點,無終點)function LineX(x, y, xt){for(let i=x; i!=xt; (x<xt? i++: i--) ){if(gameMatrix[i][y]){return false;}}return true;}// Y方向連線。(有起點,無終點)function LineY(x, y, yt){for(let i=y; i!=yt; (y<yt? i++: i--) ){if(gameMatrix[x][i]){return false;}} return true;}// 2個點被3條線連接function LinkP(P1,P2){// P1在P2下方,交換P1、P2if(P1.x>P2.x){[P1, P2] = [P2, P1];}// P1下方1點(x+1)先橫向再縱向是否可連接。(因為起點P1不為空,所以檢測其下方一點)if( LineX((P1.x+1), P1.y, P2.x) && LineY(P2.x, P1.y, P2.y) ) return true;// P1先向上側連接,再檢測該點再橫向再縱向是否可連接P2。for(let j=(P1.y-1); j>=0; j--){if(gameMatrix[P1.x][j]) break;if( LineX((P1.x+1), j, P2.x) && LineY(P2.x, j, P2.y) ) return true;}// P1先向下側連接,再檢測該點再橫向再縱向是否可連接P2。for(let j=(P1.y+1); j<ColMax; j++){if(gameMatrix[P1.x][j]) break;if( LineX((P1.x+1), j, P2.x) && LineY(P2.x, j, P2.y) ) return true;}// P1在P2左側,交換P1、P2if(P1.y>P2.y){[P1, P2] = [P2, P1];}if( LineY(P1.x, (P1.y+1), P2.y) && LineX(P1.x, P2.y, P2.x) ) return true;for(let j=(P1.x-1); j>=0; j--){if(gameMatrix[j][P1.y]) break;if( LineY(j, (P1.y+1), P2.y) && LineX(j, P2.y, P2.x) ) return true;}for(let j=(P1.x+1); j<RowMax; j++){if(gameMatrix[j][P1.y]) break;if( LineY(j, (P1.y+1), P2.y) && LineX(j, P2.y, P2.x) ) return true;}return false;}// 單擊檢測該點(僅需比較類型)function CheckP(o,x,y){if (!gameStarted) return;if(gameMatrix[x][y] !== null){ if(null==TmpObj){ TmpObj = o;TmpObj.style.border = "2px solid blue";P[0].x = x;P[0].y = y;}else if(o!=TmpObj){TmpObj.style.border = "";P[1].x = x;P[1].y = y;// 僅比較類型索引if(gameMatrix[P[0].x][P[0].y] === gameMatrix[P[1].x][P[1].y]){if(LinkP(P[0],P[1])){gameMatrix[P[0].x][P[0].y] = null;gameMatrix[P[1].x][P[1].y] = null;TmpObj.innerHTML = "";o.innerHTML = "";TmpTime++;TmpInt--;if(!TmpInt){clearInterval(st);document.getElementById("timeleft").innerHTML = "";document.getElementById("timebar-inner").style.backgroundColor = "white";alert("恭喜完成!");document.getElementById("startButton").disabled = false;gameStarted = false;}}}TmpObj = null;}} else {if(TmpObj) TmpObj.style.border = "";TmpObj = null;}}function ShowTime(){TmpTime--; // 時間減1// 更新時間顯示document.getElementById("timeleft").innerHTML = TmpTime;let percentage = Math.floor(100*TmpTime/TimeMax);document.getElementById("timebar-inner").style.width = percentage + "%";if(percentage <= 25){document.getElementById("timebar-inner").style.backgroundColor = "red";}else if(percentage <= 50){document.getElementById("timebar-inner").style.backgroundColor = "yellow";}if(!TmpTime){ // 剩余時間為0clearInterval(st); // 清除倒計時document.getElementById("timeleft").innerHTML = "";document.getElementById("timebar-inner").style.backgroundColor = "white";alert("時間到!游戲結束");// 啟用"開始"按鈕document.getElementById("startButton").disabled = false;gameStarted = false; // 重置游戲狀態}}// 頁面加載完成后,顯示初始提示信息window.onload = function() {document.getElementById("timeleft").innerHTML = "請設置游戲參數并點擊設置按鈕";document.getElementById("timebar-inner").style.backgroundColor = "#ddd";document.getElementById("startButton").disabled = true;}</script>
</body>
</html>