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 onscreen 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.