Trò chơi lật hình (Memory Game) là một trò chơi phổ biến trong năm 2024, yêu cầu người chơi lật các thẻ và tìm các cặp hình trùng nhau. Trò chơi không chỉ mang tính giải trí mà còn giúp cải thiện trí nhớ. Đặc biệt, trong bài hướng dẫn này, chúng ta sẽ tích hợp tính năng giảm giá dựa trên mức độ hoàn thành trò chơi, điều này có thể hữu ích trong việc giữ chân người chơi trên website hoặc khuyến khích mua hàng. Hôm nay, MuathemeWPgiare sẽ hướng dẫn các bạn code game này vào wordpress cực kỳ đơn giản. Hãy cùng đọc bài viết nhé:
1. Cài Đặt WordPress Shortcode
Để tạo trò chơi lật hình trong WordPress, bạn sẽ sử dụng một shortcode. Dưới đây là mã shortcode để bạn có thể nhúng trò chơi vào bất kỳ trang hoặc bài viết nào trong website WordPress của mình.
Code Shortcode:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
function memory_game_with_discount() { ob_start(); ?> <div id="start-game" class="muathemewpgiare"> <h2>Chọn cấp độ chơi</h2> <select id="level-option" class="muathemewpgiare"> <option value="4">Dễ (4 thẻ)</option> <option value="6">Trung bình (6 thẻ)</option> <option value="8">Khó (8 thẻ)</option> <option value="12">Rất Khó (12 thẻ)</option> <option value="16">Cực Khó (16 thẻ)</option> <option value="24">Siêu Khó (24 thẻ)</option> </select> <button id="btn-start-game" class="muathemewpgiare">Bắt đầu chơi</button> </div> <div id="game" class="muathemewpgiare" style="display: none;"> <h2>Thời gian còn lại: <span id="time-display">00:00</span></h2> <div class="progress-bar"> <div id="progress"></div> </div> <div id="memory-game" class="memory-game-board muathemewpgiare"></div> <p id="game-result" class="muathemewpgiare" style="display: none;"></p> <button id="btn-reset-game" class="muathemewpgiare" style="display: none;">Chơi lại</button> </div> <?php return ob_get_clean(); } add_shortcode('memory_game', 'memory_game_with_discount'); |
[memory_game]
vào một trang hoặc bài viết, giao diện trò chơi sẽ được hiển thị.
Xem thêm cách làm game rắn săn mồi: Viết Trò Chơi Con Rắn và Tạo Mã Giảm Giá Trong Game WordPress
2. Cài Đặt Styles (CSS)
Để trò chơi trông chuyên nghiệp và thân thiện, bạn cần thêm một số CSS cho các phần tử của trò chơi. Dưới đây là đoạn mã CSS giúp định hình trò chơi lật thẻ:
Code CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
function memory_game_styles() { echo '<style> .muathemewpgiare { font-family: Arial, sans-serif; animation: fadeIn 1.5s ease-in-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .memory-game-board { display: grid; gap: 10px; justify-content: center; margin-top: 20px; } .memory-card { width: 150px; height: 200px; perspective: 1000px; cursor: pointer; transform-style: preserve-3d; transition: transform 0.6s; position: relative; background-color: #f9f9f9; box-shadow: 0 5px 15px rgba(0,0,0,0.1); border-radius: 10px; } .memory-card:hover { transform: scale(1.05); box-shadow: 0 10px 25px rgba(0,0,0,0.2); } .memory-card img { width: 100%; height: 100%; position: absolute; backface-visibility: hidden; border-radius: 10px; } .memory-card .front-face { transform: rotateY(180deg); } .memory-card.flipped .front-face { transform: rotateY(0); } .memory-card.flipped .back-face { transform: rotateY(180deg); } .progress-bar { width: 80%; margin: 20px auto; background: #ddd; border-radius: 10px; height: 20px; position: relative; } #progress { height: 100%; background: linear-gradient(90deg, #4CAF50, #8BC34A); width: 0; border-radius: 10px; transition: width 0.3s; } </style>'; } add_action('wp_head', 'memory_game_styles'); |
3. Cài Đặt Logic Game (JavaScript)
Đây là phần quan trọng nhất của trò chơi lật hình: phần logic để người chơi có thể tương tác với trò chơi. Các thẻ sẽ được lật khi người chơi nhấn vào chúng, và nếu hai thẻ trùng nhau, chúng sẽ bị “khóa”, nếu không sẽ lật ngược lại. Thời gian và mã giảm giá cũng sẽ hiển thị tùy vào cấp độ mà người chơi chọn.
Code JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
function memory_game_scripts() { ?> <script> const btnStartGame = document.querySelector('#btn-start-game'); const startGameEl = document.querySelector('#start-game'); const gameEl = document.querySelector('#game'); const levelOptionEl = document.querySelector('#level-option'); const timeEl = document.querySelector('#time-display'); const memoryGameEl = document.querySelector('#memory-game'); const gameResultEl = document.querySelector('#game-result'); const btnResetGame = document.querySelector('#btn-reset-game'); const progressBar = document.querySelector('#progress'); let level, maxTime, remainingTime; let time = 0; let interval; let flippedCards = []; let matchedCards = 0; let lockBoard = false; let firstCard, secondCard; // Cài đặt cấp độ và thời gian tương ứng const levelSettings = { 4: { discount: 15, maxTime: 300, row: 2, col: 2 }, // Easy 6: { discount: 25, maxTime: 180, row: 2, col: 3 }, // Medium 8: { discount: 50, maxTime: 120, row: 2, col: 4 }, // Hard 12: { discount: 75, maxTime: 90, row: 3, col: 4 }, // Very Hard 16: { discount: 100, maxTime: 60, row: 4, col: 4 }, // Extreme 24: { discount: 150, maxTime: 45, row: 4, col: 6 } // Super Extreme }; // Khi nhấn bắt đầu trò chơi btnStartGame.addEventListener('click', function () { level = Number(levelOptionEl.value); // Lấy giá trị cấp độ từ lựa chọn của người chơi maxTime = levelSettings[level].maxTime; // Thời gian tối đa dựa trên cấp độ remainingTime = maxTime; // Đặt thời gian còn lại ban đầu // Hiển thị màn hình trò chơi và ẩn màn hình bắt đầu startGameEl.style.display = 'none'; gameEl.style.display = 'block'; btnResetGame.style.display = 'none'; // Ẩn nút chơi lại gameResultEl.style.display = 'none'; // Ẩn kết quả trò chơi // Bắt đầu trò chơi renderCards(level); // Hiển thị các thẻ dựa trên cấp độ time = 0; interval = setInterval(updateTime, 1000); // Bắt đầu đếm ngược thời gian }); // Khi nhấn nút "Chơi lại" btnResetGame.addEventListener('click', function () { clearInterval(interval); // Dừng đếm thời gian startGameEl.style.display = 'block'; // Hiển thị lại màn hình bắt đầu gameEl.style.display = 'none'; // Ẩn màn hình trò chơi timeEl.innerText = '00:00'; // Reset hiển thị thời gian progressBar.style.width = '0'; // Reset thanh tiến trình matchedCards = 0; // Reset số thẻ đã ghép flippedCards = []; // Reset thẻ lật lockBoard = false; // Mở khóa bảng }); // Hàm cập nhật thời gian và thanh tiến trình function updateTime() { remainingTime--; // Giảm thời gian còn lại timeEl.innerText = convertTime(remainingTime); // Cập nhật hiển thị thời gian // Cập nhật thanh tiến trình let progressWidth = ((maxTime - remainingTime) / maxTime) * 100; progressBar.style.width = ${progressWidth}%; // Nếu hết thời gian, kết thúc trò chơi if (remainingTime <= 0) { clearInterval(interval); // Dừng đếm thời gian gameResultEl.innerText = 'Hết thời gian! Bạn không đủ điều kiện nhận mã giảm giá.'; gameResultEl.style.display = 'block'; // Hiển thị kết quả btnResetGame.style.display = 'block'; // Hiển thị nút chơi lại lockBoard = true; // Khóa bảng để không thể lật thẻ nữa } } // Chuyển đổi thời gian từ giây sang định dạng mm:ss function convertTime(time) { let minute = 0${Math.floor(time / 60)}.slice(-2); let second = 0${time % 60}.slice(-2); return ${minute}:${second}; } // Hàm đảo ngẫu nhiên mảng thẻ function shuffle(arr) { return arr.sort(() => 0.5 - Math.random()); } // Hàm hiển thị thẻ dựa trên cấp độ function renderCards(level) { let listCards = [ { url: 'https://i.pinimg.com/564x/9f/2f/72/9f2f72f1c63e6c62ac0ca3781e270975.jpg', name: 'luffy' }, { url: 'https://i.pinimg.com/236x/d3/3f/c0/d33fc0cd1bf76766555436c2307b94d7.jpg', name: 'zoro' }, { url: 'https://i.pinimg.com/236x/c2/b4/49/c2b4490285a27881586d3e8c49c4b565.jpg', name: 'sanji' }, { url: 'https://i.pinimg.com/236x/fb/a8/ce/fba8cec6aa3a5faa06b0d5f9a21401ed.jpg', name: 'ace' }, { url: 'https://i.pinimg.com/564x/22/3c/d0/223cd0f2a3f3cb6b47c5117299f31a44.jpg', name: 'shanks' }, { url: 'https://i.pinimg.com/236x/43/2f/b7/432fb73855f9cabe66298a6c12262d44.jpg', name: 'nami' } ]; // Đảo ngẫu nhiên các thẻ listCards = shuffle(listCards); let cardsSlice = listCards.slice(0, level / 2); // Chọn thẻ dựa trên cấp độ let cards = [...cardsSlice, ...cardsSlice]; // Nhân đôi mảng để tạo cặp thẻ cards = shuffle(cards); // Đảo ngẫu nhiên lại thẻ // Cấu hình lưới thẻ dựa trên số cột và hàng theo cấp độ let size = levelSettings[level]; memoryGameEl.style.gridTemplateColumns = repeat(${size.col}, 150px); memoryGameEl.style.gridTemplateRows = repeat(${size.row}, 200px); // Xóa các thẻ cũ và thêm các thẻ mới vào giao diện memoryGameEl.innerHTML = ''; cards.forEach(card => { const cardElement = document.createElement('div'); cardElement.classList.add('memory-card'); cardElement.setAttribute('data-name', card.name); cardElement.innerHTML = <img src="${card.url}" class="front-face" alt="${card.name}"> <img src="https://i.pinimg.com/originals/b9/70/33/b97033a8708d2cbaf7d1990020a89a54.jpg" class="back-face" alt="card-back"> ; cardElement.addEventListener('click', flipCard); // Gắn sự kiện lật thẻ cho từng thẻ memoryGameEl.appendChild(cardElement); // Thêm thẻ vào DOM }); } function createSnowflakes() { const snowflake = document.createElement('div'); snowflake.classList.add('snowflake'); snowflake.innerHTML = '❆'; document.body.appendChild(snowflake); // Đặt ngẫu nhiên vị trí cho bông tuyết snowflake.style.left = ${Math.random() * window.innerWidth}px; // Xóa bông tuyết sau khi rơi khỏi màn hình setTimeout(() => { snowflake.remove(); }, 10000); } // Tạo hiệu ứng tuyết rơi liên tục setInterval(createSnowflakes, 300); // Hàm lật thẻ function flipCard() { if (lockBoard) return; // Không cho phép lật thẻ nếu bảng bị khóa if (this === firstCard) return; // Không cho phép lật lại thẻ đã lật this.classList.add('flipped'); // Lật thẻ if (!firstCard) { // Lật thẻ đầu tiên firstCard = this; } else { // Lật thẻ thứ hai secondCard = this; lockBoard = true; // Khóa bảng để kiểm tra cặp thẻ checkForMatch(); } } // Hàm kiểm tra cặp thẻ trùng nhau function checkForMatch() { let isMatch = firstCard.dataset.name === secondCard.dataset.name; if (isMatch) { disableCards(); // Khóa các thẻ trùng khớp matchedCards += 2; // Tăng số thẻ đã ghép if (matchedCards === level) { endGame(); // Kết thúc trò chơi khi ghép hết thẻ } } else { unflipCards(); // Lật lại các thẻ nếu không khớp } } // Hàm khóa các thẻ đã ghép đúng function disableCards() { firstCard.removeEventListener('click', flipCard); secondCard.removeEventListener('click', flipCard); resetBoard(); // Reset lại bảng sau khi ghép thẻ } // Hàm lật lại các thẻ nếu không khớp function unflipCards() { setTimeout(() => { firstCard.classList.remove('flipped'); secondCard.classList.remove('flipped'); resetBoard(); // Reset lại bảng sau khi lật lại thẻ }, 1000); // Đặt thời gian chờ 1 giây trước khi lật lại } // Hàm reset bảng và trạng thái sau mỗi lần lật thẻ function resetBoard() { [firstCard, secondCard] = [null, null]; // Reset lại thẻ đầu tiên và thẻ thứ hai lockBoard = false; // Mở khóa bảng để tiếp tục chơi } // Kiểm tra nếu người chơi hoàn thành trong thời gian cho phép function endGame() { clearInterval(interval); // Dừng đếm thời gian khi trò chơi kết thúc if (remainingTime > 0) { // Nếu người chơi hoàn thành trong thời gian quy định, nhận mã giảm giá let discount = levelSettings[level].discount; // Lấy giá trị mã giảm giá dựa trên cấp độ gameResultEl.innerText = Chúc mừng! Bạn nhận được mã giảm giá ${discount}% cho cấp độ này.; } else { // Nếu thời gian hết trước khi hoàn thành, thông báo không nhận được mã giảm giá gameResultEl.innerText = 'Bạn đã hết thời gian! Không đủ điều kiện nhận mã giảm giá.'; } gameResultEl.style.display = 'block'; // Hiển thị kết quả trò chơi btnResetGame.style.display = 'block'; // Hiển thị nút chơi lại để người chơi có thể chơi lại lockBoard = true; // Khóa bảng sau khi trò chơi kết thúc, không cho phép lật thêm thẻ } // Hàm reset trò chơi khi người chơi nhấn nút "Chơi lại" btnResetGame.addEventListener('click', function () { clearInterval(interval); // Dừng đếm thời gian nếu trò chơi chưa kết thúc startGameEl.style.display = 'block'; // Hiển thị lại màn hình bắt đầu gameEl.style.display = 'none'; // Ẩn màn hình trò chơi timeEl.innerText = '00:00'; // Reset thời gian hiển thị về 0 progressBar.style.width = '0'; // Reset thanh tiến trình matchedCards = 0; // Reset số thẻ đã ghép flippedCards = []; // Reset thẻ lật lockBoard = false; // Mở khóa bảng để bắt đầu lại }); </script> <?php } add_action('wp_footer', 'memory_game_scripts'); |
4.1. Các Thành Phần HTML & DOM
btnStartGame
: Đây là nút “Bắt đầu chơi”. Khi người chơi nhấn vào, trò chơi sẽ bắt đầu.startGameEl
: Phần tử chứa màn hình chọn cấp độ chơi, bao gồm nút “Bắt đầu” và các tùy chọn chọn cấp độ.gameEl
: Phần tử chứa màn hình trò chơi, nơi các thẻ được hiển thị sau khi trò chơi bắt đầu.levelOptionEl
: Đây là danh sách tùy chọn cấp độ trò chơi (Dễ, Trung Bình, Khó,…).timeEl
: Hiển thị thời gian còn lại khi chơi trò chơi.memoryGameEl
: Đây là bảng lưới chứa các thẻ trong trò chơi.gameResultEl
: Hiển thị kết quả sau khi trò chơi kết thúc (chẳng hạn như thông báo về mã giảm giá).btnResetGame
: Nút “Chơi lại” xuất hiện khi trò chơi kết thúc, cho phép người chơi khởi động lại trò chơi.progressBar
: Thanh tiến trình hiển thị mức độ thời gian còn lại của trò chơi.
4.2. Biến & Cài Đặt
level
,maxTime
,remainingTime
: Các biến để lưu cấp độ chơi, thời gian tối đa của trò chơi và thời gian còn lại.time
: Biến đếm thời gian trong trò chơi.interval
: Dùng để lưu giá trị củasetInterval
, giúp cập nhật thời gian sau mỗi giây.flippedCards
,matchedCards
: Mảng chứa các thẻ đã lật và biến đếm số cặp thẻ đã ghép đúng.lockBoard
: Biến cờ (flag) để khóa trò chơi trong khi chờ người chơi lật cặp thẻ tiếp theo.firstCard
,secondCard
: Các biến lưu thẻ đầu tiên và thẻ thứ hai mà người chơi đã lật.
4.3. Cấu Hình Cấp Độ levelSettings
Cấu hình các cấp độ của trò chơi được định nghĩa bằng đối tượng levelSettings
. Mỗi cấp độ có:
discount
: Phần trăm mã giảm giá mà người chơi nhận được nếu hoàn thành cấp độ.maxTime
: Thời gian tối đa cho phép người chơi hoàn thành cấp độ đó.row
,col
: Số hàng và số cột trong bảng lưới thẻ, giúp thiết lập kích thước lưới cho mỗi cấp độ.
Khi người chơi nhấn “Bắt đầu chơi”, chương trình lấy giá trị cấp độ từ danh sách và thiết lập thời gian tối đa tương ứng. Giao diện chọn cấp độ sẽ bị ẩn, và trò chơi sẽ bắt đầu bằng việc hiển thị các thẻ và khởi động bộ đếm thời gian. Dưới đây là toàn bộ code hoàn chỉnh, bạn chỉ cần bỏ vào funtion.php là có thể trải nghiệm toàn bộ trò chơi này rồi nhé:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
function memory_game_with_discount() { ob_start(); ?> <div id="start-game" class="muathemewpgiare"> <h2>Chọn cấp độ chơi</h2> <select id="level-option" class="muathemewpgiare"> <option value="4">Dễ (4 thẻ)</option> <option value="6">Trung bình (6 thẻ)</option> <option value="8">Khó (8 thẻ)</option> <option value="12">Rất Khó (12 thẻ)</option> <option value="16">Cực Khó (16 thẻ)</option> <option value="24">Siêu Khó (24 thẻ)</option> </select> <button id="btn-start-game" class="muathemewpgiare">Bắt đầu chơi</button> </div> <div id="game" class="muathemewpgiare" style="display: none;"> <h2>Thời gian còn lại: <span id="time-display">00:00</span></h2> <div class="progress-bar"> <div id="progress"></div> </div> <div id="memory-game" class="memory-game-board muathemewpgiare"></div> <p id="game-result" class="muathemewpgiare" style="display: none;"></p> <button id="btn-reset-game" class="muathemewpgiare" style="display: none;">Chơi lại</button> </div> <?php return ob_get_clean(); } add_shortcode('memory_game', 'memory_game_with_discount'); function memory_game_styles() { echo '<style> .muathemewpgiare { font-family: Arial, sans-serif; animation: fadeIn 1.5s ease-in-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .memory-game-board { display: grid; gap: 10px; justify-content: center; margin-top: 20px; } .memory-card { width: 150px; height: 200px; perspective: 1000px; cursor: pointer; transform-style: preserve-3d; transition: transform 0.6s; position: relative; background-color: #f9f9f9; box-shadow: 0 5px 15px rgba(0,0,0,0.1); border-radius: 10px; } .memory-card:hover { transform: scale(1.05); box-shadow: 0 10px 25px rgba(0,0,0,0.2); } .memory-card img { width: 100%; height: 100%; position: absolute; backface-visibility: hidden; border-radius: 10px; } .memory-card .front-face { transform: rotateY(180deg); } .memory-card.flipped .front-face { transform: rotateY(0); } .memory-card.flipped .back-face { transform: rotateY(180deg); } #start-game, #game { margin-top: 30px; } button.muathemewpgiare { padding: 10px 20px; font-size: 16px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; } button.muathemewpgiare:hover { background-color: #45a049; }.snowflake { position: absolute; top: -10px; font-size: 1em; color: white; animation: fall 10s linear infinite; } @keyframes fall { 0% { top: -10px; left: random(-100px, 100vw); } 100% { top: 100vh; left: random(-100px, 100vw); } } .progress-bar { width: 80%; margin: 20px auto; background: #ddd; border-radius: 10px; height: 20px; position: relative; } #progress { height: 100%; background: linear-gradient(90deg, #4CAF50, #8BC34A); width: 0; border-radius: 10px; transition: width 0.3s; } </style>'; } add_action('wp_head', 'memory_game_styles'); function memory_game_scripts() { ?> <script> const btnStartGame = document.querySelector('#btn-start-game'); const startGameEl = document.querySelector('#start-game'); const gameEl = document.querySelector('#game'); const levelOptionEl = document.querySelector('#level-option'); const timeEl = document.querySelector('#time-display'); const memoryGameEl = document.querySelector('#memory-game'); const gameResultEl = document.querySelector('#game-result'); const btnResetGame = document.querySelector('#btn-reset-game'); const progressBar = document.querySelector('#progress'); let level, maxTime, remainingTime; let time = 0; let interval; let flippedCards = []; let matchedCards = 0; let lockBoard = false; let firstCard, secondCard; // Cài đặt cấp độ và thời gian tương ứng const levelSettings = { 4: { discount: 15, maxTime: 300, row: 2, col: 2 }, // Easy 6: { discount: 25, maxTime: 180, row: 2, col: 3 }, // Medium 8: { discount: 50, maxTime: 120, row: 2, col: 4 }, // Hard 12: { discount: 75, maxTime: 90, row: 3, col: 4 }, // Very Hard 16: { discount: 100, maxTime: 60, row: 4, col: 4 }, // Extreme 24: { discount: 150, maxTime: 45, row: 4, col: 6 } // Super Extreme }; // Khi nhấn bắt đầu trò chơi btnStartGame.addEventListener('click', function () { level = Number(levelOptionEl.value); // Lấy giá trị cấp độ từ lựa chọn của người chơi maxTime = levelSettings[level].maxTime; // Thời gian tối đa dựa trên cấp độ remainingTime = maxTime; // Đặt thời gian còn lại ban đầu // Hiển thị màn hình trò chơi và ẩn màn hình bắt đầu startGameEl.style.display = 'none'; gameEl.style.display = 'block'; btnResetGame.style.display = 'none'; // Ẩn nút chơi lại gameResultEl.style.display = 'none'; // Ẩn kết quả trò chơi // Bắt đầu trò chơi renderCards(level); // Hiển thị các thẻ dựa trên cấp độ time = 0; interval = setInterval(updateTime, 1000); // Bắt đầu đếm ngược thời gian }); // Khi nhấn nút "Chơi lại" btnResetGame.addEventListener('click', function () { clearInterval(interval); // Dừng đếm thời gian startGameEl.style.display = 'block'; // Hiển thị lại màn hình bắt đầu gameEl.style.display = 'none'; // Ẩn màn hình trò chơi timeEl.innerText = '00:00'; // Reset hiển thị thời gian progressBar.style.width = '0'; // Reset thanh tiến trình matchedCards = 0; // Reset số thẻ đã ghép flippedCards = []; // Reset thẻ lật lockBoard = false; // Mở khóa bảng }); // Hàm cập nhật thời gian và thanh tiến trình function updateTime() { remainingTime--; // Giảm thời gian còn lại timeEl.innerText = convertTime(remainingTime); // Cập nhật hiển thị thời gian // Cập nhật thanh tiến trình let progressWidth = ((maxTime - remainingTime) / maxTime) * 100; progressBar.style.width = `${progressWidth}%`; // Nếu hết thời gian, kết thúc trò chơi if (remainingTime <= 0) { clearInterval(interval); // Dừng đếm thời gian gameResultEl.innerText = 'Hết thời gian! Bạn không đủ điều kiện nhận mã giảm giá.'; gameResultEl.style.display = 'block'; // Hiển thị kết quả btnResetGame.style.display = 'block'; // Hiển thị nút chơi lại lockBoard = true; // Khóa bảng để không thể lật thẻ nữa } } // Chuyển đổi thời gian từ giây sang định dạng mm:ss function convertTime(time) { let minute = `0${Math.floor(time / 60)}`.slice(-2); let second = `0${time % 60}`.slice(-2); return `${minute}:${second}`; } // Hàm đảo ngẫu nhiên mảng thẻ function shuffle(arr) { return arr.sort(() => 0.5 - Math.random()); } // Hàm hiển thị thẻ dựa trên cấp độ function renderCards(level) { let listCards = [ { url: 'https://i.pinimg.com/564x/9f/2f/72/9f2f72f1c63e6c62ac0ca3781e270975.jpg', name: 'luffy' }, { url: 'https://i.pinimg.com/236x/d3/3f/c0/d33fc0cd1bf76766555436c2307b94d7.jpg', name: 'zoro' }, { url: 'https://i.pinimg.com/236x/c2/b4/49/c2b4490285a27881586d3e8c49c4b565.jpg', name: 'sanji' }, { url: 'https://i.pinimg.com/236x/fb/a8/ce/fba8cec6aa3a5faa06b0d5f9a21401ed.jpg', name: 'ace' }, { url: 'https://i.pinimg.com/564x/22/3c/d0/223cd0f2a3f3cb6b47c5117299f31a44.jpg', name: 'shanks' }, { url: 'https://i.pinimg.com/236x/43/2f/b7/432fb73855f9cabe66298a6c12262d44.jpg', name: 'nami' } ]; // Đảo ngẫu nhiên các thẻ listCards = shuffle(listCards); let cardsSlice = listCards.slice(0, level / 2); // Chọn thẻ dựa trên cấp độ let cards = [...cardsSlice, ...cardsSlice]; // Nhân đôi mảng để tạo cặp thẻ cards = shuffle(cards); // Đảo ngẫu nhiên lại thẻ // Cấu hình lưới thẻ dựa trên số cột và hàng theo cấp độ let size = levelSettings[level]; memoryGameEl.style.gridTemplateColumns = `repeat(${size.col}, 150px)`; memoryGameEl.style.gridTemplateRows = `repeat(${size.row}, 200px)`; // Xóa các thẻ cũ và thêm các thẻ mới vào giao diện memoryGameEl.innerHTML = ''; cards.forEach(card => { const cardElement = document.createElement('div'); cardElement.classList.add('memory-card'); cardElement.setAttribute('data-name', card.name); cardElement.innerHTML = ` <img src="${card.url}" class="front-face" alt="${card.name}"> <img src="https://i.pinimg.com/originals/b9/70/33/b97033a8708d2cbaf7d1990020a89a54.jpg" class="back-face" alt="card-back"> `; cardElement.addEventListener('click', flipCard); // Gắn sự kiện lật thẻ cho từng thẻ memoryGameEl.appendChild(cardElement); // Thêm thẻ vào DOM }); } function createSnowflakes() { const snowflake = document.createElement('div'); snowflake.classList.add('snowflake'); snowflake.innerHTML = '❆'; document.body.appendChild(snowflake); // Đặt ngẫu nhiên vị trí cho bông tuyết snowflake.style.left = `${Math.random() * window.innerWidth}px`; // Xóa bông tuyết sau khi rơi khỏi màn hình setTimeout(() => { snowflake.remove(); }, 10000); } // Tạo hiệu ứng tuyết rơi liên tục setInterval(createSnowflakes, 300); // Hàm lật thẻ function flipCard() { if (lockBoard) return; // Không cho phép lật thẻ nếu bảng bị khóa if (this === firstCard) return; // Không cho phép lật lại thẻ đã lật this.classList.add('flipped'); // Lật thẻ if (!firstCard) { // Lật thẻ đầu tiên firstCard = this; } else { // Lật thẻ thứ hai secondCard = this; lockBoard = true; // Khóa bảng để kiểm tra cặp thẻ checkForMatch(); } } // Hàm kiểm tra cặp thẻ trùng nhau function checkForMatch() { let isMatch = firstCard.dataset.name === secondCard.dataset.name; if (isMatch) { disableCards(); // Khóa các thẻ trùng khớp matchedCards += 2; // Tăng số thẻ đã ghép if (matchedCards === level) { endGame(); // Kết thúc trò chơi khi ghép hết thẻ } } else { unflipCards(); // Lật lại các thẻ nếu không khớp } } // Hàm khóa các thẻ đã ghép đúng function disableCards() { firstCard.removeEventListener('click', flipCard); secondCard.removeEventListener('click', flipCard); resetBoard(); // Reset lại bảng sau khi ghép thẻ } // Hàm lật lại các thẻ nếu không khớp function unflipCards() { setTimeout(() => { firstCard.classList.remove('flipped'); secondCard.classList.remove('flipped'); resetBoard(); // Reset lại bảng sau khi lật lại thẻ }, 1000); // Đặt thời gian chờ 1 giây trước khi lật lại } // Hàm reset bảng và trạng thái sau mỗi lần lật thẻ function resetBoard() { [firstCard, secondCard] = [null, null]; // Reset lại thẻ đầu tiên và thẻ thứ hai lockBoard = false; // Mở khóa bảng để tiếp tục chơi } // Kiểm tra nếu người chơi hoàn thành trong thời gian cho phép function endGame() { clearInterval(interval); // Dừng đếm thời gian khi trò chơi kết thúc if (remainingTime > 0) { // Nếu người chơi hoàn thành trong thời gian quy định, nhận mã giảm giá let discount = levelSettings[level].discount; // Lấy giá trị mã giảm giá dựa trên cấp độ gameResultEl.innerText = `Chúc mừng! Bạn nhận được mã giảm giá ${discount}% cho cấp độ này.`; } else { // Nếu thời gian hết trước khi hoàn thành, thông báo không nhận được mã giảm giá gameResultEl.innerText = 'Bạn đã hết thời gian! Không đủ điều kiện nhận mã giảm giá.'; } gameResultEl.style.display = 'block'; // Hiển thị kết quả trò chơi btnResetGame.style.display = 'block'; // Hiển thị nút chơi lại để người chơi có thể chơi lại lockBoard = true; // Khóa bảng sau khi trò chơi kết thúc, không cho phép lật thêm thẻ } // Hàm reset trò chơi khi người chơi nhấn nút "Chơi lại" btnResetGame.addEventListener('click', function () { clearInterval(interval); // Dừng đếm thời gian nếu trò chơi chưa kết thúc startGameEl.style.display = 'block'; // Hiển thị lại màn hình bắt đầu gameEl.style.display = 'none'; // Ẩn màn hình trò chơi timeEl.innerText = '00:00'; // Reset thời gian hiển thị về 0 progressBar.style.width = '0'; // Reset thanh tiến trình matchedCards = 0; // Reset số thẻ đã ghép flippedCards = []; // Reset thẻ lật lockBoard = false; // Mở khóa bảng để bắt đầu lại }); </script> <?php } add_action('wp_footer', 'memory_game_scripts'); |
Đoạn mã này, các bạn có thể về tự cải tiến, phát triển thêm theo từng nhu cầu nhé, bên mình là làm phần khung sườn rồi nhé, một số gợi ý các bạn có thể tự phát triển thêm cho game như sau:
- Tính năng lưu điểm cao: Lưu điểm cao nhất của người chơi để hiển thị bảng xếp hạng.
- Tự động lưu tiến trình: Tự động lưu trạng thái trò chơi mỗi khi người chơi thoát hoặc tạm dừng.
- Chia sẻ kết quả trên mạng xã hội: Cho phép người chơi chia sẻ kết quả qua Facebook, Twitter, v.v.
- Âm thanh nền: Thêm nhạc nền nhẹ nhàng cho trò chơi.
- Hiệu ứng âm thanh: Thêm âm thanh khi người chơi lật thẻ hoặc hoàn thành trò chơi.
- Thông báo đẩy (Push Notifications): Gửi thông báo nhắc nhở người chơi hoàn thành trò chơi hoặc chơi lại.
- Chế độ toàn màn hình: Cho phép người chơi chuyển sang chế độ toàn màn hình khi chơi.
- Hiệu ứng hình ảnh nâng cao: Thêm hiệu ứng 3D khi người chơi lật thẻ.
- Chế độ ban đêm (Dark Mode): Tự động thay đổi giao diện theo chế độ sáng hoặc tối dựa trên cài đặt của người dùng.
- Điểm thưởng mỗi khi hoàn thành nhanh: Cộng điểm hoặc giảm thời gian nếu người chơi hoàn thành trong thời gian ngắn hơn.
- Tùy chỉnh thẻ theo người chơi: Cho phép người chơi chọn hình ảnh của các thẻ trong trò chơi.
- Hướng dẫn chơi: Thêm hướng dẫn chi tiết cho người chơi mới.
- Chức năng tạm dừng trò chơi: Cho phép người chơi tạm dừng trò chơi và tiếp tục lại sau.
- Chế độ nhiều người chơi (Multiplayer): Thêm chế độ cạnh tranh giữa nhiều người chơi trực tuyến.
- Tích hợp API thanh toán: Cho phép người chơi mua mã giảm giá hoặc quà tặng ngay trong trò chơi.
- Tính năng thưởng hàng ngày (Daily Rewards): Cung cấp phần thưởng mỗi ngày nếu người chơi đăng nhập và chơi.
- Chế độ không cần mạng (Offline Mode): Cho phép người chơi tiếp tục trò chơi khi không có kết nối mạng.
- Tự động điều chỉnh kích thước thẻ: Tự động điều chỉnh kích thước các thẻ dựa trên độ phân giải màn hình.
- Chế độ kiểm tra trí nhớ tăng dần: Tăng độ khó theo cấp độ bằng cách tăng số lượng thẻ lật mỗi vòng.
- Quản lý tài khoản người chơi: Người chơi có thể đăng ký, đăng nhập và lưu tiến trình trò chơi.
- Thay đổi ngẫu nhiên màu nền: Thêm hiệu ứng thay đổi màu nền khi người chơi di chuyển qua các cấp độ.
- Hiển thị trạng thái kết nối mạng: Cảnh báo người chơi khi mất kết nối internet trong khi chơi.
- Gợi ý lật thẻ (Hint): Thêm tính năng cho phép người chơi xem trước vị trí của một cặp thẻ.
- Khóa thời gian sau mỗi cấp: Đặt thời gian nghỉ giữa các cấp độ để người chơi có thể thư giãn.
- Cập nhật hình ảnh theo mùa: Thay đổi hình nền và thẻ dựa trên các dịp đặc biệt như Giáng Sinh, Tết Nguyên Đán.
- Tùy chọn tốc độ chơi: Cho phép người chơi chọn tốc độ của trò chơi (tăng hoặc giảm tốc độ lật thẻ).
- Bộ đếm số bước lật thẻ: Hiển thị số bước lật mà người chơi đã thực hiện.
- Tích hợp hệ thống xếp hạng (Leaderboards): So sánh điểm số với người chơi khác trên toàn thế giới.
- Hiển thị lịch sử chơi của người dùng: Hiển thị danh sách các lần chơi trước của người chơi cùng với điểm số.
- Tính năng hỗ trợ người dùng: Thêm chatbot hoặc mục FAQ để giải đáp các thắc mắc của người chơi về trò chơi và mã giảm giá.
Cảm ơn các bạn đã đọc bài viết của mình, nếu thấy hay hãy đăng ký theo dõi trang của mình nhé, các bạn có thể ủng hộ mình qua STK 0766734539 MB BANK LE TRUNG HOANG nhé. Cảm ơn mọi người nhiều.
Hướng dẫn làm game Đào vàng: Hướng dẫn viết game “Đào vàng” trong WordPress
- Bộ Sưu Tập 5+ Theme WordPress Studio Áo Cưới Đẹp, Chuẩn SEO và Dễ Dàng Tùy Chỉnh
- Tại Sao Nội Dung Ngắn Ngủi Đôi Khi Lại Hiệu Quả Hơn Nội Dung Dài?
- Cách Lập Kế Hoạch Nội Dung Để Duy Trì Traffic Liên Tục
- Sharecode chức năng chống quay màn hình wordpress
- 🌟 Sharecode Theme WordPress Miễn Phí Giống Tiki – Chất Lượng Xịn, Giá Càng Yêu 🌟