乐趣区

关于canvas:通过游戏学javascript系列第一节Canvas游戏开发基础

本节教程通过一个简略的游戏小例子,解说 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 loaded
window.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;
        }
    }

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

退出移动版