Simple Guided Missile
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
12-08-2005 10:30
Hey gang, whipped up a simple and open air-to-air missile last night. It is having trouble seeking the targets, which I suspect has something to do with the missile's damping speed and predictive target positioning. I can't get it to track a target unless it is already a pretty close shot. Thoughts? Also, I'm very interested in optimizing this code (the final version will not have a 0.1 second, 96m, PI sensor repeat-- instead, these values will be eased up a bit once it is fully working. Comments on either optimization and targeting much appreciated. The logic is to gather info about target avs, make sure they aren't the owner(!), and then walk through the list (closest target first) and point to and move to the target. Once in range, blow up. Notes: the missile object should be temp on rez; currently the only llDie() is called when near a target. Could certainly build in a lifetime function as well. No, it doesn't deal damage, push, or teleport people home. =) //Beachhead Aerospace Simple Guided Missile v. 0.1 //Use, modify, sell, run amok. //This script is released without support. Too many versions to debug once (if) //people start modding it. =) --Kage Seraph
float interval = 0.1; //the interval between scans. faster = more accurate = more serverload vector target; //where the missile will try to move to integer minDistance = 15; //inside this range (meters), the missile will airburst. integer targetingFailure =FALSE;
//from http://secondlife.com/badgeo/wakka.php?wakka=llLookAt //used to make missile point along positive X instead of positive Z vector AXIS_FWD = <1,0,0>; float strength = 1.0; //these need tweaking badly. float damping = 0.1;
rotation getRotToPointAxisAt(vector axis, vector target) { return llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos()); }
// Particle Script 0.3 // Created by Ama Omega // 10-10-2003
// Mask Flags - set to TRUE to enable integer glow = FALSE; // Make the particles glow integer bounce = FALSE; // Make particles bounce on Z plan of object integer interpColor = TRUE; // Go from start to end color integer interpSize = TRUE; // Go from start to end size integer wind = FALSE; // Particles effected by wind integer followSource = FALSE; // Particles follow the source integer followVel = TRUE; // Particles turn to velocity direction
// Choose a pattern from the following: // PSYS_SRC_PATTERN_EXPLODE // PSYS_SRC_PATTERN_DROP // PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY // PSYS_SRC_PATTERN_ANGLE_CONE // PSYS_SRC_PATTERN_ANGLE integer pattern = PSYS_SRC_PATTERN_EXPLODE;
// Select a target for particles to go towards // "" for no target, "owner" will follow object owner // and "self" will target this object // or put the key of an object for particles to go to key targetpart = "";
// Particle paramaters float age = 2; // Life of each particle float maxSpeed = 4; // Max speed each particle is spit out at float minSpeed = 3; // Min speed each particle is spit out at string texture ="fire"; // Texture used for particles, default used if blank float startAlpha = 1; // Start alpha (transparency) value float endAlpha = 0; // End alpha (transparency) value vector startColor = <1,1,1>; // Start color of particles <R,G,B> vector endColor = <0.5,0.5,0.5>; // End color of particles <R,G,B> (if interpColor == TRUE) vector startSize = <5,5,5>; // Start size of particles vector endSize = <0,0,0>; // End size of particles (if interpSize == TRUE) vector push = <0,0,5>; // Force pushed on particles
// System paramaters float rate = 0.1; // How fast (rate) to emit particles float radius = 2; // Radius to emit particles for BURST pattern integer count = 15; // How many particles to emit per BURST float outerAngle = 1.54; // Outer angle for all ANGLE patterns float innerAngle = 1.55; // Inner angle for all ANGLE patterns vector omega = <0,0,10>; // Rotation of ANGLE patterns around the source float life = 0; // Life in seconds for the system to make particles
// Script variables integer flags;
updateParticles() { flags = 0; if (targetpart == "owner") targetpart = llGetOwner(); if (targetpart == "self") targetpart = llGetKey(); if (glow) flags = flags | PSYS_PART_EMISSIVE_MASK; if (bounce) flags = flags | PSYS_PART_BOUNCE_MASK; if (interpColor) flags = flags | PSYS_PART_INTERP_COLOR_MASK; if (interpSize) flags = flags | PSYS_PART_INTERP_SCALE_MASK; if (wind) flags = flags | PSYS_PART_WIND_MASK; if (followSource) flags = flags | PSYS_PART_FOLLOW_SRC_MASK; if (followVel) flags = flags | PSYS_PART_FOLLOW_VELOCITY_MASK; if (targetpart != "") flags = flags | PSYS_PART_TARGET_POS_MASK;
llParticleSystem([ PSYS_PART_MAX_AGE,age, PSYS_PART_FLAGS,flags, PSYS_PART_START_COLOR, startColor, PSYS_PART_END_COLOR, endColor, PSYS_PART_START_SCALE,startSize, PSYS_PART_END_SCALE,endSize, PSYS_SRC_PATTERN, pattern, PSYS_SRC_BURST_RATE,rate, PSYS_SRC_ACCEL, push, PSYS_SRC_BURST_PART_COUNT,count, PSYS_SRC_BURST_RADIUS,radius, PSYS_SRC_BURST_SPEED_MIN,minSpeed, PSYS_SRC_BURST_SPEED_MAX,maxSpeed, PSYS_SRC_TARGET_KEY,targetpart, PSYS_SRC_INNERANGLE,innerAngle, PSYS_SRC_OUTERANGLE,outerAngle, PSYS_SRC_OMEGA, omega, PSYS_SRC_MAX_AGE, life, PSYS_SRC_TEXTURE, texture, PSYS_PART_START_ALPHA, startAlpha, PSYS_PART_END_ALPHA, endAlpha ]); } killparticles() { llParticleSystem([]); }
default { on_rez(integer start_param) { llSetBuoyancy(1); llSensorRepeat("","",AGENT,96,PI,interval);//This is hard on the sim. Tweak it down. } state_entry() { llSetBuoyancy(1); llSensorRepeat("","",AGENT,96,PI,interval); } sensor(integer num_detected) { llStopLookAt(); integer i; list targetKey = [];//clear the lists list targetVel = []; list targetPos = []; list targetRot = []; integer targetSelected = FALSE; for( i = 0 ; i <= num_detected ; i++) {//dump all detected avs and their info into lists targetKey += [llDetectedKey(i)]; targetVel += [llDetectedVel(i)]; targetPos += [llDetectedPos(i)]; targetRot += [llDetectedRot(i)]; } integer x = 0; do {//now we walk through the list for the first good target. if(llList2Key(targetKey,x) == llGetOwner() ) {//we've targeted the owner. No good, keep trying x++; targetSelected = FALSE; } else if(llList2Key(targetKey,x) != NULL_KEY) { targetSelected = TRUE; target = llList2Vector(targetPos,x) + llRot2Fwd(llList2Rot(targetRot,x)) * llVecMag(llList2Vector(targetVel,x)); // This line points the fwd (X) axis at the target: llRotLookAt(getRotToPointAxisAt(AXIS_FWD, target), strength, damping); llSetForce(<80,0,0>,TRUE); //llOwnerSay("target is "+llKey2Name(llList2Key(targetKey,x))+ " at "+(string)llList2Vector(targetPos,x)); } else {//we've got no targets. Scan again if(!targetingFailure) { llOwnerSay("No target"); targetingFailure = TRUE; } } }while(!targetSelected);
if( llAbs(llRound(llVecMag(llGetPos() - llList2Vector(targetPos,x)))) < minDistance ) {//detonation routine llSay(11235814,(string)llGetOwner() + " NULL_KEY 20");//for air combat scripts llPlaySound("rocket explode",1); llMessageLinked(LINK_SET,0,"collision","");//to trigger any other scripts as necessary llSetStatus(STATUS_PHYSICS, FALSE); updateParticles(); llSleep(2); killparticles(); llDie(); } } }
|
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
|
12-08-2005 12:45
hmm... just started reading but this jumps out at me: rotation getRotToPointAxisAt(vector axis, vector target) { return llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos()); } it should be: rotation getRotToPointAxisAt(vector axis, vector target) { return llRotBetween(axis, llVecNorm(target - llGetPos())); }
|
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
|
12-08-2005 12:53
other than that your target selection seems to gather information it doesn't need. Maybe I'm reading it wrong but it picks and targets the first valid target, yet you first pack all the sensor return info into lists? If you aren't going to compare every target but just use the first one, I'd step through the keys llDetectedKey(x) until I found one with valid characteristics, then update my sensor to detect only that key.
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
12-08-2005 13:08
Also, in a crowd, this will potentially switch targets each time the sensor fires, because a new av could be closest. I think, anyway 
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
12-08-2005 15:02
From: Ziggy Puff Also, in a crowd, this will potentially switch targets each time the sensor fires, because a new av could be closest. I think, anyway  That's not a bug, it's a feature! =D I'll try those suggestions, Rickard & post the result. Thanks!
|
Senuka Harbinger
A-Life, one bit at a time
Join date: 24 Oct 2005
Posts: 491
|
12-08-2005 17:42
From: Kage Seraph That's not a bug, it's a feature! =D I'll try those suggestions, Rickard & post the result. Thanks! I have a "simpler" homing missile script for my combat system, where it's simpler is that it selects a key (given by the radar selected target, but easily modified to be the closest avatar), and then uses llApplyImpulse and llLookAt to push and orientate the missile towards the target.
_____________________
My SLExchange shopTypos are forgiven; desecrating the english language with reckless abandon and necrophilic acts is not. The function is working perfectly fine. It's just not working the way you wanted it to work.
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
12-09-2005 16:05
Mark II, incorporating some improvements and suggestions. Rickard, I couldn't get the redefinition of the "rotlookatusingpositive-x" function to work, so I stuck with the old one. This seems to work pretty well for my purposes. It doesn't damp immediately to the target, which is most effective, but somehow not viscerally satisfying enough. Rather, it tries to track a bit like a real missile. Sort of. =) Perfect for my needs-- simple friendly dogfighting. float interval = 0.5;//the interval between scans. faster = more accurate = more serverload vector target; integer minDistance = 10; integer noTargetYet = TRUE; integer notified = FALSE; integer powerplant = 30; key targetKey = NULL_KEY;
//from http://secondlife.com/badgeo/wakka.php?wakka=llLookAt vector AXIS_FWD = <1,0,0>; float strength = 10; float damping = 0.04;
rotation getRotToPointAxisAt(vector axis, vector target) { return llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos()); }
// Particle Script 0.3 // Created by Ama Omega // 10-10-2003 // Mask Flags - set to TRUE to enable integer glow = FALSE; // Make the particles glow integer bounce = FALSE; // Make particles bounce on Z plan of object integer interpColor = TRUE; // Go from start to end color integer interpSize = TRUE; // Go from start to end size integer wind = FALSE; // Particles effected by wind integer followSource = FALSE; // Particles follow the source integer followVel = TRUE; // Particles turn to velocity direction
// Choose a pattern from the following: // PSYS_SRC_PATTERN_EXPLODE // PSYS_SRC_PATTERN_DROP // PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY // PSYS_SRC_PATTERN_ANGLE_CONE // PSYS_SRC_PATTERN_ANGLE integer pattern = PSYS_SRC_PATTERN_EXPLODE;
// Select a target for particles to go towards // "" for no target, "owner" will follow object owner // and "self" will target this object // or put the key of an object for particles to go to key targetpart = "";
// Particle paramaters float age = 2; // Life of each particle float maxSpeed = 4; // Max speed each particle is spit out at float minSpeed = 3; // Min speed each particle is spit out at string texture ="fire"; // Texture used for particles, default used if blank float startAlpha = 1; // Start alpha (transparency) value float endAlpha = 0; // End alpha (transparency) value vector startColor = <1,1,1>; // Start color of particles <R,G,B> vector endColor = <0.5,0.5,0.5>; // End color of particles <R,G,B> (if interpColor == TRUE) vector startSize = <5,5,5>; // Start size of particles vector endSize = <0,0,0>; // End size of particles (if interpSize == TRUE) vector push = <0,0,2.5>; // Force pushed on particles
// System paramaters float rate = 0.1; // How fast (rate) to emit particles float radius = 2; // Radius to emit particles for BURST pattern integer count = 15; // How many particles to emit per BURST float outerAngle = 1.54; // Outer angle for all ANGLE patterns float innerAngle = 1.55; // Inner angle for all ANGLE patterns vector omega = <0,0,10>; // Rotation of ANGLE patterns around the source float life = 0; // Life in seconds for the system to make particles
// Script variables integer flags;
updateParticles() { flags = 0; if (targetpart == "owner") targetpart = llGetOwner(); if (targetpart == "self") targetpart = llGetKey(); if (glow) flags = flags | PSYS_PART_EMISSIVE_MASK; if (bounce) flags = flags | PSYS_PART_BOUNCE_MASK; if (interpColor) flags = flags | PSYS_PART_INTERP_COLOR_MASK; if (interpSize) flags = flags | PSYS_PART_INTERP_SCALE_MASK; if (wind) flags = flags | PSYS_PART_WIND_MASK; if (followSource) flags = flags | PSYS_PART_FOLLOW_SRC_MASK; if (followVel) flags = flags | PSYS_PART_FOLLOW_VELOCITY_MASK; if (targetpart != "") flags = flags | PSYS_PART_TARGET_POS_MASK;
llParticleSystem([ PSYS_PART_MAX_AGE,age, PSYS_PART_FLAGS,flags, PSYS_PART_START_COLOR, startColor, PSYS_PART_END_COLOR, endColor, PSYS_PART_START_SCALE,startSize, PSYS_PART_END_SCALE,endSize, PSYS_SRC_PATTERN, pattern, PSYS_SRC_BURST_RATE,rate, PSYS_SRC_ACCEL, push, PSYS_SRC_BURST_PART_COUNT,count, PSYS_SRC_BURST_RADIUS,radius, PSYS_SRC_BURST_SPEED_MIN,minSpeed, PSYS_SRC_BURST_SPEED_MAX,maxSpeed, PSYS_SRC_TARGET_KEY,targetpart, PSYS_SRC_INNERANGLE,innerAngle, PSYS_SRC_OUTERANGLE,outerAngle, PSYS_SRC_OMEGA, omega, PSYS_SRC_MAX_AGE, life, PSYS_SRC_TEXTURE, texture, PSYS_PART_START_ALPHA, startAlpha, PSYS_PART_END_ALPHA, endAlpha ]); } killparticles() { llParticleSystem([]); }
default { on_rez(integer start_param) { llSetBuoyancy(1); llSensorRepeat("","",AGENT,96,PI/2,interval);
} state_entry() { llSetBuoyancy(1); llSensorRepeat("","",AGENT,96,PI/2,interval); } sensor(integer num_detected) { llStopLookAt(); llApplyImpulse(-1 * llGetVel(),FALSE); integer i; for ( i = 0; noTargetYet ; i++ ) { if( llDetectedKey(i) == llGetOwner() ) { } else { noTargetYet = FALSE; target = llDetectedPos(i) + llRot2Fwd(llDetectedRot(i)) * llVecMag(llDetectedVel(i) * interval); llRotLookAt(getRotToPointAxisAt(AXIS_FWD, target), strength, damping); llSetForce(<powerplant,0,0>,TRUE); llOwnerSay("targeting "+llKey2Name(llDetectedKey(i))); targetKey = llDetectedKey(i); state targetAcquired; } } } }
state targetAcquired { state_entry() { llSensorRepeat("",targetKey,AGENT,96,PI,interval); llOwnerSay("targeting "+llKey2Name(targetKey)); } on_rez(integer start_param) { llResetScript(); }
sensor(integer num_detected) { integer i; llStopLookAt(); llApplyImpulse(-1 * llGetVel(),FALSE); //reacquire the target: target = llDetectedPos(i) + llRot2Fwd(llDetectedRot(i)) * llVecMag(llDetectedVel(i) * interval); //aim at it llRotLookAt(getRotToPointAxisAt(AXIS_FWD, target), strength, damping); //move toward it llSetForce(<powerplant,0,0>,TRUE); if( llAbs(llRound(llVecMag(llGetPos() - llDetectedPos(i)))) < minDistance ) { llSay(11235814,(string)llGetOwner() + " NULL_KEY 20"); llPlaySound("rocket explode",1); llMessageLinked(LINK_SET,0,"collision",""); llMessageLinked(LINK_SET,1,llKey2Name(llDetectedKey(i)),""); llSetStatus(STATUS_PHYSICS, FALSE); llOwnerSay("Boom"); updateParticles(); llSleep(2); killparticles(); llDie(); } } no_sensor() { llOwnerSay("Lost target"); } }
|
scubadiver Albert
Registered User
Join date: 8 Oct 2006
Posts: 24
|
10-17-2006 09:36
i put the script into a missile and it only tracked it but didn't move how come or do i need to put another script in it to make it work?
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
10-18-2006 15:22
Howdy! Was the missile object physical, or no?
|