Jump to content

Turret


KiondraeLoc
 Share

You are about to reply to a thread that has been inactive for 2103 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

No idea but you might want to inspect Aley's old cannon tower's scripts to get a hint on how you can do it. You can either get it from the Aley Museum in Mieville or from the user Aleymart on MP. Both are initiatives to conserve her free items (also be sure to read  Aley's rules on redistrubuting her content).

https://marketplace.secondlife.com/p/Auto-Defense-Cannon-Tower-3-prims/6258731

My advice ist to testuse it inside a prim box in a weapon testing sandbox, as it will autofire on anyone nearby!

Or extract the scripts in a no script sandbox of course ;)

Edited by Fionalein
Link to comment
Share on other sites

There are two parts to the job.  The easy part is the dialog.  If you've never made one, start by reading the tutorial at http://wiki.secondlife.com/wiki/Dialog_Menus

Scripting the turret itself is the hard part. I suggest taking a good look at Chalice Yao's excellent treatment of the mathematics at http://www.sluniverse.com/php/vb/script-library/40698-kept-simple-rotate-object-towards.html .  You will be tempted to just copy it and drop it into your own project, but I strongly suggest that you take as much time as you need to actually understand the math.  Rotations can be tricky -- understatement of the month -- and the geometry of your own setup can make a world of difference to the results.

Oh yes .... I almost forgot the third part (echos of the Monty Python sketch are already running through my mind).  You will need to target the selected avatar too.  That will require acquiring the target position, using a sensor, or llGetObjectDetails, or llCastRay or some other method of your own devising.  Then you'll have to plug that information into the turret routine to do the actual targeting.

Edited by Rolig Loon
  • Like 2
Link to comment
Share on other sites

Thanks for the replies, I am new to scripting so it will take me a long time to figure this stuff out. I do not understand how to get the turret to look at the Agent after I select the Avatar. It only looks at the position and doesn't track the avatar and rezes the object. Here is my script I found and modified:

 

 //Touch and get near avatars in a dialog menu.
//By Kahiro Watanabe
//GPL share it!

integer listener;
integer sensorChannel;
 
float range = 96.0;
float arc = PI;
 
list avatarsKeys;
list avatarsNames;
 
menu(key user,integer channel,string title,list buttons)
{
    listener = llListen(channel,"","","");
    llDialog(user,title,buttons,channel);
    //remove listener if there's no activity in menu
    llSetTimerEvent(20.0);
}
 
integer randomNumber()
{
    return (integer)(llFrand(99999.0) * -1);
}
 
default
{
    touch_start(integer total_number)
    {
        //only owner can access the menu
        if (llDetectedKey(0) == llGetOwner())
        {
            llSensorRepeat("", "", AGENT, 20.0, PI, 0);
        }
    }
    sensor(integer total_number)
    {
        integer i;
        key tempId;
        avatarsKeys = [];
        avatarsNames = [];
        i = 0;
        while ((i < total_number) && (i < 12))
        {
            tempId = llDetectedKey(i);
            avatarsKeys = avatarsKeys + tempId;
            avatarsNames = avatarsNames + llKey2Name(tempId);
            i = i+1;
        }
 
        sensorChannel = randomNumber();
        menu(llGetOwner(),sensorChannel,"Select an avatar...",avatarsNames);
    }
 
    listen(integer channel,string name,key id,string message)
    {
        if (channel == sensorChannel)
        {
            integer pos = llListFindList(avatarsNames,[message]);
            if (pos > -1)
            {
               llLookAt( llDetectedPos(0) + <0.0, 0.0, 1.0>, 3.0, 1.0 );
llRezObject("bullet", llGetPos()+<3,0,0>*llGetRot(),<100,0,0>*llGetRot(),llGetRot(),0); 
            }
        }
    }
    timer()
    {
        llListenRemove(listener);
        llSetTimerEvent(0.0);
    }

 

 

 

I'm using it mainly as a reference to help me understand this.

Edited by KiondraeLoc
Link to comment
Share on other sites

I use a dialog menu that lists the names of people on the sim, then I click their name and send my attack bunnies after them.

Useful topics to search for and read might include dialog menus (if you want to do manual targeting), llSensor(), getting avatar keys and using them, and how to make things move to target avatars.

For my attack bunnies, the menu responds to clicking their name by rezzing the bunnies, sleeping for half a second, then shouting on a hidden channel for them to attack. They hear the command using llListen(), and the scripts inside them move them to the target every time they sense it's moved (about every half second they try to sense their target).

Your project will of course work a little differently, but knowing about these things helped me a lot.

Hope it helps to save you some time.

Edited by Berksey
Link to comment
Share on other sites

12 hours ago, KiondraeLoc said:

. I do not understand how to get the turret to look at the Agent after I select the Avatar. It only looks at the position and doesn't track the avatar

If you want to track the avatar, and then choose later when to fire the projectile, you need a more complex script that starts a timer and  calls llList2Vector(llGetObjectDetails(av,[OBJECT_POS]),0)  (find the position of the avatar or object whose uuid is av) in the timer event every second or so, and adjusts the direction in which the turret is pointing.

So, in the listen event, when your script gets hears the message telling which av has been selected as a target, it points the turret at the target and starts the timer.  It also puts up a second dialog window with the options "Fire" and "Cancel".

I am not sure but I think 

llLookAt( llDetectedPos(0) + <0.0, 0.0, 1.0>, 3.0, 1.0 );
llRezObject("bullet", llGetPos()+<3,0,0>*llGetRot(),<100,0,0>*llGetRot(),llGetRot(),0); 

looks wrong to me.  llLookAt points the object's local z axis at the target (i.e. the top of a standard box).  You will normally want to point the object's x axis at your target.   As that fragment stands, I think you're firing your bullet into the ground.      You should be using llSetRot (or, if it's a physics enabled object, llRotLookAt).    Take a look at the tutorial by Chalice Yao that Rolig referenced earlier -- that explains exactly how to calculate the rotation and how to point at the target.    It's easy to understand, if you think through the examples, and you'll find her method really simplifies things -- I bookmarked it when first she posted it and still refer to it whenever I need to point objects at targets.

  • Like 2
Link to comment
Share on other sites

4 hours ago, Innula Zenovka said:

I am not sure but I think 


llLookAt( llDetectedPos(0) + <0.0, 0.0, 1.0>, 3.0, 1.0 );
llRezObject("bullet", llGetPos()+<3,0,0>*llGetRot(),<100,0,0>*llGetRot(),llGetRot(),0); 

looks wrong to me.

Well, if nothing else, we can predict that it will not work because you are using llDetectedPos(0) in a listen event, where it is not valid. The various llDetected* functions only work in events that actually detect something (touch*, collide* and sensor events). To use the target's position in the listen event, you'll either need to capture it in another event and pass it as a global variable or collect it with llGetObjectDetails(avatar_UUID,[OBJECT_POS]) when the listen event hears your dialog message..

Edited by Rolig Loon
  • Like 1
Link to comment
Share on other sites

I've looked at some of the provided resources and came up with this: 

 

 

//Touch and get near avatars in a dialog menu.
//By Kahiro Watanabe
//GPL share it!
 
//menu listener
integer listener;
integer sensorChannel;
 
// range and arc for the sensor
float range = 96.0;
float arc = PI;
 
list avatarsKeys;
list avatarsNames;
 
menu(key user,integer channel,string title,list buttons)
{
    listener = llListen(channel,"","","");
    llDialog(user,title,buttons,channel);
    //remove listener if there's no activity in menu
    llSetTimerEvent(20.0);
}
 
integer randomNumber()
{
    return (integer)(llFrand(99999.0) * -1);
}
 
default
{
    touch_start(integer total_number)
    {
        //only owner can access the menu
        if (llDetectedKey(0) == llGetOwner())
        {
            llSensor("","",AGENT,range,arc);
        }
    }
    sensor(integer total_number)
    {
        integer i;
        key tempId;
        avatarsKeys = [];
        avatarsNames = [];
        i = 0;
        while ((i < total_number) && (i < 12))
        {
            tempId = llDetectedKey(i);
            avatarsKeys = avatarsKeys + tempId;
            avatarsNames = avatarsNames + llKey2Name(tempId);
            i = i+1;
        }
 
        sensorChannel = randomNumber();
        menu(llGetOwner(),sensorChannel,"Select an avatar...",avatarsNames);
    }
 
    listen(integer channel,string name,key id,string message)
    {
        if (channel == sensorChannel)
        {
            integer pos = llListFindList(avatarsNames,[message]);

            if (pos > -1)
            {
        float range = 96.0;
float arc = PI;  
        integer x = llSensorRepeat("","",AGENT,range,arc);
        vector vTarget=llList2Vector(llGetObjectDetails("targetkey",[OBJECT_POS]),0);
vector vPos=llGetPos()*llRotBetween(<1.33,0,0>*llGetRot(), llDetectedPos(x)-llGetPos()); //object position
float fDistance=llVecDist(<vTarget.x,vTarget.y,0>,<vPos.x,vPos.y,0>); // XY Distance, disregarding height differences.
llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTarget.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTarget.x - vPos.x,vTarget.y - vPos.y,0>)));
     llRezObject("Object",x, vTarget, vPos, 0); 
            }
        }
    }
    timer()
    {
        llListenRemove(listener);
        llSetTimerEvent(0.0);
    }

 

 

It looks at the target, but it won't track my avatar. I want it to bring up the dialog then the user selects an avatar, upon selection, the turret looks at the selected avatar , and then fires the object. How do I get it to do this? Again, thanks for the replies. 

Link to comment
Share on other sites

53 minutes ago, Rolig Loon said:

You are still using llDetectedPos in the listen event

 

I did have vector vPos=llGetPos(); as a function, but it won't look at the selected avatar. It just looks in one direction and doesn't track the avatar as he/she moves around the turret. I need it to track the avatar as he/she moves. Should I some how add a sensor function in the listen event to make it track the selected avatar? Thanks.

Link to comment
Share on other sites

That's not the point. You are using the function llDetectedPos in a listen event, where it will not have any effect.  As I said earlier, the llDetected* functions only work in events that actually detect something. You will need to find another way to get the value you want.  I explained how to do that.

Specifically, please note that you cannot use

integer x = llSensorRepeat("","",AGENT,range,arc);

to get the information you expect. That's not one of the two options that I described. The sequence of operations in any event must be completed before the flow of execution can leave the event.  That is, you cannot hop in and out of an event, interrupting execution. In this case, if you start a repeating sensor in the listen event, it will actually detect something after execution of the current cycle in the event.  The result will be detected later in the sensor event, where it won't be available to inform the calculation you have set up here.  As written, the value of x is undefined.

So ...

16 hours ago, Rolig Loon said:

To use the target's position in the listen event, you'll either need to capture it in another event and pass it as a global variable or collect it with llGetObjectDetails(avatar_UUID,[OBJECT_POS]) when the listen event hears your dialog message..

 

Link to comment
Share on other sites

8 hours ago, KiondraeLoc said:

I did have vector vPos=llGetPos(); as a function, but it won't look at the selected avatar. It just looks in one direction and doesn't track the avatar as he/she moves around the turret. I need it to track the avatar as he/she moves. Should I some how add a sensor function in the listen event to make it track the selected avatar? Thanks.

In the sensor event, you are storing the avatar's name in the list avatarsNames and the avatar's uuid (key) in the list avatarsKeys.   As Rolig has told you, you can use llDetected* only in particular events, and not in the listen event.   However, what you can do, since you know the target's UUID, is say vector vAvatarPos = llList2Vector(llGetObjectDetails(kAv,[OBJECT_POS]),0);  (since you can use llGetObjectDetails to ask for several of the target's details at once, it returns the result as a list, which you then have to break down into its component parts).   

So, you've got a list of names and a corresponding list of uuids.    You know the avatar's name.  You want to find the uuid that corresponds to it.   In a few weeks, as it happens, there will a new function available, llName2Key, which will do that for you, but it's not yet available on all regions and, anyway, scripters need to know the old technique.

You know that the two lists, name and keys, are in lockstep, so if you know the target's name is #3 in the list of names, you need to look up entry #3 in the list of keys.   

To do this, in the listen event you do something like:  

		integer index = llListFindList(names,[message]);//look up the entry number for the name the script has heard from the user in the names list
		if(~index){//shorthand for if(index != -1), or "if the name is in the list"  -- it should be, but always check this
			key kTarget = llList2Key(keys,index);//find the corresponding entry in the target list
			vector vTargetPos = llList2Vector(llGetObjectDetails(kTarget,[OBJECT_POS]),0);//use llGetObjectDetails to find kTarget's position
			//now calculate the rotation to turn and then fire a missile at vTargetPos
		}

If you want to track the target, you need to declare key kTarget as a global variable -- that is, declare it at the start of the script, before default -- and then it's available to you throughout the script (e.g. in a timer event) rather than only in the listen event.   But get the thing to fire a missile in the right direction on receiving the message first, and then worry about tracking targets later once the basic mechanism is working.

Link to comment
Share on other sites

Thanks everyone for your help. It now works as intended. Here is the finished script:

 

//menu listener
integer listener;
integer sensorChannel;
 
// sensor 
list avatarsKeys;
list avatarsNames;
 
menu(key user,integer channel,string title,list buttons)
{
    listener = llListen(channel,"","","");
    llDialog(user,title,buttons,channel);
    //remove listener if there's no activity in menu
    llSetTimerEvent(20.0);
}
 
integer randomNumber()
{
    return (integer)(llFrand(99999.0) * -1);
}
 
default
{
    touch_start(integer total_number)
    {
        //only owner can access the menu
        if (llDetectedKey(0) == llGetOwner())
        {
            llSensor("","",AGENT|PASSIVE,55,PI);
        }
    }
    sensor(integer total_number)
    {
        integer i;
        key tempId;
        avatarsKeys = [];
        avatarsNames = [];
        i = 0;
        while ((i < total_number) && (i < 12))
        {
            tempId = llDetectedKey(i);
            avatarsKeys = avatarsKeys + tempId;
            avatarsNames = avatarsNames + llKey2Name(tempId);
            i = i+1;
        }
 
        sensorChannel = randomNumber();
        menu(llGetOwner(),sensorChannel,"Select an avatar...",avatarsNames);
    }
 
    listen(integer channel,string name,key id,string message)
    {
        if (channel == sensorChannel)
        {
            integer pos = llListFindList(avatarsNames,[message]);
  integer index = llListFindList(avatarsNames,[message]);
integer i;
           if(index != -1)
            for (i = 0; i < 10; ++i)
            {
key kTarget = llList2Key(avatarsKeys,index);
vector vTargetPos = llList2Vector(llGetObjectDetails(kTarget,[OBJECT_POS]),0);
vector vPos=llGetPos();
float fDistance=llVecDist(<vTargetPos.x,vTargetPos.y,0>,<vPos.x,vPos.y,0>);
llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTargetPos.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTargetPos.x - vPos.x,vTargetPos.y - vPos.y,0>)));
llRezObject("bullet", llGetPos()+<3,0,0>*llGetRot(),<20,0,0>*llGetRot(),llGetRot(),0); 
            }
        }
    }
    timer()
    {
        llListenRemove(listener);
        llSetTimerEvent(0.0);
    }
        
}
   

 

If you have any ideas on things to add or to improve the script, please feel free to comment. Again, Thanks!

Link to comment
Share on other sites

Well, that works as a single prim turret. In a linkset on a moving vehicle that isn't pointing East, the turret doesn't fire at the avatar. The aim changes around. How do I get it to use the vehicle's front direction as its east instead of the local sim axis?

Link to comment
Share on other sites

I am in a hurry to catch a plane, so I can't take time to test, but you ought to be able to do it with

llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTargetPos.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTargetPos.x - vPos.x,vTargetPos.y - vPos.y,0>))*llGetRot());

In general, changing a reference frame in a problem like this is just a matter of doing the matrix multiplication to apply the rotation of the new reference frame to the existing one.  See http://wiki.secondlife.com/wiki/Rotation

Link to comment
Share on other sites

6 hours ago, Rolig Loon said:

I am in a hurry to catch a plane, so I can't take time to test, but you ought to be able to do it with

llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTargetPos.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTargetPos.x - vPos.x,vTargetPos.y - vPos.y,0>))*llGetRot());

In general, changing a reference frame in a problem like this is just a matter of doing the matrix multiplication to apply the rotation of the new reference frame to the existing one.  See http://wiki.secondlife.com/wiki/Rotation

I replaced the llGetRot(); functions with llGetLocalRot(); in the llRezObject(); function and that fixed the issue. I didn't need to use *llGetRot(); in the llSetRot(); function. I also replaced llSetRot(); with llSetLocalRot();. Thanks for helping me figure that out. Now the turret works like a charm. Again, Thanks!

Link to comment
Share on other sites

In general when you're making this kind of thing, a great deal is going to depend on where the script is in the linkset (is it in the root prim or the child prim it seeks to move) and on how the child prim's local axes (visible when using the local ruler option in the object editor) are oriented.   If the child prim is a mesh you've uploaded it's very likely to have the axes pointing in unexpected directions, which the script has to compensate for.

If anyone comes across this thread in future and can't get the solutions mentioned here to work, a screenshot of the prim that's being aimed at the target, showing the local axes, will greatly assist people who try to help.

Link to comment
Share on other sites

26 minutes ago, KiondraeLoc said:

I replaced the llGetRot(); functions with llGetLocalRot(); in the llRezObject(); function and that fixed the issue. I didn't need to use *llGetRot(); in the llSetRot(); function. I also replaced llSetRot(); with llSetLocalRot();. Thanks for helping me figure that out. Now the turret works like a charm. Again, Thanks!

That solution can often work too, if the geometry isn't very complicated. Congratulations. 

Link to comment
Share on other sites

1 hour ago, KiondraeLoc said:

I replaced the llGetRot(); functions with llGetLocalRot(); in the llRezObject(); function and that fixed the issue. I didn't need to use *llGetRot(); in the llSetRot(); function. I also replaced llSetRot(); with llSetLocalRot();. Thanks for helping me figure that out. Now the turret works like a charm. Again, Thanks!

It only makes the object rezzing fire at the selected AV though. The turret doesn't look at the avatar so I'm still missing something. When I multiply the vehicles rotation, like what

 

8 hours ago, Rolig Loon said:

I am in a hurry to catch a plane, so I can't take time to test, but you ought to be able to do it with

llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTargetPos.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTargetPos.x - vPos.x,vTargetPos.y - vPos.y,0>))*llGetRot());

In general, changing a reference frame in a problem like this is just a matter of doing the matrix multiplication to apply the rotation of the new reference frame to the existing one.  See http://wiki.secondlife.com/wiki/Rotation

 said, the turret starts firing in random circles instead of firing at the selected avatar. I might be missing some extra math here, but I'm not totally sure. What do you think I'm missing?

Link to comment
Share on other sites

11 hours ago, Innula Zenovka said:

In general when you're making this kind of thing, a great deal is going to depend on where the script is in the linkset (is it in the root prim or the child prim it seeks to move) and on how the child prim's local axes (visible when using the local ruler option in the object editor) are oriented.   If the child prim is a mesh you've uploaded it's very likely to have the axes pointing in unexpected directions, which the script has to compensate for.

If anyone comes across this thread in future and can't get the solutions mentioned here to work, a screenshot of the prim that's being aimed at the target, showing the local axes, will greatly assist people who try to help.

Adding a picture is a good idea, thanks Innula Zenovka. Right now the turret is just a single prim. I plan on doing a mesh turret later.

18 hours ago, Rolig Loon said:

I am in a hurry to catch a plane, so I can't take time to test, but you ought to be able to do it with

llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTargetPos.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTargetPos.x - vPos.x,vTargetPos.y - vPos.y,0>))*llGetRot());

In general, changing a reference frame in a problem like this is just a matter of doing the matrix multiplication to apply the rotation of the new reference frame to the existing one.  See http://wiki.secondlife.com/wiki/Rotation

Using the script below, the turret rotates interchangeably between clockwise and counter clockwise directions when it passes the main North, East, South, and West directions. When the front of the vehicle is pointing Northeast, Southeast, Southwest, or Northwest, the turret fires continuously in one direction, clockwise or counterclockwise. The turret is a child prim on top of the root prim of the vehicle. You can see in the Gif file what its actually doing.

 

//menu listener
integer listener;
integer sensorChannel;
 
// sensor 
list avatarsKeys;
list avatarsNames;
 
menu(key user,integer channel,string title,list buttons)
{
    listener = llListen(channel,"","","");
    llDialog(user,title,buttons,channel);
    //remove listener if there's no activity in menu
    llSetTimerEvent(20.0);
}
 
integer randomNumber()
{
    return (integer)(llFrand(99999.0) * -1);
}
 
default
{
    touch_start(integer total_number)
    {
        //only owner can access the menu
        if (llDetectedKey(0) == llGetOwner())
        {
            llSensor("","",AGENT,55,PI);
        }
    }
    sensor(integer total_number)
    {
        integer i;
        key tempId;
        avatarsKeys = [];
        avatarsNames = [];
        i = 0;
        while ((i < total_number) && (i < 12))
        {
            tempId = llDetectedKey(i);
            avatarsKeys = avatarsKeys + tempId;
            avatarsNames = avatarsNames + llKey2Name(tempId);
            i = i+1;
        }
 
        sensorChannel = randomNumber();
        menu(llGetOwner(),sensorChannel,"Select an avatar...",avatarsNames);
    }
 
    listen(integer channel,string name,key id,string message)
    {
        if (channel == sensorChannel)
        {
            integer pos = llListFindList(avatarsNames,[message]);
  integer index = llListFindList(avatarsNames,[message]);
integer i;
           if(index != -1)
            for (i = 0; i < 100; ++i)
            {
key kTarget = llList2Key(avatarsKeys,index);
vector vTargetPos = llList2Vector(llGetObjectDetails(kTarget,[OBJECT_POS]),0);
vector vPos=llGetPos();
float fDistance=llVecDist(<vTargetPos.x,vTargetPos.y,0>,<vPos.x,vPos.y,0>);


llSetRot(llRotBetween(<1,0,0>,llVecNorm(<fDistance,0,vTargetPos.z - vPos.z>)) * llRotBetween(<1,0,0>,llVecNorm(<vTargetPos.x - vPos.x,vTargetPos.y - vPos.y,0>))*llGetRot());


llRezObject("bullet", llGetPos()+<2,0,0>*llGetRot(),<20,0,0>*llGetRot(),llGetRot(),0); 
            }
        }
    }
    timer()
    {
        llListenRemove(listener);
        llSetTimerEvent(0.0);
    }
        
}
   

 

 

So, what should I do here?

 

The blue light on the front of the prim, linked as a child prim on the vehicle, is the face that aims at the target firing on the Z axis. I placed the first letter of each main direction to show the direction in which the vehicle is facing when rotating.  

 

 

GIF-180515_023808[1].gif

Edited by KiondraeLoc
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2103 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...