如何制作一款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,实现后的代码

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

<!DOCTYPE html>
<html lang="en">
    <head>
    <meta charset="utf-8" />
    <title>LTalk</title>
    <script type="text/javascript" src="../lufylegend-1.7.6.min.js"></script>
    <script type="text/javascript" src="../lufylegendrpg-1.0.0.js"></script>
    <script>
    init(30,"legend",480,320,main);
    LRPGStage.setShortcuts(true);
    LGlobal.setDebug(true);
    var backLayer,loadingLayer,talkLayer;
    var talk;
    var talkContent;
    var talkNum = 0;
    var loadData = [
        {name:"yorhom_face",path:"./yorhom.jpg"},
        {name:"lufy_face",path:"./lufy.jpg"}
    ];
    var imglist = [];
    function main(){
        //加入进度条
        loadingLayer = new LoadingSample1();
        addChild(loadingLayer);
        //加载图片并显示进度
        LLoadManage.load(
            loadData,
            function(progress){
                loadingLayer.setProgress(progress);
            },
            gameInit
        );
    }
    function gameInit(result){
        removeChild(loadingLayer);
        imglist = result;
        //初始化层
        backLayer = new LSprite();
        addChild(backLayer);
        talkLayer = new LSprite();
        backLayer.addChild(talkLayer);
        //加入操作按钮
        addEvent();
        //添加对话内容
        talkContent = [
            {name:"[Yorhom]",msg:"你好,lufy",face:imglist["yorhom_face"]},
            {name:"[lufy]",msg:"你好,yorhom",face:imglist["lufy_face"]},
            {name:"[Yorhom]",msg:"lufylegend最新版本是哪个版本啊?",face:imglist["yorhom_face"]},
            {name:"[lufy]",msg:"……你不知道自己看吗?",face:imglist["lufy_face"]},
            {name:"[Yorhom]",msg:"……说得也是",face:imglist["yorhom_face"]},
        ];
        //加入对话
        talkLayer.graphics.drawRect(5,"black",[20,15,400,130],true,"black");
        talkLayer.alpha = 0.8;
        talk = new LTalk(talkContent);
        talkLayer.addChild(talk);
        talkLayer.addEventListener(LMouseEvent.MOUSE_DOWN,say);
        //设置样式
        talk.setNameStyle({x:160,y:40,color:"white",size:12});
        talk.setMsgStyle({x:160,y:70,color:"white",size:10});
        talk.setFaceStyle({x:30,y:30});
        talk.textWidth = 260;
    }
    function addEvent(){
        LEvent.addEventListener(LGlobal.window,LKeyboardEvent.KEY_UP,say);
    }
    function say(){
        if(talkNum < talkContent.length){
            //输出对话
            talk.wind(talkNum,function(){talkNum++;});
        }
    }
    </script>
    </head>
    <body>
            <div id="legend"></div>
    </body>
</html>

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

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

但是如何实现呢?请看接下来的讲解。

2,LTalk类

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

function LTalk(content){
    var s = this;
    base(s,LSprite,[]);
    if(!content){
        s.content = [];
    }else{
        s.content = content;
    }
    s.x = 0;
    s.y = 0;
    s.textWidth = LStage.width;
    s.talkIndex = 0;
    s.faceX = 0;
    s.faceY = 0;
    s.nameX = 0;
    s.nameY = 0;
    s.nameColor = "black";
    s.nameFont = "宋体";
    s.nameSize = "15";
    s.msgX = 0;
    s.msgY = 0;
    s.msgColor = "black";
    s.msgFont = "宋体";
    s.msgSize = "15";
}

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

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

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

[
    {name:"名称",msg:"内容",face:头像图片},
    {name:"名称",msg:"内容",face:头像图片},
    {name:"名称",msg:"内容",face:头像图片},
    {name:"名称",msg:"内容",face:头像图片},
    {name:"名称",msg:"内容",face:头像图片},
];

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

3,wind方法

接下来看看wind方法:

LTalk.prototype.wind = function(num,completeFunc){
    var s = this;
    if(!num || num == null)num = 0;
    if(!completeFunc)completeFunc = null;
    s.talkIndex = num;
    s.removeAllChild();
    if(s.talkIndex < s.content.length){
        var talkObject = s.content[s.talkIndex];
        var faceBitmapdata = new LBitmapData(talkObject.face);
        var faceBitmap = new LBitmap(faceBitmapdata);
        faceBitmap.x = s.faceX;
        faceBitmap.y = s.faceY;
        s.addChild(faceBitmap);
        var name = new LTextField();
        name.x = s.nameX;
        name.y = s.nameY;
        name.size = s.nameSize;
        name.color = s.nameColor;
        name.font = s.nameFont;
        name.text = talkObject.name;
        name.width = s.textWidth;
        name.setWordWrap(true,name.getHeight()+5);
        s.addChild(name);
        var msg = new LTextField();
        msg.x = s.msgX;
        msg.y = s.msgY;
        msg.size = s.msgSize;
        msg.color = s.msgColor;
        msg.font = s.msgFont;
        msg.text = talkObject.msg;
        msg.width = s.textWidth;
        msg.setWordWrap(true,msg.getHeight()+7);
        msg.wind(completeFunc);
        s.addChild(msg);
    }else{
        trace("Error: Param exceeds the size of the content!");
    }
}

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

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

var talkObject = s.content[s.talkIndex];
var faceBitmapdata = new LBitmapData(talkObject.face);
var faceBitmap = new LBitmap(faceBitmapdata);
faceBitmap.x = s.faceX;
faceBitmap.y = s.faceY;
s.addChild(faceBitmap);
var name = new LTextField();
name.x = s.nameX;
name.y = s.nameY;
name.size = s.nameSize;
name.color = s.nameColor;
name.font = s.nameFont;
name.text = talkObject.name;
name.width = s.textWidth;
name.setWordWrap(true,name.getHeight()+5);
s.addChild(name);
var msg = new LTextField();
msg.x = s.msgX;
msg.y = s.msgY;
msg.size = s.msgSize;
msg.color = s.msgColor;
msg.font = s.msgFont;
msg.text = talkObject.msg;
msg.width = s.textWidth;
msg.setWordWrap(true,msg.getHeight()+7);
msg.wind(completeFunc);
s.addChild(msg);

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

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

刚才我们看了控制文字,图片样式的几个属性,有很多,如果一个一个用手改就会很麻烦,而且要写很多行代码,因此我们加几个控制样式的方法,它们分别是:setFaceStyle,setNameStyle,setMsgStyle。运用时只用传入参数就行了。

实现方法如下:

LTalk.prototype.setFaceStyle = function(styleData){
    var s = this;
    if(!styleData.x){s.faceX = 0;}else{s.faceX = styleData.x;}
    if(!styleData.y){s.faceY = 0;}else{s.faceY = styleData.y;}
}
LTalk.prototype.setNameStyle = function(styleData){
    var s = this;
    if(!styleData.x){s.nameX = 0;}else{s.nameX = styleData.x;}
    if(!styleData.y){s.nameY = 0;}else{s.nameY = styleData.y;}
    if(!styleData.color){s.nameColor = "black";}else{s.nameColor = styleData.color;}
    if(!styleData.font){s.nameFont = "宋体";}else{s.nameFont = styleData.font;}
    if(!styleData.size){s.nameSize = "15";}else{s.nameSize = styleData.size;}
}
LTalk.prototype.setMsgStyle = function(styleData){
    var s = this;
    if(!styleData.x){s.msgX = 0;}else{s.msgX = styleData.x;}
    if(!styleData.y){s.msgY = 0;}else{s.msgY = styleData.y;}
    if(!styleData.color){s.msgColor = "black";}else{s.msgColor = styleData.color;}
    if(!styleData.font){s.msgFont = "宋体";}else{s.msgFont = styleData.font;}
    if(!styleData.size){s.msgSize = "15";}else{s.msgSize = styleData.size;}
}

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

/*给msg和name设置样式时传的参数*/
{x:x坐标,y:y坐标,color:文字颜色,size:文字尺寸}
/*给face设置样式时传的参数*/
{x:x坐标,y:y坐标}

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

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

LTalk.prototype.clear = function(){
    var s = this;
    s.removeAllChild();
    s.die();
}

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

LTalk.prototype.setData = function(content){
    var s = this;
    s.content = content;
}

5,Debug输出

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

LTalk.prototype.showData = function(){
    var s = this;
    for(var key in s.content){
        trace("----------No."+key+"----------");
        trace("Name: " + s.content[key].name);
        trace("Msg: " + s.content[key].msg);
        trace("Face: " + s.content[key].face);
    }
}

调用此方法输出如下:

6,源代码

源代码不多,大家可以拿下去测试一下:

/**
*LTalk.js
*/
function LTalk(content){
    var s = this;
    base(s,LSprite,[]);
    if(!content){
        s.content = [];
    }else{
        s.content = content;
    }
    s.x = 0;
    s.y = 0;
    s.textWidth = LStage.width;
    s.talkIndex = 0;
    s.faceX = 0;
    s.faceY = 0;
    s.nameX = 0;
    s.nameY = 0;
    s.nameColor = "black";
    s.nameFont = "宋体";
    s.nameSize = "15";
    s.msgX = 0;
    s.msgY = 0;
    s.msgColor = "black";
    s.msgFont = "宋体";
    s.msgSize = "15";
}
LTalk.prototype.setData = function(content){
    var s = this;
    s.content = content;
}
LTalk.prototype.showData = function(){
    var s = this;
    for(var key in s.content){
        trace("----------No."+key+"----------");
        trace("Name: " + s.content[key].name);
        trace("Msg: " + s.content[key].msg);
        trace("Face: " + s.content[key].face);
    }
}
LTalk.prototype.setFaceStyle = function(styleData){
    var s = this;
    if(!styleData.x){s.faceX = 0;}else{s.faceX = styleData.x;}
    if(!styleData.y){s.faceY = 0;}else{s.faceY = styleData.y;}
}
LTalk.prototype.setNameStyle = function(styleData){
    var s = this;
    if(!styleData.x){s.nameX = 0;}else{s.nameX = styleData.x;}
    if(!styleData.y){s.nameY = 0;}else{s.nameY = styleData.y;}
    if(!styleData.color){s.nameColor = "black";}else{s.nameColor = styleData.color;}
    if(!styleData.font){s.nameFont = "宋体";}else{s.nameFont = styleData.font;}
    if(!styleData.size){s.nameSize = "15";}else{s.nameSize = styleData.size;}
}
LTalk.prototype.setMsgStyle = function(styleData){
    var s = this;
    if(!styleData.x){s.msgX = 0;}else{s.msgX = styleData.x;}
    if(!styleData.y){s.msgY = 0;}else{s.msgY = styleData.y;}
    if(!styleData.color){s.msgColor = "black";}else{s.msgColor = styleData.color;}
    if(!styleData.font){s.msgFont = "宋体";}else{s.msgFont = styleData.font;}
    if(!styleData.size){s.msgSize = "15";}else{s.msgSize = styleData.size;}
}
LTalk.prototype.wind = function(num,completeFunc){
    var s = this;
    if(!num || num == null)num = 0;
    if(!completeFunc)completeFunc = null;
    s.talkIndex = num;
    s.removeAllChild();
    if(s.talkIndex < s.content.length){
        var talkObject = s.content[s.talkIndex];
        var faceBitmapdata = new LBitmapData(talkObject.face);
        var faceBitmap = new LBitmap(faceBitmapdata);
        faceBitmap.x = s.faceX;
        faceBitmap.y = s.faceY;
        s.addChild(faceBitmap);
        var name = new LTextField();
        name.x = s.nameX;
        name.y = s.nameY;
        name.size = s.nameSize;
        name.color = s.nameColor;
        name.font = s.nameFont;
        name.text = talkObject.name;
        name.width = s.textWidth;
        name.setWordWrap(true,name.getHeight()+5);
        s.addChild(name);
        var msg = new LTextField();
        msg.x = s.msgX;
        msg.y = s.msgY;
        msg.size = s.msgSize;
        msg.color = s.msgColor;
        msg.font = s.msgFont;
        msg.text = talkObject.msg;
        msg.width = s.textWidth;
        msg.setWordWrap(true,msg.getHeight()+7);
        msg.wind(completeFunc);
        s.addChild(msg);
    }else{
        trace("Error: Param exceeds the size of the content!");
    }
}
LTalk.prototype.clear = function(){
    var s = this;
    s.removeAllChild();
    s.die();
}

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

var talkContent = [
    {name:"[Yorhom]",msg:"你好,lufy",face:imglist["yorhom_face"]},
    {name:"[lufy]",msg:"你好,yorhom",face:imglist["lufy_face"]},
    {name:"[Yorhom]",msg:"lufylegend最新版本是哪个版本啊?",face:imglist["yorhom_face"]},
    {name:"[lufy]",msg:"……你不知道自己看吗?",face:imglist["lufy_face"]},
    {name:"[Yorhom]",msg:"……说得也是",face:imglist["yorhom_face"]},
];
var talk = new LTalk(talkContent);
addChild(talk);
talk.wind();

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

最后把测试链接给大家:

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

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

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

时间: 2024-10-05 21:15:46

如何制作一款HTML5 RPG游戏引擎——第四篇,情景对话的相关文章

如何制作一款HTML5 RPG游戏引擎——第五篇,人物&amp;人物特效

上一次,我们实现了对话类,今天就来做一个游戏中必不可少的--人物类. 当然,你完全是可以自己写一个人物类,但是为了方便起见,还是决定把人物类封装到这个引擎里. 为了使这个类更有意义,我还给人物类加了几个特效,在以下讲解中会提到. 以下是本系列文章的目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/8892305 如何制作一款HTML5 RPG游戏引擎--第二篇,烟雨+飞雪效果 h

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

开言: 在RPG游戏中,如果有地图切换的地方,通常就会使用幕布效果.所谓的幕布其实就是将两个矩形合拢,直到把屏幕遮住,然后再展开直到两个矩形全部移出屏幕. 为了大家做游戏方便,于是我给这个引擎加了这么一个类. 本系列文章目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/8892305 如何制作一款HTML5 RPG游戏引擎--第二篇,烟雨+飞雪效果 http://blog.csd

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

一,话说天下大事 前不久看到lufy的博客上,有一位朋友想要一个RPG游戏引擎,出于兴趣准备动手做一做.由于我研究lufylegend有一段时间了,对它有一定的依赖性,因此就准备将这个引擎基于lufylegend.暂时命名为lufylegendRPG.毕竟基于lufylegend,如果名称中不加上lufylegend这几个字的话,有点说不通啊...最近发布了0.1.0版,但是不理想,连一惯都是鼓励和赞赏我的lufy老先生都是出于真心的表示不满意.想了解0.1.0版的朋友可以看看这里(其实最好别看

25 个超棒的 HTML5 &amp; JavaScript 游戏引擎开发库

25 个超棒的 HTML5 & JavaScript 游戏引擎开发库 就像在汽车中,引擎完成主要的工作,使汽车看起来不可思议.游戏引擎同理,游戏开发者完成细节的工作,使游戏看起来真实.吸引人眼球.游戏引擎负责其余的事情.早期,游戏开发者通常从草图做起,花费高昂,且不容易获利.为了让游戏开发更加简单容易,主要的开发者开始授权他们的基本游戏引擎,如 Unreal.而且,随着手机和平板游戏的出现,所需预算比以前更少,对 JAVASCRIPT 和HTML5 游戏引擎的需求大增. 如果你是一个游戏开发者,

Android 八款开源 Android 游戏引擎

原文地址 本文内容 Angle Rokon LGame AndEngine libgdx jPCT Alien3d Catcake 最近无意间看到一篇关于 Android 搜索引擎的文章,于是搜索了,学不学是其次,主要是要有这方面的知识--技多不压身嘛~ 下面罗列出八款常见的 Android 游戏引擎,以供参考.收费.下载量过小.不公开源码,以及鄙人不知道(-_-)的引擎不在此列. Angle Angle 是一款专为 Android 平台设计的,适合快速开发的 2D 游戏引擎,基于 OpenGL

[Android游戏开发]八款开源 Android 游戏引擎 (巨好的资源)

初学Android游戏开发的朋友,往往会显得有些无所适从,他们常常不知道该从何处入手,每当遇到自己无法解决的难题时,又往往会一边羡慕于 iPhone下有诸如Cocos2d-iphone之类的免费游戏引擎可供使用,一边自暴自弃的抱怨Android平台游戏开发难度太高,又连个像样的游 戏引擎也没有,甚至误以为使用Java语言开发游戏是一件费力不讨好且没有出路的事情. 事实上,这种想法完全是没有必要且不符合实际的,作为能和苹果iOS分庭抗礼的Android(各种意义上),当然也会有相当数量的游戏引擎存

HTML5开源RPG游戏引擎lufylegendRPG 1.0.0发布

经历了几个月的改进,终于发布1.0.0版了.虽然引擎依然存在漏洞,但是比起上次更新还是要好多了.在这里不得不感谢各位网友的大力支持. 首先为引擎做一个开场白吧,也好让大家了解一下它: lufylegendRPG是基于lufylegend的HTML5游戏引擎.使用它时,需要引入lufylegend.js. 包含了LTileMap,LCharacter,LTalk,LEffect等多个实用的类. 由于是基于lufylegend,所以你需要了解一下lufylegend的用法,这样才能更合理,更快捷地运

HTML5 JavaScript3D游戏引擎和框架

由于很多人都在用JavaScript.HTML5和WebGL技术创建基于浏览器的3D游戏,所有JavaScript 3D游戏引擎是一个人们主题.基于浏览器的游戏最棒的地方是平台独立,它们能在iOS.Android.Windows或其他任何平台上运行. 有很多的JavaScript能够用于创建基于浏览器.使用HTML5和WebGL的3D游戏.然后,选择一个合适的游戏引擎是一个不小的挑战,它有时能帮你完成项目或突破项目瓶颈. 为了让你的选择变的容易,我们已经通过分析大多数JavaScript 3D游

用egret制作一款跑酷类游戏(一)

游戏源地址:http://static.egret-labs.org/h5game/62/v20/index.html 本demo素材全是引用该地址的素材. 游戏使用egret引擎制作 关于egret  http://www.egret-labs.org/ 动画是基于starlingswf制作的,关于starlingswf http://xyliu.sinaapp.com/?p=1 一.滑动的背景. 创建一个GameMainView.ts文件,游戏的主场景是建立在该类下的. class Game