0

I'm trying to move multiple objects, simultaneously from Point A to Point B and back again, looped to serve as obstacles in blocking the player.

I've tried

StartCoroutine(Oscillate(OscillationFunction.Sine, 1f));
  public IEnumerator Oscillate(OscillationFunction method, float scalar)
  right = GameObject.FindGameObjectsWithTag("MovingObs2");
                foreach (GameObject r in right)
                {
                    startPos = r.transform.position;    
                    v = startPos;
                    v.x = (r.transform.position.x + (Mathf.Cos(Time.time) * scalar));
                    r.transform.position = v;
                    yield return new WaitForSeconds(2);
                    r.transform.position = startPos;
                }

and others, but they're all difficult to contain within a desirable distance and speed from the starting position. It's too fast, and too far.

and I tried a seemingly simpler line, which is easier to understand, for me.

 v.x = l.transform.position.x + speed * Time.deltaTime;
            l.transform.position = v;

but since i'm using an array in a foreach loop, i don't know how to preserve each GameObjects' transform.position, so that it can be used as a condition to reverse the direction of the objects' movement every time it reaches either Point A, or point B.

   if (l.transform.position.x <= startPos.x || l.transform.position.x >= startPos.x + endPos.x)
        {
            speed *= -1;
        }

edit: I apologize if I asked a duplicate question, I thought it was different due to the number of objects involved in an array.

Seiren
  • 55
  • 7
  • 1
    Why not just have each object take care of it's own movement with a script attached to the object instead of having a controller object trying to move all of them? – Scott Chamberlain Sep 04 '17 at 03:21
  • Any movement should be a function of `Time.deltaTime` as you have suspected –  Sep 04 '17 at 03:44
  • @ScottChamberlain I actually thought it would be easier and organized if its scripted together, but clearly I was wrong. and I was too occupied with making it work, and thank you for your comment, it was enlightening – Seiren Sep 04 '17 at 10:32

2 Answers2

1

I tried to assume to resolve all your question, please see the code below.

Time.deltaTime is not needed, since your code (and my) using the Time.time to calculate each time the position of the object.

I also would recommend (if possible) to not put all in on script, but give each object a swing script and also try to not use the CoRoutine. But to answer your question I show you how to do it.

I have created an internal class, to store in the "Init" the targeted gameobjects and their startPosition in a list. Later you can simply loop throu this list and always have the start position.

You need an endless loop in the "Osciallate" routine and need to wait each turn. In your example you put the Wait on the wrong place, so it waits after moving each object and stops after the first run throu all of this objects.

Here the code:

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

public class OscilateObs : MonoBehaviour {

    // internal class where all gameobjects and their startposition will be saved
    internal class OscGameObjects
    {
        public GameObject gameObject;
        public Vector3 startPosition;
    }

    // Here the information of all gameObjects stored in a list
    private List<OscGameObjects> objectList;

    public float updateSpeed = 0.05f;
    public float oscScalar = 2f;

    public enum OscillationFunction {
        Sine = 1
    }

    void Start () {
        // First, the gameobjects have to saved to our internal List
        InitializeOscGameObjects();

        // Start the Corotine
        StartCoroutine(Oscillate(OscillationFunction.Sine, oscScalar));
    }

    private void InitializeOscGameObjects()
    {
        var objects = GameObject.FindGameObjectsWithTag("MovingObs2");

        objectList = new List<OscGameObjects>();
        foreach (var o in objects)
        {
            var oscObject = new OscGameObjects();
            oscObject.gameObject = o;
            oscObject.startPosition = o.transform.position;

            objectList.Add(oscObject);
        }
    }

    public IEnumerator Oscillate(OscillationFunction method, float scalar)
    {
        // Loop forever
        while(true)
        {
            foreach (var element in objectList)
            {
                var currentPosition = element.gameObject.transform.position;
                currentPosition.x = element.startPosition.x + Mathf.Cos(Time.time) * scalar;
                element.gameObject.transform.position = currentPosition;

            }
            yield return new WaitForSeconds(updateSpeed);
        }

    }

}

EDIT:

I forgot to meantion:

1) I would recommend to use "Animation" Component for the movement and not using C# at all, so you can change the behaviour if needed and you are more flexible.

2) I would also recommend if possible to make a parent "GameObject" and moving only this and put the "MovingOb2" simply as child objects.

EDIT2:

Adding a delay increment for each object, so they not running syncron:

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

public class OscilateObs : MonoBehaviour {

    // internal class where all gameobjects and their startposition will be saved
    internal class OscGameObjects
    {
        public GameObject gameObject;
        public Vector3 startPosition;
        public float waitCount;
    }

    // Here the information of all gameObjects stored in a list
    private List<OscGameObjects> objectList;

    public float updateSpeed = 0.05f;
    public float oscScalar = 2f;
    public float waitIncrementTime = 0.01f;

    public enum OscillationFunction {
        Sine = 1
    }

    void Start () {
        // First, the gameobjects have to saved to our internal List
        InitializeOscGameObjects();

        // Start the Corotine
        StartCoroutine(Oscillate(OscillationFunction.Sine, oscScalar));
    }

    private void InitializeOscGameObjects()
    {
        var objects = GameObject.FindGameObjectsWithTag("MovingObs2");

        objectList = new List<OscGameObjects>();

        float i = 0;
        foreach (var o in objects)
        {
            i += waitIncrementTime;
            var oscObject = new OscGameObjects();
            oscObject.gameObject = o;
            oscObject.startPosition = o.transform.position;
            oscObject.waitCount = i;
            objectList.Add(oscObject);
        }
    }

    public IEnumerator Oscillate(OscillationFunction method, float scalar)
    {
        // Loop forever
        while(true)
        {
            foreach (var element in objectList)
            {
                var currentPosition = element.gameObject.transform.position;
                currentPosition.x = element.startPosition.x + Mathf.Cos(Time.time + element.waitCount) * scalar;
                element.gameObject.transform.position = currentPosition;

            }
            yield return new WaitForSeconds(updateSpeed);
        }

    }

}
  • Thank you, I'm looking into it right now, thank you so much, i wouldn't have been able to fix it myself. i hadn't realized i put the wait function at the wrong place. and i was wondering why it would move erratically too. – Seiren Sep 04 '17 at 10:36
  • Hi Seiren, thank you and nice to hear it works. Please do not forget to mark this as correct answer, if this fits your question. If you need something else, please let me know. – Christian Müller Sep 04 '17 at 12:20
  • Thank you so much, Christian! You were a big help. If it's no trouble, I would like to ask, in executing transform.position for the list, how do i delay the start in increments? for example, object 1 will move 0.1 second after block 1, and object 3 will start moving after block 2, and so on. – Seiren Sep 04 '17 at 17:59
  • I added now a delay increment and hope this it was you want to have. They start all the same time, but from different position, which make them moving asychronos. I hope this it what you wanted to have – Christian Müller Sep 04 '17 at 21:08
  • Thank you so much! I have a long way to go in discovering logic works in programming, and you have taught me a great deal, I truly appreciate it!! – Seiren Sep 04 '17 at 21:40
  • I am happy that I could help you :) Please also try out to make it without coding and "Animation" since I would prefer this way, because then unity is doing this job for you in a more optimized way. – Christian Müller Sep 04 '17 at 21:44
  • Ohh, I see. I will try that! I'm trying to learn as much as I can at the moment – Seiren Sep 04 '17 at 21:50
0

they're all difficult to contain within a desirable distance and speed from the starting position. It's too fast, and too far

Before you start monkeying with the structure of your code, I suggest you stick with the cosine function but educate yourself on the (very simple) manner in which you can manipulate output frequency and amplitude. This knowledge will serve you well (if this question is typical of your average project) and will solve the problem trivially.

If it's too fast, you can reduce the frequency (or increase the wavelength/period) by multiplying the input (which is always absolute time) by a constant coefficient between 0.0 and +1.0 (not inclusive).

If it's too far, you can reduce the amplitude by multiplying the output by a constant coefficient between 0.0 and +1.0 (not inclusive).

You just need to pick two constants and adjust to taste by running the program and seeing how you like it.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • Thank you so much for the explanation, it gave me a little more insight on how it works. I'm still trying to grasp on how the mathematical functions work. – Seiren Sep 04 '17 at 10:30