1
\$\begingroup\$

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: enter image description here

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: enter image description 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!

\$\endgroup\$
  • \$\begingroup\$ I'm pretty certain Don't Starve is a 3D game. It uses bilboarding for the 'sprites'. This is way easier to achieve that way than using 2D spritebatches. \$\endgroup\$ – Felsir Apr 7 '16 at 5:06
  • \$\begingroup\$ Both games I know wich uses this technique (Don't Starve and Realm of the mad god) have a 3d engine under the hood but achieves the 2d feel and look with ortographic projection and 2d planes wich are always facing the camera, as @Felsir said. You can achieve the same with 2d, but you need to only rotate the positions around a point and not the whole image and sprites. \$\endgroup\$ – Bálint Apr 7 '16 at 8:55
  • \$\begingroup\$ Hey, thank you for your input, I will look into Billboarding! @Bálint How would I do this? \$\endgroup\$ – shniqq Apr 7 '16 at 9:11
  • \$\begingroup\$ You rotate the positional vectors of the caracthers with a viewMatrix (if you have) and then a rotationMatrix. Then you ritate the terraib. \$\endgroup\$ – Bálint Apr 7 '16 at 9:13
  • \$\begingroup\$ No, rotate the position around a point.. My first guess is to use a translation Matrix with CreateRotationX or something like that.. But I guess Billboarding is the easier way anyway? \$\endgroup\$ – shniqq Apr 7 '16 at 9:18
0
\$\begingroup\$

If your camera is always facing the same direction (let's say north) and just pans in the horizontal plane, use quads in a 3D plane to draw your scene. Since the camera is not rotating, you don't need to change the facing of your quads, just put them in the right spot in your 3D scene. Note the camera is orthogonal for the effect.

If the camera is not fixed into a direction, you may want to use billboard technique to draw the scene. This means you need to rotate each quad to face the camera. Have a look at the Matrix.CreateBillboard method for the rotation.

\$\endgroup\$

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.