本节教程通过一个简单的游戏小例子,讲解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; } }
这是通过基本框架和一些修改而成的最终游戏。单击方块以增加您的分数并前进到下一个方块。