console
<!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: linear-gradient(135deg, #87CEEB 0%, #98FB98 100%);
overflow: hidden;
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
.game-container {
width: 100vw;
height: 100vh;
position: relative;
cursor: none;
touch-action: none;
overflow: hidden;
}
.game-info {
position: absolute;
top: 20px;
left: 20px;
z-index: 100;
background: rgba(255, 255, 255, 0.9);
padding: 15px;
border-radius: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
.score {
font-size: 24px;
font-weight: bold;
color: #FF6B6B;
margin-bottom: 10px;
}
.lives {
font-size: 18px;
color: #4ECDC4;
}
.level {
font-size: 16px;
color: #45B7D1;
margin-top: 5px;
}
.player {
position: absolute;
bottom: 20px;
width: 160px;
height: 160px;
transition: left 0.1s ease-out;
z-index: 10;
}
.player img {
width: 100%;
height: 100%;
object-fit: contain;
filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3));
}
.cat {
position: absolute;
width: 120px;
height: 120px;
z-index: 5;
}
.cat img {
width: 100%;
height: 100%;
object-fit: contain;
filter: drop-shadow(1px 1px 3px rgba(0,0,0,0.2));
}
.cat1 {
animation-duration: 7s;
}
.cat2 {
animation-duration: 5s;
}
.cat3 {
animation-duration: 3.5s;
}
@keyframes fall-straight {
0% {
top: -120px;
transform: translateX(0) rotate(-5deg);
}
25% {
transform: translateX(15px) rotate(3deg);
}
50% {
transform: translateX(-10px) rotate(-2deg);
}
75% {
transform: translateX(8px) rotate(4deg);
}
100% {
top: 100vh;
transform: translateX(0) rotate(0deg);
}
}
@keyframes fall-zigzag {
0% {
top: -120px;
transform: translateX(0) rotate(0deg);
}
20% {
transform: translateX(40px) rotate(8deg);
}
40% {
transform: translateX(-35px) rotate(-6deg);
}
60% {
transform: translateX(25px) rotate(5deg);
}
80% {
transform: translateX(-20px) rotate(-4deg);
}
100% {
top: 100vh;
transform: translateX(0) rotate(0deg);
}
}
@keyframes fall-spiral {
0% {
top: -120px;
transform: translateX(0) rotate(0deg);
}
25% {
transform: translateX(50px) rotate(90deg);
}
50% {
transform: translateX(0) rotate(180deg);
}
75% {
transform: translateX(-50px) rotate(270deg);
}
100% {
top: 100vh;
transform: translateX(0) rotate(360deg);
}
}
.start-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 200;
}
.start-screen h1 {
color: #FFD93D;
font-size: 48px;
margin-bottom: 20px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.start-screen p {
color: white;
font-size: 18px;
margin-bottom: 30px;
text-align: center;
line-height: 1.6;
}
.start-button, .restart-button {
background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
color: white;
border: none;
padding: 20px 40px;
font-size: 28px;
border-radius: 35px;
cursor: pointer;
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
transition: transform 0.2s;
min-height: 60px;
touch-action: manipulation;
}
.start-button:hover, .restart-button:hover,
.start-button:active, .restart-button:active {
transform: scale(1.05);
}
.game-over {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.9);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 200;
}
.game-over h2 {
color: #FF6B6B;
font-size: 36px;
margin-bottom: 20px;
}
.final-score {
color: #FFD93D;
font-size: 24px;
margin-bottom: 30px;
}
.restart-button {
background: linear-gradient(45deg, #4ECDC4, #45B7D1);
}
.instructions {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
padding: 15px;
border-radius: 15px;
max-width: 250px;
font-size: 14px;
line-height: 1.4;
}
.instructions h3 {
color: #FF6B6B;
margin-bottom: 10px;
}
.cloud {
position: absolute;
background: white;
border-radius: 50px;
opacity: 0.7;
animation: float 6s ease-in-out infinite;
}
.cloud:before {
content: '';
position: absolute;
background: white;
border-radius: 50px;
}
.cloud1 {
width: 80px;
height: 30px;
top: 10%;
left: 20%;
animation-delay: 0s;
}
.cloud2 {
width: 60px;
height: 25px;
top: 20%;
right: 30%;
animation-delay: 2s;
}
.cloud3 {
width: 100px;
height: 35px;
top: 15%;
left: 60%;
animation-delay: 4s;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
@media (max-width: 768px) {
.start-screen h1 {
font-size: 42px;
margin-bottom: 30px;
}
.start-screen p {
font-size: 18px;
padding: 0 30px;
line-height: 1.8;
}
.start-button, .restart-button {
font-size: 32px;
padding: 25px 50px;
min-height: 70px;
}
.game-info {
top: 15px;
left: 15px;
padding: 15px;
font-size: 16px;
}
.score {
font-size: 28px;
}
.lives {
font-size: 22px;
}
.level {
font-size: 20px;
}
.instructions {
top: 15px;
right: 15px;
padding: 12px;
max-width: 180px;
font-size: 14px;
}
.instructions h3 {
font-size: 16px;
}
.game-over h2 {
font-size: 42px;
}
.final-score {
font-size: 28px;
}
.player {
width: 140px;
height: 140px;
}
.cat {
width: 100px;
height: 100px;
}
}
@media (max-width: 480px) {
.start-screen h1 {
font-size: 36px;
}
.start-screen p {
font-size: 16px;
padding: 0 20px;
}
.start-button, .restart-button {
font-size: 28px;
padding: 20px 40px;
min-height: 65px;
}
.instructions {
display: none;
}
.game-info {
background: rgba(255, 255, 255, 0.95);
border-radius: 12px;
padding: 12px;
}
.player {
width: 120px;
height: 120px;
}
.cat {
width: 85px;
height: 85px;
}
}
</style>
</head>
<body>
<div class="game-container" id="gameContainer">
<div class="cloud cloud1"></div>
<div class="cloud cloud2"></div>
<div class="cloud cloud3"></div>
<div class="game-info">
<div class="score">得分: <span id="score">0</span></div>
<div class="lives">生命: <span id="lives">3</span></div>
<div class="level">等级: <span id="level">1</span></div>
</div>
<div class="instructions">
<h3>游戏规则</h3>
<p>�� 橙猫(慢): 30分<br>
�� 白猫(中): 20分<br>
�� 黑猫(快): 10分<br><br>
<span style="font-size: 12px;">�� 手机可开启重力感应</span></p>
</div>
<div class="player" id="player">
<img src="https://pic1.imgdb.cn/item/683ae42c58cb8da5c81eb243.png" alt="小朋友">
</div>
<div class="start-screen" id="startScreen">
<h1>�� 小猫接接乐 ��</h1>
<p>
天空中掉下了许多可爱的小猫咪!<br>
<span style="font-size: 16px;">��️ 电脑:移动鼠标控制</span><br>
<span style="font-size: 16px;">�� 手机:手指触屏控制</span><br>
<span style="font-size: 16px;">�� 可开启重力感应倾斜控制</span><br>
快去接住它们获得分数吧!
</p>
<button class="start-button" onclick="startGame()">开始游戏</button>
</div>
<div class="game-over" id="gameOver">
<h2>游戏结束</h2>
<div class="final-score" id="finalScore">最终得分: 0</div>
<button class="restart-button" onclick="restartGame()">再玩一次</button>
</div>
</div>
<script>
class CatGame {
constructor() {
this.score = 0;
this.lives = 3;
this.level = 1;
this.gameRunning = false;
this.cats = [];
this.player = document.getElementById('player');
this.gameContainer = document.getElementById('gameContainer');
this.playerWidth = 160;
this.catWidth = 120;
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth <= 768;
if (this.isMobile) {
this.playerWidth = 120;
this.catWidth = 85;
}
this.spawnRate = 2000;
this.spawnTimer = null;
this.catTypes = [
{
image: 'https://pic1.imgdb.cn/item/683ae41b58cb8da5c81eb232.png',
score: 30,
speed: 7000,
sound: 'meow1',
animation: 'fall-straight',
class: 'cat1'
},
{
image: 'https://pic1.imgdb.cn/item/683ae41f58cb8da5c81eb233.png',
score: 20,
speed: 5000,
sound: 'meow2',
animation: 'fall-zigzag',
class: 'cat2'
},
{
image: 'https://pic1.imgdb.cn/item/683ae42c58cb8da5c81eb244.png',
score: 10,
speed: 3500,
sound: 'meow3',
animation: 'fall-spiral',
class: 'cat3'
}
];
this.initSounds();
this.bindEvents();
}
initSounds() {
this.audioContext = null;
try {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
} catch (e) {
console.log('音频不支持');
}
}
playMeowSound(type) {
if (!this.audioContext) return;
const oscillator = this.audioContext.createOscillator();
const gainNode = this.audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(this.audioContext.destination);
const frequencies = {
meow1: [400, 600, 300],
meow2: [500, 700, 400],
meow3: [600, 800, 500]
};
const freq = frequencies[type] || frequencies.meow1;
oscillator.frequency.setValueAtTime(freq[0], this.audioContext.currentTime);
oscillator.frequency.setValueAtTime(freq[1], this.audioContext.currentTime + 0.1);
oscillator.frequency.setValueAtTime(freq[2], this.audioContext.currentTime + 0.2);
gainNode.gain.setValueAtTime(0.3, this.audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.3);
oscillator.type = 'triangle';
oscillator.start(this.audioContext.currentTime);
oscillator.stop(this.audioContext.currentTime + 0.3);
}
bindEvents() {
this.gameContainer.addEventListener('mousemove', (e) => {
if (this.gameRunning) {
const rect = this.gameContainer.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const playerX = Math.max(0, Math.min(mouseX - this.playerWidth / 2,
window.innerWidth - this.playerWidth));
this.player.style.left = playerX + 'px';
}
});
this.gameContainer.addEventListener('touchmove', (e) => {
e.preventDefault();
if (this.gameRunning && e.touches[0]) {
const rect = this.gameContainer.getBoundingClientRect();
const touchX = e.touches[0].clientX - rect.left;
const playerX = Math.max(0, Math.min(touchX - this.playerWidth / 2,
window.innerWidth - this.playerWidth));
this.player.style.left = playerX + 'px';
}
}, { passive: false });
this.gameContainer.addEventListener('touchstart', (e) => {
e.preventDefault();
if (this.gameRunning && e.touches[0]) {
const rect = this.gameContainer.getBoundingClientRect();
const touchX = e.touches[0].clientX - rect.left;
const playerX = Math.max(0, Math.min(touchX - this.playerWidth / 2,
window.innerWidth - this.playerWidth));
this.player.style.left = playerX + 'px';
}
}, { passive: false });
document.addEventListener('touchmove', (e) => {
if (this.gameRunning) {
e.preventDefault();
}
}, { passive: false });
document.addEventListener('gesturestart', (e) => {
e.preventDefault();
});
document.addEventListener('gesturechange', (e) => {
e.preventDefault();
});
document.addEventListener('gestureend', (e) => {
e.preventDefault();
});
if (window.DeviceOrientationEvent) {
this.setupOrientationControl();
}
}
setupOrientationControl() {
let isOrientationEnabled = false;
this.addOrientationToggle();
window.addEventListener('deviceorientation', (e) => {
if (!this.gameRunning || !isOrientationEnabled) return;
const tilt = e.gamma;
if (tilt !== null) {
const maxTilt = 30;
const normalizedTilt = Math.max(-1, Math.min(1, tilt / maxTilt));
const screenCenter = window.innerWidth / 2;
const maxMove = (window.innerWidth - this.playerWidth) / 2;
const playerX = Math.max(0, Math.min(
screenCenter + (normalizedTilt * maxMove) - this.playerWidth / 2,
window.innerWidth - this.playerWidth
));
this.player.style.left = playerX + 'px';
}
});
this.toggleOrientation = () => {
isOrientationEnabled = !isOrientationEnabled;
const button = document.getElementById('orientationToggle');
if (button) {
button.textContent = isOrientationEnabled ? '�� 关闭重力' : '�� 开启重力';
button.style.background = isOrientationEnabled ?
'linear-gradient(45deg, #FF6B6B, #FFA500)' :
'linear-gradient(45deg, #4ECDC4, #45B7D1)';
}
};
}
addOrientationToggle() {
const toggleButton = document.createElement('button');
toggleButton.id = 'orientationToggle';
toggleButton.textContent = '�� 开启重力';
toggleButton.style.cssText = `
position: absolute;
bottom: 20px;
right: 20px;
background: linear-gradient(45deg, #4ECDC4, #45B7D1);
color: white;
border: none;
padding: 12px 20px;
font-size: 16px;
border-radius: 25px;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
z-index: 50;
touch-action: manipulation;
`;
toggleButton.addEventListener('click', () => {
if (this.toggleOrientation) {
this.toggleOrientation();
}
});
this.gameContainer.appendChild(toggleButton);
}
startGame() {
this.gameRunning = true;
this.score = 0;
this.lives = 3;
this.level = 1;
this.spawnRate = 2000;
document.getElementById('startScreen').style.display = 'none';
document.getElementById('gameOver').style.display = 'none';
this.updateUI();
this.startSpawning();
this.player.style.left = (window.innerWidth / 2 - this.playerWidth / 2) + 'px';
}
startSpawning() {
this.spawnTimer = setInterval(() => {
this.spawnCat();
}, this.spawnRate);
}
spawnCat() {
if (!this.gameRunning) return;
const catType = this.catTypes[Math.floor(Math.random() * this.catTypes.length)];
const cat = document.createElement('div');
cat.className = `cat ${catType.class}`;
cat.innerHTML = `<img src="${catType.image}" alt="猫咪">`;
const x = Math.random() * (window.innerWidth - this.catWidth);
cat.style.left = x + 'px';
cat.style.top = '-120px';
cat.style.animation = `${catType.animation} ${catType.speed}ms linear`;
cat.catData = catType;
this.gameContainer.appendChild(cat);
this.cats.push(cat);
cat.addEventListener('animationend', () => {
this.catMissed(cat);
});
this.startCollisionCheck(cat);
}
startCollisionCheck(cat) {
const checkCollision = () => {
if (!this.gameRunning || !cat.parentNode) return;
const catRect = cat.getBoundingClientRect();
const playerRect = this.player.getBoundingClientRect();
if (catRect.bottom >= playerRect.top &&
catRect.right >= playerRect.left &&
catRect.left <= playerRect.right &&
catRect.top <= playerRect.bottom) {
this.catchCat(cat);
return;
}
requestAnimationFrame(checkCollision);
};
requestAnimationFrame(checkCollision);
}
catchCat(cat) {
if (!cat.parentNode) return;
const catData = cat.catData;
this.score += catData.score;
this.playMeowSound(catData.sound);
this.removeCat(cat);
this.updateUI();
this.checkLevelUp();
this.showScoreEffect(cat, catData.score);
}
showScoreEffect(cat, score) {
const effect = document.createElement('div');
effect.textContent = `+${score}`;
effect.style.cssText = `
position: absolute;
left: ${cat.offsetLeft + 30}px;
top: ${cat.offsetTop}px;
color: #FFD93D;
font-size: 24px;
font-weight: bold;
pointer-events: none;
z-index: 100;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
animation: scoreUp 1s ease-out forwards;
`;
if (!document.getElementById('scoreAnimation')) {
const style = document.createElement('style');
style.id = 'scoreAnimation';
style.textContent = `
@keyframes scoreUp {
0% { opacity: 1; transform: translateY(0) scale(1); }
100% { opacity: 0; transform: translateY(-50px) scale(1.5); }
}
`;
document.head.appendChild(style);
}
this.gameContainer.appendChild(effect);
setTimeout(() => effect.remove(), 1000);
}
catMissed(cat) {
if (!cat.parentNode) return;
this.lives--;
this.removeCat(cat);
this.updateUI();
if (this.lives <= 0) {
this.gameOver();
}
}
removeCat(cat) {
const index = this.cats.indexOf(cat);
if (index > -1) {
this.cats.splice(index, 1);
}
if (cat.parentNode) {
cat.parentNode.removeChild(cat);
}
}
checkLevelUp() {
const newLevel = Math.floor(this.score / 200) + 1;
if (newLevel > this.level) {
this.level = newLevel;
this.spawnRate = Math.max(800, 2000 - (this.level - 1) * 200);
clearInterval(this.spawnTimer);
this.startSpawning();
this.updateUI();
}
}
updateUI() {
document.getElementById('score').textContent = this.score;
document.getElementById('lives').textContent = this.lives;
document.getElementById('level').textContent = this.level;
}
gameOver() {
this.gameRunning = false;
clearInterval(this.spawnTimer);
this.cats.forEach(cat => {
if (cat.parentNode) {
cat.parentNode.removeChild(cat);
}
});
this.cats = [];
document.getElementById('finalScore').textContent = `最终得分: ${this.score}`;
document.getElementById('gameOver').style.display = 'flex';
}
restart() {
this.gameRunning = false;
clearInterval(this.spawnTimer);
this.cats.forEach(cat => {
if (cat.parentNode) {
cat.parentNode.removeChild(cat);
}
});
this.cats = [];
document.getElementById('gameOver').style.display = 'none';
document.getElementById('startScreen').style.display = 'flex';
}
}
const game = new CatGame();
function startGame() {
game.startGame();
}
function restartGame() {
game.restart();
}
window.addEventListener('load', () => {
console.log('小猫接接乐游戏已加载完成!');
});
</script>
</body>
</html>