2
\$\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\$
  • \$\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\$ – MichaelHouse Mar 18 '15 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 '15 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 '15 at 19:36
  • \$\begingroup\$ @AlexandreVaillancourt Do you mean if it is 2D or 3D? It's a 2D plaformer. \$\endgroup\$ – Caspert Mar 18 '15 at 19:42
  • \$\begingroup\$ I have update the question. \$\endgroup\$ – Caspert Mar 18 '15 at 20:05
10
\$\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;
}

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;
}

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

\$\endgroup\$
  • \$\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 '15 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 '15 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 '15 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 '15 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 '15 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.