I’m developing a small gallery-shooter type game. I’d like to have an effect where when the player strikes a target, the target falls over backwards (rotates around the X axis). I can get the effect I want using a textured quad, but is there any way to do this using SpriteBatch? I’m much more comfortable there than in 3D land lol.
I tried this test code:
if(Keyboard.GetState().IsKeyDown(Keys.F1))
transform *= Matrix.CreateFromYawPitchRoll(0, .001f, 0);
if (Keyboard.GetState().IsKeyDown(Keys.F2))
transform *= Matrix.CreateFromYawPitchRoll(0, -.001f, 0);
and then in Draw:
spriteBatch.Begin(0, null, null, null, null, null, transform);
spriteBatch.Draw(ducktex, new Vector2(50, 50), Color.White);
spriteBatch.End();
Instead of falling over, the sprite just disappears slowly as I press the corresponding key. I’ve tried googling about and searching here, and found a couple of old threads, but no definitive answers. Is there any way to achieve the effect I want using SpriteBatch?
do you see any difference if you draw at layer 0.5f ?
SpriteBatch draws everything in the Z space from 0 to 1. So maybe the sprite falls out of the view when rolled.
Try to squeeze it after the roll with something like transform * CreateScale(0,0,1f/16f) and also draw it at the ‘Z-center’ (depth =0.5f)
You can just scale the height of your component by cos(rotationX). That will give the same result. If you want lighting to go with it you can’t go with SpriteBatch since it doesn’t support actual 3D.
Edit: unless you use a custom effect of course!
nkast: Yes I did initialize my transform to Matrix.Identity. The layer depth does have a little effect, but not any 3D - it just determines how fast the sprite disappears from which rotation.
willmotil: I figured I’d have to do something like shrink the bounding rect as you suggest - or actually make a spritesheet animation in something like blender. I absolutely suck at content creation tho, so I was looking for a progmatic solution. I could use a textured quad, but all the matrices scare me lol.
Your edit made me start thinking, which led to me crash-coursing youtube vids, trying to remember trig classes from 20 years ago. I assume if I did want to light the sprite, I’d just have to calculate the normal of the plane created by the rotation, pass that to whatever shader I implemented, and then light the sprite?
@archnem What kind of lighting do you want? If you just have a directional light source you can use the color parameter in SpriteBatch.Draw. For more advanced lighting you’ll need a custom shader. That will complicate things a little.
To get the normal, use n = (0, sin(rotateX), -cos(rotateX)). Make sure you rotate in the positive direction, so let rotateX go from 0 to PI/2 (direction does not matter if you’re just scaling, but it matters if you want the normal). Then for your color if you want to use a directional light source, you can use the negated dot product of the light direction with the normal multiplied with your light color (which all your sprite’s colors should be multiplied with if you’re gonna do this). In the easy case where your light direction is along the positive z-axis (so pointing directly at your sprites. The dot product will just be cos(rotateX) again.
Well if he is passing a matrix to spritebatch as he stated previously.
if (Keyboard.GetState().IsKeyDown(Keys.F2))
transform *= Matrix.CreateFromYawPitchRoll(0, -.001f, 0);
were transform is a matrix.
spriteBatch.Begin(0, null, null, null, null, null, transform);
// were this is his sprite
spriteBatch.Draw(ducktex, new Vector2(50, 50), Color.White);
spriteBatch.End();
Then transforms.Forward or -Forward is actually the normal for his 2d spritebatch quad i.e.
n = (0, sin(rotateX), -cos(rotateX)) == transform.Forward == m31,m32,m33
The quick dirty way in the spritebatch call with a couple extra steps and no effect, is…
// Realign the drawing for this specifically
Set the origin to pass to spritebatch.Draw by new Vector2(0,ducktex.Height)
Add ducktex.Height to the draw positions Y;
Rotate his transform as he showed already in his first post.
// Pass a Color to spritebatch to simulate lighting of the sprite.
// Pre-calculate light intensity on the surface.
var L = Math.Abs( Vector3.Dot(transform.Forward, Vector3.Forward) );
Color lightBlendingColor = new Color(L,L,L,255);
// were Vector3.Forward is the light direction above.
// Create a additional perspective projection matrix p. instead of passing transform to the the begin call pass transform * p
Wrap the whole thing up in a method.
The problem with this way and not using a quad directly without a spritebatch call is that each draw of this type requires a different transform be passed to begin which is terribly inefficient.