Sprites and Debug View Alignment (Resolved)

Topics: Developer Forum
May 14, 2012 at 3:11 PM
Edited May 14, 2012 at 3:14 PM

Hi guys,


I'm building a 2D sidescrolling platformer with Farseer 3.3.1 and GLEED2D as the level editor. Importing levels into the game works well and my camera also works... if it follows the player at the centre of the screen.


I've recently changed my code and implemented a leading camera, which also worked well if the player was in the centre of the screen. However, I don't want the player to be in the middle of the screen, I want him to be close to the bottom so that you can see any floating platforms above.


This is where there's a slight issue. I've got Farseer's Debug View overlayed on top of my level, which is displaying correctly. But something is wrong with the camera, as the locations of the sprites seem to be translated by an offset which I don't know how to fix.


What is more bizarre is the fact the locations on the X axis are fine, they are only slightly wrong on the Y axis.


With the following code it seems to be aligned (like this) but when jumping the Debug View and Sprite are no longer aligned (like this).


The Camera code:

public class Camera2d
    {
        protected float _zoom; // Camera Zoom
        Matrix _transform; // Matrix Transform
        Vector2 _pos; // Camera Position
        protected float _rotation; // Camera Rotation
        int _viewportWidth, _viewportHeight;

        public Camera2d(int ViewportWidth, int ViewportHeight)
        {
            _zoom = 1.0f;
            _rotation = 0.0f;
            _pos = Vector2.Zero;
            _viewportHeight = ViewportHeight;
            _viewportWidth = ViewportWidth;
        }

        // Sets and gets zoom
        public float Zoom
        {
            get { return _zoom; }
            set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image
        }

        public float Rotation
        {
            get { return _rotation; }
            set { _rotation = value; }
        }

        // Auxiliary function to move the camera
        public void Move(Vector2 amount)
        {
            _pos += amount;
        }
        // Get set position
        public Vector2 Position
        {
            get { return _pos; }
            set { _pos = value; }
        }

        public Matrix Transform()
        {
            _transform =       //The multiplication by 64 is the MKS in Farseer
              Matrix.CreateTranslation(new Vector3(-_pos.X * 64, -_pos.Y * 64, 0)) *
              Matrix.CreateRotationZ(Rotation) *
              Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
              Matrix.CreateTranslation(new Vector3(_viewportWidth / 2, _viewportHeight / 2, 0));
            return _transform;
        }

        public Matrix Transform2(Vector2 Position)
        {
            _transform =       //The multiplication by 64 is the MKS in Farseer
              Matrix.CreateTranslation(new Vector3(-_pos.X * 64, -_pos.Y * 64, 0)) *
              Matrix.CreateTranslation(new Vector3(0, _pos.Y, 0)) *
              Matrix.CreateRotationZ(Rotation) *
              Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
              Matrix.CreateTranslation(new Vector3(_viewportWidth / 2, (_viewportHeight / 2), 0));
            return _transform;
        }
    }

 

The Draw Code:

public override void Draw(GameTime gameTime)
        {
	ScreenManager.SpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, cam.Transform());
	level.Draw(ScreenManager.SpriteBatch);
	ScreenManager.SpriteBatch.End();

	ScreenManager.SpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, cam.Transform2(player.body.Position));
	player.sprite.Draw(ScreenManager.SpriteBatch, player.body.Position, 0, player.origin);
	ScreenManager.SpriteBatch.End();

	debugProj = Matrix.CreateOrthographic(ViewportWidth / 64, -ViewportHeight / 64, 0, 1);
	debugViewMatrix = Matrix.CreateTranslation(new Vector3(-cam.Position, 0f));
	debugView.RenderDebugData(ref debugProj, ref debugViewMatrix);
	}

 


Every Update() I do { cam.Position = targetPosition; }, where targetPosition is the green rectangle's position in the screenshots earlier.


There are 2 spritebatches with different transforms as I found that the level also moved on the Y axis when I jumped with the player. Now only the player moves in the Y axis.


I'm pretty sure I'm overcomplicating things, so my questions are: What is the offset I'm missing, and is the camera code even correct for what I'm doing?


Thanks in advance for any help!

May 14, 2012 at 6:43 PM

In Transform2 I don't get the purpose of the second translation matrix. Is it to offset the center i.e. target? But then why is it not in display units (_pos.Y*64). Also why do you pass in a Position parameter that you don't actually use? Isn't that supposed to go somewhere? It's also questionable it has the same name as a property - that's confusing. I suggest using camelCase for parameters.  Sorry if I can't help more...

May 14, 2012 at 7:05 PM

The second translation matrix in Transform2 was for testing, as was passing in the Position (which I forgot to exclude). Translating it by * Matrix.CreateTranslation(new Vector3(0, _pos.Y, 0)) actually aligns the Debug View and the Sprite when on the floor, but not when jumping.

I apologise for the code being a mess, it's been frustrating trying to get a seemingly simple issue fixed.

May 14, 2012 at 8:57 PM
Edited May 14, 2012 at 9:03 PM

Does this method do the proper scaling (i.e. is the transform2 matrix correct=the same as the debug)?

player.sprite.Draw(ScreenManager.SpriteBatch, player.body.Position, 0, player.origin);
May 14, 2012 at 9:04 PM

I think so, it does:

public void Draw(SpriteBatch batch, Vector2 pos, float rotation, Vector2 origin)
        {
                batch.Draw(t2dTexture, pos * 64, null, Color.White, rotation, origin, 1f, SpriteEffects.None, 0f);
        }
I've changed the camera to follow the player.body.Position at the centre of the screen, and that keeps everything correctly aligned. When I either change the viewport translation or have it follow something else on a different Y position, the gap between the player sprite and the ground sprite seems to expand. Like a weird vertical parallax maybe?

May 15, 2012 at 5:29 PM

I managed to fix this!

The position was slightly wrong when dividing by (int) 64. Replacing all instances in the code to " / 64f" fixed the issue.

Thanks jerrysb for your support.