《HTML5游戏编程核心技术与实战》一1.2 HTML5新特性初探

    xiaoxiao2024-03-30  120

    本节书摘来异步社区《HTML5游戏编程核心技术与实战》一书中的第1章,第1.2节,作者: 向峰 责编: 杨海玲,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    1.2 HTML5新特性初探

    HTML5游戏编程核心技术与实战准备好HTML5开发工具之后,我都迫不急待地想看看HTML5给我们带来了哪些让人激动不已的新特性,相信,你也会和我一样,对它感到兴奋。由于HTML5新增加了很多元素,这里,我们重点简单介绍一下在游戏中会使用到的一些元素,在介绍每一个新的元素时,我都会列举一些小的例子。现在假定读者有一定的HTML以及JavaScript方面的知识,如果您对这些代码完全不清楚,没关系,后面的章节中会详细地解说。目前,我们只需要知道HTML5能做什么就足够了。

    1.2.1 canvas元素

    canvas是HTML5中一个非常重要的元素,canvas元素提供了硬件加速机制,能够让我们实现高效的绘图功能。第2章我们会详细介绍canvas功能,这里,我们先来领略一下canvas的魅力。

    打开你的编辑工具,输入以下代码:

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> </head> <style type="text/css"> body, div{margin:0px;padding:0px;text-align:center} #cav{   border:2px solid black;   border-radius:4px;   box-shadow:0px 0px 10px black;   -webkit-box-shadow:0px 0px 10px black;   -moz-box-shadow:0px 0px 10px black; } #bk{   margin:10px auto;   width:400px;   height:36px; } .bk{   text-align:center;   width:20px;   height:20px;   margin:12px;   display:inline-block;   border:1px dotted gray; } </style> <body> <div id="bk" align="center"></div> <canvas id="cav" width="400" height="300"></canvas> </body> <script src="../js/jquery.js"></script> <script charset="utf-8">   //定义画笔颜色 var bColor = ["#000000", "#999999", "#CC66FF", "#FF0000", "#FF9900", "#FFFF00",            "#008000", "#00CCFF"]; //当前画笔颜色 var col="#FF0000"; function initBrush() {  for(var i=0;i<bColor.length;i++)  {   var bk = $("<span class='bk'></span>")    .css("background-color", bColor[i])    .click(function(){     col = $(this).css("background-color");    });   $("#bk").append(bk)  }  } function initPainter() {   //绑定绘图canvas    var can = $("#cav"), self = this, x=0, y=0;    var ctx = can[0].getContext("2d");    ctx.lineWidth = 2;    //绑定鼠标按下时间    can.on("mousedown", function(e){         e.preventDefault();     ctx.strokeStyle = col;     x = e.offsetX,     y = e.offsetY;     //开始路径     ctx.beginPath();     ctx.moveTo(x, y);       //绑定鼠标移动事件     can.on("mousemove", function(e){      var nx = event.offsetX,         ny = event.offsetY;      ctx.lineTo(x, y);      ctx.stroke();         x = nx;      y = ny;     });     //绑定鼠标抬起事件     can.on("mouseup", function(){       //取消鼠标移动事件     can.off("mousemove");     });    }) } $(document).ready(function(){  initBrush();  initPainter(); }) </script> </html>

    虽然有点长,但当你完成它的时候,我想,一定不会让你失望的,这是一个不错的开始,也许现在你可能还看不太懂,没关系,第2章就会对canvas元素进行详细介绍。以上代码通过canvas元素完成了一个在浏览器中使用的画板,可以通过Chrome浏览器打开它,看到的效果如图1-9所示,你可以选择不同颜色的画笔在画板上进行涂鸦。

    1.2.2 WebGL

    除了支持2D渲染技术外,canvas还提供了通过WebGL的方式,利用硬件加速提供3D渲染技术。以下代码使用了开源的three.js的3D引擎,完成了一个简单的旋转方块,注意,该3D效果完全使用WebGL技术,不需要安装任何插件。顺便说一下,three.js是一款完全免费使用的3D引擎,该引擎完全基于WebGL编写,事实上WebGL也是在canvas上进行渲染,目前对WebGL支持比较好的浏览器有Chrome、Firefox以及Safari等。

    <!DOCTYPE html> <html> <head>  <meta charset="UTF-8">  <title>Cube</title>  <script src="../js/jquery.js"></script>  <!--引入Three.js-->  <script src="three.min.js"></script> </head> <style type="text/css"> body, div{margin:0px;padding:0px;text-align:center} #sce{   border:2px solid black;   border-radius:4px;   width:480px;   height:320px;   margin:10px auto;   box-shadow:0px 0px 10px black;   -webkit-box-shadow:0px 0px 10px black;   -moz-box-shadow:0px 0px 10px black; } </style> <body> <div id="sce"></canvas> <script>   $(document).ready(function(){    init();   })   //定义3D场景,摄像机光源等和立方体   var scene, cam, render, cube, light;   //初始化   function init()   {    initScene();           initCube();    animate();   }   function initScene()   {    scene = new THREE.Scene();    cam = new THREE.PerspectiveCamera(45, $("#sce").width()/$("#sce"). height(), 0.1, 2000);    cam.position.x= cam.position.y = cam.position.z=2;    cam.lookAt(new THREE.Vector3(0, 0, 0 ));    render = new THREE.WebGLRenderer({antialias:true});    render.setSize($("#sce").width(), $("#sce").height());    $("#sce").append(render.domElement);   }   function initCube()   {    //加载纹理    var text = THREE.ImageUtils.loadTexture( 'box.gif' );    text.anisotropy = render.getMaxAnisotropy();    //创建几何图形和材质    var g = new THREE.CubeGeometry(1, 1, 1),       m = new THREE.MeshBasicMaterial({ map: text });           cube = new THREE.Mesh(g, m);    scene.add(cube);   }   function animate()   {    requestAnimationFrame(animate);    cube.rotation.y += Math.PI/180;    render.render(scene, cam);   }        </script> </body> </html>

    整个代码实现了一个绕Y轴旋转的方块,最好使用Chrome浏览器进行浏览,运行效果如图1-10所示。

    当然,对于代码的细节暂时可以不用去关注,目前,我们只需要知道使用WebGL能做什么就足够了,对于目前的HTML5来说,2D的游戏将会是比3D更好的选择。

    1.2.3 多媒体元素

    正如我们所期待的一样,HTML5中增加了两个多媒体元素以及

    比如,以下代码可以直接在浏览器中播放mp3音频文件。

    <!DOCTYPE html> <meta charset="utf-8" /> <style type="text/css">  body{text-align:center;} </style> <body>   <h2>简单的音视频</h2>   <audio id="a1" src="media/scg.mp3" autoplay mediagroup="gp" controls>    您的浏览器不支持audio元素   </audio><br> </body> </html>

    在浏览器中可以看到一个带有简单控制面板的音频播放器,如图1-11所示。

    1.2.4 地理信息服务

    HTML5提供了一组关于地理信息的API,通过这组API我们可以获取到客户端所在的经度和纬度,利用这些信息可以向这个坐标附近的区域提供服务。这些服务一般指的是基于位置的服务(LBS),LBS能够广泛支持需要动态地理空间信息的应用,从寻找旅馆、急救服务到导航,从社交游戏到生活服务,几乎可以覆盖生活中的所有方面。常见的一些LBS的应用有:位置信息查询、急救服务、道路辅助与导航、社交游戏等。

    借助HTML提供的Geolocation API功能,很容易获取到用户当前的位置,结合这组API,我们可以编写基于LBS的社交类游戏。

    同样地,我们给出一段简单的代码,可以获取用户所在的位置信息。

    <!DOCTYPE html> <html> <head>   <title> Location </title>   <meta charset="utf-8" /> </head> <body>   <input type="button" id="btnLocation" value="获取位置信息"/> </body> <script src="js/jquery.js"></script> <script>      //检测是否支持地理信息    function isSupportGeo()    {     return (navigator.geolocation!=null)    }      //绑定click事件    $("#btnLocation").click(function(){     if(!isSupportGeo())     {      alert("浏览器不支持地理位置定位!");     }     else     {       navigator.geolocation.getCurrentPosition(doSucc, doFail);     }    });    //处理成功    function doSucc(position)    {     // alert("成功获取地理位置!");     alert("成功获取地理位置,您当前所处的位置位于经度:"+position.coords.longitude+"        纬度:"+position.coords.latitude);    }    //处理失败    function doFail(error)    {     var errors=["拒绝地理信息服务", "获取不到地理信息", "获取信息超时"]     alert(errors[error.code+1]);    }  </script> </html>

    代码绑定一个“获取位置信息”的按钮,单击按钮将会调用isSupportGeo方法检测浏览器是否支持地理信息,如果支持的话就调用getCurrentPosition获取当前设备的地理信息。需要注意的是,第一次访问地理信息的时候由于个人隐私的问题,浏览器会弹出一个窗口询问用户是否允许让浏览器访问自己的位置,用户可以选择接受或者拒绝,如果拒绝的话将会得到一个错误。

    1.2.5 本地存储

    我们知道在传统的Web应用程序开发过程中,当客户端和服务器进行数据交互时,远程服务器需要存储客户端的各种数据,如果需要在客户端保留数据,可以采用“Cookie”的形式,但Cookie的存储量很小,通常只有4 kB,而且安全性和使用性都还有所欠缺。为了能够满足于HTML5本地应用的迅速发展,弥补HTML在本地数据持久化的弱势,HTML5推出了新的本地存储规范,提供了容量更大、更安全和更易于使用的本地存储方案。

    HTML5中使用Web Storage技术进行本地存储,能够在Web客户端进行数据存储。Web Storage曾经属于HTML5的规范,目前已经被独立出来形成单独的规范体系。简单来说使用Web本地存储类似于HashMap一样,采用键值对的形式保存数据,而且保存的数据会根据需要持久化在浏览器所在的客户端,具体来说Web Storage又可以分为以下两种。

    localStorage。将数据保存在客户端本地的硬件设备(通常指硬盘,但也可以是其他硬件设备)中,即使浏览器被关闭了,该数据仍然存在,下次打开浏览器访问网站时仍然可以继续使用。sessionStorage。将数据保存在session对象中。session对象就是会话对象,session中存储的数据独立于每个客户,该数据会随着浏览器的关闭而消失。这两者的区别在于,sessionStorage为临时保存,而localStorage为永久保存。localStorage提供了5 MB的存储空间,而sessiongStorage甚至没有限制,取决于内存的大小。

    对于这两种本地存储对象都可以使用以下方法进行数据存取。

    setItem(key, value)。使用键值对的方式保存数据,key为键,value为值,键是一个字符串,而数据则可以是任何类型的JavaScript基本数据类型,包括字符串、Boolean、整数和浮点数。需要注意的是,这些数据在存储时实际上是以字符串保存的。因此在访问数据时需要进行数据类型的转换,也可以直接用localStorage.key = value或者localStorage[key] = value的方式设置,对于复杂的数据类型,可以使用JSON格式的对象转换成字符串对象存储。getItem(key)。根据key键值来获取数据,也可以直接用localStorage.key或者localStorage[key]获取,需要注意的是,这些数据在取出来时实际上是字符串。因此在访问数据时需要进行数据类型的转换。

    removeItem(key)。清除key键值。 clear()。清除所有的键值对。

    例如,以下简单的代码用于记录用户访问页面的总次数:

    <body>    <h2>您是第<span id="ct"></span>次访问本页面</h2> </body> <script>   $(document).ready(function(){    //获取访问次数    readCount();   })   //获取访问次数   function readCount()   {    var count = localStorage["count"];       if(count==null){count=1;}       else {count = Number(count)+1;}       $("#ct").text(count);    localStorage["count"] = count;   } </script>

    上面代码中记录了用户访问页面次数,第一次访问时,获取的count为空,设置其为1,随后的访问中获取数据后通过Number函数转成数字进行累加并重新设置到localStorage中。需要注意的是,即使关闭浏览器,下次打开时,数据依然存在,因为localStorage的数据实际上持久化在本地文件中。

    1.2.6 Web sockets网络通信

    一直以来,HTTP的无状态性和单向性作为常用的应用已经足够,但还无法实现游戏中需要的实时双向通信技术,而HTML5中新增加的WebSocket通信元素则弥补了这一缺陷,使用新的Web sockets技术对于实现高效的Web网络游戏提供了基础。

    我们可以使用以下代码连接支持Web sockets协议的服务器端,并发送数据。

    var ws = new WebSocket(“ws://localhost:9000/socket”); ws.onopen = function(){  try  {   ws.send(“Hello, Web Socket”);  }  catch(e)  {    console.log(“发送消息失败!”);  } }

    当然,需要注意的是,以上只是使用WebSocket元素的客户端代码,需要有支持WebSocket协议的服务器端支持,在本书的第5章会详细介绍使用WebSocket的客户端以及Node.js的服务器端通信技术。

    1.2.7 Web Worker多线程

    Web Worker技术填补了JavaScript中一直所缺少的多线程技术,之前的HTML中,进行DOM元素渲染以及执行JavaScript脚本都是在单一的线程中执行,一旦在JavaScript中需要执行比较耗时间的操作,则会阻塞当前线程的执行。所带来的效果就是,当前的浏览器处于无响应状态,直到浏览器会弹出一个提示脚本运行时间过长的信息。这里,我们看一个简单的例子。

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> </head> <style type="text/css"> body, div{margin:0px;padding:0px;text-align:center} </style> <body>  <input type="button" id="btn_calc" value="计算圆周率" />  <input id="txt_rt" /> </body> <script src="../js/jquery.js"></script> <script charset="utf-8">    $(document).ready(function(){   $("#btn_calc").on("click", function(){     $("#txt_rt").val(getPI(80000000));    })  })  //求圆周率  function getPI(n)  {   var a=0;   for (i=0;i<=n;i++)   {     a = a + 4*Math.pow(-1, i)/(2*i+1);     }    return a;  } </script> </html>

    在该例子中,提供了一个通过级数获取圆周率的函数,参数n表示迭代次数,次数越高,计算越精确。然后提供一个按钮计算圆周率在文本框中显示,在浏览器中运行,我们发现当迭代次数很高的时候,计算量较大,在得到计算结果之前,按钮和文本框都是处于无法响应的状态,这也符合实际情况,因为此时DOM元素的更新被大计算量的程序给阻塞了。如果使用Web Worker则不会出现此情况,我们可以把计算量大的工作放到一个单独的线程中运行,不会阻塞当前线程。

    创建后台线程可以使用以下方式:

    var worker = new Worker(“worker.js”)我们把计算工作放到worker.js文件中,前台可以通过postmessage方法发送消息给Worker线程,请求Worker进行工作,直到Worker线程工作完毕返回结果。

    对于前面计算PI的例子,我们可以修改如下,首先,创建worker.js文件,代码如下:

    function getPI(n) {  var a=0;  for (i=0;i<=n;i++)  {    a = a + 4*Math.pow(-1, i)/(2*i+1);    }   return a; } onmessage = function(e) {   var result = getPI(e.data);   postMessage(result); }

    worker.js文件中定义了计算PI的函数,我们需要定义一个onmessage函数,当前台通过调用worker对象的postmessage方法时,该回调函数被响应。

    然后,把显示结果的页面修改如下:

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> </head> <style type="text/css"> body, div{margin:0px;padding:0px;text-align:center} </style> <body>  <input type="button" id="btn_calc" value="计算圆周率" />  <input id="txt_rt" /> </body> <script src="../js/jquery.js"></script> <script charset="utf-8">    $(document).ready(function(){   $("#btn_calc").on("click", function(){    var wk = new Worker("worker.js");     //注册返回结果,当woker发送postmessage时,该回调函数响应     wk.onmessage = function(e)     {      $("#txt_rt").val(e.data);     }     //发送计算请求     wk.postMessage(80000000);    })  }) </script> </html>

    这里,首先创建了一个Worker对象,然后在Workder对象中注册一个onmessage回调函数。注意,这个回调函数和workder.js文件中的onmessage是不同的,这里的回调函数当woker.js文件中的onmessage函数执行完毕后响应,最后,调用Worker对象的postMessage方法发送计算请求,此时,woker.js文件中的onmessage函数就会执行。

    修改成Worker版本后,你会发现,当单击按钮得到计算结果之前,按钮和文本框都是可以响应的,因为此时计算线程被独立出来了。

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)