我想要一个类似羊了个羊的游戏
下面给出一种“极简可跑起来”的《羊了个羊》克隆思路,只需要浏览器就能玩。
把下面两段代码分别保存成 index.html 和 game.css,双击 index.html 即可体验,后续你可以继续加皮肤、加音效、做排行榜……
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>羊了个羊·简化版</title>
<link rel="stylesheet" href="game.css" />
</head>
<body>
<h1>羊了个羊 · 简化克隆版</h1>
<!-- 3 个卡槽 -->
<div id="slots">
<div class="slot" id="slot0"></div>
<div class="slot" id="slot1"></div>
<div class="slot" id="slot2"></div>
</div>
<!-- 游戏主区域 -->
<div id="board"></div>
<!-- 按钮 -->
<div id="controls">
<button id="shuffleBtn">洗牌</button>
<button id="restartBtn">重新开始</button>
</div>
<script>
/*****************************************************************
* 1. 配置:随便改数字就能调难度
*****************************************************************/
const COLORS = 12; // 12 种图标(12 套 3 张 = 36 张)
const LAYERS = 3; // 3 层叠叠乐
const PER_COLOR = 3; // 每种图标 3 张
const SLOT_MAX = 3; // 卡槽最多 3 张相同才能消除
/*****************************************************************
* 2. 初始化
*****************************************************************/
let board = []; // 当前场上所有卡片
let slots = Array(SLOT_MAX).fill(null); // 3 个卡槽
let selected = null; // 当前高亮的卡片
// 生成唯一卡片 36 张
const allCards = [];
for (let i = 0; i < COLORS; i++) {
for (let j = 0; j < PER_COLOR; j++) {
allCards.push(i); // 用数字做图标
}
}
shuffle(allCards);
// 造 3 层塔
const boardEl = document.getElementById('board');
for (let layer = 0; layer < LAYERS; layer++) {
const layerCards = allCards.splice(0, 12); // 每层 12 张
layerCards.forEach((type, idx) => {
// 简单摆摆,真实项目可以随机坐标
const card = document.createElement('div');
card.className = 'card';
card.dataset.type = type;
card.dataset.layer = layer;
card.style.left = 60 + (idx % 6) * 70 + 'px';
card.style.top = 20 + layer * 30 + 'px';
card.style.zIndex = 100 - layer;
card.textContent = type;
card.addEventListener('click', onCardClick);
boardEl.appendChild(card);
board.push(card);
});
}
// 绑定按钮
document.getElementById('restartBtn').onclick = initGame;
document.getElementById('shuffleBtn').onclick = shuffleRemain;
/*****************************************************************
* 3. 卡片点击逻辑
*****************************************************************/
function onCardClick(e) {
const card = e.currentTarget;
if (!canPick(card)) return; // 被压住的不能点
// 放到卡槽
const slotIdx = slots.findIndex(v => v === null);
if (slotIdx === -1) {
alert('卡槽已满!游戏失败'); return;
}
slots[slotIdx] = card.dataset.type;
renderSlots();
card.remove(); // 从场上移除
board = board.filter(c => c !== card);
// 消除检测
checkMatch();
// 通关检测
if (board.length === 0) alert('恭喜通关!');
}
// 判断卡片能否点击:上层没有别的卡片压着
function canPick(card) {
const layer = +card.dataset.layer;
const [x, y, w, h] = [card.offsetLeft, card.offsetTop, 60, 80];
for (const upper of board) {
if (+upper.dataset.layer <= layer) continue;
const [ux, uy, uw, uh] = [upper.offsetLeft, upper.offsetTop, 60, 80];
if (!(x + w < ux || ux + uw < x || y + h < uy || uy + uh < y)) {
return false;
}
}
return true;
}
/*****************************************************************
* 4. 卡槽渲染 & 消除
*****************************************************************/
function renderSlots() {
slots.forEach((t, i) => {
document.getElementById(`slot${i}`).textContent = t ?? '';
});
}
function checkMatch() {
// 遍历 3 个槽位,把相同 type 且满 3 张的清除
const count = {};
slots.forEach(t => {
if (t !== null) count[t] = (count[t] || 0) + 1;
});
Object.entries(count).forEach(([type, cnt]) => {
if (cnt === SLOT_MAX) {
slots = slots.map(s => s === type ? null : s);
}
});
renderSlots();
}
/*****************************************************************
* 5. 洗牌 / 重启
*****************************************************************/
function shuffleRemain() {
const remain = board.map(c => c.dataset.type);
shuffle(remain);
board.forEach((c, i) => {
c.dataset.type = remain[i];
c.textContent = remain[i];
});
}
function initGame() {
location.reload(); // 最简单粗暴的重启
}
// Fisher–Yates 洗牌
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
</script>
</body>
</html>
game.css
body{
font-family: Arial, sans-serif;
text-align:center;
background:#f5f5f5;
}
h1{margin:10px 0;}
#slots{
display:flex;
justify-content:center;
gap:10px;
margin:10px 0;
}
.slot{
width:60px;
height:80px;
background:#fff;
border:2px dashed #aaa;
border-radius:8px;
line-height:80px;
font-size:28px;
color:#555;
}
#board{
position:relative;
width:500px;
height:260px;
margin:0 auto;
background:#eee;
border-radius:10px;
}
.card{
position:absolute;
width:60px;
height:80px;
background:#fff;
border:1px solid #bbb;
border-radius:6px;
font-size:28px;
line-height:80px;
cursor:pointer;
transition:all .15s;
box-shadow:0 2px 4px rgba(0,0,0,.2);
}
.card:hover{
transform:scale(1.05);
box-shadow:0 4px 8px rgba(0,0,0,.3);
}
#controls{margin-top:15px;}
button{
margin:0 5px;
padding:8px 16px;
font-size:16px;
}
使用与扩展思路
代码仅 200 行左右,足够你继续魔改。祝玩得开心!