俄罗斯方块程序

所属课程: 人工智能大变革(16星期,32课时)

*惠杰

11岁半

发布于:06-18
浏览数:18

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>俄罗斯方块</title>
    <style>
        body {
            background: #202028;
            color: #fff;
            font-family: sans-serif;
            display: flex;
            justify-content: center;
        }
        .game-container {
            position: relative;
            margin-top: 20px;
        }
        canvas {
            border: 2px solid #fff;
        }
        #game {
            background: #000;
        }
        #preview {
            background: #000;
            margin-left: 20px;
        }
        .score-box {
            position: absolute;
            left: -120px;
            top: 0;
            width: 100px;
        }
        .controls {
            position: absolute;
            right: -120px;
            top: 0;
            width: 100px;
        }
        button {
            background: #306;
            color: #fff;
            border: 0;
            padding: 10px;
            margin: 5px;
            cursor: pointer;
        }
        .game-over {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            background: rgba(0,0,0,0.8);
            padding: 20px;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <canvas id="game" width="300" height="600"></canvas>
        <canvas id="preview" width="120" height="120"></canvas>
        <div class="score-box">
            <div>得分:<span id="score">0</span></div>
        </div>
        <div class="controls">
            <button id="pause">暂停</button>
        </div>
        <div id="startScreen">
            <button id="start">开始</button>
        </div>
        <div id="gameOver" class="game-over" style="display:none;">
            <div>最终得分:<span id="finalScore">0</span></div>
            <button id="restart">重新开始</button>
        </div>
    </div>

<script>
const SHAPES = [
    [[1,1,1,1]], // I
    [[1,1,1],[0,1,0]], // T
    [[1,1,1],[1,0,0]], // L
    [[1,1,1],[0,0,1]], // J
    [[1,1],[1,1]], // O
    [[1,1,0],[0,1,1]], // S
    [[0,1,1],[1,1,0]]  // Z
];
const COLORS = ['#0ff', '#f0f', '#ff0', '#0f0', '#f00', '#00f', '#f90'];

class Tetris {
    constructor() {
        this.canvas = document.getElementById('game');
        this.ctx = this.canvas.getContext('2d');
        this.preview = document.getElementById('preview').getContext('2d');
        this.cellSize = 30;
        this.rows = 20;
        this.cols = 10;
        this.board = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
        this.current = null;
        this.next = null;
        this.score = 0;
        this.gameOver = false;
        this.paused = false;
        this.interval = null;
        
        document.addEventListener('keydown', (e) => this.handleInput(e));
        document.getElementById('start').addEventListener('click', () => this.start());
        document.getElementById('restart').addEventListener('click', () => this.reset());
        document.getElementById('pause').addEventListener('click', () => this.togglePause());
    }

    start() {
        document.getElementById('startScreen').style.display = 'none';
        this.reset();
        this.interval = setInterval(() => this.update(), 1000);
    }

    reset() {
        this.board = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
        this.score = 0;
        this.gameOver = false;
        this.paused = false;
        document.getElementById('gameOver').style.display = 'none';
        this.spawnNew();
        this.draw();
    }

    spawnNew() {
        this.current = this.next || this.createPiece();
        this.next = this.createPiece();
        if (this.checkCollision(this.current.x, this.current.y, this.current.shape)) {
            this.gameOver = true;
            clearInterval(this.interval);
            document.getElementById('gameOver').style.display = 'block';
            document.getElementById('finalScore').textContent = this.score;
        }
    }

    createPiece() {
        const type = Math.floor(Math.random() * SHAPES.length);
        return {
            x: Math.floor(this.cols/2) - Math.floor(SHAPES[type][0].length/2),
            y: 0,
            shape: SHAPES[type],
            color: COLORS[type]
        };
    }

    draw() {
        // 清空画布
        this.ctx.fillStyle = '#000';
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
        
        // 绘制网格
        this.ctx.strokeStyle = '#333';
        for (let i = 0; i <= this.rows; i++) {
            this.ctx.beginPath();
            this.ctx.moveTo(0, i * this.cellSize);
            this.ctx.lineTo(this.canvas.width, i * this.cellSize);
            this.ctx.stroke();
        }
        for (let i = 0; i <= this.cols; i++) {
            this.ctx.beginPath();
            this.ctx.moveTo(i * this.cellSize, 0);
            this.ctx.lineTo(i * this.cellSize, this.canvas.height);
            this.ctx.stroke();
        }

        // 绘制当前方块
        this.drawPiece(this.current, this.ctx);
        
        // 绘制已落下的方块
        this.board.forEach((row, y) => {
            row.forEach((value, x) => {
                if (value) {
                    this.ctx.fillStyle = value;
                    this.ctx.fillRect(x * this.cellSize, y * this.cellSize, this.cellSize-1, this.cellSize-1);
                }
            });
        });

        // 绘制预览
        this.preview.clearRect(0, 0, 120, 120);
        this.drawPiece({x:1, y:1, shape:this.next.shape, color:this.next.color}, this.preview);
        
        // 更新分数显示
        document.getElementById('score').textContent = this.score;
    }

    drawPiece(piece, ctx) {
        ctx.fillStyle = piece.color;
        piece.shape.forEach((row, y) => {
            row.forEach((value, x) => {
                if (value) {
                    ctx.fillRect(
                        (piece.x + x) * this.cellSize,
                        (piece.y + y) * this.cellSize,
                        this.cellSize-1,
                        this.cellSize-1
                    );
                }
            });
        });
    }

    checkCollision(x, y, shape) {
        return shape.some((row, dy) => 
            row.some((value, dx) => 
                value && (
                    x + dx < 0 ||
                    x + dx >= this.cols ||
                    y + dy >= this.rows ||
                    (y + dy >= 0 && this.board[y + dy][x + dx])
                )
            )
        );
    }

    rotate() {
        const rotated = this.current.shape[0].map((_, i) =>
            this.current.shape.map(row => row[i]).reverse()
        );
        if (!this.checkCollision(this.current.x, this.current.y, rotated)) {
            this.current.shape = rotated;
        }
    }

    move(dx, dy) {
        if (!this.checkCollision(this.current.x + dx, this.current.y + dy, this.current.shape)) {
            this.current.x += dx;
            this.current.y += dy;
            return true;
        }
        return false;
    }

    hardDrop() {
        while (this.move(0, 1)) {}
        this.placePiece();
    }

    placePiece() {
        this.current.shape.forEach((row, y) => {
            row.forEach((value, x) => {
                if (value) {
                    this.board[this.current.y + y][this.current.x + x] = this.current.color;
                }
            });
        });
        this.clearLines();
        this.spawnNew();
    }

    clearLines() {
        let lines = 0;
        for (let y = this.rows - 1; y >= 0; y--) {
            if (this.board[y].every(cell => cell)) {
                this.board.splice(y, 1);
                this.board.unshift(Array(this.cols).fill(0));
                lines++;
                y++;
            }
        }
        if (lines) {
            this.score += lines * 100;
        }
    }

    update() {
        if (this.gameOver || this.paused) return;
        if (!this.move(0, 1)) {
            this.placePiece();
        }
        this.draw();
    }

    handleInput(e) {
        if (this.gameOver || this.paused) return;
        e.preventDefault();
        switch(e.keyCode) {
            case 37: // 左
                this.move(-1, 0);
                break;
            case 39: // 右
                this.move(1, 0);
                break;
            case 38: // 上
                this.rotate();
                break;
            case 40: // 下
                this.move(0, 1);
                break;
            case 32: // 空格
                this.hardDrop();
                break;
        }
        this.draw();
    }

    togglePause() {
        this.paused = !this.paused;
        document.getElementById('pause').textContent = this.paused ? '继续' : '暂停';
    }
}

new Tetris();
</script>
</body>
</html>

 

 

 

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!