I have a 2D tile game project in Unity where every tile has a size of (for example) 32 x 32 pixel but in the grid the tiles are mapped to full integer coordinate, so for example tile0
is at x0 y0
, tile1
is at x1 y0
, tile2
is at x2 y0
, tile10
is at x2 y1
, and so on (if I'm not mistaken this mapping is due to setting the pixel per unit size
in the sprite sheet to e.g. 32px, right?)
In any case, the player should be able to drag tiles left/right/up/down with the mouse and I want the tile to be dragged along with the mouse position. The problem I'm having is that I don't know how to translate the global mouse coordinate into the local space of the dragged tile, and in particular into a range between -1 and 1 because the drag distance is normalized to that range.
In my Update()
method I have this code:
if (_isMouseDown && sourceTile != null)
{
_isDraggingTile = true;
Vector3 dragDistance = Input.mousePosition - _originMousePosition;
dragDistance.Normalize();
GridCell targetCell;
/* Check mouse up/down drag. */
float f = Vector3.Dot(dragDistance, Vector3.up);
if (f >= 0.5f)
{
targetCell = sourceTile.gridCell.upNeighbor;
}
else if (f <= -0.5f)
{
targetCell = sourceTile.gridCell.downNeighbor;
}
else
{
/* Check mouse left/right drag. */
f = Vector3.Dot(dragDistance, Vector3.right);
targetCell = f >= 0.5f ? sourceTile.gridCell.rightNeighbor : sourceTile.gridCell.leftNeighbor;
}
if (Vector3.Distance(_originMousePosition, Input.mousePosition) > _globals.tileDragThreshold)
{
if (targetCell != null)
{
SetTargetTile(targetCell.tile);
ResolveMove();
}
}
}
The code checks into which direction the mouse is dragged and after a certain threshold switches the dragged tile with the one in the adjacent neighbor grid cell (targetCell
). What i'd like to achieve is that the dragged tile follows the mouse position until the swap happens.
Could anyone give me a hint on how to get the mouse position converted into this so to adjust the dragged tile's position accordingly?
You could add an invisible plane over the tiles so that you can use raycast and the hit position to play around with your tiles.
Considering all your tiles positions are stored in a collection, you can find the closest tile on mouse down. This becomes your current tile. Then you move it around with the position given by the cast on the plane.
When the mouse position gets too far from initial position of the current tile, then you iterate again the collection to find the nearest tile position and snap your tile to that new position. You also need to update the context so that the tile is now assign to that new position.
Pseudo code would go something like:
Tile currentTile = null;
bool movement = false;
void Update(){
if(Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
Physics.Raycast(ray, out hit);
currentTile = GetClosestTile(hit.position);
movement = true;
}
else if (Input.GetMouseButton(0))
{
if(movement == false){return;}
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
Physics.Raycast(ray, out hit);
if(PositionOutOfBound(hit.position) == true){
Tile newTile = GetClosestTile(hit.position);
newTile.currentSprite = currentTile.currentSprite;
currentTile.currentSprite = null;
movement = false;
return;
}
currentTile.currentSprite.transform.position = hit.position;
}
}
The idea is that when you press down, the cast finds for the closest tile and is assigned to the current tile.
Next frame, as you keep pressing, it goes for second section, this time it looks if the position is too far with PositionOutOfBound. If far enough, you can reuse the GetClosestTile. The returned tile receives the sprite (I assume you use a sprite for the tile), the currentTile gets the sprite removed and movement is set to false to avoid the action to be done again.
If you are not far enough from the initial tile (currentTile), PositionOutOfBound returns false and you simply gets the sprite to move around with the mouse position. You do not want to move the tile but just the sprite that is linked to it.
Again, this is just extended pseudo-code but you can easily find examples on how to find closest and so on.