简体   繁体   中英

Unity Rotate Object to Change Direction

I have a fish which is swimming across the screen. When it gets within 10% of the edge of the screen, I want it to turn begin turning around until it has completely reversed and is now swimming in the opposite direction. This should be more gradual like a fish would swim. I don't want it to rotate on its own axis.

I'm not having any luck getting it to turn around. It only turns partially.

Update Here's the fish在此处输入图像描述

public class FishSwim : MonoBehaviour
{
    public enum Direction { LeftToRight, RightToLeft };

    public Direction moveDirection;
    [SerializeField]
    private float speedMin = 0.5f;
    [SerializeField]
    private float speedMax = 1f;

    [SerializeField]
    private bool useOnlySpeedMax = false;
    private float speed;

    [HideInInspector]
    public float removeBeyond;

    private void Start()
    {
        var dist = (transform.position - Camera.main.transform.position).z;
        if (moveDirection == Direction.RightToLeft)
            removeBeyond = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, dist)).x;
        else
            removeBeyond = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, dist)).x + FindObjectOfType<SkinnedMeshRenderer>().bounds.size.x;
    }

    private void OnEnable()
    {
        speed = Random.Range(speedMin, speedMax);
        if (useOnlySpeedMax)
        {
            speed = speedMax;
        }
        if (moveDirection == Direction.RightToLeft)
        {
            speed = -speed;
        }
    }

    // Update is called once per frame
    void Update()
    {
        float realSpeed = speed * Time.deltaTime;
        transform.position += Vector3.right * realSpeed;
        if (moveDirection == Direction.RightToLeft && transform.position.x < -Mathf.Abs(removeBeyond))
        {
            transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), Time.deltaTime * 40f);
            moveDirection = Direction.LeftToRight;
        }
        else if (moveDirection == Direction.LeftToRight && transform.position.x > Mathf.Abs(removeBeyond))
        {
            
        }
    }
}

I would use Coroutines to do this. Explanation in comments:

bool isTurning = false;
[SerializeField] float turnPeriod = 0.5f; // how long it takes to turn, smaller=faster

private void OnEnable()
{
    speed = Random.Range(speedMin, speedMax);
    if (useOnlySpeedMax)
    {
        speed = speedMax;
    }
    // Get rid of negative speed
}

void Update()
{
    float realDistance = speed * Time.deltaTime;
    transform.position += transform.right * realDistance;

    // Surely there is a better way than calculating 
    // Mathf.Abs(removeBeyond) every frame... but that is off-topic
    if (!isTurning && ( 
        (moveDirection == Direction.RightToLeft 
            && transform.position.x < -Mathf.Abs(removeBeyond) 
        ) || (moveDirection == Direction.LeftToRight
            && transform.position.x > Mathf.Abs(removeBeyond) 
    ) ) )
    {
        // If we aren't already turning and we should be, start turning:
        StartCoroutine(Turn());
    }
}

IEnumerator Turn()
{
    isTurning = true;
    Vector3 startForward = transform.forward;

    // find end speed and direction
    Direction endDirection = moveDirection == Direction.RightToLeft ?
            Direction.LeftToRight:Direction.RightToLeft; 

    // keep track of how much of our turning time has elapsed
    float elapsedTimePortion = Time.deltaTime/turnPeriod;

    // turn until you've spent enough time turning
    while (elapsedTimePortion < 1f)
    {
        // by whatever portion we've spent time turning, turn starting forward
        // 180 degrees around up axis
        float angle = 180f * elapsedTimePortion;
        Vector3 newForward = Quaternion.AngleAxis(angle, Vector3.up) * startForward;
        transform.rotation = Quaternion.LookRotation(newForward);
        yield return null;
 
        // next frame - update how long we've been turning
        float newElapsedTimePortion = elapsedTimePortion + Time.deltaTime/turnPeriod;

        if (newElapsedTimePortion >= 0.5f && elapsedTimePortion < 0.5f)
        {
            // If we've just passed 50% of the turn, 
            // make fish move opposite direction
            moveDirection = endDirection; 
        }
        elapsedTimePortion = newElapsedTimePortion;
    } 

    // we're done turning, just set the rotation to the end rotation.
    isTurning = false;
    transform.rotation = Quaternion.LookRotation(-startForward);

    // Does removeBeyond need to be updated here? There are a few lines in Start()
    // which would suggest that.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM