Moving a Game Object in a specific volume/area

Hello All. I am very new at Unity and C# and I think this is my first ever forum post. I have some beginner experience in Java but that’s about it.

So I am writing… well lets be honest, trying to write a follow script to control a game object(Sphere) which is connected and relative to another game object.

Inputs touch and mouse.

The Sphere should follow the mouse as I navigate though the screen up and down left and right however the movement is constrained using mathf.clamp.
When the mouse/ touch is in the center of the screen the Sphere moves on the z axis to -1 as to not visually collide with the relative game object.

Sphere following mouse/touch:

I have managed to get the Sphere to move on the Z axis from -1 to 0 so it moves in a gradual semicircle motion while being moved on the X Axis.
However there is no movement on the Y Axis and the values which I am getting on the debug log don’t really add up.

Can anyone shed some light please. I have attached the Script below. Thank you.

using UnityEngine;
using System.Collections;

public class Follow_Script : MonoBehaviour {

	// Range of movement on X axis this will set from x to -x.
	public float clampForX = 2;
	//Value for minimum/lowest movement value on Y axis.
	public float clampForYmin = -5;
	//Value for maximum/highest movement value on Y axis.
	public float clampForYmax = 10;
	//Value for where the Game object starts off on the Z axis.
	public float startPositionOnZAxis = 0;

	
	void FixedUpdate ()
	{
		MoveUpdate ();
	}


	void MoveUpdate () {

		//Vector3 to store position of mouse or touch
		Vector3 pos;
		//keepUpWithPointX to store float value of X axis from pos for mathf.clamp
		float keepUpWithPointX;
		//keepUpWithPointY to store float value of Y axis from pos for mathf.clamp
		float keepUpWithPointY;
		// Variable used to hold mathf.clamp value of X axis
		float clampX;
		// Variable used to hold mathf.clamp value of Y axis
		float clampY;

		//if Android is running get touch input and store into Vector3 pos
		if (Application.platform == RuntimePlatform.Android) 
		{

			pos = Camera.main.ScreenToWorldPoint (new Vector3 (Input.GetTouch (0).position.x, 
			                                             Input.GetTouch (0).position.y, -1));
		} 
		// else to add in mouse input for testing mostly
		else 
		{
			pos = Camera.main.ScreenToWorldPoint (new Vector3(Input.mousePosition.x, 
			                                               Input.mousePosition.y, -1));
		}

		// Passing X Axis position of Game object value to keepUpWithPointX
		// Cursor was not following the mose properly and was lagging behind.
		// * by 30f seems to have solved it with the mouse as input
		// although I have not tried on a touch device yet.
		keepUpWithPointX = pos.x * 30f; 
		// Passing Y Axis position of Game object to keepUpWithPointY
		// This is giving a strange value and not working as expected.
		// Multiplying by 30f does not help.
		keepUpWithPointY = pos.y;

		// Added Debug to check what is happening when passing over values.
		Debug.Log ("pos.y " + pos.y + "  " + "keepUpWithPointY " + keepUpWithPointY);

		// Clamping X Axis Values into clampX
		clampX = Mathf.Clamp (keepUpWithPointX, -clampForX, clampForX);

		// Clamping Y Axis Values into clampY
		clampY = Mathf.Clamp (keepUpWithPointY, clampForYmin, clampForYmax);

		Debug.Log ("clampY " + clampY);

		/* Give object new position by passing X and Y as Clamp values and calling Rotation
		 * in order to move the game object in fixed space on Z axis.
		 */
		transform.position = new Vector3 ( -clampX, -clampY, Rotation (clampX)); 
	}

	/* create motion for Static Game Object.
	 * When mouse/touch at center of sceen the game object moves out on the z axis to 1-
	 * When mouse/touch is at max or min of mathf.clamp for movement them game object is
	 * moved gradually to 0.
	 * Basically Range 1 from 3 to 0
	 * 			 Range 2 from 0 to -1
	 * When Range 1 = 3 , Range 2 = 0
     */
	float Rotation(float clamp){

		// change from 0 to 1;
		float change;
		float rotation;

		float absVal = Mathf.Abs (clamp);

		change = absVal / clampForX;

		rotation = change - 1;

		return rotation;
	}
}

First, when you do Camera.ScreenPointToWorld with a negative z value you are getting a point behind the camera which you then need to fix by negating the x and y pos.

However the core of your problem is that when you get a point in world space and then modify the z value you also need to modify the x and y values to follow the mouse. That is why x needs to be multiplied by 30 to kind of follow the mouse and why y is also having a hard time when you modify the z to Rotation(clampX).

For instance the code

void MoveUpdate() {
    Vector3 pos=Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
                                                        Input.mousePosition.y, 10));

    float clampX=Mathf.Clamp(pos.x, -clampForX, clampForX);
    float clampY=Mathf.Clamp(pos.y, clampForYmin, clampForYmax);

    transform.position=new Vector3(clampX, clampY, pos.z);
}

But as soon as you modify the new position so z=Rotation(clampX) you’ll also have to change clampX and clampY.

Here are a few possible solutions depending on the intended effect. Personally I would go with Physics.Raycast with a fallback since this would be the easiest way to get your object to “avoid” multiple objects.

  1. You could take one ScreenToWorldPoint’s x pos as an estimate of how far from the camera your point should be and input that value in another ScreenToWorldPoint. This wouldn’t be entirely accurate but it might be good enough.

    void MoveUpdate() {
    Vector3 tempPos=Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
    Input.mousePosition.y, 10));

     float tempClampX=Mathf.Clamp(tempPos.x, -clampForX, clampForX);
    
     Vector3 pos=Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
                                                         Input.mousePosition.y, Rotation(tempClampX)+5));
    
     float clampX=Mathf.Clamp(pos.x, -clampForX, clampForX);
     float clampY=Mathf.Clamp(pos.y, clampForYmin, clampForYmax);
    
     transform.position=new Vector3(clampX, clampY, pos.z);
    

    }
    You could improve the following code with Plane.Raycast to define a plane z=estimate and intersect it with the ray from the mouse but it would still be inaccurate. You could also try using the screen coordinates to define a z distance from camera or z world position. Unity - Scripting API: Plane.Raycast

  2. Use Physics.Raycast (with a collider on the other object), Sphere.Raycast, or define your own Cylinder.Raycast. If the mouse ray intersects then use the position, otherwise just use Plane.Raycast with the plane z=value to get the new position.