I'm making a game in C# and XNA 4.0. In some levels I need a camera matrix to make the level appear to scroll left/right. Additionally, I also need a scaling matrix to scale the graphics when the settings are used to change the window size. Both of my matrices are functional, but I'm currently calling them in the draw method like this:
if (scrollingLevel)
{
//Use the camera matrix to make the stage scroll
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, camera.transform);
}
else
{
//Use the scaling matrix to scale the graphics
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, transform);
}
What I want is to apply both matrices at the same time if it is a scrolling level (scale the graphics based on the window size and then use the camera matrix to make the level scroll). However, simply adding and multiplying the matrices does not produce an accurate result (adding prevents the graphics from scaling to the exact amount that they should and multiplying makes the camera scroll inaccurately). How can I apply both of the matrices at once?
Simply multiply the matrices before passing to spriteBatch.Begin.
Matrix multiplication allows the effects of both matrices appended into a single matrix. Note that this operation is not commutative, meaning that A * B != B * A.
In your case, you should probably multiply scaling matrix with the camera matrix.
Related
I have a 3D scene of which I want to draw a specific region onto a larger canvas/viewport (think like a magnifying glass).
Something like the following image:
I want to maintain any perspective effects, simply moving my camera to the specified region wouldn't give that effect.
I gathered from http://www.mvps.org/DirectX/articles/tilerender/index.htm that it's possible to do some trickery with the Projection Matrix but I couldn't figure out the math behind getting a more specific subsection/region than what is described in that article.
If we assume the coordinates described in the article, x0y0 would be the exact center of the scene, x-1y1 would be the top-left and x1y-1 would be the bottom-right of the scene.
I would, for example, want to render the region ranging from x-0.75y0.75 to x-0.25y0.25.
I have a Projection matrix and a View matrix separately available. I am using the SharpDX library and my Projection matrix is Right-Handed(which seems the flip the y-coordinates described above).
How do I calculate the Scale/Translation matrices that I need to multiply my Projection matrix with? Or, alternatively, what other ways are there to tackle this issue?
Psuedo-code would be something like this:
public Matrix GetProjectionRegion(float topLeftX, float topLeftY, float bottomRightX, float bottomRightY)
{
var magicMatrix = Matrix.Identity;;
//some magic
return magicMatrix;
}
ProjectionMatrix *= GetProjectionRegion(-0.75f, 0.75f, -0.25f, 0.25f);
EDIT:
I am currently creating my Projection matrix using one of two methods:
ProjectionMatrix = Matrix.PerspectiveFovRH(FOV, Width / Height, NearPlane, FarPlane);
or
ProjectionMatrix = Matrix.OrthoOffCenterRH(_topLeft.X, _bottomRight.X, _topLeft.Y, _bottomRight.Y, NearPlane, FarPlane);
Nearplane is 75 farplane is 5000000; Width/Height/_topLeft/_topRight are all pixel formats as far as I remember.
The matrices are used Row-Major.
If you really want to do a very basic mechanism for zooming in, you could cheat with your camera matrix, that is the "World" in your world view projection matrix.
The zoom could be tackled through proximity to the location. Nothing more. BUT, if you are determined, you could also scale that World matrix also, which would then enlarge all objects, therefore effectively zoom.
I am creating a 2D Top-Down RPG game like the Legend of Zelda: A link to the past.
when the player is drawn i want to update the tree depth so that it is over and under the player when the player Y position is higher or lower than the trees Y position, i think whether the tree is on top or not should be decided by the players Y position, being lower or higher. is it possible to do this in this way? can i change the layer depth in the update method?
I'm not sure you can. i'm not very experienced when coding. If there's a right way of doing this even without useing the spriteBatch layer depth i would appreciate any help.
I have discovered how to use the layer depth in the
spriteBatch.Draw();
Method.
What i am attempting to do is shown in the images below
The code i am using to separate trees from grass tiles uses layer depth like below:
spriteBatch.Begin(SpriteSortMode.FrontToBack, blendState = null, samplerState = null, DepthStencilState.DepthRead);
spriteBatch.Draw(tree, treePos, null, null, Vector2.Zero, 0, null, Color.White, SpriteEffects.None, 0.6f);
spriteBatch.End();
Tile draw method for the
tile
has the float value set
0.5f
Here's a way to do it:
Slice your sprites and do tile-based rendering, starting from the ground up to the sky.
Say you have a tile grid whose each is 32*32 pixels, if you have a tree that is 32*96 pixels, then when sliced it will be like:
A // layer 2
A // layer 1
A // layer 0 (floor)
Logic:
draw all tiles on floor 0
draw all tiles on floor 1
etc ...
Then obviously the part that should hide your player will be drawn correctly (before, if player is behind).
(note that the lowest tile of the tree should not be walk-able)
I have a 2D tower defense game I'm making and I want my sprites to scale to the screen size. So someone suggested using a matrix. So I tried to use one but I don't really know how to use it and how it works. So, how would I create a matrix and use it to scale 2D sprites in monogame. Thank you!
you can scale SpriteBatch using matrix, could be used to zoom in/out to affect whole screen.
ScalingFactor = new Vector3(widthScaling, heightScaling, 1);
Scale = Matrix.CreateScale(ScalingFactor);
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null,null, Scale);
I have a small game level laid out with a cartesian coordinate system. I have a camera class that I want to translate all of the points from cartesian space to isometric space using this matrix:
[cos(45), sin(45)]
[-sin(45), cos(45)]
On paper, multiplying any vector by the matrix successfully puts that vector into the isometric space after the first rotation.
Right now, I am only able to get the level to draw according to the cameras position using this matrix:
public Matrix GetTransformation()
{
_mTransform =
Matrix.CreateTranslation(-Position.X, -Position.Y, 0);
return _mTransform;
}
Where I am confused is where the matrix I listed above fits into that equation.
CameraIso2D takes no parameters, but here is the Draw function
public void Draw(SpriteBatch sb)
{
// Start drawing from this GameLayer
sb.Begin(
SpriteSortMode.FrontToBack,
BlendState.AlphaBlend,
null,
null,
null,
null,
_transformation);
// Draw all contained objects
foreach (DrawableGameObject dgo in _drawableGameObjects)
dgo.Draw(sb);
// End drawing from this GameLayer
sb.End();
}
_transformation is the matrix _mTransform returned from CameraIso2D every update
I solved this by using two matrices. The first matrix uses the regular camera transformation and is passed into spriteBatch.Begin as the transformation matrix. For the isometric transformation matrix, I used Matrix.CreateRotationZ to mimic the isometric Y axis rotation, and then I used Matrix.CreateScale to mimic the isometric rotation down from the Y axis. GameObjects need a position for cartesian coordinates, and a vector2 for their isometric coordinates. Pass the GameObject's cartesian coordinates through the isometric transformation matrix to get the isometric coordinates, and then draw to that location.
How can I render text in the form of an isometric projection? I understand the principle but I'm not sure how to actually transform a SpriteFont programmatically to do this.
Example of what I mean:
I'm not even sure what I should be searching for. It seems I could accomplish this by using an isometric projection matrix and a 3D mesh font, but that seems overcomplicated considering I'm working in 2D.
Any ideas?
SpriteBatch.Begin takes a Matrix parameter, transforming the sprites you draw (including SpriteFont) onto whichever plane you desire.
Unfortunately Matrix does not provide Create* methods for creating skew matrices. But it is simple enough to create such a matrix by hand. The following piece of code is tested and is pretty close to what you want:
Matrix skew = Matrix.Identity;
skew.M12 = (float)Math.Tan(MathHelper.ToRadians(36.87f));
Matrix rotate = Matrix.CreateRotationZ(MathHelper.ToRadians(270+26.565f));
sb.Begin(SpriteSortMode.Deferred, null, null, null, null, null, skew * rotate);
// ... draw your sprites here ...
sb.End();
The only difference to your diagram is that Y and Y' point in the opposite direction, because XNA's SpriteBatch works in "client" coordinates ((0,0) at top left, and Y+ is down).
You can use a matrix transformation together with a sprite batch to achieve this. You can read more about matrix translation here.