Reputation: 912
So basically it's a 2D platform shooter game. And I want to draw the path of each individual bullet. There should be a white line after every bullet, and the alpha value should be decreasing from the bullet to the position that it was fired from.
How can I create such effect?
EDIT: I'm just asking for a basic method instead of detailed code. I think I might need to use particle effects to do it?
EDIT 2: Thanks! But can I change the source rectangle of gradline texture instead of scaling it?
Please correct me if I got it wrong somewhere, thanks!
Texture2D gradline should look like this:
(As far as I remember when using Math.Atan2 to find the angle of a vector, the 0 deg should be at the positive Y axis)
I'm using this method to find the degree of a vector. Since the positive Y goes down the window in the window coordinate system, I changed to -vector.Y here: (which makes more sense to me)
protected float VectorToRadians(Vector2 vector)
{
return (float)Math.Atan2(vector.X, -vector.Y);
}
And I also need to find the distance between the bullet and the position that it was fired, to determine the height of source rectangle. So I have a method like this
protected int GetRectangleHeight(Vector2 startingPos, Vector2 currentPos, int lineTextureLength)
{
float distance = (startingPos - currentPos).Length();
if (distance < lineTextureLength) // if distance is smaller than the texture length, only draw part of it
return distance;
else // if distance is larger or equal to the texture length, draw the entire texture
return lineTextureLength;
}
And finally in draw
spriteBatch.Draw(
gradline,
bulletCurrentPos,
new Rectangle(0, 0, gradline.Width, GetRectangleHeight(bulletStartingPos, bulletCurrentPos),
Color.White,
VectorToRadians(bulletCurrentPos - bulletStartingPos),
Vector2.Zero, // actually i think setting the top-center as origin might look better
1f, // full scale
SpriteEffects.None,
0f);
And when the bullet hits something and is gone, the path should still be drawn onto screen. During that time the source rectangle's y (and also height, I think, to make sure that the rectangle doesn't go out of the texture) should be changed to draw the end part of the trail only, until y reaches the height of the texture.
Upvotes: 1
Views: 870
Reputation: 8721
You can do this with an image of a line fading to transparent color. Like this:
Here is a version that will draw a trace from the center of the screen to the cursor (laser sight):
(If you want it to be drawn from someplace else, you can replace centerScreen
and cursor_v2
with your preferred Vector2, like current position of a bullet and the position from which that bullet was originally shot. For that, the code piece in the end of my answer might be best.)
Texture2D gradline; // set this var to your fading line texture in LoadContent
Vector2 centerScreen = new Vector2(
GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
Vector2 cursor_v2 = new Vector2(currentMouseState.X, currentMouseState.Y);
spriteBatch.Draw( // this is one of many Draw overloads
gradline, // your line texture
centerScreen, // we just set this to be at your game window center
null, // this means entire texture will be drawn
Color.White, // no tinting
GetAngle(centerScreen, cursor_v2), // this rotates texture, see my code below
Vector2.Zero, // texture will be drawn from screen center without offset
new Vector2(GetDistance(centerScreen, cursor_v2) / gradline.Width, 1),
// ↑ This is scaling vector, X scales texture to distance from screen center
// to cursor and then divides by the texture's length.
// See how Y is set to 1, which means texture height will not be changed.
SpriteEffects.None, // this can mirror the texture, we don't do this now
0f); // everybody leaves this zero :p
One more time without comments:
spriteBatch.Draw(gradline, centerScreen, null, Color.White, GetAngle(centerScreen, cursor_v2), Vector2.Zero, new Vector2(GetDistance(centerScreen, cursor_v2) / gradline.Width, 1), SpriteEffects.None, 0f);
My code for getting angle value: (just place it somewhere in your Game class)
public float GetAngle(Vector2 v1, Vector2 v2)
{
Vector2 v = Vector2.Normalize(Vector2.Subtract(v2, v1));
return (float)Math.Atan2(v.Y, v.X);
}
Alternatively, you can make a texture of constant length and just rotate it with this code:
spriteBatch.Draw(gradline, centerScreen, null, Color.White,
GetAngle(centerScreen, cursor_v2), Vector2.Zero, 1, SpriteEffects.None, 0f);
// look here ↑
// this Draw overload takes float value instead of Vector2 for scaling textures
// so with 1 the texture size will not be scaled
Another way is to create particles every half-second or so at positions of every bullet in the game, and after particle expires, delete it. I suspect your bullets move in lines, not in parabolas, so it's probably not worth it performance wise.
If your bullets change their direction often, you could draw their full path, but that would require drawing a list of VertexPositionColor
, which is more complex, but may give nice results.
Upvotes: 1