Guest User

Gravity Gun with object rotation

a guest
Jan 3rd, 2018
3,998
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.30 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. /* "Gravity Gun" script I quickly threw together to help another user out on Reddit.
  6.  * When clicking the mouse button, you will grab a rigidbody object in front of the
  7.  * main camera's view.
  8.  * Some initial information is recorded about where you grabbed the object, and
  9.  * the difference between it's rotation and yours.
  10.  *
  11.  * The object will be moved around according to the offset point you initially
  12.  * picked up.
  13.  * Moving around, the object will rotate with the player so that the player will
  14.  * always be viewing the object at the same angle.
  15.  *
  16.  *
  17.  * Feel free to use or modify this script however you see fit.
  18.  * I hope you guys can learn something from this script. Enjoy :)
  19.  *
  20.  * Original author: Jake Perry, reddit.com/user/nandos13
  21.  */
  22. public class GravGun : MonoBehaviour
  23. {
  24.     /// <summary>The rigidbody we are currently holding</summary>
  25.     private new Rigidbody rigidbody;
  26.  
  27.     #region Held Object Info
  28.     /// <summary>The offset vector from the object's position to hit point, in local space</summary>
  29.     private Vector3 hitOffsetLocal;
  30.  
  31.     /// <summary>The distance we are holding the object at</summary>
  32.     private float currentGrabDistance;
  33.  
  34.     /// <summary>The interpolation state when first grabbed</summary>
  35.     private RigidbodyInterpolation initialInterpolationSetting;
  36.  
  37.     /// <summary>The difference between player & object rotation, updated when picked up or when rotated by the player</summary>
  38.     private Vector3 rotationDifferenceEuler;
  39.     #endregion
  40.    
  41.     /// <summary>Tracks player input to rotate current object. Used and reset every fixedupdate call</summary>
  42.     private Vector2 rotationInput;
  43.  
  44.     /// <summary>The maximum distance at which a new object can be picked up</summary>
  45.     private const float maxGrabDistance = 30;
  46.    
  47.     /// <returns>Ray from center of the main camera's viewport forward</returns>
  48.     private Ray CenterRay()
  49.     {
  50.         return Camera.main.ViewportPointToRay(Vector3.one * 0.5f);
  51.     }
  52.    
  53.     void Update ()
  54.     {
  55.         if (!Input.GetMouseButton(0))
  56.         {
  57.             // We are not holding the mouse button. Release the object and return before checking for a new one
  58.  
  59.             if (rigidbody != null)
  60.             {
  61.                 // Reset the rigidbody to how it was before we grabbed it
  62.                 rigidbody.interpolation = initialInterpolationSetting;
  63.  
  64.                 rigidbody = null;
  65.             }
  66.            
  67.             return;
  68.         }
  69.  
  70.         if (rigidbody == null)
  71.         {
  72.             // We are not holding an object, look for one to pick up
  73.  
  74.             Ray ray = CenterRay();
  75.             RaycastHit hit;
  76.  
  77.             Debug.DrawRay(ray.origin, ray.direction * maxGrabDistance, Color.blue, 0.01f);
  78.  
  79.             if (Physics.Raycast(ray, out hit, maxGrabDistance))
  80.             {
  81.                 // Don't pick up kinematic rigidbodies (they can't move)
  82.                 if (hit.rigidbody != null && !hit.rigidbody.isKinematic)
  83.                 {
  84.                     // Track rigidbody's initial information
  85.                     rigidbody = hit.rigidbody;
  86.                     initialInterpolationSetting = rigidbody.interpolation;
  87.                     rotationDifferenceEuler = hit.transform.rotation.eulerAngles - transform.rotation.eulerAngles;
  88.  
  89.                     hitOffsetLocal = hit.transform.InverseTransformVector(hit.point - hit.transform.position);
  90.  
  91.                     currentGrabDistance = Vector3.Distance(ray.origin, hit.point);
  92.  
  93.                     // Set rigidbody's interpolation for proper collision detection when being moved by the player
  94.                     rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
  95.                 }
  96.             }
  97.         }
  98.         else
  99.         {
  100.             // We are already holding an object, listen for rotation input
  101.  
  102.             if (Input.GetKey(KeyCode.R))
  103.             {
  104.                 rotationInput += new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
  105.             }
  106.         }
  107.  
  108.         // NOTE: You may want to write some code here to prevent your player's aim from moving while you rotate objects
  109.         // Eg.
  110.         // playerAimScript.enabled = !Input.GetKey(KeyCode.R);
  111.     }
  112.  
  113.     private void FixedUpdate()
  114.     {
  115.         if (rigidbody)
  116.         {
  117.             // We are holding an object, time to rotate & move it
  118.            
  119.             Ray ray = CenterRay();
  120.  
  121.             // Rotate the object to remain consistent with any changes in player's rotation
  122.             rigidbody.MoveRotation(Quaternion.Euler(rotationDifferenceEuler + transform.rotation.eulerAngles));
  123.  
  124.             // Get the destination point for the point on the object we grabbed
  125.             Vector3 holdPoint = ray.GetPoint(currentGrabDistance);
  126.             Debug.DrawLine(ray.origin, holdPoint, Color.blue, Time.fixedDeltaTime);
  127.  
  128.             // Apply any intentional rotation input made by the player & clear tracked input
  129.             Vector3 currentEuler = rigidbody.rotation.eulerAngles;
  130.             rigidbody.transform.RotateAround(holdPoint, transform.right, rotationInput.y);
  131.             rigidbody.transform.RotateAround(holdPoint, transform.up, -rotationInput.x);
  132.            
  133.             // Remove all torque, reset rotation input & store the rotation difference for next FixedUpdate call
  134.             rigidbody.angularVelocity = Vector3.zero;
  135.             rotationInput = Vector2.zero;
  136.             rotationDifferenceEuler = rigidbody.transform.rotation.eulerAngles - transform.rotation.eulerAngles;
  137.            
  138.             // Calculate object's center position based on the offset we stored
  139.             // NOTE: We need to convert the local-space point back to world coordinates
  140.             Vector3 centerDestination = holdPoint - rigidbody.transform.TransformVector(hitOffsetLocal);
  141.  
  142.             // Find vector from current position to destination
  143.             Vector3 toDestination = centerDestination - rigidbody.transform.position;
  144.  
  145.             // Calculate force
  146.             Vector3 force = toDestination / Time.fixedDeltaTime;
  147.  
  148.             // Remove any existing velocity and add force to move to final position
  149.             rigidbody.velocity = Vector3.zero;
  150.             rigidbody.AddForce(force, ForceMode.VelocityChange);
  151.         }
  152.     }
  153. }
Add Comment
Please, Sign In to add comment