3
\$\begingroup\$

I have created a 2D platform game with Unity and C# where I have collectable items that can be picked up by the player. What I want is to give the items more focus by having them bobbing up and down.

I came up with the following version:

Vector2 floatY;

public float FloatStrength; // Set strength in Unity

void Update () {
    floatY = transform.position;
    floatY.y = (Mathf.Sin(Time.time) * FloatStrength);
    transform.position = floatY;
}

But, this makes the object float in the middle of the level instead of where the object is positioned. How can I fix that?

Here is a screenshot of the prototype of the game:

enter image description here

The player can collect the wood stumps which should be bobbing up and down in space just above the ground.

\$\endgroup\$
9
  • \$\begingroup\$ Why don't you tell us what you've tried? That'll give people a starting point and makes it more likely for you to get an answer that you can use. It's likely you're looking for simple harmonic motion. \$\endgroup\$
    – House
    Mar 18, 2015 at 19:26
  • \$\begingroup\$ use a sine wave to determine the amount to move and the direction per frame and adjust the y pos on your floating object ... assuming y is up and down. This question is so vague that's about the best I can suggest without clarity. \$\endgroup\$
    – War
    Mar 18, 2015 at 19:34
  • \$\begingroup\$ @Wardy, I have update my code and I think this is what you suggest. Is that right? \$\endgroup\$
    – Caspert
    Mar 18, 2015 at 19:36
  • \$\begingroup\$ @AlexandreVaillancourt Do you mean if it is 2D or 3D? It's a 2D plaformer. \$\endgroup\$
    – Caspert
    Mar 18, 2015 at 19:42
  • \$\begingroup\$ I have update the question. \$\endgroup\$
    – Caspert
    Mar 18, 2015 at 20:05

2 Answers 2

12
\$\begingroup\$

You have a pretty simple solution. What your problem here is that you are not preserving the original y position. Essentially, you need to store the original y position in a variable, that would look like this: (Don't forget to set the variable in the Start() function.)

Vector2 floatY;
float originalY;

public float floatStrength;

void Start ()
{
    this.originalY = this.transform.position.y;
}

void Update () {
    floatY = transform.position;
    floatY.y = (Mathf.Sin(Time.time) * floatStrength);
    transform.position = floatY;
}

After that, I suggest that instead of directly setting the y value of the floatY to Mathf.Sin(Time.time) * floatStrength, you set it based on the sum of that value and the original transform position. The final code should look something like this:

Vector2 floatY;
float originalY;

public float floatStrength;

void Start ()
{
    this.originalY = this.transform.position.y;
}

void Update () {
    floatY = transform.position;
    floatY.y = originalY + (Mathf.Sin(Time.time) * floatStrength);
    transform.position = floatY;
}

Finally, instead of storing floatY as a Vector, you could store it as a float. Alternatively, you could use transform.position directly, doing something like this:

Vector2 floatY;
float originalY;

public float floatStrength;

void Start ()
{
    this.originalY = this.transform.position;
}

void Update () {
    /* Old code:
    floatY = transform.position;
    floatY.y = originalY + (Mathf.Sin(Time.time) * floatStrength);
    transform.position = floatY;
    */
    transform.position = new Vector2(transform.position.x, 
        originalY + (Math.Sinf(Time.time) * floatStrength));
}

Finally, the last step is to do some minor refactoring as to remove some errors that have popped up along the way. Math.Sin (Note: not Math.Sinf) yields a double instead of the desired float, so we have to explicitly convert that value. Next, we can remove the Vector2 floatY completely. Note that this would need to actually be a Vector3 to store transform.position, as that also has a z component, if we were to actually have kept using that. Finally, we must fix that same problem in the Update() function, and change:

    transform.position = new Vector2(transform.position.x, 
        originalY + (Math.Sinf(Time.time) * floatStrength));

to:

    transform.position = new Vector3(transform.position.x,
        originalY + (Math.Sinf(Time.time) * floatStrength), transform.position.z);

That code segment does not implement the other changes that I mentioned. In the end the complete code is as follows:

using UnityEngine;
using System;
using System.Collections;

public class FloatBehavior : MonoBehaviour
{
    float originalY;

    public float floatStrength = 1; // You can change this in the Unity Editor to 
                                    // change the range of y positions that are possible.

    void Start()
    {
        this.originalY = this.transform.position.y;
    }

    void Update()
    {
        transform.position = new Vector3(transform.position.x,
            originalY + ((float)Math.Sin(Time.time) * floatStrength),
            transform.position.z);
    }
}

Note that this code can be attached to an object either through New Object >> 2D >> Sprite and then by adding this code as a script, or through the following code programmatically:

    GameObject object = new GameObject();
    object.name = "Floating Box";
    object.AddComponent<SpriteRenderer>().sprite = SOME_SPRITE;
    object.AddComponent<FloatBehavior>();

Here's an example of what this could look like:

Sample Image illustrating code

Edit: Fixed compile errors

\$\endgroup\$
9
  • \$\begingroup\$ Thanks Pip for the answer. Unfortunately, I receive the following error: The referenced script on this Behaviour is missing!. The floated object have a box collider 2D and a Rigidbody2D. \$\endgroup\$
    – Caspert
    Mar 18, 2015 at 21:26
  • \$\begingroup\$ @Caspert can you include a screenshot of the error, a pastebin of the code, and the line number that that occurred on? \$\endgroup\$
    – Pip
    Mar 18, 2015 at 23:48
  • \$\begingroup\$ @Caspert also, I suggest removing the Rigidbody2D while keeping the box collider, as you don't actually need it in this case. If you do not have a SpriteRenderer on the object, I suggest adding one and using the image with that rather than rendering it directly. \$\endgroup\$
    – Pip
    Mar 19, 2015 at 12:18
  • \$\begingroup\$ here is the error that I receive after past your code in mine. i59.tinypic.com/2aeo41g.jpg \$\endgroup\$
    – Caspert
    Mar 19, 2015 at 19:03
  • \$\begingroup\$ @Caspert the issue here is a missing semicolon, which I have fixed. Next time, try playing around with the code before you ask a question, and then you can edit the answer as needed. \$\endgroup\$
    – Pip
    Mar 19, 2015 at 19:09
-1
\$\begingroup\$

I use this for my 3D game:

using UnityEngine;
using System;
using System.Collections;

public class BobbingEffect : MonoBehaviour
{
    float originalY;

    public float floatStrength = 1; // You can change this in the Unity Editor to 
                                    // change the range of y positions that are possible.

    void Start()
    {
        this.originalY = this.transform.position.y;
    }

    void Update()
    {
        transform.position = new Vector3(transform.position.x,
            originalY + ((float)Math.Sin(Time.time) * floatStrength),
            transform.position.z);
            transform.Rotate(0,1,0);
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ How is this solution different from the one posted 3 years ago? In fact it looks like a copy&paste from the last code snippet from the old answer, just with a transform.Rotate(0,1,0); added to it. Can you tell us what that line does and why it's an improvement? \$\endgroup\$
    – Philipp
    Feb 8, 2021 at 15:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .