虚拟世界/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接收到化身或物体与他的通信