3
\$\begingroup\$

I am trying to apply a slight sine wave movement to objects that float around the screen to make them a little more interesting. I would like to apply this to the objects so that they oscillate from side to side, not front to back (so the oscillation does not affect their forward velocity).

After reading various threads and tutorials, I have come to the conclusion that I need to create and add vectors, but I simply cannot come up with a solution that works.

This is where I'm at right now, in the object's update method (updated based on comments):

Vector2 oldPosition = new Vector2(spritePos.X, spritePos.Y);

//note: newPosition is initially set in the constructor to spritePos.x/y
Vector2 direction = newPosition - oldPosition;

Vector2 perpendicular = new Vector2(direction.Y, -direction.X);

perpendicular.Normalize();

sinePosAng += 0.1f;
perpendicular.X += 2.5f * (float)Math.Sin(sinePosAng);

spritePos.X += velocity * (float)Math.Cos(radians);
spritePos.Y += velocity * (float)Math.Sin(radians);

spritePos += perpendicular;

newPosition = spritePos;
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

EDIT: Based on the discussion in the comments and your updated code, I suggest you try doing something like this:

// oldPosition is a member variable, it holds the real position of the
// object (without the "wobble" applied).
Vector2 newPosition = oldPosition;
newPosition.X += velocity * (float)Math.Cos(radians);
newPosition.Y += velocity * (float)Math.Sin(radians);

// This gives us a vector from the old position to the new position, indicating
// the direction our object is moving.
Vector2 direction = newPosition - oldPosition;

// We normalize the perpendicular vector so that we can scale it reliably later.
Vector2 perpendicular = new Vector(direction.Y, -direction.X);
perpendicular.Normalize();

float offset = 5.0f * (float)Math.Sin(sinPosAng);
sinPosAng += 0.01;f

// By keeping spritePos independent from oldPosition, we allow the wobble to visually
// affect the object without logically affecting it's real location; this prevents
// the wobble from feeding back on to itself.
spritePos = newPosition + (offset * perpendicular);

// For the next frame, the old position will be what is currently the new position.
oldPosition = newPosition;

If you have a perpendicular vector and you normalize it, you can then scale it by the result of Math.Sin(sinePosAng) and then scale it again to achieve the desired total offset, which you then add to the new position. The purpose of the normalization is to ensure the scale is reliable each frame -- you know the length of the vector before you scale it, so you know the results will be exactly what you expect.

The other thing you'll want to watch out for is that you may want to the old/new positions distinctly from the offset position (after the "wobble" is applied) -- this is because otherwise the "wobble" applied on frame N will factor in to the computation of the direction vector on frame N + 1 and if the scale of the wobble is large enough, you're object may start to curve in an undesired fashion. In the example above, I assume that both oldPosition and spritePos are member variables -- spritePos will contain the location of the sprite (which has the wobble applied), but oldPosition contains the un-wobble'd position.

\$\endgroup\$
6
  • \$\begingroup\$ What do you mean by normalizing the vector? I looked around for information and found some methods for normalizing, but they only seem to shrink the vector down to 1 unit in the direction it's pointing (i.e. XNA's Vector2.Normalize). Also, what should I do with the perpendicular vector after it is normalized? \$\endgroup\$ Feb 2, 2011 at 2:37
  • 1
    \$\begingroup\$ Normalizing a vector scales it such that it becomes unit length, as you note. This is a useful property for a lot of reasons, in this case it allows us to ensure that we always offset the sprite by a fixed amount (whatever the scale factor is). If you didn't normalize, the actual offset would be proportional to both the scale factor and the length of the direction vector. \$\endgroup\$
    – user1430
    Feb 2, 2011 at 2:43
  • 1
    \$\begingroup\$ Once you have the normalized perpendicular, scale it by whatever offset you desire that represents how far to "wobble" the sprite. This will probably be something like 2.0f * Math.Sin(sinePosAng). Then render the sprite at newPosition + scaledPerpendicular. \$\endgroup\$
    – user1430
    Feb 2, 2011 at 2:44
  • \$\begingroup\$ How would I scale a vector by the offset? Scale it's x/y independently? Also, strangely, when I normalize the perpendicular vector, it makes the sprites sit at 0, 0 with no movement. I've updated the original post with the current code. If I comment out the perpendicular.Normalize(); line, the sprites render at the correct location with oscillation on the X axis. \$\endgroup\$ Feb 2, 2011 at 2:59
  • 1
    \$\begingroup\$ Scaling vector by a scalar (float, in this case) value just means to multiple the scalar value by both the X and Y components. XNA's vector classes have overloads for this, so you can do (float * Vector2) and it will do the proper scaling. I've updated my code in response to your changes; I think part of your problem has to do with initializing newPosition once in the constructor. You also don't want to scale just the X component of the perpendicular. \$\endgroup\$
    – user1430
    Feb 2, 2011 at 3:47

You must log in to answer this question.

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