c# – Unity3D: How can I move GameObjects from the same script independently?

Question:

I created a script in Unity3D that makes a GameObject move sinusoidally.

The movement happens perfectly, but when more than one GameObject containing this script is in the scene, they all move as a mirror of each other and not in a relative way, making the game very artificial.

I tried using local positioning and still couldn't solve the problem.

Here's the code:

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

public class Enemy4 : Nave {

 public float horizontalSpeed;
 public int yFactor;
 private float count = 3;
 private Vector3 s;
 private bool setPos = false;
 private float x;
 private float y;
 // Use this for initialization
 void Start () {
     x = 0;
     y = 0;
     s = transform.position;
     side = Side.defside.ENEMY;
 }

 // Update is called once per frame
 void Update () {
     y += yFactor * Time.deltaTime;
     x = Mathf.Sin (Time.time) * horizontalSpeed;
     transform.position = s + new Vector3 (x,y, 0);
 }

}

Answer:

sine waves

A sine wave has three relevant properties:

  • Frequency – It is the inverse of the distance between two peaks of a sine wave.

  • Amplitude – It is the difference between the height of the peak and the valley of the wave.

  • Phase – It is the part of the sine wave in which an object that moves through it is.

For example, let's assume that x and y are two consecutive wave peaks, so that:

— [a] x < y ,
— [b] Mathf.Sin(x) = Mathf.Sin(y) = p ,
— [c] there is no t such that ( x < t < y and Mathf.Sin(t) = 1 ) and
— [d] for all real b -a <= Mathf.Sin(b) <= a .

Therefore, the frequency would be given by 1 / (y - x) . The amplitude is 2 * a . The phase is given by t for the expression f(t) , where f is its sine function (not necessarily the sin function itself, as f(x) = 2 * Mathf.Sin(x) is also a sine function).

analyzing your code

You are using the following to set your object's position:

x = Mathf.Sin (Time.time) * horizontalSpeed;

Its sinusoidal function in this case is f(x) = Mathf.Sin (Time.time) * horizontalSpeed . The horizontalSpeed turns out to be the amplitude. The phase is given by Time.time and the frequency is 2π seconds . This means that your objects will have a position that always oscillates in cycles of 2π seconds and they will all be synchronized as to the wave phase.

The solution is to introduce something that makes them out of sync in phase and frequency.

Also, use FixedUpdate instead of Update . FixedUpdate has consistent time intervals and is useful for updating game logic, while Update is more for the purpose of preparing for on-screen rendering.

resulting code

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

public class Enemy4 : Nave {

    public float horizontalSpeed;
    public int yFactor;
    public float frequency;
    public float phaseOffset;
    private float count = 3;
    private Vector3 s;
    private bool setPos = false;
    private float x;
    private float y;

    void Start() {
        x = 0;
        y = 0;
        s = transform.position;
        side = Side.defside.ENEMY;
    }

    void FixedUpdate() {
        y += yFactor * Time.deltaTime;
        x = Mathf.Sin(Time.time * frequency / Mathf.PI + phaseOffset) * horizontalSpeed;
        transform.position = s + new Vector3(x, y, 0);
    }
}

The frequency value will be the number of times per second you want your object to go one full cycle on the wave (and it cannot be zero). The phaseOffset value defines the phase the object is in when the time is zero. These values, you can set a different one for each object or put some random number whatever, according to what you think is best.

Scroll to Top