Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by BilboStabbins · Dec 05, 2012 at 05:53 PM · rigidbodydragworldspacelocalspacedragrigidbody

DragRigidbody - move object in Local Space, not World Space

I have been searching for a solution to this problem for a few days without any joy so any help would be fantastic!

I have the DragRigidBody script attached to my Player which is a child of my camera and is being moved forward, around curves etc. I would like to be able to drag the Player along the X and Y axes in his local space (Eg. so if he is facing a certain direction, his X axis will change).

What's happening now is that he is moving along the X-axis in World Space, so basically left and right in World space, regardless of his direction.

Some more about the game setup; It is a 3D shooter, where the camera is on 'rails' and move forward around different shaped tubes using markers along the way, facing in the correct forward direction. The game is in third person and so the Player is in front of the camera and can move along the X and Y axes (Up/Down/Left/Right). He is a Rigidbody and so has his Z-position constrained as well as his X and Z -rotations. He moves around the 'track' the same way as the camera, but instead of also doing the exact same path-following using the markers, I have instead made him a child of the camera to minimise the processing time, etc (game is for iOS). To take care of his rotation (so that he's always always facing the correct direction), I have a 'lookAt target' object ahead of him, which is also a child of the camera (so Player is in-between Camera and lookAt target).

Please see the attached sketch (at bottom) to show the Player's movement along the X-axis as he moves around a curved section of the track. The current movement (at top-left) shows that he moves from left to right (basically horizontally) regardless of where along the curve the camera (and so he) is. The correct movement is shown at top-right, where his X-axis changes at different points long the curve. The lower two boxes just show the different perspectives and the path markers.

The slightly modified DragRigidBody script I am using (converted to C#) is as follows (I have left the commenting in for anyone that doesn't know how the script works - feel free to correct any mistakes);

Thanks

 using UnityEngine;
 using System.Collections;
 
 /* Note, this script is attached to the Player object in the scene. 
  * It is used to allow the user to drag the Player around the screen using the mouse / finger on mobile devices.
  * It also clamps the values/positions of the X and Y where the Player can be dragged (the edges of the walls, etc), 
  * as well as some other useful things. */
 
 public class MovementController : MonoBehaviour
 {
     public float Spring = 50.0F;
     public float Damper = 5.0F;
     public float Drag = 10.0F;
     public float AngularDrag = 5.0F;
     public float Distance = 0.2F;
     public bool AttachToCenterOfMass = false;
 
     private SpringJoint springJoint;
   
     //-----------------------------------------------------
     // Use this for initialization
     void Start()
     {
 
     }
 
     //-----------------------------------------------------
     // Update is called once per frame
     void Update()
     {    
         // Make sure the user pressed the mouse down
         if (!Input.GetMouseButtonDown(0))
         {
             return;
         }
 
         var mainCamera = FindCamera();
 
         // Create a RaycastHit object called hit
         RaycastHit hit;
 
         // Cast a ray from the mouse point in Screen Space, storing the information in the hit variable
         // If we don't hit anything..
         if (!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit, 100))
             // ignore
             return;
 
         // if we hit a non-rigidbidy OR a non-kinematic object
         if (!hit.rigidbody || hit.rigidbody.isKinematic)
         {
             // ignore
             return;
         }    
 
         // if a springJoint object does not exsist..
         if (!springJoint)
         {
             // Create a Rigidbody dragger object
             GameObject go = new GameObject("Rigidbody dragger");
 
             // Create a Rigidbody and add the component to the dragger
             Rigidbody body = go.AddComponent("Rigidbody") as Rigidbody;
 
             // Add a SprintJoint component to the dragger
             springJoint = go.AddComponent("SpringJoint") as SpringJoint;
 
             // Set the Rigidbody to be Kinematic (ie. to be moveable)
             body.isKinematic = true;
         }
 
         // Set the position of the springJoint object to be the position that was hit by the mouse
         springJoint.transform.position = hit.point;
 
         // Iff we checked this option (AttachToCenterOfMass)..
         if (AttachToCenterOfMass)
         {
             //**            var anchor = transform.TransformDirection(hit.rigidbody.centerOfMass) + hit.rigidbody.transform.position;
 
             // Set the anchor point of the object that scriopt is attached to.
             // This is the centre of mass + its position
             var anchor = hit.rigidbody.centerOfMass + hit.rigidbody.transform.position;
 
             //**        anchor = springJoint.transform.InverseTransformPoint(anchor);
 
             springJoint.anchor = anchor;
         }
        
         // if the collider that the ray hit is part of the 'Player' layer..
         if (hit.rigidbody.gameObject.layer == LayerMask.NameToLayer("Player"))
         {
             // Reset the anchor point
             springJoint.anchor = Vector3.zero;
         }
 
         // otherwise, do nothing
         else
             return;
 
         // Update the attributes of the springJoint object
         springJoint.spring = Spring;
         springJoint.damper = Damper;
         springJoint.maxDistance = Distance;
         springJoint.connectedBody = hit.rigidbody;
 
         //        StartCoroutine ("DragObject", hit.distance);
 
         // Call the DragObject Coroutine, passing the distance that the hit variable has stored. 
         StartCoroutine(DragObject(hit.distance));
     }
 
     //-----------------------------------------------------
     IEnumerator DragObject(float distance)
     {
         float oldDrag = springJoint.connectedBody.drag;
         float oldAngularDrag = springJoint.connectedBody.angularDrag;
         springJoint.connectedBody.drag = Drag;
         springJoint.connectedBody.angularDrag = AngularDrag;
         Camera mainCamera = FindCamera();
 
         // While the mouse button is pressed down..
         while (Input.GetMouseButton(0))
         {
             // Assign the position in World Space to the 'ray' variable.
             // Note, ScreenPointToRay returns a ray going from camera through a screen point. Resulting ray is in world space, 
             // starting on the near plane of the camera and going through position's (x,y) pixel coordinates on the screen 
             // (position.z is ignored). Screenspace is defined in pixels. The bottom-left of the screen is (0,0); the right-top
             // is (pixelWidth,pixelHeight).
             var ray = mainCamera.ScreenPointToRay(Input.mousePosition);
 
             // Assign the distance from the ray that was touched to the position of the springJoint.
             // Note, 'GetPoint' returns a point at distance units along the ray.
             springJoint.transform.position = ray.GetPoint(distance);
 
             // Wait for the end of that frame
             yield return new WaitForEndOfFrame();
         }
 
         // if the springJoint connectedBody object exists..
         if (springJoint.connectedBody)
         {
             // Update the attributes of the connectedBody object
             springJoint.connectedBody.drag = oldDrag;
             springJoint.connectedBody.angularDrag = oldAngularDrag;
             springJoint.connectedBody = null;
         }
     }
 
     //-----------------------------------------------------
     Camera FindCamera()
     {
         if (camera)
             return camera;
         else
             return Camera.main;
     }
 }

alt text

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Dec 05, 2012 at 07:41 PM

You should spend more words on how your actual setup looks like and what you actually want to do. Is it a 3d or 2d game (i guess 3d)? Is it a 3rd person, first person or top down game (i guess 3rd person)?

You said you have your player object as child of your camera and it's moving forward? Having the player a child of the camera seems really strange, usually you have the camera follow. Also "he moves forward", in the local space of the camere? Or do you move the camera?

This script does not move the object along world axis. It moves it relative to the camera. Also if you use a perspective camera it doesn't move the object on a flat plane. The movement will happen on a curved (deformed) surface around the camera origin. That's because you use a ray that always have the same length and always go through the camera's origin. Because the ray starts at the near plane it's not a perfect arc, but almost.

Maybe post a screenshot or paint a scribble of your situation. How the player can move / rotate how the camera is in relation to that and on which axis you want to move.

edit

I would say your problem is:

  • The player is a rigidbody and is a child of another object

  • The players movement constraint on z axis

Rigidbodies are always moved in world space. You can't have it simulated in "local physics". The rigidbodies velocity angular velocity and position are always in worldspace. When you lock the movement on the z axis (the world z-axis of course) your player can't be move along the z axis by forces. It can still be moved on the z axis by "overriding" the physics and use the transform component.

A Rigidbody that is a child of another moving object will behave strange. The Rigidbody itself calculates it's movement velocity based in FixedUpdate (the physics loop). Those calculations are, as already mentioned, in worldspace. Now when the parent object moves it transfers it's motion to it's child transforms. So the naturally physics based movement is overlayed with a non physics based offset.

Since you don't actually use physics in your game (since you use a fix path), i wouldn't use a Rigidbody at all.

I would suggest to use a Plane which position should be the center point on the path where the player should be, and the normal vector should be set to the opposite of the look direction of the player. So the Plane is the plane in which the player can move.

Now just use Plane.Raycast to get the mouseposition on this plane. Do either a smoothed lerping to this point of just set the player to this point.

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image BilboStabbins · Dec 05, 2012 at 08:34 PM 0
Share

Thanks, I'll add some more information shortly.

avatar image BilboStabbins · Dec 10, 2012 at 04:21 PM 0
Share

Any ideas guys, any suggestions at all? :)

avatar image Bunny83 · Dec 11, 2012 at 11:28 PM 0
Share

Sorry, we have around 500 new questions and about 300 new users a day, so you can really get lost here ;)

I'll edit my answer...

avatar image BilboStabbins · Dec 12, 2012 at 10:58 PM 0
Share

No problem Bunny, thanks for taking the time to explain that - appreciate it! :)

Your suggestions sounds like it'll work really well for this purpose. I'll give it a try and let you know how it goes. Also, correct me if I'm wrong but using this method will also keep the Z-position of the Player relative to the camera (offset) constant too, right? Since ScreenToWorldPoint ignores the z-position (makes it 0).

As I'm removing the Rigidbody from the Player am I right to assume that it can now be kept as a child of the Camera?

Thanks

avatar image Bunny83 · Dec 13, 2012 at 12:46 AM 0
Share

Sure, it can be the child of the camera. Well, it depends on how you use it ;) ScreenToWorldPoint doesn't ignore the z position. The z position you pass into the function is taken as the distance from the camera's origin in worldunits.

I'm still not sure if you player "looks" into a different position as the camera. If so ScreenToWorldPoint would move the player relative to camera and not relative to the player. That's why is suggested the Plane. It does quite the same thing, but projects the mouseposition onto an arbitary plane that isn't bound to the camera. The plane can be moved / rotated with the player object.

Here's an example:

 public Transform Player;
 
 void Update()
 {
     Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
     Plane plane = new Plane(-Player.forward, Player.position);
     float dist;
     if (plane.Raycast(ray, out dist))
     {
         Vector3 pos = ray.GetPoint(dist);
         Player.position = pos;
     }
 }

Since we rebuild the plane each time from the players position, it might get slowly offset. It might be better to use a fix position relative to the camera, ideally the center on the path where the player would be when not moved manually.

     Transform cam = Camera.main.transform;
     Plane plane = new Plane(-Player.forward, cam.position + cam.forward * DesiredPlayerDistanceFromCam);
Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

10 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Drag Rigidbody 2 Answers

problem with dragrigidbody 0 Answers

How can i set AddRelativeForce relative to how fast/slow im moving my mouse? 2 Answers

Limiting the top speed of a rigidbody in 3d space? 1 Answer

Drag around riggidbodies with a "pin" 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges