Cách tạo game 2048 bằng Claude AI
Nếu bạn là người đam mê các tựa game giải đố như 2048 và tò mò không biết làm sao để tự tay tạo ra một phiên bản của riêng mình, thì bài viết này là dành cho bạn.
Điều thú vị là bạn không cần phải biết viết code mà vẫn có thể tạo được game nhờ sự hỗ trợ của Claude AI. Trong bài viết dưới đây, GameVui sẽ hướng dẫn bạn từ những bước cơ bản nhất cho đến khi bạn có thể tự tạo ra một trò chơi hoàn chỉnh. Chúng ta bắt đầu thôi
Hướng dẫn tạo game 2048 bằng Claude AI
Bước 1: Trước tiên, bạn hãy mở ứng dụng Claude AI lên rồi nhập Prompt sau để nó tạo game 2048
hãy tạo giúp tôi một game 2048 được chơi trên một bảng 4×4, nơi người chơi có thể di chuyển các ô số theo bốn hướng: lên, xuống, trái và phải. Mỗi lần lướt, tất cả các ô sẽ di chuyển theo hướng đó và khi 2 ô có cùng số chạm vào nhau, chúng sẽ kết hợp thành một ô mới có giá trị bằng tổng của chúng. Mục tiêu của trò chơi là tạo ra ô 2048Bước 2: Sau đó, Claude AI sẽ phân tích Prompt rồi tạo một game 2048 theo yêu cầu để bạn chơi thử

Bước 3: Bạn có thể yêu cầu Claude AI chỉnh sửa, nâng cấp cho game 2048 với các Prompt sau
hãy làm tiêu đề 2048 nổi bật hơn, thay chữ cao nhất bằng kỷ lục, khi không di chuyển được ô số nữa thì hiện bảng kết thúc và nút Chơi Lại, ô cao nhất không thấy hiển thị, thay chữ chơi lại bằng chơi mới, tối ưu responsive màn hình kích thước 915x607khi các ô số không di chuyển được nữa, chưa thấy bảng thông báo kết thúc game, hình ảnh chuyển động của các ô số chưa rõ ràng, dường như mới chỉ nhìn thấy giá trị số tăng lênchuyển động của các ô vẫn quá nhanh, cần làm chậm lại để thấy được nó đang di chuyển, kỷ lục phải lấy số điểm cao nhất từ tất cả các lần chơi chứ không phải lấy điểm đang chơi hiện tại. Chọn font chữ tiếng Việt chuẩn hơn và làm nổi bật chữ Kết thúcBước 4: Khi đã cảm thấy ưng ý với game mà Claude AI tạo, bạn hãy tải file html như dưới đây về máy tính để chơi
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2048</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { width: 100%; height: 100%; overflow: hidden; }
body {
font-family: 'Be Vietnam Pro', sans-serif;
background: #faf8ef;
display: flex;
justify-content: center;
align-items: center;
}
#g {
display: flex;
flex-direction: column;
align-items: center;
width: 100vmin;
max-width: 520px;
padding: clamp(8px, 2vmin, 20px);
}
#hdr {
display: flex;
align-items: flex-end;
justify-content: space-between;
width: 100%;
margin-bottom: clamp(6px, 1.5vmin, 12px);
gap: 8px;
}
#ttl {
font-size: clamp(44px, 12vmin, 88px);
font-weight: 700;
line-height: 1;
color: #f67c5f;
letter-spacing: -2px;
}
#sub {
font-size: clamp(11px, 1.8vmin, 13px);
color: #776e65;
margin-top: 3px;
}
#scores {
display: flex;
gap: 8px;
align-items: flex-end;
}
/* Hai ô điểm cùng width cố định để luôn bằng nhau */
.sb {
background: #bbada0;
border-radius: 8px;
padding: 9px 0;
text-align: center;
width: 110px;
flex-shrink: 0;
overflow: hidden;
}
.sl {
font-size: 13px;
color: #eee4da;
text-transform: uppercase;
letter-spacing: .07em;
font-weight: 600;
display: block;
}
.sv {
font-size: 26px;
font-weight: 700;
color: #fff;
margin-top: 2px;
line-height: 1.15;
white-space: nowrap;
display: block;
}
#btns {
display: flex;
gap: 10px;
margin-bottom: clamp(6px, 1.5vmin, 14px);
}
#btns button {
font-size: clamp(13px, 2.4vmin, 16px);
padding: clamp(8px, 1.6vmin, 11px) clamp(18px, 3.5vmin, 28px);
border-radius: 8px;
border: none;
background: #8f7a66;
color: #f9f6f2;
cursor: pointer;
font-family: 'Be Vietnam Pro', sans-serif;
font-weight: 600;
transition: background .15s;
}
#btns button:hover { background: #7a6655; }
#win-banner {
display: none;
background: #edc22e;
color: #5a4a00;
text-align: center;
padding: clamp(6px, 1.2vmin, 9px) 16px;
border-radius: 8px;
font-size: clamp(12px, 1.8vmin, 14px);
font-weight: 600;
margin-bottom: clamp(6px, 1.2vmin, 10px);
width: 100%;
}
#win-banner.show { display: block; }
#board-outer { position: relative; width: 100%; }
#bw {
background: #bbada0;
border-radius: 12px;
padding: clamp(6px, 1.5vmin, 12px);
width: 100%;
position: relative;
}
#tile-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: clamp(6px, 1.5vmin, 12px);
}
.bg-cell {
aspect-ratio: 1;
border-radius: 6px;
background: rgba(238, 228, 218, .35);
}
#tile-layer {
position: absolute;
top: clamp(6px, 1.5vmin, 12px);
left: clamp(6px, 1.5vmin, 12px);
right: clamp(6px, 1.5vmin, 12px);
bottom: clamp(6px, 1.5vmin, 12px);
pointer-events: none;
}
.tile {
position: absolute;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-family: 'Be Vietnam Pro', sans-serif;
transition: top .22s cubic-bezier(.25, .8, .25, 1),
left .22s cubic-bezier(.25, .8, .25, 1);
}
.tile.new { animation: tpop .25s ease forwards; }
.tile.merged { animation: tbump .25s ease forwards; }
@keyframes tpop { 0%{transform:scale(0);opacity:0} 60%{transform:scale(1.12)} 100%{transform:scale(1);opacity:1} }
@keyframes tbump { 0%{transform:scale(1)} 40%{transform:scale(1.22)} 100%{transform:scale(1)} }
#overlay {
display: none;
position: absolute;
inset: 0;
background: rgba(238, 228, 218, .94);
border-radius: 12px;
align-items: center;
justify-content: center;
flex-direction: column;
gap: clamp(14px, 3vmin, 24px);
z-index: 20;
}
#overlay.show { display: flex; }
#ov-title {
font-size: clamp(34px, 8vmin, 60px);
font-weight: 700;
color: #f65e3b;
letter-spacing: -1.5px;
}
#ov-score,
#ov-best-txt {
font-size: clamp(23px, 5.2vmin, 33px);
line-height: 1.2;
margin: 5px 0;
}
#ov-score {
font-weight: 700;
color: #776e65;
}
#ov-best-txt {
font-weight: 700; /* Cùng độ đậm */
color: #665d52; /* Màu đậm hơn một chút so với trước */
}
#ov-btn {
font-size: clamp(16px, 3vmin, 20px);
padding: clamp(12px, 2.4vmin, 17px) clamp(36px, 7vmin, 56px);
border-radius: 10px;
border: none;
background: #f67c5f;
color: #fff;
cursor: pointer;
font-weight: 700;
font-family: 'Be Vietnam Pro', sans-serif;
transition: background .15s;
margin-top: 4px;
}
#ov-btn:hover { background: #f65e3b; }
#hint {
font-size: clamp(10px, 1.6vmin, 12px);
color: #a09580;
margin-top: clamp(6px, 1.2vmin, 10px);
text-align: center;
}
</style>
</head>
<body>
<div id="g">
<div id="hdr">
<div>
<div id="ttl">2048</div>
<div id="sub">Ghép các ô để đạt 2048!</div>
</div>
<div id="scores">
<div class="sb"><div class="sl">Điểm</div><div class="sv" id="score">0</div></div>
<div class="sb"><div class="sl">Kỷ lục</div><div class="sv" id="best">0</div></div>
</div>
</div>
<div id="win-banner">Chúc mừng! Bạn đã đạt 2048 — tiếp tục chơi!</div>
<div id="btns">
<button onclick="initGame()">Chơi mới</button>
<button onclick="undoMove()">Hoàn tác</button>
</div>
<div id="board-outer">
<div id="bw">
<div id="tile-grid"></div>
<div id="tile-layer"></div>
<div id="overlay">
<div id="ov-title">Kết thúc!</div>
<div id="ov-score"></div>
<div id="ov-best-txt"></div>
<button id="ov-btn" onclick="initGame()">Chơi lại</button>
</div>
</div>
</div>
<div id="hint">Dùng phím mũi tên hoặc vuốt để di chuyển</div>
</div>
<script>
const COLORS = {
2: { bg: '#eee4da', color: '#776e65' },
4: { bg: '#ede0c8', color: '#776e65' },
8: { bg: '#f2b179', color: '#f9f6f2' },
16: { bg: '#f59563', color: '#f9f6f2' },
32: { bg: '#f67c5f', color: '#f9f6f2' },
64: { bg: '#f65e3b', color: '#f9f6f2' },
128: { bg: '#edcf72', color: '#f9f6f2' },
256: { bg: '#edcc61', color: '#f9f6f2' },
512: { bg: '#edc850', color: '#f9f6f2' },
1024: { bg: '#edc53f', color: '#f9f6f2' },
2048: { bg: '#edc22e', color: '#f9f6f2' },
4096: { bg: '#3c3a32', color: '#f9f6f2' },
8192: { bg: '#3c3a32', color: '#f9f6f2' }
};
function tileFS(v) {
if (v >= 1000) return 'clamp(11px,2.5vmin,18px)';
if (v >= 100) return 'clamp(14px,3vmin,22px)';
return 'clamp(18px,4vmin,30px)';
}
let board, score, best, prevBoard, prevScore, won, over, moving;
let nextId = 1;
function loadBest() {
try { return parseInt(localStorage.getItem('2048best') || '0'); } catch(e) { return 0; }
}
function saveBest(v) {
try { localStorage.setItem('2048best', v); } catch(e) {}
}
best = loadBest();
function initGame() {
board = Array.from({ length: 4 }, () => Array(4).fill(null));
score = 0; won = false; over = false; moving = false;
prevBoard = null; prevScore = 0; nextId = 1;
spawnTile(); spawnTile();
document.getElementById('overlay').classList.remove('show');
document.getElementById('win-banner').classList.remove('show');
document.getElementById('best').textContent = best.toLocaleString();
renderBoard();
}
function spawnTile() {
let empty = [];
for (let r = 0; r < 4; r++)
for (let c = 0; c < 4; c++)
if (!board[r][c]) empty.push([r, c]);
if (!empty.length) return null;
let [r, c] = empty[Math.floor(Math.random() * empty.length)];
board[r][c] = { v: Math.random() < .9 ? 2 : 4, id: nextId++, isNew: true, merged: false };
return [r, c];
}
function cloneBoard(b) {
return b.map(row => row.map(cell => cell ? { ...cell } : null));
}
function slideRow(row) {
let arr = row.filter(x => x), pts = 0, out = [];
let i = 0;
while (i < arr.length) {
if (i + 1 < arr.length && arr[i].v === arr[i + 1].v) {
let nv = arr[i].v * 2; pts += nv;
out.push({ v: nv, id: arr[i].id, isNew: false, merged: true });
i += 2;
} else {
out.push({ ...arr[i], isNew: false, merged: false }); i++;
}
}
while (out.length < 4) out.push(null);
return { row: out, pts };
}
function move(dir) {
if (over || moving) return;
prevBoard = cloneBoard(board); prevScore = score;
let moved = false, ns = score, nb = cloneBoard(board);
if (dir === 'left') {
for (let r = 0; r < 4; r++) {
let { row, pts } = slideRow(nb[r]);
if (JSON.stringify(row.map(x => x ? x.v : 0)) !== JSON.stringify(nb[r].map(x => x ? x.v : 0))) moved = true;
nb[r] = row; ns += pts;
}
} else if (dir === 'right') {
for (let r = 0; r < 4; r++) {
let rev = [...nb[r]].reverse();
let { row, pts } = slideRow(rev); row.reverse();
if (JSON.stringify(row.map(x => x ? x.v : 0)) !== JSON.stringify(nb[r].map(x => x ? x.v : 0))) moved = true;
nb[r] = row; ns += pts;
}
} else if (dir === 'up') {
for (let c = 0; c < 4; c++) {
let col = nb.map(r => r[c]);
let { row, pts } = slideRow(col);
if (JSON.stringify(row.map(x => x ? x.v : 0)) !== JSON.stringify(col.map(x => x ? x.v : 0))) moved = true;
row.forEach((v, r) => nb[r][c] = v); ns += pts;
}
} else if (dir === 'down') {
for (let c = 0; c < 4; c++) {
let col = nb.map(r => r[c]).reverse();
let { row, pts } = slideRow(col); row.reverse();
if (JSON.stringify(row.map(x => x ? x.v : 0)) !== JSON.stringify(nb.map(r => r[c]).map(x => x ? x.v : 0))) moved = true;
row.forEach((v, r) => nb[r][c] = v); ns += pts;
}
}
if (!moved) return;
moving = true;
renderMoveAnimation(board, nb, () => {
board = nb; score = ns;
if (score > best) { best = score; saveBest(best); }
spawnTile();
renderBoard();
moving = false;
checkState();
});
}
function getGap() {
return Math.max(6, Math.min(12, document.getElementById('tile-layer').offsetWidth * 0.022));
}
function renderMoveAnimation(oldBoard, newBoard, cb) {
const layer = document.getElementById('tile-layer');
const gapPx = getGap();
const cellW = (layer.offsetWidth - gapPx * 3) / 4;
layer.innerHTML = '';
for (let r = 0; r < 4; r++) for (let c = 0; c < 4; c++) {
const cell = oldBoard[r][c];
if (!cell) continue;
let dR = r, dC = c;
outer: for (let nr = 0; nr < 4; nr++) for (let nc = 0; nc < 4; nc++) {
if (newBoard[nr][nc] && newBoard[nr][nc].id === cell.id) { dR = nr; dC = nc; break outer; }
}
const div = document.createElement('div');
div.className = 'tile';
const col = COLORS[Math.min(cell.v, 8192)] || COLORS[8192];
div.style.cssText = `width:${cellW}px;height:${cellW}px;top:${r*(cellW+gapPx)}px;left:${c*(cellW+gapPx)}px;background:${col.bg};color:${col.color};font-size:${tileFS(cell.v)};`;
div.textContent = cell.v;
layer.appendChild(div);
if (dR !== r || dC !== c) {
requestAnimationFrame(() => requestAnimationFrame(() => {
div.style.top = `${dR * (cellW + gapPx)}px`;
div.style.left = `${dC * (cellW + gapPx)}px`;
}));
}
}
setTimeout(cb, 240);
}
function isGameOver() {
for (let r = 0; r < 4; r++) for (let c = 0; c < 4; c++) {
if (!board[r][c]) return false;
if (c < 3 && board[r][c] && board[r][c+1] && board[r][c].v === board[r][c+1].v) return false;
if (r < 3 && board[r][c] && board[r+1][c] && board[r][c].v === board[r+1][c].v) return false;
}
return true;
}
function checkState() {
if (!won) {
for (let r = 0; r < 4; r++) for (let c = 0; c < 4; c++) {
if (board[r][c] && board[r][c].v >= 2048) {
won = true;
document.getElementById('win-banner').classList.add('show');
return;
}
}
}
if (isGameOver()) {
over = true;
document.getElementById('ov-score').textContent = 'Điểm: ' + score.toLocaleString();
document.getElementById('ov-best-txt').textContent = 'Kỷ lục: ' + best.toLocaleString();
setTimeout(() => document.getElementById('overlay').classList.add('show'), 300);
}
}
function undoMove() {
if (!prevBoard || moving) return;
board = prevBoard; score = prevScore; prevBoard = null; over = false;
document.getElementById('overlay').classList.remove('show');
renderBoard();
}
function renderBoard() {
const layer = document.getElementById('tile-layer');
const tg = document.getElementById('tile-grid');
tg.innerHTML = '';
for (let i = 0; i < 16; i++) {
let d = document.createElement('div'); d.className = 'bg-cell'; tg.appendChild(d);
}
requestAnimationFrame(() => {
const gapPx = getGap();
const cellW = (layer.offsetWidth - gapPx * 3) / 4;
layer.innerHTML = '';
for (let r = 0; r < 4; r++) for (let c = 0; c < 4; c++) {
const cell = board[r][c];
if (!cell) continue;
const v = cell.v;
const col = COLORS[Math.min(v, 8192)] || COLORS[8192];
const div = document.createElement('div');
div.className = 'tile' + (cell.isNew ? ' new' : cell.merged ? ' merged' : '');
div.style.cssText = `width:${cellW}px;height:${cellW}px;top:${r*(cellW+gapPx)}px;left:${c*(cellW+gapPx)}px;background:${col.bg};color:${col.color};font-size:${tileFS(v)};`;
div.textContent = v;
layer.appendChild(div);
}
document.getElementById('score').textContent = score.toLocaleString();
document.getElementById('best').textContent = best.toLocaleString();
});
}
document.addEventListener('keydown', e => {
if (['ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.key)) {
e.preventDefault();
move(e.key.replace('Arrow','').toLowerCase());
}
});
let tx = 0, ty = 0;
const bwEl = document.getElementById('bw');
bwEl.addEventListener('touchstart', e => { tx = e.touches[0].clientX; ty = e.touches[0].clientY; }, { passive: true });
bwEl.addEventListener('touchend', e => {
let dx = e.changedTouches[0].clientX - tx, dy = e.changedTouches[0].clientY - ty;
if (Math.max(Math.abs(dx), Math.abs(dy)) < 20) return;
if (Math.abs(dx) > Math.abs(dy)) move(dx > 0 ? 'right' : 'left');
else move(dy > 0 ? 'down' : 'up');
}, { passive: true });
window.addEventListener('resize', () => renderBoard());
initGame();
</script>
</body>
</html>
Cách chơi game 2048 cơ bản
Nhiệm vụ của bạn là ghép các ô có cùng giá trị lại với nhau để tạo ra ô mới có số lớn hơn, với mục tiêu cuối cùng là đạt được ô mang giá trị 2048.
Bạn sẽ di chuyển các số trên bảng bằng cách vuốt theo 4 hướng: lên, xuống, trái hoặc phải. Mỗi lần di chuyển, toàn bộ các ô sẽ trượt theo hướng đã chọn cho đến khi gặp mép bảng hoặc bị chặn bởi ô khác.
Khi 2 ô liền kề có cùng số và di chuyển cùng hướng, chúng sẽ hợp nhất thành một ô duy nhất với giá trị bằng tổng của 2 ô ban đầu. Chẳng hạn, hai ô số 2 sẽ gộp lại thành ô số 4, quá trình này tiếp tục để tạo ra các giá trị cao hơn.
Bài viết liên quan
Bài viết mới nhất
Game PC
-

The Sims 4: Cách thêm Sim vào hộ gia đình
-

Cách tìm các NPC trong Fortnite Chapter 7 Season 1
-

Hướng dẫn chơi game PS3 trên PC bằng giả lập RPCS3
-

Grow A Garden: Cách nhận và sử dụng Queen Bee
-

Top 10 vũ khí mạnh nhất trong Call of Duty: Black Ops 6
-

Tổng hợp top 5 vị tướng mạnh nhất trong Liên Minh Huyền Thoại 10.19
TOP Game
Game Mobile
Game PC
Code game
Cách chơi Game
Mẹo vặt
Anime Manga
Đấu Trường Chân Lý
Game AI
Liên Minh Huyền Thoại
Call Of Duty
Coin Master 
