虚拟世界/NPC
百科首页 - 3D虚拟世界 - 音乐与人工智能 - 人工智能机器人 - 知识百科 - 关于我们 - 网站首页
目录
- 1 服务器配置
- 2 相关API
- 2.1 osIsNpc
- 2.2 osNpcCreate
- 2.3 osGetNpcList
- 2.4 osNpcGetOwner
- 2.5 osNpcGetPos
- 2.6 osNpcGetRot
- 2.7 osNpcLoadAppearance
- 2.8 osNpcMoveTo
- 2.9 osNpcMoveToTarget
- 2.10 osNpcPlayAnimation
- 2.11 osNpcRemove
- 2.12 osNpcSaveAppearance
- 2.13 osNpcSay
- 2.14 osNpcSetProfileAbout
- 2.15 osNpcSetProfileImage
- 2.16 osNpcSetRot
- 2.17 osNpcShout
- 2.18 osNpcSit
- 2.19 osNpcStand
- 2.20 osNpcStopAnimation
- 2.21 osNpcStopMoveToTarget
- 2.22 osNpcTouch
- 2.23 osNpcWhisper
- 2.24 OsOwnerSaveAppearance
- 3 综合实例
- 4 专题探索与应用
脚本首页 | Vehicles | NPC | HTTP | 脚本间通信 | 翻译参考
开源社区提供了一组 OSSL NPC 函数,用于创建和操作机器人(NPC、BOT)。
这种方法的一个优点是,机器人不需要外部客户端,并且机器人的外观可以保存在岛屿备份中。一个缺点是可用的功能集非常有限,因为需要编写脚本方法来控制 NPC 的不同方面。此外,这样的机器人不能移动到它们被创建的岛屿之外。
服务器配置
- Opensim.ini
[NPC] ;# {Enabled} {} {Enable Non Player Character (NPC) facilities} {true false} false Enabled = true ;; several options to control NPCs creation ;# {AllowNotOwned} {} {allow NPCs to be created not Owned} {true false} true ;; allow NPCs to be created not Owned {true false} default: true AllowNotOwned = true ;# {AllowSenseAsAvatar} {} {allow NPCs to set to be sensed as Avatars} {true false} true ;; allow NPCs to set to be sensed as Avatars {true false} default: true AllowSenseAsAvatar = true ;# {AllowCloneOtherAvatars} {} {allow NPCs to created cloning any avatar in region} {true false} true ;; allow NPCs to created cloning any avatar in region {true false} default: true AllowCloneOtherAvatars = true ;# {NoNPCGroup} {} {if true NPCs will have no group title, if false display "- NPC -"} {true false} true ;; if true NPCs will have no group title, if false display "- NPC -" for easy identification {true false} default: true NoNPCGroup = true …… [OSSL] ;# {Include-osslEnable} {} {Include file for enabling and permissions for OSSL functions} {} ;; Optionally include file to enable OSSL functions and set permissions on who can use which. ;; If this INI file is not included, the OSSL functions are disabled. Include-osslEnable = "config-include/osslEnable.ini"
- config-include/osslEnable.ini
在该文件中包含对各种os*函数的授权
相关API
osIsNpc
函数:integer osIsNpc(key npc)。
功能:判断一个指定的key是不是一个NPC。
返回值:NPC的状态
- 如果提供的key是一个NPC,则返回值为TRUE (1),否则为FALSE (0);
- 如果提供的key是一个NPC,但不存在于场景中,返回FALSE (0);
osNpcCreate
函数:
- key osNpcCreate(string firstname, string lastname, vector position, string cloneFrom)
- key osNpcCreate(string firstname, string lastname, vector position, string cloneFrom, integer options)
功能:创建一个名为firstname lastname, 位置为position, 外观为cloneFrom的NPC。
示例:
// touch to create a NPC clone of the toucher in front of this emitter // NPC will move to the toucher, then will greet them. // Touch again to remove the NPC key npc; vector toucherPos; default { touch_start(integer number) { vector npcPos = llGetPos() + <1,0,0>; osAgentSaveAppearance(llDetectedKey(0), "appearance"); // coud use avatar UUID directly in osNpcCreate, but then NPC appearance is not persisted npc = osNpcCreate("ImYour", "Clone", npcPos, "appearance"); toucherPos = llDetectedPos(0); state hasNPC; } } state hasNPC { state_entry() { osNpcMoveTo(npc, toucherPos + <1,1,0>); osNpcSay(npc, "Hi there! My name is " + llKey2Name(npc)); } touch_start(integer number) { osNpcSay(npc, "Goodbye!"); osNpcRemove(npc); npc = NULL_KEY; state default; } }
[备注]
- 您可以从保存的外观记录卡名称或UUID或从登录到相同区域中克隆外观。
- 您可以使用以下函数创建和加载外观记录卡:osOwnerSaveAppearance,osAgentSaveAppearance,osNpcLoadAppearance,osNpcSaveAppearance。
- 在当前的OpenSimulator开发代码中(从2012年1月12日的提交c4972e77),已经添加了osNpcCreate()的重载版本。
- 关于重载函数key osNpcCreate(string firstname, string lastname, vector position, string cloneFrom, integer options)
- options字段可以是OS_NPC_CREATOR_OWNED或OS_NPC_NOT_OWNED。
- OS_NPC_CREATOR_OWNED将创建一个“被拥有”的NPC,只会响应与创建NPC相同的所有者脚本发出的osNpc *命令。
- OS_NPC_NOT_OWNED将创建一个“无主”的NPC,它将响应任何具有OSSL权限的脚本来调用osNpc *命令。
- 例如:key npc = osNpcCreate("ImYour", "Clone", npcPos, "appearance", OS_NPC_CREATOR_OWNED);
- 现有的没有options字段的osNpcCreate()函数将继续存在。
osGetNpcList
函数:list osGetNPCList( ).
功能:显示该区域中每个NPC的UUID、位置和名称的列表。
示例:
default { touch_start(integer total_number) { list npcs = osGetNPCList(); if (npcs == []) llSay(0, "You must be the owner. There is nobody else here who could have touched me."); else llSay(0, "NPC's in this region (without avatars):" + llList2CSV(npcs)); } }
osNpcGetOwner
函数:key osNpcGetOwner(key npc).
功能:获取NPC的所有者的UUID。
osNpcGetPos
函数:vector osNpcGetPos(key npc).
功能:返回NPC的当前位置。
osNpcGetRot
函数:rotation osNpcGetRot(key npc).
功能:获取化身的旋转。欧拉旋转(水平旋转)中只有Z平面的旋转才有意义。
osNpcLoadAppearance
函数:osNpcLoadAppearance(key npc, string notecard).
功能:从记事卡加载外观。此记事卡必须包含使用其中一个保存外观功能创建的外观数据。
osNpcMoveTo
函数:void osNpcMoveTo(key npc, vector position).
功能:移动NPC到指定位置。
osNpcMoveToTarget
函数:osNpcMoveToTarget(key npc, vector target, integer options).
功能:随着时间的推移,到达指定的地点。如何到达目的地取决于options的值。
- OS_NPC_FLY :将飞到指定的位置。NPC将不会着陆,除非OS_NPC_LAND_AT_TARGET选项也被给出。
- OS_NPC_NO_FLY : 不要飞到目标。NPC将尝试走向该地点。如果它在空中,那么NPC将一直处于无望的状态,直到另一个移动目标被提供或移动被停止。
- OS_NPC_LAND_AT_TARGET : 如果给出,NPC正在飞行,那么它会在到达目标时着陆。如果给出OS_NPC_NO_FLY,那么这个选项不起作用。
- OS_NPC_FLY和OS_NPC_NO_FLY是不能合并的选项 - NPC最终会做一个或另一个。如果你想让NPC飞行并落在目标上,那么OS_NPC_LAND_AT_TARGET必须与OS_NPC_FLY结合。
- OS_NPC_RUNNING : 将NPC运行到给定的位置。
osNpcPlayAnimation
函数:osNpcPlayAnimation(key npc, string animation).
功能:在NPC的身份标识上播放动画。
osNpcRemove
函数:void osNpcRemove(key npc).
功能:移除指定key的NPC。
示例:
// sim-wide NPC killer // kill all of NPCs in this SIM // Attempts to kill agents too, but it will silently fail // http://opensimulator.org/wiki/OsNpcRemove default { touch_start(integer number) { list avatars = llList2ListStrided(osGetAvatarList(), 0, -1, 3); integer i; llSay(0,"NPC Removal: No avatars will be harmed or removed in this process!"); for (i=0; i<llGetListLength(avatars); i++) { string target = llList2String(avatars, i); osNpcRemove(target); llSay(0,"NPC Removal: Target "+target); } } }
[备注] 如果化身是任何其他类型的代理(即用户的常规化身,而不是NPC)的UUID,则该功能将默认失败,不会擦除已存在的化身。
osNpcSaveAppearance
函数:key osNpcSaveAppearance(key npc, string notecard).
功能:将NPC的当前外表保存在资产库中的记事卡中。这包括身体部位数据,衣物和附件。如果同名的记事卡已经存在,则被替换。当这个函数被调用时,化身必须出现在该区域。化身的烘焙纹理(重现外观所必需的)被永久保存。
osNpcSay
函数:
- void osNpcSay(key npc, int channel, string message).
- void osNpcSay(key npc, string message).
功能:NPC在已给的通道表示信息(第二个通道为0).
osNpcSetProfileAbout
函数:osNpcSetProfileAbout(LSL_Key npc, string about).
功能:在创建的NPC的配置文件中设置。
示例:
// // osNpcSetProfileImageScript Example // key npc = NULL_KEY; string about = "I'm your Clone"; default { touch_start(integer number) { if (npc == NULL_KEY) { osOwnerSaveAppearance("MyClone"); llSetTimerEvent(2.0); } else { osNpcRemove(npc); npc = NULL_KEY; llRemoveInventory("MyClone"); } } timer() { llSetTimerEvent(0.0); npc = osNpcCreate("John", "Smith", llGetPos() + <0.0, 0.0, 2.0>, "MyClone"); osNpcSetProfileAbout(npc, about); } }
osNpcSetProfileImage
函数:osNpcSetProfileImage(LSL_Key npc, string image).
功能:在创建的NPC的个人资料中设置图像。可以通过名称或UUID使用包含在资产库中的纹理。
示例:
// // osNpcSetProfileImage Example // key npc = NULL_KEY; string image = "My Photo"; default { touch_start(integer number) { if (npc == NULL_KEY) { osOwnerSaveAppearance("MyClone"); llSetTimerEvent(2.0); } else { osNpcRemove(npc); npc = NULL_KEY; llRemoveInventory("MyClone"); } } timer() { llSetTimerEvent(0.0); npc = osNpcCreate("John", "Smith", llGetPos() + <0.0, 0.0, 2.0>, "MyClone"); osNpcSetProfileImage(npc, image); } }
osNpcSetRot
函数:osNpcSetRot(key npc, rotation rot).
功能:设置化身的旋转。只有在欧拉旋转中设置Z平面中的旋转将会产生任何有意义的效果(将化身指向一个方向或另一个方向)。设置X或Y欧拉值将导致化身以不确定的方式旋转。
osNpcShout
函数:void osNpcShout(key npc, int channel, string message).
功能:NPC在给定的通道上呼喊信息。
osNpcSit
函数:osNpcSit(key npc,key target,integer options).
功能:让一个NPC坐在一个物体上。
options : OS_NPC_SIT_NOW。
- 让npc在可能的情况下,立即坐在prim上。这是唯一可用的选项,而且当前总是在选项字段中指定的任何内容上。
- 如果prim有一个sit目标,那么无论在NPC和prim之间的距离,都要坐着。
- 如果prim没有坐目标的话,如果prim在NPC的10米以内,那么坐就会成功。
osNpcStand
函数:osNpcStand(key npc).
功能:让一个坐着的NPC站起来。
osNpcStopAnimation
函数:osNpcStopAnimation(key npc, string animation).
功能:停止正在用指定NPC的密钥标识播放的动画。
osNpcStopMoveToTarget
函数:osNpcStopMoveToTarget(key npc).
功能:停止当前移动到目标的行为。
osNpcTouch
osNpcWhisper
函数:void osNpcWhisper(key npc, int channel, string message).
功能:NPC在给定的通道中低语指定消息。
OsOwnerSaveAppearance
函数:key osOwnerSaveAppearance(string notecard).
功能:将所有者的当前外观保存到资产库中的记事卡中。这包括身体部位数据,衣物和附件。如果同名的记事卡已经存在,则被替换。当这个函数被调用时,所有者必须在区域中。所有者的烘焙纹理(需要在NPC上重现外观)被永久保存。
示例:
// // osOwnerSaveAppearance exxample. // This example creates the notecard with the user's appearance in the inventory of a prim. // You will find the notecard in the contents of the prim after the script has run. // default { state_entry() { string ownername = llKey2Name(llGetOwner()); // Retrieve the owner's key, and find out his/her name. string date = (string)llGetDate(); // Store the date in a string. string notecard_name = ownername+" "+date; // Combine the name and the date for use as a notecard name. osOwnerSaveAppearance(notecard_name); // Make the notecard. } }
综合实例
综合实例1
在此实例中,囊括了大多数关于NPC的API,通过对话框的形式成功实现了一个NPC的建立、移动、说话、站立、坐下、显示位置等功能。
功能 | 菜单等级 | 功能描述 |
---|---|---|
触碰 | 无 | 用户化身触碰物体开始相关操作 |
create | 一级菜单 | 创建一个npc,可以输入npc的姓名,也可系统命名 |
remove | 一级菜单 | 移除该区域所有npc,并删除相应生成的外观记事卡 |
other | 一级菜单 | 点击可输入指定npc的key值,随后可对该npc进行相关操作 |
exit | 一级菜单 | 点击以退出对话框 |
return | 二级菜单 | 点击返回一级菜单 |
exit | 二级菜单 | 点击以退出对话框 |
get... | 二级菜单 | 返回给定npc的位置、旋转角度、拥有者 |
move | 二级菜单 | 输入坐标位置,将npc移动到给定位置 |
stopMove | 二级菜单 | 若npc在移动工程中,可停止移动 |
remove | 二级菜单 | 移除指定npc,并返回一级菜单 |
sit | 二级菜单 | 输入坐下物体的key值,npc将坐在该物体上 |
stand | 二级菜单 | 若npc坐在某物体上,将会站立 |
say | 二级菜单 | npc将和你打招呼 |
// //一个关于NPC的综合案例,通过对话框的形式实现相关功能 // integer gchannel; //记录指定监听通道 integer glistener; //记录相应监听ID key toucherID; //记录触碰者ID key npc; //记录用户输入的NPC的key值 string msg; list options; //记录相关操作的列表 list choices; //记录对指定NPC进行相关操作的列表 integer num = 1; //记录已生成的NPC的数量 //删除除了脚本以外所有生成的文件 delete_all_other_contents() { string thisScript = llGetScriptName(); string inventoryItemName; integer index = llGetInventoryNumber(INVENTORY_ALL); while (index) { --index; // (faster than index--;) inventoryItemName = llGetInventoryName(INVENTORY_ALL, index); if (inventoryItemName != thisScript) llRemoveInventory(inventoryItemName); } } //移除函数:移除岛屿上所有NPC remove() { list avatars = llList2ListStrided(osGetAvatarList(),0,-1,3); //llList2ListStrided:从列表的第一个条到最后,返回第三项 integer i; llSay(0,"NPC Removal: No avatars will be harmed or removed in this process!"); for (i=0; i<llGetListLength(avatars); i++) { string target = llList2String(avatars, i); osNpcRemove(target); llSay(0,"NPC Removal: Target "+target); } delete_all_other_contents(); num = 1; //重置NPC计数 } default { state_entry() { llSay(0, "Click here to start!"); } touch_start(integer total_number) { toucherID = llDetectedKey(0); //获取触碰者ID gchannel = (integer)(llFrand(5000)+5000); //随机生成对话通道,避免对话通道冲突 state init; } } state init { state_entry() { msg = "create: create a npc. \nremove: remove all npc in the region. \n" + "other: operation to given npc."; glistener = llListen(gchannel,"","",""); options = ["create","remove","other","exit"]; llDialog(toucherID,msg,options,gchannel); } //监听函数,获取用户的操作或提交的相关信息,下同 listen(integer channel, string name, key id, string message) { if(message == "create"){ llListenRemove(glistener); state create; }else if(message == "remove"){ remove(); llDialog(toucherID,msg,options,gchannel); }else if(message == "other"){ llListenRemove(glistener); state other; }else{ llListenRemove(glistener); state default; } } } //创建事件:创建一个NPC state create { state_entry() { glistener = llListen(gchannel,"","",""); llTextBox(toucherID,"Enter the name of the npc:",gchannel); } listen(integer channel, string name, key id, string message) { if(channel == gchannel){ llListenRemove(glistener); vector npcPos = llGetPos() + <1,0,0>; string npcName = (string)message; string npcIdname = (string)("clone"+num); osAgentSaveAppearance(toucherID,npcIdname); //保存触碰者当前外观为记事卡中 key NPC = osNpcCreate(npcIdname,npcName,npcPos,npcIdname); osNpcSay(NPC, "Hi there! My name is " + llKey2Name(NPC)); num++; state init; } } } state other { state_entry() { glistener = llListen(gchannel,"","",""); llTextBox(toucherID,"The following operation are for a given NPC.\n"+ "Now,Enter a key for an npc:",gchannel); } listen(integer channel, string name, key id, string message) { llListenRemove(glistener); npc = (string)message; //确定输入key值是否为在岛上存在的NPC if(!osIsNpc(npc)) { msg = "The npc which key is " + npc + " is not existing in the region."; llSay(0,msg); state init; } state option; } } state option { state_entry() { msg = "Please select the operation you want to perform for the NPC."; choices = ["sit","stand","say","move","stopMove","remove","getPos","getRot","getOwner","return","exit"]; glistener = llListen(gchannel,"","",""); llDialog(toucherID,msg,choices,gchannel); } listen(integer channel, string name, key id, string choice) { if(choice == "sit"){ llListenRemove(glistener); state SIT; }else if(choice == "stand"){ osNpcStand(npc); osNpcSay(npc,"I'm standing."); llDialog(toucherID,msg,choices,gchannel); }else if(choice == "say"){ osNpcSay(npc,"Hello!"); llDialog(toucherID,msg,choices,gchannel); }else if(choice == "move"){ llListenRemove(glistener); state move; }else if(choice == "stopMove"){ osNpcStopMoveToTarget(npc); llSay(gchannel,"The npc has stop moving!"); llDialog(toucherID,msg,choices,gchannel); }else if(choice == "remove"){ llListenRemove(glistener); osNpcSay(npc, "Goodbye!"); osNpcRemove(npc); state init; }else if(choice == "getPos"){ vector pos = osNpcGetPos(npc); osNpcSay(npc,"The position of the npc is " + (string)pos); llDialog(toucherID,msg,choices,gchannel); }else if(choice == "getRot"){ rotation rot = osNpcGetRot(npc); osNpcSay(npc,"The rotation of the npc is " + (string)rot); llDialog(toucherID,msg,choices,gchannel); }else if(choice == "getOwner"){ key owner = osNpcGetOwner(npc); osNpcSay(npc,"The npc belongs to the user whose ID is " + (string)owner); llDialog(toucherID,msg,choices,gchannel); }else if(choice == "return"){ llListenRemove(glistener); state init; }else{ llListenRemove(glistener); state default; } } } //移动事件:将指定NPC移动到指定地点 state move { state_entry() { msg = "Please input the new vector,in sample format,<x,y,z>"; glistener = llListen(gchannel,"","",""); llTextBox(toucherID,msg,gchannel); } listen(integer channel, string name, key id, string message) { if(channel == gchannel){ llListenRemove(glistener); vector position = (vector)message; osNpcMoveTo(npc, position); osNpcSay(npc,"The npc has been moved to a given position."); state option; } } } //坐下事件:命令指定NPC坐在某物体上,最好在该物体上有相应的设置坐下的脚本 state SIT { state_entry() { msg = "Please input the key what the npc sit on."; glistener = llListen(gchannel,"","",""); llTextBox(toucherID,msg,gchannel); } listen(integer channel, string name, key id, string message) { if(channel == gchannel){ llListenRemove(glistener); key sitNpc = (string)message; osNpcSit(npc, sitNpc, OS_NPC_SIT_NOW); osNpcSay(npc,"I'm sitting."); state option; } } }
综合实例2
在此实例中,囊括了大多数关于NPC的API,通过在指定通道上通讯的形式成功实现了一个乃至多个NPC的建立、移动、说话、站立、坐下等功能。
操作说明:
- 输入“/10 help”获取命令菜单(10为给定通讯通道,可以在脚本中进行修改)
- 输入“/10 show”显示具体每个命令的通讯格式
- 在执行针对于指定NPC的相关操作之前,利用npckey命令输入指定NPC的key值,即为其UUID
命令 | 通讯格式 | 功能描述 |
---|---|---|
create | create <notecard-name> | Create NPC from a stored notecard |
create | create <notecard-name> <firstName> <lastName> | Create NPC from a stored notecard |
createm | createm <num> | Create a specified number of NPCS |
remove | remove | Remove the current NPC |
delete | delete | Delete all generated files except the script |
npckey | npckey <npc-uuid> | Enter a key value for an NPC |
say | say | NPCS greet you |
clone | clone <notecard-name> | Clone own appearance to a notecard |
load | load <notecard-name> | Load appearance on notecard to current npc |
save | save <notecard-name> | Save appearance of current NPC to notecard |
rot | rot | NPCS rotate in one direction |
rotabs | rotabs <angles> | NPC rotation specifies angles |
move | move <x> <y> <z> | move to absolute position |
movetarget | movetarget | Move NPCS to users nearby |
stop | stop | If the NPC is moving, it will stop moving |
sit | sit <target-uuid> | Make a NPC sit on the specified object |
stand | stand | If the NPC is sitting, it will stand |
key npc; integer listenChannel = 10; default { state_entry() { llListen(listenChannel,"",NULL_KEY,""); //监听listenChannel对话通道 llSetText("Listening on " + listenChannel, <0, 255, 0>, 1); //设置提示语显示在物体上方 llOwnerSay("Say '/" + (string)listenChannel + " help' for commands"); } listen(integer channel, string name, key id, string msg) { if (msg != "") { list commands = llParseString2List(msg, [ " " ], []); //接收用户在通道listenChannel输入的对话,并以空格分隔成多个字段 string msg0 = llList2String(commands, 0); //msg0记录用户输入的第一个字段 string msg1 = llList2String(commands, 1); string msg2 = llList2String(commands, 2); string msg3 = llList2String(commands, 3); if (msg0 == "create" && msg1 != "")//创建一个npc { osOwnerSaveAppearance("appearance"); //保存所有者的外观为记事卡appearance string notecardName = "appearance"; string firstName = "clone"; string lastName = "tom"; //判断用户输入的外观卡是否有效,若无效,则用默认记事卡 string thisScript = llGetScriptName(); string inventoryItemName; integer index = llGetInventoryNumber(INVENTORY_ALL); while (index) { --index; // (faster than index--;) inventoryItemName = llGetInventoryName(INVENTORY_ALL, index); if (inventoryItemName == msg1) notecardName = msg1; } //在用户通信格式正确且输入了npc的姓名的情况下,设置npc的姓名 if(msg2 != "" && msg3 != "") { firstName = msg2; lastName = msg3; } npc = osNpcCreate(firstName, lastName, llGetPos() + <5, 5, 0>, notecardName); //生成给定条件的npc llOwnerSay("Good morning! "); } else if (msg0 =="createm" && msg1 != "") //创建多个npc { osOwnerSaveAppearance("appearance"); vector pos = llGetPos(); integer i; for (i = 0; i < (integer)msg1; i++) { osNpcCreate("clone", (string)i, pos + <8, 0, 0>, "appearance"); llSleep(1); } } else if (msg0 == "remove" && osIsNpc(npc)) //删除指定npc { osNpcSay(npc, "You will pay for this with your liiiiiivvveeessss!!!....."); osNpcRemove(npc); } else if(msg0 == "delete") //删除除了脚本以外所有生成的外观记事卡 { string thisScript = llGetScriptName(); string inventoryItemName; integer index = llGetInventoryNumber(INVENTORY_ALL); while (index) { --index; // (faster than index--;) inventoryItemName = llGetInventoryName(INVENTORY_ALL, index); if (inventoryItemName != thisScript) llRemoveInventory(inventoryItemName); } llOwnerSay("All generated files except the script have been deleted."); } else if (msg0 == "say" && osIsNpc(npc)) //npc说话,打招呼 { osNpcSay(npc, " I am your worst Nightmare, " + (string)npc); } else if (msg0 == "move" && msg1 != "" && msg2 != "" && osIsNpc(npc)) //移动一个npc,输入的为npc移动的目标地址 { vector pos = <(integer)msg1, (integer)msg2, 0>; //z值可输入,也可不输入,最终高度取决于地形 if (msg3 != "") { pos.z = (integer)msg3; } osNpcMoveTo(npc, pos); } else if (msg0 == "movetarget" && osIsNpc(npc)) //移动npc到人物(用户)附近 { osNpcMoveToTarget(npc, llGetPos() + <9,9,5>, OS_NPC_FLY|OS_NPC_LAND_AT_TARGET); } else if (msg0 == "rot" && osIsNpc(npc)) //使npc旋转一个方向 { vector xyz_angles = <0,0,90>; // 定义一个度数改变值 vector angles_in_radians = xyz_angles * DEG_TO_RAD; //改变弧度 rotation rot_xyzq = llEuler2Rot(angles_in_radians); //改变旋转度数 rotation rot = osNpcGetRot(npc); osNpcSetRot(npc, rot * rot_xyzq); } else if (msg0 == "rotabs" && msg1 != "") //使npc旋转给定角度 { vector xyz_angles = <0, 0, (integer)msg1>; vector angles_in_radians = xyz_angles * DEG_TO_RAD; rotation rot_xyzq = llEuler2Rot(angles_in_radians); osNpcSetRot(npc, rot_xyzq); } else if (msg0 == "save" && msg1 != "" && osIsNpc(npc)) //保存npc的外观到给定名称的记事卡中 { osNpcSaveAppearance(npc, msg1); llOwnerSay("Saved appearance " + msg1 + " to " + npc); } else if (msg0 == "load" && msg1 != "" && osIsNpc(npc)) //npc加载指定外观记事卡 { osNpcLoadAppearance(npc, msg1); llOwnerSay("Loaded appearance " + msg1 + " to " + npc); } else if (msg0 == "clone" && msg1 != "") //保存拥有者外观到给定名称的记事卡中 { osOwnerSaveAppearance(msg1); llOwnerSay("Cloned your appearance to " + msg1); } else if (msg0 == "stop" && osIsNpc(npc)) //使npc停止移动,如果npc在运动中的话 { osNpcStopMoveToTarget(npc); } else if (msg0 == "sit" && msg1 != "" && osIsNpc(npc)) //使npc坐到指定物体上 { osNpcSit(npc, msg1, OS_NPC_SIT_NOW); } else if (msg0 == "stand" && osIsNpc(npc)) //使npc站立起来 { osNpcStand(npc); } else if(msg0 == "npckey" && msg1 != "") //输入npc的key值,为其他操作提供npc的key值 { npc = msg1; if(osIsNpc(npc)) llOwnerSay("The value of key is valid."); else llOwnerSay("The value of key is not valid.Please re-enter!"); } else if (msg0 == "help") //显示所有命令 { llOwnerSay("Commands are:"); llOwnerSay("create \t createm \t remove \t delete \t npckey \n" + "\t say \t clone \t load \t save \t rot \t rotabs \n" + "\t move \t movetarget \t stop \t sit \t stand \n" ); llOwnerSay("You can enter '/" + listenChannel +" instruction' to learn more about the communication rules"); } else if(msg0 == "instruction") //显示所有命令的具体说明 { llOwnerSay("In addition to creating and removing operations, you need to enter or check whether the NPC's key values are valid before the rest of the operations are performed."); llOwnerSay("create <notecard-name> - Create NPC from a stored notecard."); llOwnerSay("create <notecard-name> <firstName> <lastName> - Create NPC from a stored notecard."); llOwnerSay("createm <num> - Create a specified number of NPCS."); llOwnerSay("remove - Remove the current NPC."); llOwnerSay("delete - Delete all generated files except the script."); llOwnerSay("npckey <npc-uuid> - Enter a key value for an NPC."); llOwnerSay("say - NPCS greet you."); llOwnerSay("clone <notecard-name> - Clone own appearance to a notecard."); llOwnerSay("load <notecard-name> - Load appearance on notecard to current npc."); llOwnerSay("save <notecard-name> - Save appearance of current NPC to notecard."); llOwnerSay("rot - NPCS rotate in one direction."); llOwnerSay("rotabs <angles> - NPC rotation specifies angles."); llOwnerSay("move <x> <y> <z> - move to absolute position."); llOwnerSay("movetarget - Move NPCS to users nearby."); llOwnerSay("stop - If the NPC is moving, it will stop moving."); llOwnerSay("sit <target-uuid> - Make a NPC sit on the specified object"); llOwnerSay("stand - If the NPC is sitting, it will stand."); } else { llOwnerSay("I don't understand [" + msg + "]"); llOwnerSay("You can enter '/" + listenChannel +" help' to learn more about the communication rules"); } } } }
专题探索与应用
NPC生命周期的控制
osNpcRemove可以移除化身,但有时候发现模型无缘无故消失了。如何在岛屿启动和关闭时生成和移除化身
- 移除化身工具
integer gchannel; // dialog channel integer glistener; // holds the listener handle; default { state_entry() { llSay(0, "单击我开始"); } touch_start(integer x) { if (llDetectedKey(0) == llGetOwner()) { gchannel = llCeil(llFrand(5000) + 5000); glistener = llListen(gchannel,"","",""); llTextBox(llDetectedKey(0), "输入一个NPC的KEY", gchannel); } } listen(integer channel, string name, key id, string message) { if(channel==gchannel){ llListenRemove(glistener); key npc=(key)message; osNpcSay(npc, "Goodbye!"); osNpcRemove(npc); } } }
NPC形象如何个性化
目前来看,可以通过制作一个化身,然后讲将化身保存下来,然后供其他使用。
可以研究下danger上的化身
如何控制NPC
包括移动、控制动作等
如何与NPC对话
如何让NPC接收到化身或物体与他的通信