本节教程通过一个简略的游戏小例子,解说Canvas的基础知识。

最终成果:

点击挪动的方块,方块上的分数会减少,方块的前进方向会扭转,并且方块的速度会减少。

在线演示

源码

HTML5引入了canvas元素。canvas元素为咱们提供了一块空白画布。咱们能够应用此画布来绘制和绘制咱们想要的任何货色。JavaScript为咱们提供了动静制作动画并绘制到画布上所需的工具。它不仅提供绘图和动画零碎,还能够解决用户交互。在本教程中,咱们将应用纯JavaScript制作根本的HTML5 Canvas框架,该框架可用于制作实在的游戏。在本教程的结尾创立了一个非常简单的游戏,以演示HTML5 Canvas与JavaScript联合的劣势。

HTML5 Canvas根本游戏框架

让咱们围绕canvas元素创立一个根本的游戏框架。咱们须要一个HTML5文件和一个JavaScript文件。HTML5文件应蕴含canvas元素和对JavaScript文件的援用。JavaScript文件蕴含将代码绘制到canvas元素的代码。

这是HTML5文件index.html:

<head><meta charset="UTF-8"><title>Canvas Example</title><script type="text/javascript" src="framework.js"></script></head><body><canvas id="viewport" width="640" height="480"></canvas></body></html> 

如您所见,JavaScript文件game.js蕴含在html文件的头部。画布元素以名称“ viewport”定义,其宽度为640像素,高度为480像素。在咱们的framework.js中,咱们须要应用其名称查找canvas元素,以便能够在其上进行绘制。咱们正在创立的框架应反对渲染循环以及玩家与鼠标的交互。对于渲染循环,咱们将应用Window.requestAnimationFrame()。通过增加鼠标事件侦听器来启用鼠标交互。

这是JavaScript文件framework.js:

// The function gets called when the window is fully loadedwindow.onload = function() {    // Get the canvas and context    var canvas = document.getElementById("viewport");     var context = canvas.getContext("2d");    // Timing and frames per second    var lastframe = 0;    var fpstime = 0;    var framecount = 0;    var fps = 0;        // Initialize the game    function init() {        // Add mouse events        canvas.addEventListener("mousemove", onMouseMove);        canvas.addEventListener("mousedown", onMouseDown);        canvas.addEventListener("mouseup", onMouseUp);        canvas.addEventListener("mouseout", onMouseOut);            // Enter main loop        main(0);    }        // Main loop    function main(tframe) {        // Request animation frames        window.requestAnimationFrame(main);                // Update and render the game        update(tframe);        render();    }        // Update the game state    function update(tframe) {        var dt = (tframe - lastframe) / 1000;        lastframe = tframe;                // Update the fps counter        updateFps(dt);    }        function updateFps(dt) {        if (fpstime > 0.25) {            // Calculate fps            fps = Math.round(framecount / fpstime);                        // Reset time and framecount            fpstime = 0;            framecount = 0;        }                // Increase time and framecount        fpstime += dt;        framecount++;    }        // Render the game    function render() {        // Draw the frame        drawFrame();    }        // Draw a frame with a border    function drawFrame() {        // Draw background and a border        context.fillStyle = "#d0d0d0";        context.fillRect(0, 0, canvas.width, canvas.height);        context.fillStyle = "#e8eaec";        context.fillRect(1, 1, canvas.width-2, canvas.height-2);                // Draw header        context.fillStyle = "#303030";        context.fillRect(0, 0, canvas.width, 65);                // Draw title        context.fillStyle = "#ffffff";        context.font = "24px Verdana";        context.fillText("HTML5 Canvas Basic Framework ", 10, 30);                // Display fps        context.fillStyle = "#ffffff";        context.font = "12px Verdana";        context.fillText("Fps: " + fps, 13, 50);    }        // Mouse event handlers    function onMouseMove(e) {}    function onMouseDown(e) {}    function onMouseUp(e) {}    function onMouseOut(e) {}        // Get the mouse position    function getMousePos(canvas, e) {        var rect = canvas.getBoundingClientRect();        return {            x: Math.round((e.clientX - rect.left)/(rect.right - rect.left)*canvas.width),            y: Math.round((e.clientY - rect.top)/(rect.bottom - rect.top)*canvas.height)        };    }        // Call init to start the game    init();};

下面的代码绘制了一个带有边框,题目和每秒帧数的简略框架。这是代码生成的内容

带有弹跳方块的游戏

当初咱们有了一个框架,让咱们用它创立一个简略的游戏。咱们将创立一个在屏幕上具备反弹方块的游戏。当玩家单击它时,方块上的分数会减少,方块的前进方向会扭转,并且方块的速度会减少。

首先,咱们定义一些对象和属性。该级别定义了方块能够反弹的区域。方块自身具备地位,尺寸和静止属性。最初,有一个分数。

    // Level properties    var level = {        x: 1,        y: 65,        width: canvas.width - 2,        height: canvas.height - 66    };     // Square    var square = {        x: 0,        y: 0,        width: 0,        height: 0,        xdir: 0,        ydir: 0,        speed: 0    }     // Score    var score = 0;

咱们须要在init()函数中初始化对象和属性。

    // Initialize the game    function init() {        // Add mouse events        canvas.addEventListener("mousemove", onMouseMove);        canvas.addEventListener("mousedown", onMouseDown);        canvas.addEventListener("mouseup", onMouseUp);        canvas.addEventListener("mouseout", onMouseOut);         // Initialize the square        square.width = 100;        square.height = 100;        square.x = level.x + (level.width - square.width) / 2;        square.y = level.y + (level.height - square.height) / 2;        square.xdir = 1;        square.ydir = 1;        square.speed = 200;         // Initialize the score        score = 0;         // Enter main loop        main(0);    }

这些对象须要更新,因而让咱们批改update()函数。方块须要挪动,并且应该检测并解决与标高边缘的碰撞。

    // Update the game state    function update(tframe) {        var dt = (tframe - lastframe) / 1000;        lastframe = tframe;         // Update the fps counter        updateFps(dt);         // Move the square, time-based        square.x += dt * square.speed * square.xdir;        square.y += dt * square.speed * square.ydir;         // Handle left and right collisions with the level        if (square.x <= level.x) {            // Left edge            square.xdir = 1;            square.x = level.x;        } else if (square.x + square.width >= level.x + level.width) {            // Right edge            square.xdir = -1;            square.x = level.x + level.width - square.width;        }         // Handle top and bottom collisions with the level        if (square.y <= level.y) {            // Top edge            square.ydir = 1;            square.y = level.y;        } else if (square.y + square.height >= level.y + level.height) {            // Bottom edge            square.ydir = -1;            square.y = level.y + level.height - square.height;        }    }

咱们须要绘制方块和分数。这须要在render()函数中实现。

    // Render the game    function render() {        // Draw the frame        drawFrame();         // Draw the square        context.fillStyle = "#ff8080";        context.fillRect(square.x, square.y, square.width, square.height);         // Draw score inside the square        context.fillStyle = "#ffffff";        context.font = "38px Verdana";        var textdim = context.measureText(score);        context.fillText(score, square.x+(square.width-textdim.width)/2, square.y+65);    }

最初一步是增加鼠标交互。让咱们将代码增加到onMouseDown()函数中。

   function onMouseDown(e) {        // Get the mouse position        var pos = getMousePos(canvas, e);         // Check if we clicked the square        if (pos.x >= square.x && pos.x < square.x + square.width &&            pos.y >= square.y && pos.y < square.y + square.height) {             // Increase the score            score += 1;             // Increase the speed of the square by 10 percent            square.speed *= 1.1;             // Give the square a random position            square.x = Math.floor(Math.random()*(level.x+level.width-square.width));            square.y = Math.floor(Math.random()*(level.y+level.height-square.height));             // Give the square a random direction            square.xdir = Math.floor(Math.random() * 2) * 2 - 1;            square.ydir = Math.floor(Math.random() * 2) * 2 - 1;        }    }

这是通过根本框架和一些批改而成的最终游戏。单击方块以减少您的分数并后退到下一个方块。