I have tried every way I found online to get the mouse position relative to the camera, but nothing will work. The selection tile always draws far away from the mouse. Also how would I only change the tile I am clicking on and not every tile with the same texture
Camera Class
public class Camera : Game1
{
protected float _zoom;
public Matrix _transform;
public Vector2 _pos;
protected float _rotation;
public Camera()
{
_zoom = 1.0f;
_rotation = 0.0f;
_pos = Vector2.Zero;
}
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; }
}
public void Move(Vector2 amount)
{
_pos += amount;
}
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public Matrix get_transformation()
{
_transform =
Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(_zoom) *
Matrix.CreateTranslation(new Vector3(1024 * 0.5f, 768 * 0.5f, 0));
return _transform;
}
public void Update()
{
Input();
}
protected virtual void Input()
{
KeyboardState _keyState;
_keyState = Keyboard.GetState();
if (_keyState.IsKeyDown(Keys.A))
{
_pos.X -= 5f;
}
if (_keyState.IsKeyDown(Keys.D))
{
_pos.X += 5f;
}
if (_keyState.IsKeyDown(Keys.W))
{
_pos.Y -= 5f;
}
if (_keyState.IsKeyDown(Keys.S))
{
_pos.Y += 5f;
}
}
}
Tile Class
class TileGeneration
{
public Block[] tiles = new Block[3];
public int width, height;
public int[,] index;
public Texture2D grass, dirt, selection;
bool selected;
MouseState MS;
Vector2 mousePos;
Camera camera;
public TileGeneration()
{
}
public void Load(ContentManager content, GraphicsDevice g)
{
grass = content.Load<Texture2D>(@"Tiles/grass");
dirt = content.Load<Texture2D>(@"Tiles/dirt");
selection = content.Load<Texture2D>(@"Tiles/selection");
tiles[0] = new Block { Type = BlockType.Grass, Position = Vector2.Zero, texture = grass};
tiles[1] = new Block { Type = BlockType.Dirt, Position = Vector2.Zero, texture = dirt};
width = 50;
height = 50;
index = new int[width, height];
camera = new Camera();
Random rand = new Random();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
index[x,y] = rand.Next(0,2);
}
}
}
public void Update()
{
MS = Mouse.GetState();
Matrix inverseViewMatrix = Matrix.Invert(camera.get_transformation());
Vector2 mousePosition = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
Vector2 worldMousePosition = Vector2.Transform(mousePosition, inverseViewMatrix);
mousePos = worldMousePosition;
Console.WriteLine(mousePos);
if (MS.LeftButton == ButtonState.Pressed)
{
Console.WriteLine("Selected");
selected = true;
}
}
public void Draw(SpriteBatch spriteBatch)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
spriteBatch.Draw(tiles[index[x,y]].texture, new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
if (selected && IsMouseInsideTile(x, y))
{
if (tiles[index[x,y]].texture == grass)
tiles[index[x,y]].texture = dirt;
}
if(IsMouseInsideTile(x, y))
spriteBatch.Draw(selection, new Rectangle(x * 64, y * 64, 64, 64), Color.White);
}
}
}
public bool IsMouseInsideTile(int x, int y)
{
return (mousePos.X >= x * 64 && mousePos.X <= (x + 1) * 64 &&
mousePos.Y >= y * 64 && mousePos.Y <= (y + 1) * 64);
}
Game1 Draw
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null,
camera.get_transformation());
tile.Draw(this.spriteBatch);
player.Draw(this.spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
GameComponent
that you activate in the Game1 (add it to components list) and then use statically. Same thing for all managers. In fact in most of my projects, Game1 is EMPTY, everything is done in external (often singleton) managers - NoName 2012-04-04 02:35
There may be a better way, but:
// absoluteMouseX will be the value from your MouseState, and camera will be an instance of your class
// You may need to convert your rotation to radians.
float relativeMouseX = absoluteMouseX + camera.Pos.X;
float relativeMouseY = absoluteMouseY + camera.Pos.Y;
TileGeneration.Update()
? I can't think of anything else that would yield these results - annonymously 2012-04-04 03:44
I don't have XNA right now to test it, but I recall having problems with this.
A snippet of code I have which may help:
Vector2 mouse = new Vector2(ms.X, ms.Y);
Matrix transform = Matrix.Invert(camera.ViewMatrix);
Vector2.Transform(ref mouse, ref transform, out mouse);
selectedRow = (int)(mouse.Y / Tile.SIZE);
if (selectedRow < 0) selectedRow = 0;
else if (selectedRow >= rows) selectedRow = rows - 1;
selectedCol = (int)(mouse.X / Tile.SIZE);
if (selectedCol < 0) selectedCol = 0;
else if (selectedCol >= cols) selectedCol = cols - 1;
Two things:
1. Notice how the row depends on the Y component of the Mouse, and the column on the X component.
2. Notice that it's considerably faster to directly get which tile the Mouse lays on rather than asking every single tile if it has the Mouse "inside".