Home > OS >  Why the transform is rotating 360 degrees even if I limit the rotation randomly between specific deg
Why the transform is rotating 360 degrees even if I limit the rotation randomly between specific deg

Time:11-08

The guns is rotating 360 degrees and not between -40 and 0

This screenshot is the default before running the game the rotation on x is 0 :

guns x rotation value is 0

and this screenshot is after I changed the guns x rotation value to -40

guns x rotation value is 0

I want the guns to rotate up down between 0 and -40 but when I'm running the game the guns rotating 360 degrees.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MissleLauncherRotation : MonoBehaviour
{
    public Transform body;
    public Transform guns;
    public Vector3 spinAxisBody;
    public Vector3 spinAxisGuns;
    public float timeToSpin = 5f;
    public float spinSpeed = 20f;
    public bool randomSpin = false;

    private void Start()
    {
        StartCoroutine("Spin");
    }

    private void Update()
    {

    }

    IEnumerator Spin()
    {
        float spinTimer;
        while (true)
        {
            if (randomSpin == true)
            {
                spinAxisBody = new Vector3(0,Random.Range(-180, 180),0);

                spinAxisGuns = new Vector3(Random.Range(-40, 0), 0, 0);
            }

            spinTimer = timeToSpin;
            while (spinTimer > 0f)
            {
                body.transform.Rotate(spinAxisBody, Time.deltaTime * spinSpeed);
                guns.Rotate(spinAxisGuns, Time.deltaTime * spinSpeed);
                spinTimer -= Time.deltaTime;
                yield return null;
            }
        }
    }
}

I tried this :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MissleLauncherRotation : MonoBehaviour
{
    public Transform body;
    public Transform guns;
    public Vector3 spinAxisBody;
    public Vector3 spinAxisGuns;
    public float timeToSpin = 5f;
    public float spinSpeed = 20f;
    public bool randomSpin = false;

    Quaternion rot;

    private void Start()
    {
        rot = guns.rotation;
    }

    private void Update()
    {
        guns.Rotate(guns.up, (spinSpeed * Time.deltaTime));
        var rot = guns.rotation.eulerAngles;
        rot = new Vector3
                                        (
                                            guns.eulerAngles.x,
                                            Mathf.Clamp(rot.x, -40, 0),
                                            guns.eulerAngles.z
                                        );
        guns.rotation = Quaternion.Euler(rot);
    }
}

The only thing is working now is the clamping but the clamping is not only on the x and I want to use coroutine or somehow to make that it will rotate ever x seconds.

I did it this way to test the clamping if it's working at all now how do I use it with my first code ?

This script is attached to empty gameobject :

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class DronesManager : MonoBehaviour
{
    public Transform dronesUnchild;

    private List<GameObject> drones = new List<GameObject>();
    private static System.Random rnd = new System.Random();

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(MoveDrone());
    }

    // Update is called once per frame
    void Update()
    {

    }

    private IEnumerator MoveDrone()
    {
        // same as you did:
        var drones = GameObject.FindGameObjectsWithTag("Drone").ToList();

        while (drones.Count > 0)
        {
            // pick one at random, get it
            int index = Random.Range(0, drones.Count);
            var drone = drones[index];

            // remove it from list
            drones.RemoveAt(index);

            // TODO: might want to check/guard if drone == null ... this guards against it
            // being Destroy()ed and yet still lying around in our list marked as "dead"

            // simplified your get-component-and-go-if-not-already-going code here
            var droneControl = drone.GetComponent<DroneControl>();
            if (droneControl.go == false)
            {
                droneControl.movingSpeed = 5f;
                droneControl.go = true;
                drone.transform.parent = dronesUnchild;
            }

            // wait
            yield return new WaitForSeconds(0.3f);
        }
    }
}

And this script is attached to each drone object :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DroneControl : MonoBehaviour
{
    public float movingSpeed;
    public bool go = false;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if(go)
        {
            transform.position -= transform.forward * movingSpeed * Time.deltaTime;
        }
    }
}

Maybe one of this scripts making the problem that it's freezing when trying to change values of variables in the script MissleLauncherRotation ?

CodePudding user response:

As already mentioned Rotate adds a rotation to the current one.

I would rather precalculate the target rotation and use e.g.

public Transform body;
public Transform guns;
public Vector3 spinAxisBody;
public Vector3 spinAxisGuns;
public float timeToSpin = 5f;

public bool randomSpin = false;

// Yes, if you make Start return IEnumerator it is automatically run as a 
// Coroutine by Unity without the need for extra code
IEnumerator Start()
{
    while (true)
    {
        // This is the more convenient way of checking for a bool == true
        if (randomSpin)
        {
            spinAxisBody = new Vector3(0,Random.Range(-180, 180),0);

            spinAxisGuns = new Vector3(Random.Range(-40, 0), 0, 0);
        }
        else
        {
            // whatever you want to happen otherwise
        }

        // Pre cache/calculate the start and end rotations 
        // Rotate per default uses the LOCAL space so we will do the same and use localRotation
        // But instead of adding to the existing rotation we will use it as a complete new rotation
        var startBodyRotation = body.localRotation;
        var targetBodyRotation = Quaternion.Euler(spinAxisBody);   

        var startGunsRotation = guns.localRotation;
        var targetGunsRotation = Quaternion.Euler(spinAxisGuns);  

        // Basically same as the while loop but I prefer to use a for loop so I can't forget to increase the timer
        // In my opinion this is simply better readable
        for(var spinTimer = 0f; spinTimer < timeToSpin; spinTimer  = Time.deltaTime)
        {
            // Factor linear moving from 0 to 1 within timeToSpin seconds
            var factor = spinTimer / timeToSpin;
            // optional add ease-in and -out
            //factor = Mathf.SmoothStep(0, 1, factor);

            // Interpolate linear (or with ease-in and -out) between the pre cached start and end rotations
            body.transform.localRotation = Quaternion.Lerp(startBodyRotation, targetBodyRotation, factor);
            guns.localRotation = Quaternion.Lerp(startGunsRotation, targetGunsRotation, factor);

            yield return null;
        }

        // Just to be sure to end up with clean values
        body.transform.localRotation = targetBodyRotation;
        guns.localRotation = targetGunsRotation;

        yield return null;
    }
}
  • Related