用HTML5+CSS3+JavaScript实现找不同游戏
用HTML5+CSS3+JavaScript实现找不同游戏
找不同游戏,用户可以选择一张加载图片——用“加载图片”按钮,将在两个图片显示去中加载图片(显示的图片最好不变形显示——按比例缩放)左边的设置不同之处,用户设置不同数值,按下“设置”按钮,自动在左边图上添加不同标识(使用特殊字符或符号),用户单击“开始游戏”,在左边的不同处 点击,若真不同,就加上细线红圈,等到找出全部不同之处,给出“成功”提示,可以进行下一局游戏。
运行截图:
源码如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>找不同游戏</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: Arial, sans-serif;background-color: #f0f0f0;display: flex;justify-content: center;align-items: center;min-height: 100vh;padding: 20px;}.game-container {background-color: white;border-radius: 10px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);padding: 20px;max-width: 900px;width: 100%;}.controls {display: flex;gap: 10px;margin-bottom: 20px;flex-wrap: wrap;align-items: center;}button {padding: 8px 16px;border: none;border-radius: 5px;background-color: #4CAF50;color: white;cursor: pointer;font-size: 14px;transition: background-color 0.3s;}button:hover {background-color: #45a049;}button:disabled {background-color: #cccccc;cursor: not-allowed;}input[type="file"] {display: none;}input[type="number"] {padding: 6px;border: 1px solid #ddd;border-radius: 4px;width: 60px;}.status {color: #2196F3;font-weight: bold;margin-left: auto;}.status.success {color: #4CAF50;}.game-area {display: flex;gap: 20px;justify-content: center;flex-wrap: wrap;}.image-container {text-align: center;}.image-container h3 {margin-bottom: 10px;color: #333;}.canvas-wrapper {position: relative;display: inline-block;border: 2px solid #ddd;border-radius: 5px;overflow: hidden;background-color: #f9f9f9;}canvas {display: block;cursor: crosshair;}#leftCanvas {cursor: pointer;}.marker {position: absolute;font-size: 20px;font-weight: bold;pointer-events: none;transition: opacity 0.3s;}.found-circle {position: absolute;border: 3px solid red;border-radius: 50%;pointer-events: none;animation: pulse 0.5s ease-out;}@keyframes pulse {0% {transform: scale(0.8);opacity: 0;}50% {transform: scale(1.1);border-color: yellow;}100% {transform: scale(1);border-color: red;}}.wrong-mark {position: absolute;color: #888;font-size: 30px;pointer-events: none;animation: fadeOut 0.5s ease-out forwards;}@keyframes fadeOut {0% {opacity: 1;transform: scale(1);}100% {opacity: 0;transform: scale(0.8);}}.instructions {margin-top: 20px;padding: 15px;background-color: #f5f5f5;border-radius: 5px;font-size: 14px;color: #666;}</style>
</head>
<body><div class="game-container"><h1 style="text-align: center; margin-bottom: 20px; color: #333;">找不同游戏</h1><div class="controls"><label for="imageInput" class="button-label"><button type="button" onclick="document.getElementById('imageInput').click()">加载图片</button></label><input type="file" id="imageInput" accept="image/*"><label>设置不同数:<input type="number" id="diffCount" value="5" min="1" max="20"></label><button id="setBtn" onclick="setDifferences()">设置</button><button id="startBtn" onclick="startGame()">开始游戏</button><div class="status" id="status"></div></div><div class="game-area"><div class="image-container"><h3>点击这里找不同</h3><div class="canvas-wrapper" id="leftWrapper"><canvas id="leftCanvas" width="400" height="300"></canvas></div></div><div class="image-container"><h3>原图</h3><div class="canvas-wrapper"><canvas id="rightCanvas" width="400" height="300"></canvas></div></div></div><div class="instructions"><strong>游戏说明:</strong><br>1. 点击"加载图片"选择一张图片<br>2. 设置想要的不同之处数量(1-20个)<br>3. 点击"设置"在左图添加标识<br>4. 点击"开始游戏"开始寻找<br>5. 在左图点击找到的不同之处,找到所有即可获胜!</div></div><script>// 游戏状态let gameState = {originalImage: null,differences: [],foundDifferences: [],gameStarted: false,markers: ['✱', '✿', '❀', '❁', '❂', '❃', '❈', '❉', '❊', '❋','♠', '♣', '♥', '♦', '★', '☆', '✤', '✥', '✦', '✧']};// 获取画布和上下文const leftCanvas = document.getElementById('leftCanvas');const rightCanvas = document.getElementById('rightCanvas');const leftCtx = leftCanvas.getContext('2d');const rightCtx = rightCanvas.getContext('2d');const leftWrapper = document.getElementById('leftWrapper');// 图片加载document.getElementById('imageInput').addEventListener('change', function(e) {const file = e.target.files[0];if (file) {const reader = new FileReader();reader.onload = function(event) {const img = new Image();img.onload = function() {gameState.originalImage = img;displayImage();updateStatus('图片已加载');};img.src = event.target.result;};reader.readAsDataURL(file);}});// 显示图片function displayImage() {if (!gameState.originalImage) return;const img = gameState.originalImage;const canvasWidth = 400;const canvasHeight = 300;// 计算缩放比例const scale = Math.min(canvasWidth / img.width, canvasHeight / img.height);const width = img.width * scale;const height = img.height * scale;const x = (canvasWidth - width) / 2;const y = (canvasHeight - height) / 2;// 清空画布leftCtx.clearRect(0, 0, canvasWidth, canvasHeight);rightCtx.clearRect(0, 0, canvasWidth, canvasHeight);// 绘制图片leftCtx.drawImage(img, x, y, width, height);rightCtx.drawImage(img, x, y, width, height);// 保存图片位置信息gameState.imageInfo = { x, y, width, height, scale };}// 设置不同之处// 设置不同之处function setDifferences() {if (!gameState.originalImage) {alert('请先加载图片!');return;}const count = parseInt(document.getElementById('diffCount').value);if (count < 1 || count > 20) {alert('不同之处数量应在1-20之间!');return;}// 清除之前找到的红圈标记document.querySelectorAll('.found-circle').forEach(c => c.remove());// 清除之前的标记document.querySelectorAll('.marker').forEach(m => m.remove());gameState.differences = [];gameState.foundDifferences = [];// 重新显示图片displayImage();// 打乱 markers 数组const shuffledMarkers = gameState.markers.slice();for (let i = shuffledMarkers.length - 1; i > 0; i--) {const j = Math.floor(Math.random() * (i + 1));[shuffledMarkers[i], shuffledMarkers[j]] = [shuffledMarkers[j], shuffledMarkers[i]];}const selectedMarkers = shuffledMarkers.slice(0, count);const info = gameState.imageInfo;// 生成不重叠的位置for (let i = 0; i < count; i++) {let x, y;let attempts = 0;do {x = info.x + Math.random() * (info.width * 0.8) + info.width * 0.1;y = info.y + Math.random() * (info.height * 0.8) + info.height * 0.1;attempts++;} while (isTooClose(x, y) && attempts < 50);// 创建标记元素const marker = document.createElement('div');marker.className = 'marker';marker.textContent = selectedMarkers[i];marker.style.left = (x - 20) + 'px';marker.style.top = (y - 20) + 'px';// 随机颜色和透明度const colors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', '#FFA500', '#800080'];marker.style.color = colors[i % colors.length];marker.style.opacity = '0.6';leftWrapper.appendChild(marker);gameState.differences.push({x: x,y: y,marker: selectedMarkers[i],element: marker});}updateStatus(`已设置${count}个不同之处`);}// 检查位置是否太近function isTooClose(x, y) {for (let diff of gameState.differences) {const distance = Math.sqrt(Math.pow(x - diff.x, 2) + Math.pow(y - diff.y, 2));if (distance < 60) return true;}return false;}// 开始游戏function startGame() {if (gameState.differences.length === 0) {alert('请先设置不同之处!');return;}gameState.gameStarted = true;gameState.foundDifferences = [];// 清除已找到的标记document.querySelectorAll('.found-circle').forEach(c => c.remove());updateGameStatus();}// 点击检测leftCanvas.addEventListener('click', function(e) {if (!gameState.gameStarted) return;const rect = leftCanvas.getBoundingClientRect();const x = e.clientX - rect.left;const y = e.clientY - rect.top;let found = false;// 检查是否点击到不同之处for (let diff of gameState.differences) {const distance = Math.sqrt(Math.pow(x - diff.x, 2) + Math.pow(y - diff.y, 2));if (distance < 40 && !gameState.foundDifferences.includes(diff)) {// 找到了!found = true;gameState.foundDifferences.push(diff);// 添加红圈标记const circle = document.createElement('div');circle.className = 'found-circle';circle.style.left = (diff.x - 25) + 'px';circle.style.top = (diff.y - 25) + 'px';circle.style.width = '30px';circle.style.height = '30px';leftWrapper.appendChild(circle);updateGameStatus();// 检查是否获胜if (gameState.foundDifferences.length === gameState.differences.length) {gameState.gameStarted = false;updateStatus('恭喜!你找到了所有不同之处!', true);setTimeout(() => {alert('恭喜你赢了!可以开始新一局游戏了。');}, 500);}break;}}// 如果没找到,显示错误标记if (!found && gameState.gameStarted) {const wrongMark = document.createElement('div');wrongMark.className = 'wrong-mark';wrongMark.textContent = '✗';wrongMark.style.left = (x - 15) + 'px';wrongMark.style.top = (y - 15) + 'px';leftWrapper.appendChild(wrongMark);setTimeout(() => wrongMark.remove(), 500);}});// 更新游戏状态function updateGameStatus() {if (gameState.gameStarted) {const found = gameState.foundDifferences.length;const total = gameState.differences.length;updateStatus(`游戏进行中:已找到 ${found}/${total} 个不同`);}}// 更新状态文本function updateStatus(text, success = false) {const status = document.getElementById('status');status.textContent = text;status.className = success ? 'status success' : 'status';}</script>
</body>
</html>
OK!