Following off of this question , I was able to generate objects in a sine wave using the following code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateInSineWave : MonoBehaviour
{
public GameObject obj;
public float amplitude;
public float frequency;
public float alpha;
private float t;
void Start()
{
for(float i=-2*Mathf.PI;i<2*Mathf.PI;i+=1.0f) {
Instantiate(obj,transformcoords(i, amplitude*Mathf.Sin(i/frequency))+transform.position,Quaternion.identity);
}
alpha = alpha*(Mathf.PI/180);
}
Vector3 transformcoords(float x, float y) {
float x_prime = x*Mathf.Cos(alpha) - y*Mathf.Sin(alpha);
float y_prime = x*Mathf.Sin(alpha) + y*Mathf.Cos(alpha);
return new Vector3(x_prime,y_prime,0);
}
}
How may I now get one of these objects (asteroids) to move along the transformed sinusoidal trajectory? I was thinking of storing the transformed values into an array, and letting the array elements be nodes for an object to traverse on via Vector3.Lerp or Vector3.MoveTowards. But that requires checking if each node is passed - which probably isn’t done with just checking distance greater than or less than, since the nodes’ values will go up and down. Any help would be appreciated.
preserve the original position velocity and add the transformed lateral sine wave to it
or
update the original asteroid position (in a straight line) but actually place the asteroid laterally deflected from this position by the transformed lateral sine wave
You also don’t need to do a lot of monkeying around with all that crazy math.
You can turn the asteroid’s velocity 90 degrees to the right (or left) and use that normal vector to deflect it.
Vector3 velocity = ... whateter you have it as
Vector3 lateral = Quaternion.Euler( 0, 0, 90) * velocity; // 90 degrees to path
lateral.Normalize();
Vector3 offsetFromSourcePosition = lateral * Mathf.Sin( t) * deflectionAmount;
// TODO : now add offsetFromSourcePosition to the linear position of the asteroids before placing it each frame
Otherwise you could make use of the circular differentiality (is that the correct term?) of the trig functions:
d / dx of sine is cosine
d / dx of cosine is -sine
etc around the unit circle
and then you would specify the lateral movement as the differential and allow the position to “integrate” into the next function up. This means your movement must be 90 degrees out of phase with position and may be harder to reason about.
The first suggestion would require heavy reworking as I am not moving the asteroids by velocity - I am translating them. As per the second suggestion, I would have to look into the math behind that! I did not know any method like it existed.
However, I was able to attain the effect I wanted via the method I mentioned. I referenced the code in this thread as well as this tutorial on Lerping (albeit using the MoveTowards vector instead for a constant movement speed).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SinusMove : MonoBehaviour
{
public float amplitude;
public float frequency;
public float speed;
public float alpha;
private int index,posindex,nodeCount;
private Vector3[] nodes;
private Vector3 _current;
void Start()
{
nodeCount = NumOfNodes(2*Mathf.PI-(-2*Mathf.PI),Mathf.PI/8);
nodes = new Vector3[nodeCount];
Debug.Log("nodeCount="+nodeCount);
index=0;
posindex = 0;
for(float i=-2*Mathf.PI;i<2*Mathf.PI;i+=Mathf.PI/8) {
nodes[index] = transformcoords(i, amplitude*Mathf.Sin(i/frequency))+transform.position;
index++;
}
index=0; //reset index to 0
alpha = alpha*(Mathf.PI/180);
transform.position = nodes[posindex]; //posindex=0
/*
for(int j=0;j<nodes.Length;j++) {
Debug.Log("nodes["+j+"] =");
Debug.Log(nodes[j]);
}*/
_current = transform.position;
}
Vector3 transformcoords(float x, float y) {
float x_prime = x*Mathf.Cos(alpha) - y*Mathf.Sin(alpha);
float y_prime = x*Mathf.Sin(alpha) + y*Mathf.Cos(alpha);
return new Vector3(x_prime,y_prime,0);
}
int NumOfNodes(float range, float interval) {
//Debug.Log("range/interval=" +range/interval);
return (int) ((range/interval)+1); //interval should have even denominator
}
void CheckNode(int n) {
_current = nodes[n];
}
void Update() {
if(transform.position != _current) {
transform.position = Vector3.MoveTowards(transform.position,_current,speed*Time.deltaTime);
}
else {
if(_current == nodes[index]) {
index++;
if(index >=nodeCount-1) {
return;
}
CheckNode(index);
}
}
}
}
And here is the code which generates the objects. It’s a simpler version of the auto-gun in this tutorial. The individual objects are set to self-destruct after a certain time and have RigidBodies/collisions.
using System;
using System.Collections.Generic;
using UnityEngine;
public class GunAuto : MonoBehaviour
{
public GameObject bullet;
public bool autoShoot = true;
public float shootInterval = 0.5f;
public float shootDelay = 0.0f; //waits this amount before starting to shoot
public float shootTimer = 0f;
public float delayTimer = 0f;
void Update()
{
//direction = (transform.localRotation * Vector2.left);
if (autoShoot == true)
{
if (delayTimer >= shootDelay)
{
if (shootTimer >= shootInterval)
{
Shoot();
shootTimer = 0;
}
else
{
shootTimer += Time.deltaTime;
}
}
else
{
delayTimer += Time.deltaTime;
}
}
}
public void Shoot()
{
Instantiate(bullet.gameObject, transform.position, Quaternion.identity);
}
}