서론:
원래는 2년 전에 쓰려고 했는데, 너무 오래 걸려서 최근에 친구가 관련 내용을 물어보는 걸 보고, 남은 추억이 완전히 잊혀지기 전에 마지막으로 글을 쓰기로 했어요. 종이, 펜...쓰기!
MSAgent를 완전히 이해했다고는 하지 마세요. 그냥 알고 계실 수도 있습니다~~~~~~~~
오프닝:
MSAgent라는 이름을 모르실 수도 있겠지만, Office Assistant에 관해서는 현재 Microsoft가 세계를 장악하고 있는 이 컴퓨터 세계에서 MSAgent를 어떻게 부르는지 모르는 사람은 거의 없을 것 같습니다. 웹 페이지의 온라인 아름다움.
주제 소개:
1. 새로운 아이디어를 끌어내기 위해
우선 가장 간단한 효과를 살펴보겠습니다:
<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를 가져왔습니다. 무엇? 아무것도 못 봤나요? 브라우저 오류만 발생합니다! 그것은 중요하지 않습니다. 다음 기사에서는 그를 보는 방법도 알려 드리겠습니다. 물론 이 보는 것은 귀하의 웹 페이지를 탐색하는 모든 사람을 의미합니다!
2. 말문이 막히다
다음에는 실용적인 일을 하게 하세요. 말을 하세요! 위의 예를 계속해서 설명합니다.
<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의 두 가지 언어 표현 표시 동작입니다. 유일한 차이점은 표시 그래픽입니다.
이 기능을 이해하고 나면 중독되시나요? 걱정하지 마세요. 더 좋은 것이 있습니다!
3. 살아나다
항상 둔한 것을 가만히 보고 있으면, 비록 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(요청, 목록)은 관련 MSAgent 애니메이션 데이터를 미리 로드합니다. MSAgent 캐릭터 데이터 파일은 단일 구조의 캐릭터 파일(.acs, 캐릭터 데이터 및 애니메이션 데이터가 동일한 파일에 저장됨)을 지원하며 분리된 구조의 캐릭터도 지원합니다. 파일(.acs, 캐릭터 데이터 및 애니메이션 데이터는 동일한 파일에 저장됩니다.) .acf, 캐릭터 데이터는 .acf에 저장되고 애니메이션 데이터는 .aca에 저장됩니다. 이 두 가지 모드는 로컬 하드디스크와 네트워크 호출을 기반으로 사용할 수 있으며, 네트워크 acf 파일 호출 시 캐릭터 데이터와 애니메이션 데이터가 별도로 다운로드되기 때문에 해당 애니메이션 데이터를 미리 로드하여 acs 파일을 사용해야 합니다(일반적으로 없음). 로컬 acf 파일 가능성), 사전 로드가 필요하지 않습니다.
이 예에서는 AgentLoadRequest, AgentLoadRequest 및 AgentAnimationRequest의 세 가지 매개변수가 실제로 사용되지 않습니다. 이는 관련 작업에 해당하는 상태 개체(readystatus 속성과 동일)를 반환하며, 이는 호출할 때 더 실용적으로 사용됩니다. network acf 파일에 대해서는 나중에 설명하겠습니다!
4. 변신
MSAgent = 멀린? 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, 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>
注意到窗口底部状态栏的显示了吗?虽然无法获取具体的下载进度,但是至少也可以让浏览者知道角色的动作为什么会有停顿(这个停顿只在某动画第一次调用的时候出现,调用后该动画会被缓存)。