zoukankan      html  css  js  c++  java
  • 如何实现一个HTML5 RPG游戏引擎——第四章,实现情景对话

    今天我们来实现情景对话。这是一个重要的功能,沒有它,游戏将变得索然无味。所以我们不得不来完成它。

    可是要知道,使用对话可不是一件简单的事,由于它内部的东西非常多,比方说人物头像,人物名称,对话内容。。。

    因此我们仅仅能通过数组+JSON来将对话信息装起来,然后依据信息作出不同的显示。接下来我便要向大家展示实现方法。

    先看本系列文章文件夹:

    怎样制作一款HTML5 RPG游戏引擎——第一篇,地图类的实现

    http://blog.csdn.net/yorhomwang/article/details/8892305

    怎样制作一款HTML5 RPG游戏引擎——第二篇,烟雨+飞雪效果

    http://blog.csdn.net/yorhomwang/article/details/8915020

    怎样制作一款HTML5 RPG游戏引擎——第三篇,利用幕布切换场景

    http://blog.csdn.net/yorhomwang/article/details/9042571

    该引擎是基于lufylegend开发的,学习时请先了解lufylegend。

    官方站点地址:http://lufylegend.com/lufylegend

    API地址:http://lufylegend.com/lufylegend/api

    1,实现后的代码

    为了向大家展示封装的必要性,所以我们先看实现后的代码:

    [javascript] view plaincopy
     
    1. <!DOCTYPE html>  
    2. <html lang="en">  
    3.     <head>  
    4.     <meta charset="utf-8" />  
    5.     <title>LTalk</title>  
    6.     <script type="text/javascript" src="../lufylegend-1.7.6.min.js"></script>  
    7.     <script type="text/javascript" src="../lufylegendrpg-1.0.0.js"></script>   
    8.     <script>  
    9.     init(30,"legend",480,320,main);  
    10.     LRPGStage.setShortcuts(true);  
    11.     LGlobal.setDebug(true);  
    12.     var backLayer,loadingLayer,talkLayer;  
    13.     var talk;  
    14.     var talkContent;  
    15.     var talkNum = 0;  
    16.     var loadData = [  
    17.         {name:"yorhom_face",path:"./yorhom.jpg"},  
    18.         {name:"lufy_face",path:"./lufy.jpg"}  
    19.     ];  
    20.     var imglist = [];  
    21.     function main(){  
    22.         //添加进度条  
    23.         loadingLayer = new LoadingSample1();   
    24.         addChild(loadingLayer);   
    25.         //载入图片并显示运行进度  
    26.         LLoadManage.load(  
    27.             loadData,  
    28.             function(progress){  
    29.                 loadingLayer.setProgress(progress);  
    30.             },  
    31.             gameInit  
    32.         );   
    33.     }  
    34.     function gameInit(result){  
    35.         removeChild(loadingLayer);  
    36.         imglist = result;  
    37.         //初始化层  
    38.         backLayer = new LSprite();  
    39.         addChild(backLayer);  
    40.         talkLayer = new LSprite();  
    41.         backLayer.addChild(talkLayer);  
    42.         //添加操作button  
    43.         addEvent();  
    44.         //增加对话内容  
    45.         talkContent = [  
    46.             {name:"[Yorhom]",msg:"你好,lufy",face:imglist["yorhom_face"]},  
    47.             {name:"[lufy]",msg:"你好,yorhom",face:imglist["lufy_face"]},  
    48.             {name:"[Yorhom]",msg:"lufylegend最新版本号是哪个版本号啊?",face:imglist["yorhom_face"]},  
    49.             {name:"[lufy]",msg:"……你不知道自己看吗?",face:imglist["lufy_face"]},  
    50.             {name:"[Yorhom]",msg:"……说得也是",face:imglist["yorhom_face"]},  
    51.         ];  
    52.         //添加对话  
    53.         talkLayer.graphics.drawRect(5,"black",[20,15,400,130],true,"black");  
    54.         talkLayer.alpha = 0.8;  
    55.         talk = new LTalk(talkContent);  
    56.         talkLayer.addChild(talk);  
    57.         talkLayer.addEventListener(LMouseEvent.MOUSE_DOWN,say);  
    58.         //设置样式  
    59.         talk.setNameStyle({x:160,y:40,color:"white",size:12});  
    60.         talk.setMsgStyle({x:160,y:70,color:"white",size:10});  
    61.         talk.setFaceStyle({x:30,y:30});  
    62.         talk.textWidth = 260;  
    63.     }  
    64.     function addEvent(){  
    65.         LEvent.addEventListener(LGlobal.window,LKeyboardEvent.KEY_UP,say);  
    66.     }  
    67.     function say(){  
    68.         if(talkNum < talkContent.length){  
    69.             //输出对话  
    70.             talk.wind(talkNum,function(){talkNum++;});  
    71.         }  
    72.     }  
    73.     </script>  
    74.     </head>  
    75.     <body>  
    76.             <div id="legend"></div>  
    77.     </body>  
    78. </html>  


    这78行代码就能够实现进行5次对话的效果,先发两张截图,例如以下:

    由此可见,本次封装还是非常有作用的。

    可是怎样实现呢?请看接下来的解说。

    2,LTalk类

    LTalk是一个对话类,构造器例如以下:

    [javascript] view plaincopy
     
    1. function LTalk(content){  
    2.     var s = this;  
    3.     base(s,LSprite,[]);  
    4.     if(!content){  
    5.         s.content = [];  
    6.     }else{  
    7.         s.content = content;  
    8.     }  
    9.     s.x = 0;  
    10.     s.y = 0;  
    11.     s.textWidth = LStage.width;  
    12.     s.talkIndex = 0;  
    13.     s.faceX = 0;  
    14.     s.faceY = 0;  
    15.     s.nameX = 0;  
    16.     s.nameY = 0;  
    17.     s.nameColor = "black";  
    18.     s.nameFont = "宋体";  
    19.     s.nameSize = "15";  
    20.     s.msgX = 0;  
    21.     s.msgY = 0;  
    22.     s.msgColor = "black";  
    23.     s.msgFont = "宋体";  
    24.     s.msgSize = "15";  
    25. }  

    当中,textWidth属性是为了设置文字区宽度的,设置后,假设文字过多而超出这个区域就会自己主动换行。talkIndex指对话编号。faceX,faceY指人物头像位置。nameX,nameY指人物名称的位置;nameColor,nameFont,nameSize分别用来设置名称颜色,字体,尺寸。msgX,msgY,msgColor,msgFont,msgSize同分别代表对话内容的x坐标,y坐标,颜色,字体,尺寸。

    设定好刚才的那些属性后,就能够自己定义对话样式了。

    这个类构造时要传个參数,这个參数是对话内容。是一个数组套JSON的格式,例如以下:

    [plain] view plaincopy
     
    1. [  
    2.     {name:"名称",msg:"内容",face:头像图片},  
    3.     {name:"名称",msg:"内容",face:头像图片},  
    4.     {name:"名称",msg:"内容",face:头像图片},  
    5.     {name:"名称",msg:"内容",face:头像图片},  
    6.     {name:"名称",msg:"内容",face:头像图片},  
    7. ];  

    每往这个列表里加一条,就会多一段对话。

    3,wind方法

    接下来看看wind方法:

    [javascript] view plaincopy
     
    1. LTalk.prototype.wind = function(num,completeFunc){  
    2.     var s = this;  
    3.     if(!num || num == null)num = 0;  
    4.     if(!completeFunc)completeFunc = null;  
    5.     s.talkIndex = num;  
    6.     s.removeAllChild();  
    7.     if(s.talkIndex < s.content.length){  
    8.         var talkObject = s.content[s.talkIndex];  
    9.         var faceBitmapdata = new LBitmapData(talkObject.face);  
    10.         var faceBitmap = new LBitmap(faceBitmapdata);  
    11.         faceBitmap.x = s.faceX;  
    12.         faceBitmap.y = s.faceY;  
    13.         s.addChild(faceBitmap);  
    14.         var name = new LTextField();  
    15.         name.x = s.nameX;  
    16.         name.y = s.nameY;  
    17.         name.size = s.nameSize;  
    18.         name.color = s.nameColor;  
    19.         name.font = s.nameFont;  
    20.         name.text = talkObject.name;  
    21.         name.width = s.textWidth;  
    22.         name.setWordWrap(true,name.getHeight()+5);  
    23.         s.addChild(name);  
    24.         var msg = new LTextField();  
    25.         msg.x = s.msgX;  
    26.         msg.y = s.msgY;  
    27.         msg.size = s.msgSize;  
    28.         msg.color = s.msgColor;  
    29.         msg.font = s.msgFont;  
    30.         msg.text = talkObject.msg;  
    31.         msg.width = s.textWidth;  
    32.         msg.setWordWrap(true,msg.getHeight()+7);  
    33.         msg.wind(completeFunc);  
    34.         s.addChild(msg);  
    35.     }else{  
    36.         trace("Error: Param exceeds the size of the content!");  
    37.     }  
    38. }  

    这个方案有两个參数,第一个是播放序号,第二个參数是输出完成后调用的函数。

    首先我们推断一下參数num是不是没定义,假设是就自己主动设0,然后再推断第二个參数是否定义,假设沒有,就设为null。这样做能够确保程序运行无误。接着,我们把控制播放序号的属性talkIndex设为num,然后清空一次,以便不和上次输出的重叠在一起。接着推断talkIndex有沒有超出最大值,沒有的话就运行输出命令。代码例如以下:

    [javascript] view plaincopy
     
    1. var talkObject = s.content[s.talkIndex];  
    2. var faceBitmapdata = new LBitmapData(talkObject.face);  
    3. var faceBitmap = new LBitmap(faceBitmapdata);  
    4. faceBitmap.x = s.faceX;  
    5. faceBitmap.y = s.faceY;  
    6. s.addChild(faceBitmap);  
    7. var name = new LTextField();  
    8. name.x = s.nameX;  
    9. name.y = s.nameY;  
    10. name.size = s.nameSize;  
    11. name.color = s.nameColor;  
    12. name.font = s.nameFont;  
    13. name.text = talkObject.name;  
    14. name.width = s.textWidth;  
    15. name.setWordWrap(true,name.getHeight()+5);  
    16. s.addChild(name);  
    17. var msg = new LTextField();  
    18. msg.x = s.msgX;  
    19. msg.y = s.msgY;  
    20. msg.size = s.msgSize;  
    21. msg.color = s.msgColor;  
    22. msg.font = s.msgFont;  
    23. msg.text = talkObject.msg;  
    24. msg.width = s.textWidth;  
    25. msg.setWordWrap(true,msg.getHeight()+7);  
    26. msg.wind(completeFunc);  
    27. s.addChild(msg);  

    熟悉lufylegend的朋友不难理解这些,就是将名称,内容,头像所有加到界面上。显示内容为构造器參数中相应的内容。
    wind做好后,大家想让文本逐字显示时仅仅用写一行obj.wind();就可以了。

    4,更改样式&手动清空对话&重设数据

    刚才我们看了控制文字,图片样式的几个属性,有非常多,假设一个一个用手改就会非常麻烦,并且要写非常多行代码,因此我们加几个控制样式的方法,它们各自是:setFaceStyle,setNameStyle,setMsgStyle。运用时仅仅用传入參数就可以了。

    实现方法例如以下:

    [javascript] view plaincopy
     
    1. LTalk.prototype.setFaceStyle = function(styleData){  
    2.     var s = this;  
    3.     if(!styleData.x){s.faceX = 0;}else{s.faceX = styleData.x;}  
    4.     if(!styleData.y){s.faceY = 0;}else{s.faceY = styleData.y;}  
    5. }  
    6. LTalk.prototype.setNameStyle = function(styleData){  
    7.     var s = this;  
    8.     if(!styleData.x){s.nameX = 0;}else{s.nameX = styleData.x;}  
    9.     if(!styleData.y){s.nameY = 0;}else{s.nameY = styleData.y;}  
    10.     if(!styleData.color){s.nameColor = "black";}else{s.nameColor = styleData.color;}  
    11.     if(!styleData.font){s.nameFont = "宋体";}else{s.nameFont = styleData.font;}  
    12.     if(!styleData.size){s.nameSize = "15";}else{s.nameSize = styleData.size;}  
    13. }  
    14. LTalk.prototype.setMsgStyle = function(styleData){  
    15.     var s = this;  
    16.     if(!styleData.x){s.msgX = 0;}else{s.msgX = styleData.x;}  
    17.     if(!styleData.y){s.msgY = 0;}else{s.msgY = styleData.y;}  
    18.     if(!styleData.color){s.msgColor = "black";}else{s.msgColor = styleData.color;}  
    19.     if(!styleData.font){s.msgFont = "宋体";}else{s.msgFont = styleData.font;}  
    20.     if(!styleData.size){s.msgSize = "15";}else{s.msgSize = styleData.size;}  
    21. }  

    值得注意的是,參数是一个JSON对象。格式例如以下:

    [javascript] view plaincopy
     
    1. /*给msg和name设置样式时传的參数*/  
    2. {x:x坐标,y:y坐标,color:文字颜色,size:文字尺寸}  
    3. /*给face设置样式时传的參数*/  
    4. {x:x坐标,y:y坐标}  

    OK,给对话设定样式就搞定了。

    再加一个手动清空对话的方法,这样一来能够方便用户手动清空对话:

    [javascript] view plaincopy
     
    1. LTalk.prototype.clear = function(){  
    2.     var s = this;  
    3.     s.removeAllChild();  
    4.     s.die();  
    5. }  

    最后加一个重设对话数据的函数:

    [javascript] view plaincopy
     
    1. LTalk.prototype.setData = function(content){  
    2.     var s = this;  
    3.     s.content = content;  
    4. }  

    5,Debug输出

    前面在设计类时,没考虑到大家debug,所以都没添加什么debug输出。这次想到了,就顺便做一下,顺便把曾经的也做了一下。今天就仅仅呈现LTalk中的Debug输出,代码例如以下:

    [javascript] view plaincopy
     
    1. LTalk.prototype.showData = function(){  
    2.     var s = this;  
    3.     for(var key in s.content){  
    4.         trace("----------No."+key+"----------");  
    5.         trace("Name: " + s.content[key].name);  
    6.         trace("Msg: " + s.content[key].msg);  
    7.         trace("Face: " + s.content[key].face);  
    8.     }  
    9. }  

    调用此方法输出例如以下:

    6,源码

    源码不多,大家能够拿下去測试一下:

    [javascript] view plaincopy
     
    1. /** 
    2. *LTalk.js 
    3. */  
    4. function LTalk(content){  
    5.     var s = this;  
    6.     base(s,LSprite,[]);  
    7.     if(!content){  
    8.         s.content = [];  
    9.     }else{  
    10.         s.content = content;  
    11.     }  
    12.     s.x = 0;  
    13.     s.y = 0;  
    14.     s.textWidth = LStage.width;  
    15.     s.talkIndex = 0;  
    16.     s.faceX = 0;  
    17.     s.faceY = 0;  
    18.     s.nameX = 0;  
    19.     s.nameY = 0;  
    20.     s.nameColor = "black";  
    21.     s.nameFont = "宋体";  
    22.     s.nameSize = "15";  
    23.     s.msgX = 0;  
    24.     s.msgY = 0;  
    25.     s.msgColor = "black";  
    26.     s.msgFont = "宋体";  
    27.     s.msgSize = "15";  
    28. }  
    29. LTalk.prototype.setData = function(content){  
    30.     var s = this;  
    31.     s.content = content;  
    32. }  
    33. LTalk.prototype.showData = function(){  
    34.     var s = this;  
    35.     for(var key in s.content){  
    36.         trace("----------No."+key+"----------");  
    37.         trace("Name: " + s.content[key].name);  
    38.         trace("Msg: " + s.content[key].msg);  
    39.         trace("Face: " + s.content[key].face);  
    40.     }  
    41. }  
    42. LTalk.prototype.setFaceStyle = function(styleData){  
    43.     var s = this;  
    44.     if(!styleData.x){s.faceX = 0;}else{s.faceX = styleData.x;}  
    45.     if(!styleData.y){s.faceY = 0;}else{s.faceY = styleData.y;}  
    46. }  
    47. LTalk.prototype.setNameStyle = function(styleData){  
    48.     var s = this;  
    49.     if(!styleData.x){s.nameX = 0;}else{s.nameX = styleData.x;}  
    50.     if(!styleData.y){s.nameY = 0;}else{s.nameY = styleData.y;}  
    51.     if(!styleData.color){s.nameColor = "black";}else{s.nameColor = styleData.color;}  
    52.     if(!styleData.font){s.nameFont = "宋体";}else{s.nameFont = styleData.font;}  
    53.     if(!styleData.size){s.nameSize = "15";}else{s.nameSize = styleData.size;}  
    54. }  
    55. LTalk.prototype.setMsgStyle = function(styleData){  
    56.     var s = this;  
    57.     if(!styleData.x){s.msgX = 0;}else{s.msgX = styleData.x;}  
    58.     if(!styleData.y){s.msgY = 0;}else{s.msgY = styleData.y;}  
    59.     if(!styleData.color){s.msgColor = "black";}else{s.msgColor = styleData.color;}  
    60.     if(!styleData.font){s.msgFont = "宋体";}else{s.msgFont = styleData.font;}  
    61.     if(!styleData.size){s.msgSize = "15";}else{s.msgSize = styleData.size;}  
    62. }  
    63. LTalk.prototype.wind = function(num,completeFunc){  
    64.     var s = this;  
    65.     if(!num || num == null)num = 0;  
    66.     if(!completeFunc)completeFunc = null;  
    67.     s.talkIndex = num;  
    68.     s.removeAllChild();  
    69.     if(s.talkIndex < s.content.length){  
    70.         var talkObject = s.content[s.talkIndex];  
    71.         var faceBitmapdata = new LBitmapData(talkObject.face);  
    72.         var faceBitmap = new LBitmap(faceBitmapdata);  
    73.         faceBitmap.x = s.faceX;  
    74.         faceBitmap.y = s.faceY;  
    75.         s.addChild(faceBitmap);  
    76.         var name = new LTextField();  
    77.         name.x = s.nameX;  
    78.         name.y = s.nameY;  
    79.         name.size = s.nameSize;  
    80.         name.color = s.nameColor;  
    81.         name.font = s.nameFont;  
    82.         name.text = talkObject.name;  
    83.         name.width = s.textWidth;  
    84.         name.setWordWrap(true,name.getHeight()+5);  
    85.         s.addChild(name);  
    86.         var msg = new LTextField();  
    87.         msg.x = s.msgX;  
    88.         msg.y = s.msgY;  
    89.         msg.size = s.msgSize;  
    90.         msg.color = s.msgColor;  
    91.         msg.font = s.msgFont;  
    92.         msg.text = talkObject.msg;  
    93.         msg.width = s.textWidth;  
    94.         msg.setWordWrap(true,msg.getHeight()+7);  
    95.         msg.wind(completeFunc);  
    96.         s.addChild(msg);  
    97.     }else{  
    98.         trace("Error: Param exceeds the size of the content!");  
    99.     }  
    100. }  
    101. LTalk.prototype.clear = function(){  
    102.     var s = this;  
    103.     s.removeAllChild();  
    104.     s.die();  
    105. }  

    运用时,就仅仅用写这些代码:

    [javascript] view plaincopy
     
    1. var talkContent = [  
    2.     {name:"[Yorhom]",msg:"你好,lufy",face:imglist["yorhom_face"]},  
    3.     {name:"[lufy]",msg:"你好,yorhom",face:imglist["lufy_face"]},  
    4.     {name:"[Yorhom]",msg:"lufylegend最新版本号是哪个版本号啊?",face:imglist["yorhom_face"]},  
    5.     {name:"[lufy]",msg:"……你不知道自己看吗?",face:imglist["lufy_face"]},  
    6.     {name:"[Yorhom]",msg:"……说得也是",face:imglist["yorhom_face"]},  
    7. ];  
    8. var talk = new LTalk(talkContent);  
    9. addChild(talk);  
    10. talk.wind();  

    顺便提示一下,LTalk构造时所传的对话内容參数是一个数组套JSON的格式,它要在游戏图片载入完成后再初始化,否则显示不出对话头像。

    最后把測试链接给大家:

    http://www.cnblogs.com/yorhom/articles/3132075.html

    进入后点击黑框開始对话。祝大家測试愉快~


    近天就先讲到这里,下次我们接着研究。

    谢谢大家阅读本文,支持就是最大的鼓舞。(^_^)

    ----------------------------------------------------------------

    欢迎大家转载我的文章。

    转载请注明:转自Yorhom's Game Box

    http://blog.csdn.net/yorhomwang

  • 相关阅读:
    通过JavaScript垃圾回收机制来理解WeakSet/WeakMap中对象的弱引用
    json处理
    dotenv 加载本地环境变量
    各种ast库
    类型检测库
    npm 加解密库
    用计算机语言的爱情表白
    情侣在招聘会上搂抱招致企业反感
    《软件性能测试与LoadRunner实战》网上订购问题
    F1赛车的起源
  • 原文地址:https://www.cnblogs.com/mfryf/p/3138684.html
Copyright © 2011-2022 走看看