2016年9月10日土曜日

開発環境

Javascript for Kids (Nick Morgan 著、Angus Croll 寄稿、Miran Lipovaca イラスト、No Starch Press)のPart 3(Canvas)、Chapter 17(Making a Snake Game: Part 2)、PROGRAMMING CHALLENGES、#1(MAKING THE GAME BIGGER)、#2(COLORING THE SNAKE)、#3(MAKING THE GAME SPEED UP AS YOU PLAY)、#4(FIXING THE APPLE.MOVE METHOD)(No. 5084)を取り組んでみる。

PROGRAMMING CHALLENGES、#1(MAKING THE GAME BIGGER)、#2(COLORING THE SNAKE)、#3(MAKING THE GAME SPEED UP AS YOU PLAY)、#4(FIXING THE APPLE>MOVE METHOD)(No. 5084)

コード(Emacs)

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Snake!</title>
  </head>
  <body>
    <canvas id="canvas0" width="600" height="600"></canvas>
    <script src="sample.js"></script>
  </body>
</html>
(function () {
    'use strict';
    var Block,
        Snake,
        Apple,
        directions,
        score = 0,
        animation_time = 100,
        flag = true,
        occupied = [],
        body = document.querySelector('body'),
        canvas = document.querySelector('#canvas0'),
        ctx = canvas.getContext('2d'),
        width = canvas.width,
        height = canvas.height,
        block_size = 10,
        width_in_blocks = width / block_size,
        height_in_blocks = height / block_size,
        circle,
        snake,
        apple,
        intervalId,
        clearRect,
        drawBorder,
        drawScore,
        gameOver,
        gameClear,
        gameLoop;

    directions = {
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down',
    };
    body.onkeydown = function (event) {
        var new_direction = directions[event.keyCode];

        if (new_direction !== undefined) {
            snake.setDirection(new_direction);
        }
    };
    Block = function (col, row) {
        this.col = col;
        this.row = row;
    };
    Block.prototype.drawSquare = function (color) {
        var x = this.col * block_size,
            y = this.row * block_size;

        ctx.fillStyle = color;
        ctx.fillRect(x, y, block_size, block_size);
    };
    Block.prototype.drawCircle = function (color) {
        var center_x = this.col * block_size + block_size,
            center_y = this.row * block_size + block_size;

        ctx.fillStyle = color;
        circle(center_x, center_y, block_size / 2, true);
    };
    Block.prototype.equal = function (other) {
        return this.col === other.col && this.row === other.row;
    };
    Snake = function () {
        this.segments = [
            new Block(7, 5),
            new Block(6, 5),
            new Block(5, 5)
        ];
        this.direction = 'right';
        this.next_direction = 'right';
    };
    Snake.prototype.draw = function () {
        var i,
            max;

        this.segments[0].drawSquare('green');
        for (i = 1, max = this.segments.length; i < max; i += 1) {
            if (i % 2 === 1) {
                this.segments[i].drawSquare('blue');
            } else {
                this.segments[i].drawSquare('yellow');
            }
        }
    };
    Snake.prototype.move = function () {
        var head = this.segments[0],
            new_head;

        this.direction = this.next_direction;

        if (this.direction === 'right') {
            new_head = new Block(head.col + 1, head.row);
        } else if (this.direction === 'down') {
            new_head = new Block(head.col, head.row + 1);
        } else if (this.direction === 'left') {
            new_head = new Block(head.col - 1, head.row);
        } else if (this.direction === 'up') {
            new_head = new Block(head.col, head.row - 1);
        }
        if (this.checkCollision(new_head)) {
            gameOver();
            return;
        }

        this.segments.unshift(new_head);
        if (new_head.equal(apple.position)) {        
            score += 1;
            if (animation_time > 5) {
                animation_time -= 1;
            }
            occupied.push(apple.position);
            if (occupied.length ===
                (width_in_blocks - 2) * (height_in_blocks - 2)) {
                gameClear();
            } else {
                apple.move();
            }
        } else {
            this.segments.pop();
        }
    };
    Snake.prototype.checkCollision = function (head) {
        var left_collision = (head.col === 0),
            top_collision = (head.row === 0),
            right_collision = (head.col === width_in_blocks - 1),
            bottom_collision = (head.row === height_in_blocks - 1),
            wall_collision,
            self_collision = false,
            i,
            max;

        wall_collision = left_collision || top_collision ||
            right_collision || bottom_collision;

        for (i = 0, max = this.segments.length; i < max; i += 1) {
            if (head.equal(this.segments[i])) {
                self_collision = true;
            }
        }
        return wall_collision || self_collision;
    };
    Snake.prototype.setDirection = function (new_direction) {
        if (this.direction === 'up' && new_direction === 'down') {
            return;
        }
        if (this.direction === 'right' && new_direction === 'left') {
            return;
        }
        if (this.direction === 'down' && new_direction === 'up') {
            return;
        }
        if (this.direction === 'left' && new_direction === 'right') {
            return;
        }
        this.next_direction = new_direction;
    };
    Apple = function () {
        this.position = new Block(10, 10);
    };
    Apple.prototype.draw = function () {
        this.position.drawCircle('LimeGreen');
    };

    drawBorder = function () {
        ctx.fillStyle = 'gray';
        ctx.fillRect(0, 0, width, block_size);
        ctx.fillRect(0, height - block_size, width, block_size);
        ctx.fillRect(0, 0, block_size, height);
        ctx.fillRect(width - block_size, 0, block_size, height);
    };
    Apple.prototype.move = function () {
        var random_col,
            random_row,
            block,
            flag = true,
            i,
            max;

        while (flag) {
            random_col = Math.floor(Math.random() * (width_in_blocks - 2));
            random_row = Math.floor(Math.random() * (height_in_blocks - 2));
            block = new Block(random_row, random_col);
            for (i = 0, max = occupied.length; i < max; i += 1) {
                if (occupied[i].equal(block)) {
                    break;
                }
            }
            if (i === max) {
                break;
            }
        }
        this.position = block;
    };
    drawScore = function () {
        ctx.font = '20px Courier';
        ctx.fillStyle = 'black';
        ctx.textAlign = 'left';
        ctx.textBaseline = 'top';
        ctx.fillText('Score: ' + score, block_size, block_size);
    };

    gameOver = function () {
        flag = false;
        clearInterval(intervalId);
        ctx.font = '60px Courier';
        ctx.fillStyle = 'black';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('Game Over', width / 2, height / 2);    
    };
    gameClear = function () {
        flag = false;
        clearInterval(intervalId);
        ctx.font = '60px Courier';
        ctx.fillStyle = 'black';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('Congratulations!', width / 2, height / 2);    
    };
    circle = function (x, y, radius, fillCircle) {
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2, false);
        if (fillCircle) {
            ctx.fill();
        } else {
            ctx.stroke();
        }
    };

    snake = new Snake();
    apple = new Apple();

    gameLoop = function () {
        ctx.clearRect(0, 0, width, height);
        drawScore();
        snake.move();
        snake.draw();
        apple.draw();
        drawBorder();
        if (flag) {
            setTimeout(gameLoop, animation_time);
        }
    };
    gameLoop();
}());
Snake!

0 コメント:

コメントを投稿