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;
}
}