您好,欢迎访问一九零五行业门户网

MSAgent 详细解说第1/5页_javascript技巧

引子:
本来两年前就打算写了,结果拖了这么长时间,近日看到有朋友问及相关的东西,终于决定在还没有完全遗忘之前把自己残存的记忆表达出来,纸、笔...写!
不要说你完全了解 msagent,可能你对它的认识也不过是知道而已~~~~~~~~
开篇:
可能 msagent 这个名字你不清楚,但如果提起 office 助手我想在这个目前 microsoft 独霸天下的电脑世界应该鲜有人不知道,本文就是交给你如何在网页中调用这个在线尤物。
入题:
一、抛砖引玉
首先,我们先来看一下一个最简单的效果:
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid = "merlin"; var agentacs = "merlin.acs"; msagent.connected = true; msagent.characters.load(agentid,agentacs); agent = msagent.characters.character(agentid); agent.show(); </script>
看到没有,如果顺利的话,你的屏幕上会出现一个很 q 的卡通魔法师。对,这就是传说中的 msagent !下面讲解一下各个部分的作用:
agentid 内部索引字串,由用户定义;
agentacs 所调用的角色文件,可以为浏览者本地或远程文件,后面会有单独的部分说明。
msagent.connected 建立连接;
msagent.characters.load 读取角色;
msagent.characters.character 返回角色对象;
agent.show 显示角色;
好了,我现在已经把 msagent 带到你面前了。什么?什么东西都没看到?只有浏览器的报错!没关系,在后面的文章里,我也会告诉你如何才能看到他,当然,这个看到指的是所有浏览你网页的人!
二、伶牙俐齿
下面,我们就让他来做一点实际的东西 —— 说话!还是接续上例:
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid = "merlin"; var agentacs = "merlin.acs"; msagent.connected = true; msagent.characters.load(agentid,agentacs); agent = msagent.characters.character(agentid); agent.languageid = 0x0409; agent.show(); agent.speak("hello everybody, i am merlin!"); agent.think("what shall i do the next?"); </script>
merlin 说话了(如果要读出声音来的话,需要客户端在 microsoft 的网站上下载并安装相应的语音引擎)!这里涉及到这么几个新的东西:
agent.languageid 声明语言种类,0x0409是英文的编号(有关语言编号请参考 www.microsoft.com/globaldev/reference/oslocversion.mspx ),目前如果没有这个声明,或声明为错误的语种,则语言只是一次性完全显示agent.speak() 和 agent.think() 是 msagent 的两个语言表达显示行为,只有显示图形的区别。
了解了这些功能,是不是正在陶醉呀?别急,还有更好的东西呢!
三、活灵活现
总是看着一个呆头呆脑的东西一动不动,即使是很 q ,也会有感到多少的厌烦,下面我们就让他动起来。
这个例子由于调用的是网络文件,所以会慢一点,请耐心等待一下!
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid = "merlin"; var agentacs = "http://agent.microsoft.com/agent2/chars/merlin/merlin.acf"; var agentstates = "showing, hiding, speaking, moving"; var agentanimations = "getattention, getattentionreturn, congratulate, acknowledge, read, writecontinued, writereturn, wave"; var agentloadrequest, agentstaterequest, agentanimationrequest; msagent.connected = true; agentloadrequest = msagent.characters.load(agentid,agentacs); agent = msagent.characters.character(agentid); agent.languageid = 0x0409; agentstaterequest = agent.get("state", agentstates); agentanimationrequest = agent.get("animation", agentanimations); agent.show(); agent.moveto(400,300); agent.play("getattention"); agent.play("getattentionreturn"); agent.speak("hi, may i have your attention, please?"); agent.play("congratulate"); agent.speak("so nice to meet you!"); agent.play("think"); agent.speak("how do think about me?"); agent.play("acknowledge"); agent.speak("it's very cool, ya?"); agent.play("read"); agent.play("writecontinued"); agent.play("writereturn"); agent.speak("oh, i have lots of things to do, see you !"); agent.play("wave"); agent.speak("bye-bye!"); agent.hide(); </script>
看到没有?其实只要你善于调动它的积极性,msagent 也蛮活泼的!信息观察,不难发现,原来让 msagent 动起来,也不过就这么简单:
agent.moveto(x, y) 是角色移动到指定的坐标;
agent.play(action) 命令角色做某个动作,动作列表见: msdn.microsoft.com/library/default.asp?url=/library/en-us/msagent/deschar_3pgy.asp (这里需要说明一下,不是所有的角色都支持这些动作的,处理方法后面会有说明!)
agent.hide() 隐藏角色(不是释放角色,通过 agent.show() 可以再次显示)
agent.get(request, list) 预载相关 msagent 动画数据,msagent人物数据文件支持单结构角色文件(.acs,角色数据与动画数据存于同一个文件),也支持分离结构角色文件(.acf,角色数据存于.acf中,动画数据存于.aca中)。基于本地硬盘和网络调用均可采用这两种模式,当调用网络 acf 文件时,由于角色数据与动画数据分别下载,所以需要预载相关动画数据,使用 acs 文件(一般没有本地 acf 文件的可能性),不需要预载。
agentloadrequest, agentloadrequest 和 agentanimationrequest 这三个参数本例并没有实际用到,返回应相关操作的状态对象(相当于 readystatus 属性),在调用网络 acf 文件时有比较实际的用途,这个会在后面说明!
四、改头换面
msagent = merlin ? 错!msagent 是指一系列动画人物的总称,最常见的 office 中的那些活宝,各位应该都熟悉吧?先来看看下面的这个例子:
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid, agentacs; var agentload = false; function loadagent(newagent) { if(agentload) { msagent.characters.unload(agentid); msagent.connected = false; agent = null; } agentid = newagent; agentacs = "http://agent.microsoft.com/agent2/chars/" + newagent + "/" + newagent + ".acf"; msagent.connected = true; msagent.characters.load(agentid, agentacs); agentload = true; agent = msagent.characters.character(agentid); agent.get("state", "showing, hiding"); agent.moveto(400, 300); agent.show(); return; } loadagent("merlin"); </script> msagent select : <select name="agent_select" onchange="loadagent(this[this.selectedindex].text)"> <option>merlin</option> <option>peedy</option> <option>genie</option> <option>robby</option> </select>
看到没有? 原来 msagent 还有这么多可爱的造型呢!上面的例程中,我定义了一个读取角色的函数 loadagent ,通过这个函数更换角色,其中的大部分的功能在前面的章节中已经介绍了,这里仅仅说明一下,新的方法:
msagent.characters.unload() 卸载角色,其中 agentid ,必须是 msagent.characters.load() 中声明过的
agent.moveto() 这个方法上一节中介绍过,但是如果把它放在 agent.show() ,则相当于定义角色的出现位置
其实,msagent 绝对不仅仅是那么多,但是 microsoft 的官方网站上只提供了那么多……怎么办?可以从他的网站上连接角色,当然可可以从你的网站上呀!你可以在这里 www.microsoft.com/msagent/downloads/user.asp 下载官方角色以及语音引擎(可惜没有中文);当然,如果你有兴趣的话也可以开发一个属于自己的 agent ,相关开发工具 www.microsoft.com/msagent/downloads/developer.asp ,网上也有很多高手做好的动画人物,推荐一个网站 www.msagentring.org/chars.htm 你也可以自己搜索一下。
安装后角色文件存放在 %windows%\msagent\chars 目录下的 *.acs 文件,上传到服务器上,直接引用到那个路径就可以了!(你也可以在你的硬盘里搜索一下 *.acs 会有不小的收获呦)这里要说明一下,请自行更改程序中标明网络路径的相关语句,且注意扩展名是 .acs !
如果要让本机支持相应的 msagent ,也就是说不用网络调用,只要把 *.acs 文件 copy 到 %windows%\msagent\chars 目录就可以了,但如果是 *.exe 的安装文件,则会自动把角色文件放置到相应的路径下。
五、排难解错
能否显示 msagent 的关键在于是否安装了 msagent 的核心组件
( microsoft agent core components - activex.microsoft.com/activex/controls/agent2/msagent.exe ),但是如何让这一被动行为变为主动呢?可以用下面两种方法:
方法一:
运行代码框
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f" codebase="http://activex.microsoft.com/activex/controls/agent2/msagent.exe#version=2,0,0,0"></object>
特点:自动下载组件并安装,比较方便,但会下载的等待时间不会提示,在网速慢的时候会以为页免死掉,且不是很方便控制。
方法一:
<script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 function agent_load_error(){ alert("to make the msagent available, /nplease install microsoft agent core components first !"); window.open("http://activex.microsoft.com/activex/controls/agent2/msagent.exe"); return; } </script> <object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f" onerror="agent_load_error()"></object>
特点:方便出错控制,用户控制下载,但是不能当时显示,需要安装后再次刷新页面。
使用哪种方法就属于见仁见智了,但是最不明智的方法就是两种方法一起上,实践证明 codebase 会先于 onerror 生效!
不管怎么说,调用本地角色也比网络角色速度上要快得多,但是你如何预知客户端是否安装了该角色呢?看看下面的例子:
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid, agentacs; var agentload = false; function loadagent(newagent) { var remote = false; if(agentload) { msagent.characters.unload(agentid); msagent.connected = false; agent = null; } agentid = newagent; agentacs = newagent + ".acs"; msagent.connected = true; try { msagent.characters.load(agentid, agentacs); agent_exist.innertext = "local msagent load successfully!"; } catch(e) { agentacs = "http://agent.microsoft.com/agent2/chars/" + newagent + "/" + newagent + ".acf"; remote = true; msagent.characters.load(agentid, agentacs); agent_exist.innertext = "local msagent load unsuccessfully, as a advice, you'd better to download the charactor file to your hard disk!"; } agentload = true; agent = msagent.characters.character(agentid); if(remote) agent.get("state", "showing, hiding"); agent.moveto(400, 300); agent.show(); return; } window.onload = function(){loadagent("merlin");}; </script> msagent select : <select name="agent_select" onchange="loadagent(this[this.selectedindex].text)"> <option>merlin</option> <option>peedy</option> <option>genie</option> <option>robby</option> </select> load status: <span id="agent_exist"></span>
通过设置错误捕获,可以方便的找到调用 msagent 的最佳方式,当然,你还可以通过 dhtml 加上相应的角色下载链接,并指导用户将 *.acs 文件 copy 到相应目录(%windows%\msagent\chars)或直接安装 *.exe 的角色安装文件以方便下次浏览,我仅仅是为你提供一个思路,具体实践还是自己发挥吧!
六、事件响应
像所有 oop 一样,msagent 也设置有相应的事件响应,看看下面的例子,试试在角色或任务栏的图标上点击鼠标(单/双击),你也可以移动一下角色,看看它有什么反应:
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript" for="msagent" event="click(characterid, button, shift, x, y)"> //coded by windy_sk <windy_sk@126.com> 20040214 if(button==1 && agent.visible) { if(remote) { agent.get("state", "speaking"); agent.get("animation", "acknowledge, pleased"); } agent.play("acknowledge"); agent.speak("yes sir! " + characterid + " is right here!"); agent.play("pleased") agent.speak("what can i do for you?"); } else if(button==4097) { agent.visible?agent.hide():agent.show(); } </script> <script language="javascript" for="msagent" event="dblclick(characterid, button, shift, x, y)"> //coded by windy_sk <windy_sk@126.com> 20040214 if(button==1 || button==4097) { agent.stopall(); if (!agent.hasotherclients) { msagent.characters.unload(agentid); msagent.connected = false; agent = null; agentload = false; } } </script> <script language="javascript" for="msagent" event="move(characterid, x, y, cause)"> //coded by windy_sk <windy_sk@126.com> 20040214 if(cause == 1) { if(remote) { agent.get("state", "moving, speaking"); agent.get("animation", "confused, restpose"); } agent.moveto(400, 300); agent.play("confused"); agent.speak("don't move me ok?"); agent.play("restpose"); } </script> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid, agentacs; var agentload = false; var remote = false; function loadagent(newagent) { if(agentload) { msagent.characters.unload(agentid); msagent.connected = false; agent = null; } agentid = newagent; agentacs = newagent + ".acs"; msagent.connected = true; try { msagent.characters.load(agentid, agentacs); } catch(e) { agentacs = "http://agent.microsoft.com/agent2/chars/" + newagent + "/" + newagent + ".acf"; remote = true; msagent.characters.load(agentid, agentacs); if(confirm("cannot find the msagent charactor file on your hard disk! \nwould you like to download the msagent charactor file for the next show?")) window.open("http://www.msagentring.org/download.asp?char="+newagent.tolowercase(),"_blank","top=2000px"); } agentload = true; agent = msagent.characters.character(agentid); agent.languageid = 0x0409; if(remote) agent.get("state", "showing, hiding"); agent.moveto(400, 300); agent.show(); return; } loadagent("merlin"); </script> msagent select : <select name="agent_select" onchange="loadagent(this[this.selectedindex].text)"> <option>merlin</option> <option>peedy</option> <option>genie</option> <option>robby</option> </select>
是不是感觉交互性强了许多?我们来看一下事件处理的声明方法:
<script language="javascript" for="msagent_object" event="event_name()">
//code...
</script>
熟悉一点 js 编程的应该不会陌生这种声明方式,也就是对某一对象某一事件的单独处理的声明方法,但是如果是该成 msagent_object.event_name = function() {//code...} 的事件处理声明是不可以的!(the only way to do this)
如果是采用网络调用的话,如果向用户通知相应的调用进度呢?
<object style="visibility:hidden" id="msagent" classid="clsid:d45fd31b-5c6e-11d1-9ec1-00c04fd7081f"></object> <script language="javascript" for="msagent" event="requeststart(requestobject)"> //coded by windy_sk <windy_sk@126.com> 20040214 switch (requestobject) { case agentloadrequest : window.status = "loading msagent file from internet for " + agentid + " ..."; break; case agentstaterequest : window.status = "loading msagent state from internet for " + agentid + " ..."; break; case agentanimationrequest : window.status = "loading msagent animation from internet for " + agentid + " ..."; break; default: break; } </script> <script language="javascript" for="msagent" event="requestcomplete(requestobject)"> //coded by windy_sk <windy_sk@126.com> 20040214 switch (requestobject) { case agentloadrequest : if(requestobject.status == 0) { window.status = "msagent file for " + agentid + " has been loaded successfully !"; } else { window.status = "cannot load msagent file for " + agentid + " from " + agentacs + " !"; } break; case agentstaterequest : if(requestobject.status == 0) { window.status = "msagent state for " + agentid + " has been loaded successfully !"; } else { window.status = "cannot load msagent state for " + agentid + " from " + agentacs + " !"; } break; break; case agentanimationrequest : if(requestobject.status == 0) { window.status = "msagent animation for " + agentid + " has been loaded successfully !"; } else { window.status = "cannot load msagent animation for " + agentid + " from " + agentacs + " !"; } break; break; default: window.status = ""; break; } </script> <script language="javascript" for="msagent" event="dragstart(characterid, button, shift, x, y)"> //coded by windy_sk <windy_sk@126.com> 20040214 cur_x = x - agent.width/2; cur_y = y - agent.height/2; </script> <script language="javascript" for="msagent" event="dragcomplete(characterid, button, shift, x, y)"> //coded by windy_sk <windy_sk@126.com> 20040214 if(remote) { agentstaterequest = agent.get("state", "moving, speaking"); agentanimationrequest = agent.get("animation", "confused, restpose"); } agent.moveto(cur_x, cur_y); agent.play("confused"); agent.speak("don't move me ok?"); agent.play("restpose"); </script> <script language="javascript"> //coded by windy_sk <windy_sk@126.com> 20040214 var agent = null; var agentid, agentacs; var agentload = false; var remote = false; var cur_x, cur_y; var agentloadrequest, agentstaterequest, agentanimationrequest; function loadagent(newagent) { if(agentload) { msagent.characters.unload(agentid); msagent.connected = false; agent = null; } agentid = newagent; agentacs = newagent + ".acs"; msagent.connected = true; try { agentloadrequest = msagent.characters.load(agentid, agentacs); } catch(e) { agentacs = "http://agent.microsoft.com/agent2/chars/" + newagent + "/" + newagent + ".acf"; remote = true; agentloadrequest = msagent.characters.load(agentid, agentacs); if(confirm("cannot find the msagent charactor file on your hard disk! \nwould you like to download the msagent charactor file for the next show?")) window.open("http://www.msagentring.org/download.asp?char="+newagent.tolowercase(),"_blank","top=2000px"); } agentload = true; agent = msagent.characters.character(agentid); agent.languageid = 0x0409; if(remote) { agentstaterequest = agent.get("state", "showing, thinking, hiding"); agentanimationrequest = agent.get("animation", "getattention, getattentioncontinued, getattentionreturn"); } agent.moveto(400, 300); agent.show(); agent.play("getattention"); agent.play("getattentioncontinued"); agent.play("getattentionreturn"); agent.speak("hi, i am " + newagent + "!"); agent.think("oh so bad, i just wanna take a nap..."); return; } loadagent("merlin"); </script> msagent select : <select name="agent_select" onchange="loadagent(this[this.selectedindex].text)"> <option>merlin</option> <option>peedy</option> <option>genie</option> <option>robby</option> </select>
注意到窗口底部状态栏的显示了吗?虽然无法获取具体的下载进度,但是至少也可以让浏览者知道角色的动作为什么会有停顿(这个停顿只在某动画第一次调用的时候出现,调用后该动画会被缓存)。
其它类似信息

推荐信息