Search Unity

Resolved How to Modify an Object's Position Relative to its Initial Spawn Position

Discussion in 'Scripting' started by DrZwieback, May 4, 2023.

  1. DrZwieback

    DrZwieback

    Joined:
    Mar 8, 2015
    Posts:
    6
    Hi all,

    First post here from someone who is new to Unity and programming. I'm having a lot of fun learning the basics based on a Flappy Bird clone project but I'm stuck with the following seeking some help. Also, I love the forum and the active community. I was able to get much help based on previous threads but not on this one I fear.

    In short, I'm trying to have an object move back and forth between two points on the y axis relative to it's original y position after instantiated. Unfortunately, the original y position gets overwritten with 0 it seems when calling the MoveVertical method (see below please).

    First, I'm instantiating prefabs in my scene through a SpawnManager class using a SpawnObstacle method on a random position between two points on the y axis. So far, so good. See code snippet below.

    Code (CSharp):
    1.     void SpawnObstacle()
    2.     {
    3.         float lowestPoint = transform.position.y - spawnableDataSO.heightOffsetObstacle;
    4.         float highestPoint = transform.position.y + spawnableDataSO.heightOffsetObstacle;
    5.         float RandomPointY = Random.Range(lowestPoint, highestPoint);
    6.         var spawnPos = new Vector3(transform.position.x, RandomPointY, transform.position.z);
    7.         var spawn = Instantiate(spawnObstaclePrefab, spawnPos, Quaternion.identity, parent);
    8.         transform.position = spawnPos;
    9.         spawn._Spawn(this);
    10.         Spawns.Add(spawn);
    11.     }

    The problem starts when I'm trying to modify the transform.position through a Spawn script which is attached to the prefab that is being instantiated. I'm trying to reference the position where the object has spawned (with Vector3 originalPosition), so I can apply a new Vector3 where y is either a Mathf.Sin or Mathf.PingPong class method with the goal to have the object move back and forth between two points on the y axis relative to it's initial spawn Position. Both Mathf methods work but the issue is that these are overwriting the original transform.position and it seems that y is declared as 0 instead of the original position. It happens instantly but can be seen nicely when adding a Coroutine where the objects spawns at the desired position on y but once the method (see below please) gets called is being reset to 0 it seems.
    In addition, moving the object from right to left works like a charm using transform.Translate.

    Code (CSharp):
    1.     void MoveVertical()
    2.     {
    3.         float newY = Mathf.PingPong(Time.time * spawnableDataSO.verticalSpeed, verticalMoveDistance) - verticalMoveDistance / 2;
    4.         Vector3 originalPosition = transform.position;
    5.         transform.position = new Vector3(transform.position.x, newY, transform.position.z);
    6.     }

    Any help on this and advice in general would be much appreciated. I guess I'm misunderstanding something fundamentally here.

    Thanks so much!

    P.S. Here is a quick screenshot of how the scene looks in case this helps visualising it.

    upload_2023-5-4_12-57-37.png
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Have you been using your Debug.log calls to find out what values everything is?
    I feel like there is something wrong with your MoveVertical method.
    What are you doing with originalPosition? It looks like a local variable that you do nothing with. What is the value of newY? Assuming this is moving something up and down like flappy bird, how are you calculating where it should be based on where it was prior?
     
    DrZwieback likes this.
  3. DrZwieback

    DrZwieback

    Joined:
    Mar 8, 2015
    Posts:
    6
    Thanks for looking into this, Brathnann, and for providing a few impulses. I did use the Debug.Log function to make sure it's not a sequence thing. Sorry for not adding the first place to give more clarity. See screenshot below now. So, the Spawn Obstacle function gets called first and the y pos in this case would be -5.69 on y but instantly afterwards gets overwritten by MoveVertical() looking at newY.

    upload_2023-5-5_8-15-47.png

    How to best solve this as in based on the spawn position have the object move back and forth on y in a selected range? I've tried to increment the transform.position.y with += but the movement gets bogus. Seems to multiply rather. I think I do misunderstand what Mathf.Sin and PingPong really do here or lack understanding how to grab the original y position.

    I've tried to grab the original position with this var and apply it. But when I do by replacing transform.position with the local original.position var, it does no longer apply the newY at all or in other words no vertical movement is happening. The obstacles spawn at the right position and then move left (separate but simple transform.Translate method). See Debug.Log below. Here it is "stuck" at the spawn y pos (in this case -3.05).

    upload_2023-5-5_8-24-27.png

    How would you approach this while also instantiating at different pos on y? More than happy to iterate here. Thanks!
     
  4. Reaktion

    Reaktion

    Joined:
    Nov 8, 2019
    Posts:
    53
    Hi,

    If I'm understanding it correctly, you're trying to move your object from spawn y location to verticalMoveDistance, back and forth.
    If you want to keep using the PingPong function, see that in documentation, the function will return a value between 0 and length. For the value to be between spawn y location and spawn y location + verticalMoveDistance, I think something like this should work :

    float newY = Mathf.PingPong(Time.time * spawnableDataSO.verticalSpeed, verticalMoveDistance) + spawnPos.y;


    Alternatively, you can try to work something your way. I'm thinking about storing a movement direction for example, and to change this direction once you reach the verticalMoveDistance.
    So in Update function, Translate your object in direction of verticalMoveDistance, at the correct speed, and right after, check if the new transform.position > spawnPos + verticalMoveDistance, then you can change direction, and check for transform.position at spawnPos too (for the back and forth movement). Don't forget to set your transform.position to the values when they are reached, to avoid your object moving past your point for a frame.

    I hope my ideas will help you to get through !
     
    DrZwieback likes this.
  5. DrZwieback

    DrZwieback

    Joined:
    Mar 8, 2015
    Posts:
    6
    Thanks for looking into this and throwing in some feedback, Reaktion.

    I've tried this but the obstacles were either flying up or down instantly. I need to dig deeper into the Mathf.PingPong function I think.

    What I did try as well though is replacing
    transform.position = new Vector3(transform.position.x, newY, transform.position.z);

    with
    transform.position += (Vector3.up * newY) * Time.deltaTime;


    This instantiates the obstacles at the desired position and these move up and down. But the movement is very off while pretty much perfect when using the code being "transform.position = new Vector3(transform.position.x, newY, transform.position.z)" which unfortunately overwrites the spawn position.

    Thanks for this. That makes a lot of sense and sounds like a clean solution. I will try to implement this unless no one else has another suggestion. I was hoping to make use of the Mathf.PingPong, but hey...
     
  6. Reaktion

    Reaktion

    Joined:
    Nov 8, 2019
    Posts:
    53
    If the behaviour is correct, it may be your verticalSpeed that is too fast. You can try to work on a smaller example to really understand how the PingPong function works, and how you can use it to your needs. This post is also a good place to start to understand the function : https://stackoverflow.com/a/61307619
     
    DrZwieback likes this.
  7. DrZwieback

    DrZwieback

    Joined:
    Mar 8, 2015
    Posts:
    6
    Thank you. That's a good read and makes things clearer. The PingPong itself works perfectly though. But when trying to run it from a predefined spawn position is where the issues starts.

    Here is what I've (naively) tried as well now:
    transform.position = new Vector3(transform.position.x, originalPosition.y + newY, transform.position.z);


    So, I add the original spawn position through originalPosition.y to newY. Now this does lead to the object instantiating at the right position and also to let it move back and forth but now the movement speed is off the charts as it seems to increment the result from Mathf.PingPong. Which makes sense.

    Anyway, beyond me for now. I guess I will try to come up with something in line with what you proposed not using Mathf.PingPong.
     
  8. DrZwieback

    DrZwieback

    Joined:
    Mar 8, 2015
    Posts:
    6
    Yeah... not my brightest moment as the solution is so easy.

    The simple mistake I did here was to not save the original aka spawn position properly in a variable in the Start() method but instead let it constantly get overwritten by putting it in the Update() method. And that's about it. :x

    Thanks for chiming in Brathnann and Reaktion!
     
    Reaktion likes this.