Help to figure a logic to achieve a movement.

Hello ,

Plot :

I have a bird. This bird revolves around a trunk of a tree. At certain point, this bird changes the tree. On the scene there are more than 2 trees. Hence let’s say I have 3 trees. At certain point, the system generates a random tree (as the target) and the bird moves towards it. Once it reaches a specific distance from the tree, the bird starts revolving around the tree.

Constraints :

I would like the bird to be perpendicular to the trunk when it flies around; and face the trunk when it is moving towards the trunk until it reaches the specific distance.

Flexibility :
The bird while flying around could rotate clockwise or anti-clockwise direction around the trunk of the tree.

Problem :
I really do not know to rotate the bird while flying either towards the trunk or rotating around the trunk. The alignment of the bird is the issue I am facing.

CODE :

// Inside the update function of the bird
            if(Vector3.SqrMagnitude(Trunks[TrunkIndex].position - this.transform.position) < 1000)
    		{
    			this.transform.RotateAround(Trunks[TrunkIndex].position, Vector3.up, 20*Time.deltaTime);
    		}
    		else
    		{
    			this.transform.localRotation = Quaternion.LookRotation(Trunks[TrunkIndex].position, Vector3.up);
    			this.transform.position = Vector3.Lerp(this.transform.position, Trunks[TrunkIndex].position, (Time.deltaTime));
    		}

Request :

I am not sure as of how to approach this.

Your help is always appreciated.

Thank you,

Karsnen.

IMAGE:
This is a top-down view.

Top - Down View

if the bird is rotating clockwise then the right side of the bird should face the center, otherwise the left for counter-clockwise. keep that in mind for the next part.

to make one facing of an object align with the facing of another.

this is code i wrote to take the 2 nearest facings of 2 objects and rotate them to face (be parallel to eachother

/* Function:
 * 			To take 2 objects and rotate object Rotate such that its face closest to SnapTo
 * Params:
 *        Rotate: The object that you want to rotate.
 * 		  SnapTo: The object you want Rotate to snap to.
 *
 */
public class AutoSnap : MonoBehaviour
{
		Vector3 axis;
		float angle;
		Vector3 direction;
		Ray ray;
		RaycastHit SnapToHit;
		RaycastHit RotateHit;
		Vector3 MoveDistance;
		AutoSnappedMove MoveComponent;
	void Start(){
		MoveComponent = GetComponent<AutoSnappedMove>();
		ray = new Ray();
	}
	
	public void SnapToNearest (GameObject Rotate, GameObject SnapTo)
	{
		ray.origin = Rotate.transform.position;
		ray.direction = SnapTo.transform.position - Rotate.transform.position;
		Physics.Raycast (ray, out SnapToHit);
		
		ray.origin = SnapTo.transform.position;
		ray.direction = Rotate.transform.position - SnapTo.transform.position;
		Physics.Raycast (ray, out RotateHit);
		
		axis = Vector3.Cross (RotateHit.normal, -SnapToHit.normal);
		if (axis != Vector3.zero) {
			angle = Mathf.Atan2 (Vector3.Magnitude (axis), Vector3.Dot (RotateHit.normal, -SnapToHit.normal));
			Debug.Log(Mathf.Rad2Deg);
			Debug.Log(axis);
			if(angle > .5f)
			{
				Rotate.transform.RotateAround (axis, angle);
			}
		}
		MoveComponent.Move (RotateHit, SnapToHit);

	}

in this case rotate would be the bird and snapto would be the tree
(this code is designed to make 2 objects snap together but it will work just fine for what you want which is to snap together at a distance)

you’ll want to replace

MoveComponent.Move (RotateHit, SnapToHit); (the last line of code)

with your own movement code
(presumably the transform.rotatearound())

these lines

ray.origin = SnapTo.transform.position;
ray.direction = Rotate.transform.position - SnapTo.transform.position;
Physics.Raycast (ray, out RotateHit);

are what work for myself. they find the NEAREST FACING of the moving(in your case bird)
object. You may want to change it to just the left or right side of the bird using a boolean (clockwise or counter clock) to determine which side

in that case you would remove that code and just do

axis = vector3.cross(transform.right/-transform.right, snaptohit.normal)

the tranform.right or -transform.right of course depending on left or right side of bird.

when you move you’ll want to set the distance from the trunk at some point thats easy
just pick a distance say 3 and begin the rotate when it’s approx 3 away as it moves in.

alternatly you can do

ray.direction = (bird.position - trunk.position)
ray.origion = trunk.position

ray.getpoint(distance)
or for a distance of 3

bird.transform.position = ray.getpoint(3);

also you could instead of moving towards the trunk you could slerp towards this point that is 3 units along the line drawn between the far trunk your aiming for and the bird however you would need to do a check to make sure the ray didnt pass through the tree it’s already currently circling (and if it did just call a wait command and wait half a second for the bird to circle more so it’s not in the way and try again)

otherwise it’d fly through the tree its already around and look wierd

When the bird first select a new tree, calculate a target to the side of the tree. You can calculate the target position by taking the cross product between the vertical of the tree and the vector between the bird and the tree and multiplying the result by how far you want the bird to be away from the center of the tree. Something like:

v3T = newTreePos - birdPos;
v3TargetPosition = Vector3.Cross(v3T, Vector3.up).normalized * birdDistanceFromTree;

This position will be where he flies to, but it is also the position you can use for transform.LookAt(). Also you can randomly select between using Vector3.up and Vector3.down to randomly indicate which side of the tree to fly around.

When the bird reaches the position, you can begin the transform.RotateAround(). Since the bird will be tangent to tree, you won’t have to rotate the bird at all.