for a university project we are creating a small "2d" game. Im writing 2D in "" because we would like to achieve a look similiar to the one in games like Don't Starve (so more like 2.5D).
As you might see, all the characters, trees, etc. are always drawn facing the camera. Because we are working with monogame/xna, spritebatch is pretty much the way to go there.
We use the following code to draw our WorldObjects:
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, currentCamera.CompleteMatrix);
//spriteBatch.Draw(texture, objectRectangle, Color) <- this works perfect and as intended:
//if we move the cameraPosition the sprites move accordingly.
Now on to our problem: We (of course) don't want the ground also to always face the camera, but instead to be looked at an slight angle of let's say 45 degrees. Spritebatch doesn't directly let us do so, but the aforementioned .Begin()-Method takes a Effect (in our case a BasicEffect) as well. This should us in theory allow to draw in 3D with spritebatch (or am I getting something completely wrong here?).
Our drawing-code for the ground looks like this:
BasicEffect effect = new BasicEffect(Resources.graphicsDevice);
Matrix projection = Matrix.CreateOrthographicOffCenter(0, Resources.graphicsDevice.Viewport.Width, Resources.graphicsDevice.Viewport.Height, 0, -1000, 100000);
Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
effect.World = currentCamera.Translation * Matrix.CreateRotationX(0) * currentCamera.Scale * currentCamera.TransformToScreencenter;
effect.View = Matrix.Identity;
effect.Projection = halfPixelOffset * projection;
effect.TextureEnabled = true;
effect.VertexColorEnabled = true;
Resources.spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, effect, null);
The code above is from a blog post of Shawn Hargreaves at msdn on how to use BasicEffect with SpriteBatch (not allowed to post more links here :/ ). It just mimics the standard spritebatch effect for drawing in 2D. I modified it slightly to fit how we implemented our camera. The code for the Cameraclass is the following:
public Matrix CompleteMatrix
{
get
{
return Translation * Matrix.CreateRotationX(0f) *
Scale *
TransformToScreenCenter;
}
}
public Matrix Translation
{
get
{
return Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0));
}
}
public Matrix Scale
{
get
{
return Matrix.CreateScale(new Vector3(2, 2, 1));
}
}
public Matrix TransformToScreenCenter
{
get
{
return Matrix.CreateTranslation(new Vector3(Resources.graphicsDevice.Viewport.Width * 0.5f,
Resources.graphicsDevice.Viewport.Height * 0.5f, 1f));
}
}
Now the question is: How can we achive this "tilted ground"-effect using the BasicEffect? I already tried things like using
Matrix.CreateLookAt(new Vector3(cameraPos.X, cameraPos.Y, 1f), new Vector3(cameraPos.X, cameraPos.Y - 1f, 0f), Vector3.Up)
and apply it to effect.View. But this didn't resulted in the way I expected it to (drawing the ground at an certain angle). I also tried applying a Matrix.CreateRotationX(MathHelper.ToRadians(30)) to our WorldMatrix, but this didn't gave me the desired effect eihter.
Is it just not possible (which I'm shure isn't the case)? Or am I getting something horribly wrong here (which is what I think is the problem)?
If some information is missing, i can provide more code or what ever is needed.
Edit: I looked into Billboards as mentioned in the comments: It looks like a very good solution, but would break all collisiondetection and mechanics we already implemented. So I experimented a little bit more with spritebatch, and came up with the following:
I used the following Matrix for the spriteBatch.Begin() overload:
public Matrix CompleteMatrix
{
get
{
return Translation * Matrix.CreateRotationX(45) * Matrix.CreateRotationY(-45) * Scale *
TransformToScreenCenter;
}
}
Problem now: We don't want the gameobjects (in this case trees and characters) to "lay down flat" like the background does. I can achieve this, if I apply the same CompleteMatrix into a new spriteBatch.Begin() call (and draw all gameobjects after this begin call) but change the rotation around the X-axis to 0 (of course). But now if I move the camera/player down (along the Y-axis), the background moves at a different speed than the game objects and the gameobjects' positions are no more aligned with their expected positions relative to the background (because I removed the rotation around the X-axis).
See here:
I think I'm on the right track but missing something small yet crucial here.. My question now is how can I combine the correct alignement of the background and foreground but still getting the foreground to be drawn "normal" like with the standard spritebatch.Draw call? Any links or advice is very much appreciated!