将屏幕鼠标位置转换为介于-1和1之间的本地鼠标位置

时间:2016-01-04 14:45:23

标签: c# unity3d 2d mouse game-engine

我在Unity中有一个2D平铺游戏项目,其中每个平铺块的大小(例如)为32 x 32像素,但在网格中,平铺块被映射到完整的整数坐标,因此例如tile0位于x0 y0tile1位于x1 y0tile2位于x2 y0tile10位于x2 y1,依此类推(如果我没错,这个映射是由于将精灵表中的pixel per unit size设置为例如32px,对吗?)

在任何情况下,玩家都应该能够使用鼠标向左/向右/向上/向下拖动图块,并且我希望将图块与鼠标位置一起拖动。我遇到的问题是我不知道如何将全局鼠标坐标转换为拖动图块的局部空间,特别是在-1和1之间的范围内,因为拖动距离标准化为该范围。

在我的Update()方法中,我有以下代码:

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();
        }
    }
}

代码检查拖动鼠标的方向,并在某个阈值之后切换拖动的图块与相邻的相邻网格单元格中的一个(targetCell)。我想要实现的是拖动的磁贴跟随鼠标位置,直到交换发生。

有人可以给我一个关于如何将鼠标位置转换成这个的提示,以便相应地调整拖动的平铺位置吗?

2 个答案:

答案 0 :(得分:1)

你可以在瓷砖上添加一个不可见的平面,这样你就可以使用光线投射和点击位置来玩你的瓷砖了。

考虑到所有瓷砖位置都存储在一个集合中,您可以在鼠标按下时找到最近的瓷砖。这将成为您当前的磁贴。然后你用飞机上的演员给出的位置移动它。

当鼠标位置离当前图块的初始位置太远时,您再次迭代集合以查找最近的图块位置并将图块捕捉到该新位置。您还需要更新上下文,以便现在将磁贴分配给该新位置。

伪代码会像:

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;
    }
}

我们的想法是,当您按下时,演员会找到最近的图块并分配给当前图块。

下一帧,当你按下时,它会进入第二部分,这次它看起来位置是否与PositionOutOfBound相距太远。如果足够远,您可以重用GetClosestTile。返回的tile接收sprite(我假设你使用了一个sprite用于tile),currentTile删除了sprite并将move设置为false以避免再次执行该操作。

如果距离初始图块(currentTile)不够远,则PositionOutOfBound返回false,您只需使用鼠标位置移动子画面即可。您不想移动磁贴,只想移动链接到它的精灵。

同样,这只是扩展的伪代码,但您可以轻松找到有关如何找到最接近等的示例。

答案 1 :(得分:1)

我不了解规格,但我有一个通用代码,用于拖动没有rigidbody的对象。检查您是否可以根据需要自定义此代码。

void Update ()
    {
        if (Input.GetMouseButton (0)) {

            Vector3 point = Camera.main.ScreenToWorldPoint (Input.mousePosition);

            transform.position = Vector3.MoveTowards (transform.position, new Vector3 (point.x, point.y, transform.position.z), 1);


        }

    }

此代码目前正在移动附加此脚本的GameObject,因为transform.positio代表当前GameObject's transform