Advertisement
Guest User

Sansar Vehicle v1

a guest
Aug 11th, 2017
360
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 30.65 KB | None | 0 0
  1. /*
  2.  * This work uses content from the Sansar Knowledge Base. © 2017 Linden Research, Inc. Licensed under the Creative Commons Attribution 4.0 International License (license summary available at https://creativecommons.org/licenses/by/4.0/ and complete license terms available at https://creativecommons.org/licenses/by/4.0/legalcode).
  3.  * This work uses content from LGG. © 2017 Greg Hendrickson. Licensed under the Creative Commons Attribution 4.0 International License (license summary available at https://creativecommons.org/licenses/by/4.0/ and complete license terms available at https://creativecommons.org/licenses/by/4.0/legalcode).
  4.  */
  5.  
  6. using Sansar.Script;
  7. using Sansar.Simulation;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.ComponentModel;
  11.  
  12. namespace ufo
  13. {
  14.     /// <summary>
  15.     /// This is a script for turning a dynamic object into a movable vehicle
  16.     /// As avatars enter the region, this script grabs their controls so that
  17.     /// it can listen to see if they try to enter it when they are nearby
  18.     /// Then it listens to the control inputs W A S D to apply linear velocity
  19.     ///
  20.     /// This script was written for a very alpha version of Sansar which does not have a way
  21.     /// To sit on an object, or snap the avatar to it's position and rotation
  22.     /// As such, it assumes that the avatar will be rotating inside the vehicle
  23.     /// and makes use of this
  24.     ///
  25.     /// Because there is no sit, to keep the avatar in the vehicle, you must make the physical
  26.     /// object help with this, build a min cage around the avatar to hold them in place || av ||
  27.     /// This script does not support rotating the object to match the avatars facing direction
  28.     /// It could, but as such this currently works best with objects that are radially symmetrical
  29.     ///
  30.     /// </summary>
  31.     public class movingUFOVehicle : SceneObjectScript
  32.     {
  33.         #region different versions of the avatar driving
  34.         /// <summary>
  35.         /// This is used to save what object (avatar) is currently driving the vehicle.  If it is empty, it will allow a new avatar to drive, etc
  36.         /// </summary>
  37.         private ObjectId objectInVehicle;
  38.         /// <summary>
  39.         /// the objectPrivate object of the driver so that we can get information off them easier
  40.         /// </summary>
  41.         private ObjectPrivate avObject;
  42.         /// <summary>
  43.         /// the agent private of the avatar driving
  44.         /// </summary>
  45.         private AgentPrivate avAgent;
  46.         /// <summary>
  47.         /// the animation component of the avatar driving, so that we can move the avatar or even get where their camera is facing
  48.         /// </summary>
  49.         AnimationComponent avAnim;
  50.         #endregion
  51.  
  52.         #region we change these a lot in this script!
  53.         /// <summary>
  54.         /// This stores the current target speed, we increase this when they press WAD and decrease it over time to act like friction
  55.         /// </summary>
  56.         private float speed = 0.0f;
  57.         /// <summary>
  58.         /// Direction the avatar is facing on key press
  59.         /// </summary>
  60.         Sansar.Vector direction;
  61.         /// <summary>
  62.         /// Important direction that stores not only the direction, but also the speed we want the vehicle to go
  63.         /// </summary>
  64.         Sansar.Vector totalDirection;
  65.         /// <summary>
  66.         /// controls the engine sound settings, we increase the volume and the pitch with speed
  67.         /// we put this globally so that we don't have to keep allocating memory to it each loop
  68.         /// </summary>
  69.         private PlaySettings Engine_Settings;
  70.         #endregion
  71.  
  72.         #region constants
  73.         /// <summary>
  74.         /// Max speed we want to allow the object to go, anything higher than about 20 gets a little weird with physics
  75.         /// </summary>
  76.         private const float maxSpeed = 25.0f;
  77.         /// <summary>
  78.         /// When they press a button, how much target speed should we add
  79.         /// </summary>
  80.         private const float speedIncriment = 1.5f;
  81.         /// <summary>
  82.         /// Every updates per second, we decrease the speed by multiplying by this percent to emulate friction
  83.         /// </summary>
  84.         private const float decreaseSpeedPercentage = .95f;
  85.         /// <summary>
  86.         /// how many speed updates we should do per second, more will follow the av rotation better
  87.         /// </summary>
  88.         private const double updatesPerSecond = 10.0f;
  89.         /// <summary>
  90.         /// How many times per second we check for collisions, to play sounds or move out of the way
  91.         /// </summary>
  92.         private const double collisionChecksPerSecond = 5;
  93.         /// <summary>
  94.         /// This controls how strongly we will change our direction based on the way the user is facing
  95.         /// We don't want it one, else it will look like the object can turn on a dime, add some slide to make
  96.         /// it feel like it has momentum
  97.         /// </summary>
  98.         private const float turnPowerPercent = .4f;
  99.         /// <summary>
  100.         /// What channel the script will talk to other vehicles and a helper script to reset their position if things go crazy
  101.         /// </summary>
  102.         private const int channel = 3;
  103.         #endregion
  104.  
  105.         #region mostly stays the same the whole time
  106.         /// <summary>
  107.         /// This array holds the list of keys to listen to for entering and exiting the vehicle
  108.         /// </summary>
  109.         private string[] keysToUseEnterandExit = { "Key_1", "Key_2", "Key_3", "Key_4", "Key_F5", "Key_F6", "Key_F7", "Key_F8", "Key_F9", "Key_F10", "Key_F11", "Key_F12" };
  110.         /// <summary>
  111.         /// A few seconds after initialization (after the vehicle settles on the ground) save it's position as the start position to return to if stuff goes crazy
  112.         /// </summary>
  113.         private Sansar.Vector startPos;
  114.         /// <summary>
  115.         /// So this is the sound component that is attached to the object
  116.         /// You will need to make this!!!
  117.         /// on the worlds object viewer, right click your vehicle, and add a audio component.  
  118.         /// Don't bother giving it a sound or volume, but you can play with the shape
  119.         /// We use this so that the sounds move with this object instead of staying still at a location
  120.         /// </summary>
  121.         private AudioComponent LocalAudioComponent = null;
  122.         /// <summary>
  123.         /// At start, we grab our objects rigid body so that we can move it and see where it is in the script
  124.         /// </summary>
  125.         private RigidBodyComponent RigidBody = null;
  126.         /// <summary>
  127.         /// The sound of the engine, make it around 1 second long so the pitch shifts sort of blend in together
  128.         /// This must be public so that you can assign a sound to this script
  129.         /// </summary>
  130.         public SoundResource Engine_Sound;
  131.         /// <summary>
  132.         /// Sound to play on collision, must be public so that it can be assigned
  133.         /// </summary>
  134.         public SoundResource Colision_Sound;
  135.         /// <summary>
  136.         /// Whether or not to complain to the log
  137.         /// </summary>
  138.         public Boolean debug = false;
  139.         /// <summary>
  140.         /// Just a variable to store the random generator
  141.         /// </summary>
  142.         private Random Rnd = new Random();
  143.  
  144.         #endregion
  145.  
  146.         /// <summary>
  147.         /// Runs when the script starts, initialize vars, start coroutines, etc
  148.         /// </summary>
  149.         public override void Init()
  150.         {
  151.  
  152.             // When unhandled exceptions occur, they may be caught with this event handler.
  153.             // Certain exceptions may not be recoverable at all and may cause the script to
  154.             // immediately be removed. This will also break out of any loops in coroutines!
  155.             Script.UnhandledException += UnhandledException;
  156.  
  157.             //Reset our vars to defaults
  158.             objectInVehicle = ObjectId.Invalid;
  159.             direction = Sansar.Vector.Zero;
  160.             totalDirection = Sansar.Vector.Zero;
  161.             Engine_Settings = PlaySettings.PlayOnce;
  162.             CollisionEventType trackedEvents = 0;
  163.             trackedEvents |= CollisionEventType.cCharacterContact;
  164.             trackedEvents |= CollisionEventType.cRigidBodyContact;
  165.             if (RigidBody == null)
  166.             {
  167.                 if (!ObjectPrivate.TryGetFirstComponent(out RigidBody))
  168.                 {
  169.                     // This example will only work on a dynamic object with a rigid body. Bail if there isn't one.
  170.                     return;
  171.                 }
  172.             }
  173.             if (LocalAudioComponent == null)
  174.             {
  175.                 if (!ObjectPrivate.TryGetFirstComponent(out LocalAudioComponent))
  176.                 {
  177.                     return;
  178.                 }
  179.             }
  180.             startPos = RigidBody.GetPosition();
  181.  
  182.             //Start up the coroutines
  183.             StartCoroutine(checkIfAvatarIsStillWithUs);
  184.             StartCoroutine(moveUFO);// Convert the supplied booleans to the correct CollisionEventType to track
  185.             StartCoroutine(CheckForCollisions, trackedEvents);
  186.             //Grab the new user event to grab hot keys
  187.             ScenePrivate.User.Subscribe(User.AddUser, NewUser);
  188.             //Grab the chat event for listening to each other vehicle and resetting
  189.             ScenePrivate.Chat.Subscribe(channel, "script", OnChat);
  190.  
  191.             //in 3 seconds, after we fall to and settle on the ground, save the start position
  192.             Timer.Create(TimeSpan.FromSeconds(3), () => saveStartPos());
  193.         }
  194.  
  195.         #region coroutines!
  196.         /// <summary>
  197.         /// Subroutine to check the av position to see if they fell out, and if so, reset
  198.         /// </summary>
  199.         void checkIfAvatarIsStillWithUs()
  200.         {
  201.             while (true)
  202.             {
  203.                 if (weHaveADriver())
  204.                 {
  205.                     //See if they are too far away, if yes, they fell out, release!
  206.                     if (GetDistance(avObject.Position, RigidBody.GetPosition()) > 4)
  207.                     {
  208.                         resetEverythingish();
  209.                         if (debug) Log.Write(string.Format("We physically lost controlled by {0} , {1} , {2}", avAgent.AgentInfo.Name, objectInVehicle, avObject));
  210.                     }
  211.                 }
  212.                 Wait(TimeSpan.FromSeconds(5));
  213.             }
  214.         }
  215.         /// <summary>
  216.         /// Subroutine to apply friction and enforce speed, engine sound, etc
  217.         /// </summary>
  218.         void moveUFO()
  219.         {
  220.             while (true)
  221.             {
  222.                 if (weHaveADriver())
  223.                 {
  224.                     try
  225.                     {
  226.                         // This is used for volume stuff, basically how fast are we going as a percent? 0.00 to 1.00
  227.                         float magPercent = (((float)GetMagnitude(totalDirection)) / maxSpeed);
  228.                         // enforce the speed and apply it
  229.                         WaitFor(RigidBody.SetLinearVelocity,totalDirection);
  230.                         // apply a fake sort of friction, we will use this next loop
  231.                         totalDirection *= decreaseSpeedPercentage;
  232.                         //make the loudness be louder the faster, and make the pitch go up as well, then play it
  233.                         Engine_Settings.Loudness = (magPercent * 50.0f) - 50.0f;
  234.                         if (magPercent > .05) Engine_Settings.Loudness += 10.0f;
  235.                         Engine_Settings.PitchShift = ((magPercent / maxSpeed) * 25.0f);
  236.                         if (Engine_Sound != null && Engine_Settings.Loudness > -50.0f) LocalAudioComponent.PlaySoundOnComponent(Engine_Sound, Engine_Settings);//.OnFinished(OnSoundFinished);                            
  237.                     }
  238.                     catch (Exception)
  239.                     {   // If we got a bad force value it could cause an exception in SetLinearVelocity.
  240.                         continue;
  241.                     }
  242.                 }
  243.                 Wait(TimeSpan.FromSeconds(1.0 / updatesPerSecond));
  244.             }
  245.         }
  246.         /// <summary>
  247.         /// Check to see if we hit someone, play a sound if we did, subroutine
  248.         /// </summary>
  249.         /// <param name="trackedEvents"></param>
  250.         private void CheckForCollisions(CollisionEventType trackedEvents)
  251.         {
  252.             while (true)
  253.             {
  254.                 // This will block the coroutine until a collision happens
  255.                 CollisionData data = (CollisionData)WaitFor(RigidBody.Subscribe, trackedEvents, Sansar.Script.ComponentId.Invalid);
  256.  
  257.                 // Check that the collision is good.
  258.                 if (
  259.                     (data.HitObject != null)
  260.                     //  && (objectInVehicle != ObjectId.Invalid)
  261.                     && (data.HitObject.ObjectId != objectInVehicle)
  262.                     && (GetMagnitude(data.HitObject.Position) > 1)
  263.                     )
  264.                 {
  265.  
  266.                     if (data.HitObject == null)
  267.                     {
  268.                         // This is slightly more common, collided with something were no object was given from the physics system.
  269.                         // Again, just sleep a little and continue.
  270.                         Log.Write("Hit nothing? " + data.HitComponentId);
  271.                         //Wait(TimeSpan.FromSeconds(0.2));
  272.                         continue;
  273.                     }
  274.  
  275.                     // This position - collision object position gives a vector away from the object we collided with.
  276.                     // This is not "away from the collision point". Complex shapes or large objects will confuse this simple math.
  277.                     Sansar.Vector direction = ObjectPrivate.Position - data.HitObject.Position;
  278.                     direction = direction.Normalized();
  279.  
  280.                     if (Math.Abs(direction.X) < 0.1 && Math.Abs(direction.Y) < 0.1)
  281.                     {
  282.                         // This object is mostly above or below us: it is probably the floor. ignore
  283.                         continue;
  284.                     }
  285.                     try
  286.                     {
  287.  
  288.                         if (Colision_Sound != null) LocalAudioComponent.PlaySoundOnComponent(Colision_Sound, PlaySettings.PlayOnce);
  289.                         //We could try to propel away RigidBody.AddLinearImpulse(direction * 100000);
  290.                     }
  291.                     catch (Exception e)
  292.                     {
  293.                         //if(debug)Log.Write("Collision Exception " + e.GetType().ToString() + " in AddLinearImpulse for value: " + (direction * 100000).ToString());
  294.                     }
  295.                 }
  296.  
  297.                 // Always wait after a collision before checking for more collisions to reduce duplicates
  298.                 Wait(TimeSpan.FromSeconds(1.0 / collisionChecksPerSecond));
  299.             }
  300.  
  301.         }
  302.  
  303.         #endregion
  304.  
  305.         #region chat handling
  306.         /// <summary>
  307.         /// We use the chat to talk to other vehicles to find out their position, and reset ourself if it looks like there is a physics problem
  308.         /// </summary>
  309.         /// <param name="Channel"></param>
  310.         /// <param name="Source"></param>
  311.         /// <param name="SourceId"></param>
  312.         /// <param name="SourceScriptId"></param>
  313.         /// <param name="Message"></param>
  314.         void OnChat(int Channel, string Source, SessionId SourceId, ScriptId SourceScriptId, string Message)
  315.         {
  316.             if (debug) Log.Write(string.Format("vehicle of script {0} got chat Channel {1},Source {2},ScriptId {3},Message {4}", this.Script.ID, Channel, Source, SourceScriptId, Message));
  317.             // ignore any messages that are not from a script
  318.             if (SourceScriptId != ScriptId.Invalid)
  319.             {
  320.                 object talkingScript = ScenePrivate.FindScript(SourceScriptId);
  321.  
  322.                 if (talkingScript == null)
  323.                 {
  324.                     Log.Write(LogLevel.Warning, "Unable to find the script who was talking.");
  325.                     return;
  326.                 }
  327.                 if (Message.StartsWith("UFOs where are you?"))
  328.                 {
  329.                     messageAllScripts();
  330.                 }
  331.                 //another vehicle has told us where they are, check to see if we are too close, and if we don't have a driver, go back to the start
  332.                 if (Message.StartsWith("I am a vehicle at position id "))
  333.                 {
  334.                     //don't go home if someone is driving!
  335.                     if (!weHaveADriver())
  336.                     {
  337.                         Sansar.Vector otherUFOPos = vectorFromString(Message.Substring(26));
  338.                         Sansar.Vector myPos2 = RigidBody.GetPosition();
  339.                         double dist = GetDistance(otherUFOPos, myPos2);
  340.                         if (debug) Log.Write(string.Format("Got a vehicle at position {0} i am at  position {1} and distance of {2} from {3} and i am {4}", otherUFOPos, myPos2, dist, SourceScriptId, Script.ID));
  341.                         if (((dist < 4.0 && (SourceScriptId != Script.ID)) || Math.Abs(myPos2.Z - startPos.Z) > 1.0))
  342.                         {
  343.                             resetEverythingish(true);
  344.                         }
  345.                     }
  346.  
  347.                     //notes.Add(SourceScriptId);
  348.                     //logCurrentDictionary();
  349.                 }
  350.             }
  351.         }
  352.  
  353.  
  354.         /// <summary>
  355.         /// Uses ScriptId.AllScript to message all other listening vehicles
  356.         /// </summary>
  357.         private void messageAllScripts()
  358.         {
  359.             ScenePrivate.Chat.MessageScript("I am a vehicle at position id " + RigidBody.GetPosition().ToString(), ScriptId.AllScripts, channel);
  360.         }
  361.         #endregion
  362.  
  363.         #region grabbing the hot keys
  364.         /// <summary>
  365.         /// When a new user enters, grab their keys to see if they try to control this vehicle
  366.         /// </summary>
  367.         /// <param name="action"></param>
  368.         /// <param name="userSessionId"></param>
  369.         /// <param name="data"></param>
  370.         void NewUser(string action, SessionId userSessionId, string data)
  371.         {
  372.             // Set up the hot key listener.
  373.             SubscribeToHotkeys(userSessionId);
  374.             //if(one_to_six_not_7_to_12) Timer.Create(TimeSpan.FromSeconds(30), () => { messageUser(userSessionId); });
  375.         }
  376.         /// <summary>
  377.         /// Ties the avatars keys to the functions to enter or move our vehicle
  378.         /// </summary>
  379.         /// <param name="userId"></param>
  380.         private void SubscribeToHotkeys(SessionId userId)
  381.         {
  382.             AgentPrivate agent = ScenePrivate.FindAgent(userId);
  383.             // Lookup the scene object for this agent
  384.             ObjectPrivate agentObejct = ScenePrivate.FindObject(agent.AgentInfo.ObjectId);
  385.  
  386.             if (debug) Log.Write(string.Format("User id is {0} and obj id is {1}", userId, agent.AgentInfo.ObjectId));
  387.             if (agentObejct == null) { Log.Write($"Unable to find a SceneObject component for user {userId}"); return; }
  388.             // Lookup the animation component. There should be just one, so grab the first, we need this to tie to the keys
  389.             AnimationComponent animationComponent = null;
  390.             if (!agentObejct.TryGetFirstComponent(out animationComponent)) { Log.Write($"Unable to find an animation component on user {userId}"); return; }
  391.             // Listen for all the list of number key presses to enter the vehicle
  392.             int keyNum = 0; foreach (string key in keysToUseEnterandExit)
  393.             {
  394.                 int localKeyNum = keyNum;
  395.                 //now I know how to use lambda statements.. sometimes
  396.                 animationComponent.Subscribe(key.Replace("Key_F", "Key_"), (BehaviorName, ComponentId) => HopInVehicle(localKeyNum, ComponentId), true);
  397.                 keyNum++;
  398.             }
  399.             //Listen to WASD to move the vehicle
  400.             animationComponent.Subscribe("Key_W", (BehaviorName, ComponentId) => goForeward(1, ComponentId), true);
  401.             animationComponent.Subscribe("Key_A", (BehaviorName, ComponentId) => goForeward(1, ComponentId), true);
  402.             animationComponent.Subscribe("Key_D", (BehaviorName, ComponentId) => goForeward(1, ComponentId), true);
  403.             animationComponent.Subscribe("Key_S", (BehaviorName, ComponentId) => slowDown(1, ComponentId), true);
  404.         }
  405.         #endregion
  406.  
  407.         #region mostly small helper methods
  408.  
  409.  
  410.  
  411.         /// <summary>
  412.         /// The user has left, or we are resetting
  413.         /// Resets the locations and rotations and speed etc
  414.         /// </summary>
  415.         /// <param name="resetStartPos"></param>
  416.         void resetEverythingish(bool resetStartPos = false)
  417.         {
  418.             objectInVehicle = ObjectId.Invalid;
  419.             speed = 0;
  420.             totalDirection = Sansar.Vector.Zero;
  421.             RigidBody.SetLinearVelocity(Sansar.Vector.Zero);
  422.             RigidBody.SetAngularVelocity(Sansar.Vector.Zero);
  423.             RigidBody.SetOrientation(Sansar.Vector.Up);
  424.             if (resetStartPos) RigidBody.SetPosition(startPos);
  425.  
  426.         }
  427.         /// <summary>
  428.         /// We use this mostly to catch error so the whole script does not crash
  429.         /// </summary>
  430.         /// <param name="sender"></param>
  431.         /// <param name="e"></param>
  432.         private void UnhandledException(object sender, Exception e)
  433.         {
  434.             // Depending on the script scheduling policy, the exception may or may not be recoverable.
  435.             // An unrecoverable exception that can be handled will only be given a short time to run
  436.             // so the handler method needs to be kept small.
  437.             // Any exception thrown from this method will terminate the script regardless of the value
  438.             // of UnhandledExceptionRecoverable
  439.             if (!Script.UnhandledExceptionRecoverable)
  440.             {
  441.                 Log.Write("Unrecoverable exception, this is useless.");
  442.                 Log.Write(e.ToString());
  443.             }
  444.             else
  445.             {
  446.                 Log.Write("Exception!");
  447.                 Log.Write(e.ToString());
  448.  
  449.                 // While we have recovered, whatever coroutine had the exception will have stopped.
  450.                 // The script will still run so logs can be recovered.
  451.             }
  452.         }
  453.  
  454.         /// <summary>
  455.         /// just saves the start position, used to have more here
  456.         /// </summary>
  457.         public void saveStartPos()
  458.         {
  459.             startPos = RigidBody.GetPosition();
  460.         }
  461.         /// <summary>
  462.         /// Whether or not we have a driver currently
  463.         /// </summary>
  464.         /// <returns></returns>
  465.         private Boolean weHaveADriver()
  466.         {
  467.             return objectInVehicle != ObjectId.Invalid;
  468.         }
  469.  
  470.         #endregion        
  471.  
  472.         #region responseTOKeypresses
  473.  
  474.         /// <summary>
  475.         /// The avatar is pressing a movement key that would increase speed
  476.         /// Don't care about what direction, as we are going to use the avatars fwd vector instead, let the experience handle the avatar
  477.         /// </summary>
  478.         /// <param name="nothing"></param>
  479.         /// <param name="ComponentId"></param>
  480.         private void goForeward(int nothing, ComponentId ComponentId)
  481.         {
  482.             //check to see if our driver pressed this button
  483.             if (objectInVehicle == ComponentId.ObjectId)
  484.             {
  485.                 float currentSpeed = (float)GetMagnitude(totalDirection);
  486.                 //get the direction the avatar is now facing, we will try to go that direction
  487.                 direction = avObject.ForwardVector;
  488.                 //This could be weird, don't go up or down
  489.                 direction.Z = 0;
  490.                 //We are not even moving fast, so lets force in a slight boost so we are not working with 0s when we normalize
  491.                 if (currentSpeed <= speedIncriment)
  492.                 {
  493.                     totalDirection = direction;
  494.                 }
  495.                 //So i broke apart the math some, but here is the idea
  496.                 //Find the direction we are currently moving, add in a percent of the direction the avatar is facing to get a direction between the two, then go that way
  497.                 Sansar.Vector origonTotalDirection = totalDirection;
  498.                 Sansar.Vector totalNormalized = totalDirection.Normalized();
  499.                 Sansar.Vector newDirection = totalNormalized + (direction.Normalized() * turnPowerPercent);
  500.                 Sansar.Vector newDirectionNormalize = newDirection.Normalized();
  501.                 //totalDirection = (totalDirection.Normalized() + (direction.Normalized() * turnPowerPercent)).Normalized() * (currentSpeed + speedIncriment);
  502.                 totalDirection = newDirectionNormalize * (currentSpeed + speedIncriment);
  503.                 if (debug) Log.Write(string.Format("TD was {0} and normalized is {1} and direction av is {2} and with turn %{3} new direction is {4} normal is {5} so final is {6}",
  504.                       origonTotalDirection, totalNormalized, direction, turnPowerPercent, newDirection, newDirectionNormalize, totalDirection));
  505.                 if (GetMagnitude(totalDirection) > maxSpeed) totalDirection = totalDirection.Normalized() * maxSpeed;
  506.  
  507.                 //This is just a helper because sometimes stuff is crazy
  508.                 RigidBody.SetOrientation(Sansar.Vector.Up);
  509.             }
  510.         }
  511.  
  512.         /// <summary>
  513.         /// Avatar presses S, lower the speed , but otherwise use goFwd
  514.         /// </summary>
  515.         /// <param name="nothing"></param>
  516.         /// <param name="ComponentId"></param>
  517.         private void slowDown(int nothing, ComponentId ComponentId)
  518.         {
  519.             //check to see if our driver pressed this button
  520.             if (objectInVehicle == ComponentId.ObjectId)
  521.             {
  522.                 speed = (float)GetMagnitude(totalDirection) - (speedIncriment * 2);
  523.                 goForeward(nothing, ComponentId);
  524.             }
  525.         }
  526.         /// <summary>
  527.         /// This happens when a user preses a key that would enter them into a vehicle
  528.         /// Check to see if they are close by and facing the vehicle, then assign them to us so that we care about their controls
  529.         /// also, throw them into the cockpit
  530.         /// </summary>
  531.         /// <param name="soundNum"></param>
  532.         /// <param name="ComponentId"></param>
  533.         private void HopInVehicle(int soundNum, ComponentId ComponentId)
  534.         {
  535.             if (!weHaveADriver())
  536.             {
  537.                 ObjectPrivate agentObejct = ScenePrivate.FindObject(ComponentId.ObjectId);
  538.                 Sansar.Vector targetPos = RigidBody.GetPosition();
  539.                 //We check to see if they are looking at us, project a vector form their position 2m fwd, and see if it is close to us
  540.                 if (GetDistance(agentObejct.Position + (agentObejct.ForwardVector * 2), targetPos) < 4)
  541.                 {
  542.                     resetEverythingish();
  543.                     //This is what makes us believe we have a driver now
  544.                     objectInVehicle = ComponentId.ObjectId;
  545.                     //Grab the other objects of this avatar for later use
  546.                     avAgent = ScenePrivate.FindAgent(ComponentId.ObjectId);
  547.                     avObject = agentObejct;
  548.                     avAnim = null;
  549.  
  550.                     if (debug) Log.Write(string.Format("We are now controlled by {0} , {1} , {2}", avAgent.AgentInfo.Name, objectInVehicle, avObject));
  551.                     //Throw the avatar above us into the cockpit (centered in this case)
  552.                     if (avObject.TryGetFirstComponent(out avAnim))
  553.                     {
  554.                         targetPos.Z += 1.0f;
  555.                         avAnim.SetPosition(targetPos);
  556.                     }
  557.                 }
  558.  
  559.             }
  560.             //We already have a driver, and further more he pressed a button to leave
  561.             else if (objectInVehicle == ComponentId.ObjectId)
  562.             {
  563.                 //hop out
  564.                 avAnim.SetPosition(RigidBody.GetPosition() - (avObject.ForwardVector * 5));
  565.                 if (debug) Log.Write(string.Format("We are no longer controlled by {0} , {1} , {2}", avAgent.AgentInfo.Name, objectInVehicle, avObject));
  566.                 resetEverythingish();
  567.             }
  568.         }
  569.         #endregion
  570.  
  571.         #region mostly library helper functions
  572.         /// <summary>
  573.         /// Get the magnitude of a vector
  574.         /// </summary>
  575.         /// <param name="vector"></param>
  576.         /// <returns></returns>
  577.         private double GetMagnitude(Sansar.Vector vector)
  578.         {
  579.             return Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z);
  580.         }
  581.         /// <summary>
  582.         /// Get the distance between 2 vectors
  583.         /// </summary>
  584.         /// <param name="vector1"></param>
  585.         /// <param name="vector2"></param>
  586.         /// <returns></returns>
  587.         private double GetDistance(Sansar.Vector vector1, Sansar.Vector vector2)
  588.         {
  589.             return Math.Sqrt(Math.Pow((vector1.X - vector2.X), 2) + Math.Pow((vector1.Y - vector2.Y), 2) + Math.Pow((vector1.Z - vector2.Z), 2));
  590.         }
  591.         /// <summary>
  592.         /// Get a random vector
  593.         /// </summary>
  594.         /// <param name="magnitude"></param>
  595.         /// <param name="weights">a vector to multiple against to restrict the randomness to certain axis</param>
  596.         /// <returns></returns>
  597.         Sansar.Vector randomVector(double magnitude, Sansar.Vector weights)
  598.         {
  599.             if (GetMagnitude(weights) == 0)
  600.             {
  601.                 weights = new Sansar.Vector(1, 1, 1);
  602.             }
  603.             return new Sansar.Vector(
  604.                 (float)(Rnd.NextDouble() * magnitude - (magnitude / 2.0)) * weights.X,
  605.                 (float)(Rnd.NextDouble() * magnitude - (magnitude / 2.0)) * weights.Y,
  606.                 (float)(Rnd.NextDouble() * magnitude - (magnitude / 2.0)) * weights.Z
  607.                 );
  608.         }
  609.  
  610.         /// <summary>
  611.         /// Takes a string from vector.tostring and turns it back into a vector
  612.         /// Note, this is sloppy and could crash if the string is bad, use try parse, etc
  613.         /// </summary>
  614.         /// <param name="input"></param>
  615.         /// <returns></returns>
  616.         Sansar.Vector vectorFromString(string input)
  617.         {
  618.             Sansar.Vector output = new Sansar.Vector(0, 0, 0);
  619.             string[] splitted = input.Replace("<", "").Replace(">", "").Replace(" ", "").Split(new char[] { ',' });
  620.             if (splitted.Length == 3)
  621.             {
  622.                 output.X = float.Parse(splitted[0]);
  623.                 output.Y = float.Parse(splitted[1]);
  624.                 output.Z = float.Parse(splitted[2]);
  625.             }
  626.             return output;
  627.         }
  628.         #endregion
  629.     }
  630. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement