小恐龙

“小恐龙”通常指的是谷歌浏览器(Google Chrome)中的隐藏彩蛋游戏——“恐龙游戏”(Chrome Dino/T-Rex Game)。当浏览器无法连接网络时(断网状态下),页面会显示一个像素风的小恐龙图标,并提示“未连接到互联网”。此时按下键盘的空格键↑键 ,即可启动这款简单的跑酷游戏。

游戏玩法:

  1. 操作:按空格键或↑键让小恐龙跳跃,躲避仙人掌和飞行翼龙;↓键可以下蹲躲避高障碍物。
  2. 规则:随着时间推移,游戏速度会逐渐加快,难度增加。
  3. 彩蛋:即使有网络时,你也可以通过地址栏输入 chrome://dino 直接进入游戏。

html游戏

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>恐龙游戏(修复计分版)</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f7f7f7;
            font-family: 'Courier New', monospace;
            overflow: hidden;
            -webkit-tap-highlight-color: transparent;
        }
        
        #game-container {
            position: relative;
            width: 800px;
            height: 300px;
            background-color: white;
            border: 2px solid #ddd;
            box-shadow: 0 0 20px rgba(0,0,0,0.1);
            overflow: hidden;
            touch-action: manipulation;
        }
        
        canvas {
            width: 100%;
            height: 100%;
            display: block;
        }
        
        #score {
            position: absolute;
            top: 10px;
            right: 20px;
            font-size: 20px;
            color: #666;
            z-index: 10;
            user-select: none;
            -webkit-user-select: none;
        }
        
        #high-score {
            position: absolute;
            top: 10px;
            left: 20px;
            font-size: 20px;
            color: #666;
            z-index: 10;
            user-select: none;
            -webkit-user-select: none;
        }
        
        #game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255,255,255,0.8);
            display: none;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 20;
        }
        
        #start-screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255,255,255,0.9);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 30;
        }
        
        h1 {
            color: #333;
            margin-bottom: 10px;
            font-size: 2.5em;
            user-select: none;
            -webkit-user-select: none;
        }
        
        p {
            color: #666;
            margin-bottom: 30px;
            font-size: 1.2em;
            user-select: none;
            -webkit-user-select: none;
        }
        
        button {
            padding: 12px 30px;
            font-size: 1.2em;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            user-select: none;
            -webkit-user-select: none;
            touch-action: manipulation;
        }
        
        button:active {
            transform: scale(0.98);
        }
    </style>
</head>
<body>
    <div id="game-container">
        <canvas id="game-canvas"></canvas>
        
        <div id="score">00000</div>
        <div id="high-score">00000</div>
        
        <div id="game-over">
            <h1>游戏结束!</h1>
            <p>你的分数: <span id="final-score">00000</span></p>
            <button id="restart-btn">再来一次</button>
        </div>
        
        <div id="start-screen">
            <h1>恐龙游戏(修复计分版)</h1>
            <p>按空格键或上箭头键跳跃,下箭头键下蹲</p>
            <button id="start-btn">开始游戏</button>
        </div>
    </div>

    <script>
        // 游戏配置
        const CONFIG = {
            INITIAL_SPEED: 6,
            SPEED_INCREMENT: 0.002,
            OBSTACLE_INTERVAL: 1000,
            MIN_GAP: 300,
            JUMP_FORCE: 12,
            GRAVITY: 0.4,
            BIRD_HEIGHT: 70,
            BIRD_PROBABILITY: 0.3,
            CLOUD_PROBABILITY: 0.006,
            MAX_CLOUDS: 6,
            DAY_NIGHT_CYCLE: 10000,
            SCORE_INCREMENT: 1  // 每帧增加的分数
        };
        
        // 游戏元素
        const canvas = document.getElementById('game-canvas');
        const ctx = canvas.getContext('2d');
        const scoreElement = document.getElementById('score');
        const highScoreElement = document.getElementById('high-score');
        const finalScoreElement = document.getElementById('final-score');
        const gameOverScreen = document.getElementById('game-over');
        const startScreen = document.getElementById('start-screen');
        const startBtn = document.getElementById('start-btn');
        const restartBtn = document.getElementById('restart-btn');
        
        // 设置画布大小
        canvas.width = 800;
        canvas.height = 300;
        
        // 游戏变量
        let score = 0;
        let highScore = localStorage.getItem('dinoHighScore') || 0;
        let gameSpeed = CONFIG.INITIAL_SPEED;
        let isGameOver = false;
        let isGameStarted = false;
        let isDucking = false;
        let animationId;
        let clouds = [];
        let obstacles = [];
        let lastObstacleTime = 0;
        let timeOfDay = 0;
        let isNight = false;
        let stars = [];
        let lastScoreUpdateTime = 0;
        
        // 初始化星星
        function initStars() {
            stars = [];
            for (let i = 0; i < 30; i++) {
                stars.push({
                    x: Math.random() * 800,
                    y: Math.random() * 150,
                    size: Math.random() * 1.5 + 0.5,
                    alpha: Math.random() * 0.5 + 0.5
                });
            }
        }
        
        // 游戏对象
        const dino = {
            x: 50,
            y: 0,
            width: 50,
            height: 50,
            duckWidth: 70,
            duckHeight: 30,
            velocityY: 0,
            isJumping: false,
            frame: 0,
            frameCount: 0,
            
            init: function() {
                this.y = 300 - this.height - 20;
                this.velocityY = 0;
                this.isJumping = false;
                this.frame = 0;
                this.frameCount = 0;
                isDucking = false;
            },
            
            update: function() {
                this.velocityY += CONFIG.GRAVITY;
                this.y += this.velocityY;
                
                const groundY = 300 - (isDucking ? this.duckHeight : this.height) - 20;
                if (this.y > groundY) {
                    this.y = groundY;
                    this.velocityY = 0;
                    this.isJumping = false;
                }
                
                if (!this.isJumping && !isDucking) {
                    this.frameCount++;
                    if (this.frameCount >= 5) {
                        this.frame = (this.frame + 1) % 2;
                        this.frameCount = 0;
                    }
                }
            },
            
            draw: function() {
                ctx.fillStyle = isNight ? '#e0e0e0' : '#535353';
                
                if (isDucking) {
                    ctx.beginPath();
                    ctx.roundRect(this.x, this.y + this.height - this.duckHeight, this.duckWidth, this.duckHeight, 5);
                    ctx.fill();
                    
                    if (this.frame === 0) {
                        ctx.fillRect(this.x + 15, this.y + this.height - 10, 20, 10);
                        ctx.fillRect(this.x + 45, this.y + this.height - 10, 20, 10);
                    } else {
                        ctx.fillRect(this.x + 10, this.y + this.height - 10, 20, 10);
                        ctx.fillRect(this.x + 40, this.y + this.height - 10, 20, 10);
                    }
                } else {
                    ctx.beginPath();
                    ctx.roundRect(this.x, this.y, this.width, this.height, 5);
                    ctx.fill();
                    
                    ctx.beginPath();
                    ctx.moveTo(this.x - 5, this.y + this.height - 15);
                    ctx.lineTo(this.x + 10, this.y + this.height - 5);
                    ctx.lineTo(this.x - 5, this.y + this.height + 5);
                    ctx.fill();
                    
                    if (!this.isJumping) {
                        if (this.frame === 0) {
                            ctx.fillRect(this.x + 10, this.y + this.height - 10, 15, 15);
                            ctx.fillRect(this.x + 35, this.y + this.height - 5, 15, 10);
                        } else {
                            ctx.fillRect(this.x + 10, this.y + this.height - 5, 15, 10);
                            ctx.fillRect(this.x + 35, this.y + this.height - 10, 15, 15);
                        }
                    }
                }
                
                ctx.fillStyle = 'white';
                ctx.beginPath();
                ctx.arc(this.x + 35, this.y + 15, 5, 0, Math.PI * 2);
                ctx.fill();
                
                ctx.fillStyle = isNight ? '#e0e0e0' : '#535353';
                ctx.beginPath();
                ctx.arc(this.x + 37, this.y + 15, 2, 0, Math.PI * 2);
                ctx.fill();
            },
            
            jump: function() {
                if (!this.isJumping && isGameStarted) {
                    this.velocityY = -CONFIG.JUMP_FORCE;
                    this.isJumping = true;
                    this.frame = 0;
                    this.frameCount = 0;
                }
            },
            
            duck: function() {
                if (!this.isJumping && isGameStarted) {
                    isDucking = true;
                }
            },
            
            stand: function() {
                isDucking = false;
            }
        };
        
        // 障碍物类
        class Obstacle {
            constructor() {
                this.type = Math.random() < CONFIG.BIRD_PROBABILITY ? 'bird' : 'cactus';
                
                if (this.type === 'cactus') {
                    this.cactusType = Math.floor(Math.random() * 3) + 1;
                    
                    if (this.cactusType === 1) {
                        this.width = 30;
                        this.height = 60;
                    } else if (this.cactusType === 2) {
                        this.width = 60;
                        this.height = 60;
                    } else {
                        this.width = 90;
                        this.height = 60;
                    }
                    
                    this.y = 300 - this.height - 20;
                } else {
                    this.width = 50;
                    this.height = 25;
                    this.y = 300 - CONFIG.BIRD_HEIGHT - 20;
                }
                
                this.x = 800;
                this.frame = 0;
                this.frameCount = 0;
                this.scored = false; // 标记是否已经计分
            }
            
            update() {
                this.x -= gameSpeed;
                
                if (this.type === 'bird') {
                    this.frameCount++;
                    if (this.frameCount >= 5) {
                        this.frame = (this.frame + 1) % 2;
                        this.frameCount = 0;
                    }
                }
            }
            
            draw() {
                const obstacleColor = isNight ? '#a0a0a0' : '#535353';
                const cactusColor = isNight ? '#3a5f3a' : '#2e8b57';
                
                if (this.type === 'cactus') {
                    ctx.fillStyle = cactusColor;
                    
                    if (this.cactusType === 1) {
                        ctx.beginPath();
                        ctx.roundRect(this.x, this.y, 20, this.height, 5);
                        ctx.fill();
                        ctx.fillRect(this.x - 5, this.y + 25, 5, 5);
                    } else if (this.cactusType === 2) {
                        ctx.beginPath();
                        ctx.roundRect(this.x, this.y, 20, this.height, 5);
                        ctx.roundRect(this.x + 30, this.y + 10, 20, this.height - 10, 5);
                        ctx.fill();
                        ctx.fillRect(this.x + 15, this.y + 25, 5, 5);
                    } else {
                        ctx.beginPath();
                        ctx.roundRect(this.x, this.y + 15, 20, this.height - 15, 5);
                        ctx.roundRect(this.x + 25, this.y, 20, this.height, 5);
                        ctx.roundRect(this.x + 50, this.y + 5, 20, this.height - 5, 5);
                        ctx.fill();
                        ctx.fillRect(this.x + 15, this.y + 30, 5, 5);
                    }
                } else {
                    ctx.fillStyle = obstacleColor;
                    ctx.beginPath();
                    ctx.ellipse(this.x + 25, this.y + 12, 25, 12, 0, 0, Math.PI * 2);
                    ctx.fill();
                    
                    ctx.beginPath();
                    ctx.arc(this.x + 45, this.y + 5, 7, 0, Math.PI * 2);
                    ctx.fill();
                    
                    ctx.fillStyle = isNight ? '#c0c0c0' : '#ff9900';
                    ctx.beginPath();
                    ctx.moveTo(this.x + 52, this.y + 5);
                    ctx.lineTo(this.x + 60, this.y + 5);
                    ctx.lineTo(this.x + 52, this.y + 10);
                    ctx.fill();
                    
                    ctx.fillStyle = obstacleColor;
                    if (this.frame === 0) {
                        ctx.beginPath();
                        ctx.moveTo(this.x + 15, this.y + 10);
                        ctx.quadraticCurveTo(this.x, this.y - 5, this.x - 10, this.y + 5);
                        ctx.quadraticCurveTo(this.x, this.y + 15, this.x + 15, this.y + 15);
                        ctx.fill();
                    } else {
                        ctx.beginPath();
                        ctx.moveTo(this.x + 15, this.y + 10);
                        ctx.quadraticCurveTo(this.x, this.y + 25, this.x - 10, this.y + 15);
                        ctx.quadraticCurveTo(this.x, this.y + 5, this.x + 15, this.y + 5);
                        ctx.fill();
                    }
                    
                    ctx.fillStyle = 'white';
                    ctx.beginPath();
                    ctx.arc(this.x + 48, this.y + 3, 2, 0, Math.PI * 2);
                    ctx.fill();
                }
            }
            
            isOffScreen() {
                return this.x + this.width < 0;
            }
            
            collidesWith(dino) {
                const dinoLeft = dino.x;
                const dinoRight = dino.x + (isDucking ? dino.duckWidth : dino.width);
                const dinoTop = dino.y;
                const dinoBottom = dino.y + (isDucking ? dino.duckHeight : dino.height);
                
                const obsLeft = this.x;
                const obsRight = this.x + this.width;
                const obsTop = this.y;
                const obsBottom = this.y + this.height;
                
                return !(
                    dinoRight < obsLeft || 
                    dinoLeft > obsRight || 
                    dinoBottom < obsTop || 
                    dinoTop > obsBottom
                );
            }
        }

        // 云朵类
        class Cloud {
            constructor() {
                this.width = 46 + Math.random() * 64;
                this.height = 14 + Math.random() * 16;
                this.x = 800;
                this.y = 30 + Math.random() * 80;
                this.speed = 0.2 + Math.random() * 0.8;
            }
            
            update() {
                this.x -= this.speed;
            }
            
            draw() {
                const cloudAlpha = isNight ? 0.4 : 0.8;
                ctx.fillStyle = `rgba(255, 255, 255, ${cloudAlpha})`;
                
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.height/2, 0, Math.PI * 2);
                ctx.arc(this.x + this.width/3, this.y - this.height/4, this.height/2, 0, Math.PI * 2);
                ctx.arc(this.x + this.width/1.5, this.y, this.height/2, 0, Math.PI * 2);
                ctx.fill();
            }
            
            isOffScreen() {
                return this.x + this.width < 0;
            }
        }
        
        // 绘制星星
        function drawStars() {
            ctx.fillStyle = 'white';
            stars.forEach(star => {
                ctx.globalAlpha = star.alpha * (isNight ? 1 : 0);
                const spikes = 5;
                const outerRadius = star.size;
                const innerRadius = star.size * 0.4;
                let rot = Math.PI/2*3;
                let x = star.x;
                let y = star.y;
                let step = Math.PI/spikes;

                ctx.beginPath();
                ctx.moveTo(star.x, star.y - outerRadius);
                for(let i = 0; i < spikes; i++) {
                    x = star.x + Math.cos(rot) * outerRadius;
                    y = star.y + Math.sin(rot) * outerRadius;
                    ctx.lineTo(x, y);
                    rot += step;

                    x = star.x + Math.cos(rot) * innerRadius;
                    y = star.y + Math.sin(rot) * innerRadius;
                    ctx.lineTo(x, y);
                    rot += step;
                }
                ctx.lineTo(star.x, star.y - outerRadius);
                ctx.closePath();
                ctx.fill();
            });
            ctx.globalAlpha = 1;
        }
        
        // 更新昼夜周期
        function updateDayNightCycle(timestamp) {
            timeOfDay = (timestamp % CONFIG.DAY_NIGHT_CYCLE) / CONFIG.DAY_NIGHT_CYCLE;
            isNight = timeOfDay > 0.5;
            
            const dayColor = '#f7f7f7';
            const nightColor = '#0a0a1a';
            
            const r = Math.floor(parseInt(dayColor.substr(1, 2), 16) * (1 - timeOfDay) + 
                     parseInt(nightColor.substr(1, 2), 16) * timeOfDay);
            const g = Math.floor(parseInt(dayColor.substr(3, 2), 16) * (1 - timeOfDay) + 
                     parseInt(nightColor.substr(3, 2), 16) * timeOfDay);
            const b = Math.floor(parseInt(dayColor.substr(5, 2), 16) * (1 - timeOfDay) + 
                     parseInt(nightColor.substr(5, 2), 16) * timeOfDay);
            
            return `rgb(${Math.floor(r)}, ${Math.floor(g)}, ${Math.floor(b)})`;
        }
        
        // 绘制地面
        function drawGround() {
            const groundColor = isNight ? '#2a2a2a' : '#535353';
            const lineColor = isNight ? '#3a3a3a' : '#636363';
            
            ctx.fillStyle = groundColor;
            ctx.fillRect(0, 280, 800, 20);
            
            ctx.strokeStyle = lineColor;
            ctx.lineWidth = 2;
            for (let x = 0; x < 800; x += 40) {
                ctx.beginPath();
                ctx.moveTo(x, 285 + Math.sin(x * 0.05) * 3);
                ctx.lineTo(x + 20, 285 + Math.sin((x + 20) * 0.05) * 3);
                ctx.stroke();
            }
        }
        
        // 游戏主循环
        function gameLoop(timestamp) {
            if (isGameOver) return;
            
            const bgColor = updateDayNightCycle(timestamp);
            
            ctx.fillStyle = bgColor;
            ctx.fillRect(0, 0, 800, 300);
            
            drawStars();
            updateClouds();
            drawClouds();
            drawGround();
            generateObstacle();
            updateObstacles();
            drawObstacles();
            dino.update();
            dino.draw();
            
            // 更新游戏速度
            gameSpeed += CONFIG.SPEED_INCREMENT;
            
            // 修复计分问题:每帧增加固定分数,同时障碍物通过时也增加分数
            if (timestamp - lastScoreUpdateTime > 100) { // 每100毫秒增加一次分数
                score += CONFIG.SCORE_INCREMENT;
                lastScoreUpdateTime = timestamp;
            }
            
            updateScoreDisplay();
            
            animationId = requestAnimationFrame(gameLoop);
        }
        
        // 更新分数显示
        function updateScoreDisplay() {
            scoreElement.textContent = String(score).padStart(5, '0');
            scoreElement.style.color = isNight ? '#e0e0e0' : '#666';
            highScoreElement.style.color = isNight ? '#e0e0e0' : '#666';
        }
        
        // 开始游戏
        function startGame() {
            score = 0;
            gameSpeed = CONFIG.INITIAL_SPEED;
            isGameOver = false;
            isGameStarted = true;
            obstacles = [];
            clouds = [];
            dino.init();
            lastObstacleTime = 0;
            lastScoreUpdateTime = 0;
            initStars();
            
            scoreElement.textContent = '00000';
            highScoreElement.textContent = String(highScore).padStart(5, '0');
            startScreen.style.display = 'none';
            gameOverScreen.style.display = 'none';
            
            for (let i = 0; i < 2; i++) {
                clouds.push(new Cloud());
                clouds[i].x = Math.random() * 800;
            }
            
            animationId = requestAnimationFrame(gameLoop);
        }
        
        // 结束游戏
        function endGame() {
            isGameOver = true;
            isGameStarted = false;
            cancelAnimationFrame(animationId);
            
            if (score > highScore) {
                highScore = score;
                localStorage.setItem('dinoHighScore', highScore);
                highScoreElement.textContent = String(highScore).padStart(5, '0');
            }
            
            finalScoreElement.textContent = String(score).padStart(5, '0');
            gameOverScreen.style.display = 'flex';
        }
        
        // 生成障碍物
        function generateObstacle() {
            const now = Date.now();
            
            if (now - lastObstacleTime > CONFIG.OBSTACLE_INTERVAL && 
                (obstacles.length === 0 || 
                 obstacles[obstacles.length-1].x < 800 - CONFIG.MIN_GAP)) {
                obstacles.push(new Obstacle());
                lastObstacleTime = now;
            }
        }
        
        // 更新障碍物
        function updateObstacles() {
            for (let i = obstacles.length - 1; i >= 0; i--) {
                obstacles[i].update();
                
                // 检测障碍物是否通过恐龙(用于计分)
                if (!obstacles[i].scored && obstacles[i].x + obstacles[i].width < dino.x) {
                    obstacles[i].scored = true;
                    score += 10; // 每个障碍物通过增加10分
                }
                
                if (obstacles[i].collidesWith(dino)) {
                    endGame();
                    return;
                }
                
                if (obstacles[i].isOffScreen()) {
                    obstacles.splice(i, 1);
                }
            }
        }
        
        // 绘制障碍物
        function drawObstacles() {
            obstacles.forEach(obstacle => obstacle.draw());
        }
        
        // 更新云朵
        function updateClouds() {
            for (let i = clouds.length - 1; i >= 0; i--) {
                clouds[i].update();
                
                if (clouds[i].isOffScreen()) {
                    clouds.splice(i, 1);
                }
            }
            
            if (Math.random() < CONFIG.CLOUD_PROBABILITY && clouds.length < CONFIG.MAX_CLOUDS) {
                clouds.push(new Cloud());
            }
        }
        
        // 绘制云朵
        function drawClouds() {
            clouds.forEach(cloud => cloud.draw());
        }
        
        // 事件监听
        function handleKeyDown(e) {
            if (e.code === 'Space' || e.key === 'ArrowUp') {
                e.preventDefault();
                dino.jump();
            }
            
            if (e.key === 'ArrowDown') {
                e.preventDefault();
                dino.duck();
            }
            
            if (e.code === 'Space' && !isGameStarted) {
                startGame();
            }
        }
        
        function handleKeyUp(e) {
            if (e.key === 'ArrowDown') {
                e.preventDefault();
                dino.stand();
            }
        }
        
        function handleStartClick() {
            if (!isGameStarted) {
                startGame();
            }
        }
        
        function handleRestartClick() {
            startGame();
        }
        
        // 添加事件监听
        document.addEventListener('keydown', handleKeyDown);
        document.addEventListener('keyup', handleKeyUp);
        startBtn.addEventListener('click', handleStartClick);
        restartBtn.addEventListener('click', handleRestartClick);
        
        // 添加触摸事件支持
        document.addEventListener('touchstart', function(e) {
            if (!isGameStarted) {
                startGame();
            } else {
                dino.jump();
            }
        });
        
        // 初始化游戏
        dino.init();
        initStars();
        highScoreElement.textContent = String(highScore).padStart(5, '0');
        
        // 确保按钮可以点击
        startBtn.style.pointerEvents = 'auto';
        restartBtn.style.pointerEvents = 'auto';
    </script>
</body>
</html>