Introduction:
I originally planned to write it two years ago, but it took so long. Recently, I saw a friend asking about related things, and finally decided to express my remaining memories before I completely forget them. , paper, pen...write!
Don’t say that you fully understand MSAgent, maybe you just know it~~~~~~~~
Opening:
Maybe you don’t know the name MSAgent, but when it comes to Office Assistant, I think few people in this computer world where Microsoft currently dominates the world don’t know it. This article will give you how to call this online beauty on a web page.
Introduction to the topic:
1. To attract new ideas
First of all, let’s take a look at the simplest effect:
<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>
Do you see it? If it goes well, your screen will A very Q cartoon magician appears. Yes, this is the legendary MSAgent! The following explains the function of each part:
AgentID internal index string, defined by the user;
The role file called by AgentACS can be the browser's local or remote file, which will be explained in a separate section later.
MSAgent.Connected establishes a connection;
MSAgent.Characters.Load reads characters;
MSAgent.Characters.Character returns the character object;
Agent.Show shows the role;
Okay, I have brought MSAgent to you now. What? Didn't see anything? Only browser error! It doesn’t matter, in the following article, I will also tell you how to see him. Of course, this seeing refers to everyone who browses your webpage!
2. Speechless
Next, let’s let him do something practical – speak! Continuing with the above example:
<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 spoke (if you want to read the voice, the client needs to download and install the corresponding speech engine on the Microsoft website)! Several new things are involved here:
Agent.LanguageID declares the language type. 0x0409 is the English number (for the language number, please refer to www.microsoft.com/globaldev/reference/oslocversion.mspx). Currently, if there is no such declaration, or the declaration is wrong Language, the language is only fully displayed at one time. Agent.Speak() and Agent.Think() are the two language expression display behaviors of MSAgent. The only difference is the display graphics.
Are you intoxicated after understanding these functions? Don’t worry, there’s something better out there!
3. Come to life
Always looking at a dull thing motionless, even if it is very Q, will make you feel a little bored. Now let’s make it move.
This example will be a little slower because it calls a network file, please be patient!
<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>
See? In fact, as long as you are good at mobilizing its enthusiasm, MSAgent is quite lively! Information observation, it is not difficult to find that it turns out that making MSAgent move is just that simple:
Agent.MoveTo(x, y) is to move the character to the specified coordinates;
Agent.Play(action) commands the character to do a certain action. For the list of actions, see: msdn.microsoft.com/library/default.asp?url=/library/en-us/msagent/deschar_3pgy.asp (need to explain here) Note, not all characters support these actions, the processing method will be explained later!)
Agent.Hide() hides the role (not releasing the role, it can be displayed again through Agent.Show())
Agent.get(Request, list) preloads related MSAgent animation data. MSAgent character data files support single-structure character files (.acs, character data and animation data are stored in the same file), and also support separated structure character files (.acs, character data and animation data are stored in the same file). .acf, character data is stored in .acf, and animation data is stored in .aca). These two modes can be used based on local hard disk and network calls. When calling network acf files, since the character data and animation data are downloaded separately, it is necessary to preload the relevant animation data and use acs files (generally there is no possibility of local acf files ), no preloading is required.
The three parameters of AgentLoadRequest, AgentLoadRequest and AgentAnimationRequest are not actually used in this example. They return the status object corresponding to the relevant operation (equivalent to the readystatus attribute), which has a more practical use when calling the network acf file. This Will explain later!
4. Makeover
MSAgent = Merlin ? Wrong! MSAgent refers to the general name of a series of animated characters, the most common ones in office. Everyone should be familiar with them, right? Let’s take a look at the following example:
<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>
是不是感觉交互性强了许多?我们来看一下事件处理的声明方法:
熟悉一点 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>
注意到窗口底部状态栏的显示了吗?虽然无法获取具体的下载进度,但是至少也可以让浏览者知道角色的动作为什么会有停顿(这个停顿只在某动画第一次调用的时候出现,调用后该动画会被缓存)。