<font color="#000"><font face="Tahoma, Arial, Helvetica, snas-serif"><font style="font-size:14px">本篇将以零基础的视点,来讲解如何开发一款RPG游戏。<br> <br> 在游戏的世界里,我们可以看到各种地图,各种游戏人物,看到人物在地图上行走,对话等,无论是地图还是人物,其实都是图片的处理与显示,把不同的图片显示到屏幕上,我们就看到不同的游戏界面,要想让这些图片同时显示到界面上,我们就需要处理好层次,让他们来分层显示,我们可以想象,如果游戏人物显示在地图的下层的话,显然会被地图遮挡住。<br> 一款RPG游戏,我简单把它分为地图层,人物层,效果层(一些法术效果等),对话层,控制层(按钮菜单等)。<br> <br> 如下图<br> </font></font></font><p align="center"><font color="#000"><font face="Tahoma, Arial, Helvetica, snas-serif"><font style="font-size:14px"><a href="http://www.html5cn.org/data/attachment/portal/201201/30/114252j4q4k4zk4nm2jbm4.gif" target="_blank"><img src="http://www.html5cn.org/data/attachment/portal/201201/30/114252j4q4k4zk4nm2jbm4.gif" onload="thumbImg(this)" alt=""></a></font></font></font><br> </p> <br> <font color="#000"><font face="Tahoma, Arial, Helvetica, snas-serif"><font style="font-size:14px"><br> <br> 我们只要依次将图片画在屏幕上,游戏人物将站在地图上,如果有对话,对话将出现在人物和地图的上面,而按钮等控件会出现在游戏的最外层<br> <br> 下面,我们一步步来实现一个简单的RPG游戏的开发<br> <br> <br> <br> <strong>准备工作</strong><br> <br> <strong>一,库件下载</strong><br> <br> 本游戏开发,需要用到开源库件:LegendForHtml5Programming<br> <br> 请到这里下载最新版的LegendForHtml5Programming,本次开发需要1.2版以上<br> <br> <a href="http://code.google.com/p/legendforhtml5programming/downloads/list" target="_blank">http://code.google.com/p/legendforhtml5programming/downloads/list</a><br> <br> 库件的开发过程请看这里<br> <br> <br> <a href="http://www.html5cn.org/thread-2712-1-1.html" target="_blank">http://bbs.html5cn.org/thread-2712-1-1.html</a><br> <br> <strong>二,库件配置</strong><br> <br> 首先建立一个文件夹rpg(你也可以起其他的名字)<br> <br> <br> 然后将下载的库件解压,解压后将legend文件夹放到与rpg文件夹同目录<br> 然后,在rpg文件夹里建一个index.html文件和一个js文件夹,在js文件夹里建一个Main.js文件<br> <br> 最后,在index.html里加入下面的代码<br> <div class="blockcode"> <div id="code_z8p"><ol> <li> <br> </li> <li> <br> </li> <li> <br> </li> <li> <meta charset="UTF-8"> <br> </li> <li> <title>rpg</title> <br> </li> <li> <br> </li> <li> <br> </li> <li> <div id="mylegend">loading……</div> <br> </li> <li> <!-- 引入LegendForHtml5Programming库件 --><br> </li> <li> <script type="text/javascript" src="../legend/legend.js"></script> <br> </li> <li> <script type="text/javascript" src="./js/Main.js"></script> <br> </li> <li> </ol></div> <em onclick="copycode($('code_z8p'));">复制代码</em> </div> <br> 当然,你也可以将legend文件夹放到其他地方,但是你需要修改legend文件夹下的legend.js文件中的LEGEND_PATH的值,来配置库件的路径<br> <br> 游戏地图的实现<br> <br> 接下来,我们先来画最底层的地图层,<br> <br> 地图当然就是是由图片来组成的,如何在画面上显示一张图片,我之前已经写过专门的文章,代码如下<br> <div class="blockcode"> <div id="code_hh5"><ol> <li>var loader; <br> </li> <li>function main(){ <br> </li> <li> loader = new LLoader(); <br> </li> <li> loader.addEventListener(LEvent.COMPLETE,loadBitmapdata); <br> </li> <li> loader.load("map.jpg","bitmapData"); <br> </li> <li>} <br> </li> <li>function loadBitmapdata(event){ <br> </li> <li> var bitmapdata = new LBitmapData(loader.content); <br> </li> <li> var bitmap = new LBitmap(bitmapdata); <br> </li> <li> addChild(bitmap); <br> </li> <li>} </li> </ol></div> <em onclick="copycode($('code_hh5'));">复制代码</em> </div> <br> 如果想更详细了解的话,看下面的帖子<br> <br> 用仿ActionScript的语法来编写html5——第一篇,显示一张图片<br> <br> <a href="http://www.html5cn.org/thread-2700-1-1.html" target="_blank">http://bbs.html5cn.org/thread-2700-1-1.html</a><br> <br> 游戏中的地图可以是一张比较大的图片,即整个图片就是游戏的地图,当人物或者地图移动的时候,改变图片显示的区域范围,从而实现地图的滚动和显示等,这样的话,必须为每个场景准备一张地图。<br> <br> 另外,地图也可以是由许多小的地图块儿来组成,比如,我们熟悉的《吞食天地》,《勇者斗恶龙》等经典小型rpg游戏,这样的地图,我们需要准备一张或几张地图块儿,把这些地图块组合成地图来显示,比如下图<br> <p align="center"><img id="_aimg_1007" aid="1007" zoomfile="data/attachment/forum/201201/30/12014685w523x808fj0x2f.gif" src="data/attachment/forum/201201/30/12014685w523x808fj0x2f.gif" class="zoom" onclick="zoom(this, this.src, 0, 0, 0)" style="max-width:90%" alt="0_13238754463fxE.gif" title="0_13238754463fxE.gif" w="320"><br> </p> <br> 在地图显示的时候,首先把图片切割,然后在根据预先设定好的位置显示到地图层上,这样我们就看到了一张完整的地图了<br> <br> 接下来,打开Main.js<br> <br> 在里面加入<br> <div class="blockcode"> <div id="code_w53"><ol><li>init(50,"mylegend",480,320,main);</li></ol></div> <em onclick="copycode($('code_w53'));">复制代码</em> </div> <br> 在legendForHtml5Progarmming中,用init这个函数来初始化canvas,上面的代码表示,初始化一个速度为50,名字为mylegend,大小为480*320的游戏界面,初始化完成后调用main(),这个速度值是说每个多少毫秒游戏循环一次,所以这个值设定的越小,游戏运行的速度就越快<br> <br> 因为要调用main方法,所以我们要写一个main方法,main方法里做一些简单的准备工作。<br> <br> 虽说读取图片只需要一个<br> <div class="blockcode"> <div id="code_xR0"><ol><li>loader.load("map.jpg","bitmapData"); </li></ol></div> <em onclick="copycode($('code_xR0'));">复制代码</em> </div> <br> 但是游戏中往往用到很多张图片,你可以用到哪一张再加载哪一张,也可以一次性全部加载完,然后再开始显示游戏<br> <br> 为了一次性把图片加载完,我的做法是,将需要的图片放到一个数组里,然后设定一个索引,每加载一个图片,让这个索引加1,当这个索引小于数组的长度,则继续加载,直到将数组中的图片全部加载完,然后开始进行下一步的工作<br> <br> 具体实现看下面的代码<br> <div class="blockcode"> <div id="code_97w"><ol> <li>//图片path数组<br> </li> <li>var imgData = new Array();<br> </li> <li>//读取完的图片数组<br> </li> <li>var imglist = {};<br> </li> <li> <br> </li> <li>function main(){<br> </li> <li> //准备读取图片<br> </li> <li> imgData.push({name:"map",path:"./image/map.jpg"});<br> </li> <li> imgData.push({name:"mingren",path:"./image/mingren.png"});<br> </li> <li> imgData.push({name:"e1",path:"./image/e1.png"});<br> </li> <li> imgData.push({name:"e2",path:"./image/e2.png"});<br> </li> <li> //实例化进度条层<br> </li> <li> loadingLayer = new LSprite();<br> </li> <li> loadingLayer.graphics.drawRect(1,"black",[50, 200, 200, 20],true,"#ffffff");<br> </li> <li> addChild(loadingLayer);<br> </li> <li> //开始读取图片<br> </li> <li> loadImage();<br> </li> <li>}<br> </li> <li>function loadImage(){<br> </li> <li> //图片全部读取完成,开始初始化游戏<br> </li> <li> if(loadIndex >= imgData.length){<br> </li> <li> removeChild(loadingLayer);<br> </li> <li> legendLoadOver();<br> </li> <li> gameInit();<br> </li> <li> return;<br> </li> <li> }<br> </li> <li> //开始读取图片<br> </li> <li> loader = new LLoader();<br> </li> <li> loader.addEventListener(LEvent.COMPLETE,loadComplete);<br> </li> <li> loader.load(imgData[loadIndex].path,"bitmapData");<br> </li> <li>}<br> </li> <li>function loadComplete(event){<br> </li> <li> //进度条显示<br> </li> <li> loadingLayer.graphics.clear();<br> </li> <li> loadingLayer.graphics.drawRect(1,"black",[50, 200, 200, 20],true,"#ffffff");<br> </li> <li> loadingLayer.graphics.drawRect(1,"black",[50, 203, 200*(loadIndex/imgData.length), 14],true,"#000000");<br> </li> <li> //储存图片数据<br> </li> <li> imglist[imgData[loadIndex].name] = loader.content;<br> </li> <li> //读取下一张图片<br> </li> <li> loadIndex++;<br> </li> <li> loadImage();<br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_97w'));">复制代码</em> </div> <br> 上面的代码不难明白,当图片没有读取完之前,会不断循环loadImage和loadComplete两个方法,当读取完之后,移除进度条,用legendLoadOver告诉游戏已经读取完成,然后调用gameInit方法,进行游戏的初始化工作。<br> <br> 看gameInit方法<br> <div class="blockcode"> <div id="code_0A4"><ol> <li>function gameInit(event){<br> </li> <li> //游戏层显示初始化<br> </li> <li> layerInit();<br> </li> <li> //添加地图<br> </li> <li> addMap();<br> </li> <li> //添加人物<br> </li> <li> addChara();<br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_0A4'));">复制代码</em> </div> <br> 在gameInit方法中,首先进行游戏层的初始化,然后添加游戏地图,然后添加人物<br> <br> 游戏层显示初始化,按照我们一开始所说,我们一次来初始化地图层,人物层,效果层,对话层,控制层<br> <div class="blockcode"> <div id="code_6F6"><ol> <li>//游戏层显示初始化<br> </li> <li>function layerInit(){<br> </li> <li> //游戏底层添加<br> </li> <li> backLayer = new LSprite();<br> </li> <li> addChild(backLayer);<br> </li> <li> //地图层添加<br> </li> <li> mapLayer = new LSprite();<br> </li> <li> backLayer.addChild(mapLayer);<br> </li> <li> //人物层添加<br> </li> <li> charaLayer = new LSprite();<br> </li> <li> backLayer.addChild(charaLayer);<br> </li> <li> //效果层添加<br> </li> <li> effectLayer = new LSprite();<br> </li> <li> backLayer.addChild(effectLayer);<br> </li> <li> //对话层添加<br> </li> <li> talkLayer = new LSprite();<br> </li> <li> backLayer.addChild(talkLayer);<br> </li> <li> //控制层添加<br> </li> <li> ctrlLayer = new LSprite();<br> </li> <li> backLayer.addChild(ctrlLayer);<br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_6F6'));">复制代码</em> </div> <br> 有了游戏层次的划分,我们在添加游戏对象的时候,将地图添加到地图层,人物添加到人物层,他们就会依次显示在游戏的界面<br> <br> 下面开始添加地图<br> <br> 首先我们需要准备好显示地图的数组<br> <div class="blockcode"> <div id="code_7ik"><ol> <li>//地图图片数组<br> </li> <li>var map = [<br> </li> <li>[18,18,18,18,18,18,18,18,18,18,18,18,55,55,18],<br> </li> <li>[18,18,18,17,17,17,17,17,17,17,17,17,55,55,18],<br> </li> <li>[18,18,17,17,17,17,18,18,17,17,17,17,55,55,18],<br> </li> <li>[18,17,17,17,18,18,18,18,18,17,17,55,55,17,18],<br> </li> <li>[18,17,17,18,22,23,23,23,24,18,17,55,55,17,18],<br> </li> <li>[18,17,17,18,25,28,26,79,27,18,55,55,17,17,18],<br> </li> <li>[18,17,17,17,17,10,11,12,18,18,55,55,17,17,18],<br> </li> <li>[18,18,17,17,10,16,16,16,11,55,55,17,17,17,18],<br> </li> <li>[18,18,17,17,77,16,16,16,16,21,21,17,17,17,18],<br> </li> <li>[18,18,18,18,18,18,18,18,18,55,55,18,18,18,18]<br> </li> <li>];</li> </ol></div> <em onclick="copycode($('code_7ik'));">复制代码</em> </div> <br> 这些数字分别对应着图中如下位置<br> <br> <p align="center"><img id="_aimg_1008" aid="1008" zoomfile="data/attachment/forum/201201/30/131624wyt2btu8hccwtzrc.gif" src="data/attachment/forum/201201/30/131624wyt2btu8hccwtzrc.gif" class="zoom" onclick="zoom(this, this.src, 0, 0, 0)" style="max-width:90%" alt="0_13238754743Gp2.gif" title="0_13238754743Gp2.gif" w="325"><br> </p> <br> <br> 然后看下面代码<br> <div class="blockcode"> <div id="code_151"><ol> <li>//添加地图<br> </li> <li>function addMap(){<br> </li> <li> var i,j,index,indexX,indexY;<br> </li> <li> var bitmapdata,bitmap;<br> </li> <li> //地图图片数据<br> </li> <li> bitmapdata = new LBitmapData(imglist["map"]);<br> </li> <li> //将地图图片拆分,得到拆分后的各个小图片的坐标数组<br> </li> <li> imageArray = LGlobal.divideCoordinate(bitmapdata.image.width,bitmapdata.image.height,10,10);<br> </li> <li> <br> </li> <li> //在地图层上,画出15*10的小图片<br> </li> <li> for(i=0;i </li> <li> for(j=0;j </li> <li> //从地图数组中得到相应位置的图片坐标<br> </li> <li> index = map[i][j];<br> </li> <li> //小图片的竖坐标<br> </li> <li> indexY = Math.floor(index /10);<br> </li> <li> //小图片的横坐标<br> </li> <li> indexX = index - indexY*10;<br> </li> <li> //得到小图片<br> </li> <li> bitmapdata = new LBitmapData(imglist["map"],indexX*32,indexY*32,32,32);<br> </li> <li> bitmap = new LBitmap(bitmapdata);<br> </li> <li> //设置小图片的显示位置<br> </li> <li> bitmap.x = j*32;<br> </li> <li> bitmap.y = i*32;<br> </li> <li> //将小图片显示到地图层<br> </li> <li> mapLayer.addChild(bitmap);<br> </li> <li> }<br> </li> <li> }<br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_151'));">复制代码</em> </div> <br> 这样,我们就把预先设置好的图片显示到了游戏界面上,形成了地图<br> <br> 先把addChara方法加上<br> <div class="blockcode"> <div id="code_Yo8"><ol> <li>//添加人物<br> </li> <li>function addChara(){<br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_Yo8'));">复制代码</em> </div> <br> 然后运行游戏<br> <br> 可以得到下面画面<br> <br> <p align="center"><img id="_aimg_1009" aid="1009" zoomfile="data/attachment/forum/201201/30/131805zpqlpp29vi3snpph.gif" src="data/attachment/forum/201201/30/131805zpqlpp29vi3snpph.gif" class="zoom" onclick="zoom(this, this.src, 0, 0, 0)" style="max-width:90%" alt="0_1323875497G8BG.gif" title="0_1323875497G8BG.gif" w="485"><br> </p> <br> <br> 游戏人物的实现<br> <br> 为了更好的实现游戏人物的控制,我们新建一个游戏人物类Character.js<br> <br> 里面代码如下<br> <div class="blockcode"> <div id="code_etB"><ol> <li>function Character(data,row,col,speed){<br> </li> <li> base(this,LSprite,[]);<br> </li> <li> var self = this;<br> </li> <li> //设定人物动作速度<br> </li> <li> self.speed = speed==null?3:speed;<br> </li> <li> self.speedIndex = 0;<br> </li> <li> //设定人物大小<br> </li> <li> data.setProperties(0,0,data.image.width/col,data.image.height/row);<br> </li> <li> //得到人物图片拆分数组<br> </li> <li> var list = LGlobal.divideCoordinate(data.image.width,data.image.height,row,col);<br> </li> <li> //设定人物动画<br> </li> <li> self.anime = new LAnimation(this,data,list);<br> </li> <li>};<br> </li> <li>Character.prototype.onframe = function (){<br> </li> <li> var self = this;<br> </li> <li> if(self.speedIndex++ </li> <li> self.speedIndex = 0;<br> </li> <li> self.anime.onframe();<br> </li> <li>};</li> </ol></div> <em onclick="copycode($('code_etB'));">复制代码</em> </div> <br> 在legendForHtml5Programming里,有一个LAnimation类,用来实现图片数组顺序播放,形成动画<br> 使用LAnimation类需要三个参数,一个是显示动画的层,一个是图片,一个是图片的坐标数组<br> <br> 然后,调用LAnimation类的onframe方法,就可以实现动画的播放了<br> <br> 在index.html中引入Character类,然后修改addChara方法<br> <div class="blockcode"> <div id="code_KCK"><ol> <li>//添加人物<br> </li> <li>function addChara(){<br> </li> <li> bitmapdata = new LBitmapData(imglist["mingren"]);<br> </li> <li> player = new Character(bitmapdata,4,4);<br> </li> <li> player.x = 32*5;<br> </li> <li> player.y = 32*6;<br> </li> <li> charaLayer.addChild(player);<br> </li> <li> <br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_KCK'));">复制代码</em> </div> <br> 在gameInit的末尾添加循环事件<br> <div class="blockcode"> <div id="code_YYr"><ol> <li>//添加贞事件,开始游戏循环<br> </li> <li> backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);</li> </ol></div> <em onclick="copycode($('code_YYr'));">复制代码</em> </div> <br> 最后,添加onframe方法<br> <div class="blockcode"> <div id="code_Q9w"><ol> <li>/**<br> </li> <li> * 循环<br> </li> <li> * */<br> </li> <li>function onframe(){<br> </li> <li> player.onframe();<br> </li> <li>}</li> </ol></div> <em onclick="copycode($('code_Q9w'));">复制代码</em> </div> <br> 运行代码,看到了吗<br> <br> 一个会动的鸣人出现在游戏的地图上了<br> <br> <p align="center"><img id="_aimg_1010" aid="1010" zoomfile="data/attachment/forum/201201/30/132031us7gc1cumzzawsbz.gif" src="data/attachment/forum/201201/30/132031us7gc1cumzzawsbz.gif" class="zoom" onclick="zoom(this, this.src, 0, 0, 0)" style="max-width:90%" alt="0_1323875534sUfb.gif" title="0_1323875534sUfb.gif" w="482"><br> </p> <br> <br> <br> <br> 游戏演示<br> <br> <a href="http://fsanguo.comoj.com/html5/rpg/index.html" target="_blank">http://fsanguo.comoj.com/html5/rpg/index.html</a><br> <br> 最后,附上这次的游戏源代码<br> <br> <a href="http://legend-demo.googlecode.com/files/rpg.zip" target="_blank">http://legend-demo.googlecode.com/files/rpg.zip</a><br> <br> <br> </font></font></font><br> <div><span class="Apple-style-span" style="font-family: 微软雅黑, Tahoma, Helvetica, SimSun, sans-serif; background-color: rgb(255, 255, 255); ">本文转自个人博客:<a href="http://blog.csdn.net/lufy_legend" style="word-wrap: break-word; color: rgb(51, 51, 51); text-decoration: none; ">http://blog.csdn.net/lufy_legend</a></span></div>