将2D游戏世界坐标转换为屏幕位置

3
我有一个生成2D游戏地图块的系统。每个块都是16x16个瓦片,每个瓦片大小为25x25。
这些块被赋予自己的坐标,例如0,0、0,1等。根据它们所在的块,确定了每个瓦片在世界中的坐标。我已经验证了所有块/瓦片都显示正确的x/y坐标。
我的问题是将这些坐标转换成屏幕坐标。在之前的问题中,有人建议使用以下公式:
(worldX * tileWidth) % viewport_width
通过此计算每个瓦片的x/y,并返回屏幕的x/y坐标。
这适用于适合视口内的瓦片,但对于任何不在屏幕上的东西,它会重置屏幕的x/y位置计算。
在我的地图中,我加载玩家周围一定半径内的瓦片块,因此一些内部瓦片将不在屏幕上(直到它们移动为止,在屏幕上的瓦片位置会发生变化)。
我尝试了一个将会不在屏幕上的瓦片的测试:
Tile's x coord: 41
41 * 25 = 1025
Game window: 1024
1025 % 1024 = 1

这意味着瓷砖x(如果屏幕0,0在地图0,0处,则应位于x:1025,刚好在屏幕右侧)实际上位于x:1,出现在左上角。
我无法想出如何正确处理它 - 在我看来,我需要将 tileX * tileWidth 用于确定其“初始屏幕位置”,然后以某种偏移量确定如何在屏幕上显示它。但是什么偏移量?
更新:当玩家移动时,我已经存储了一个x/y偏移值,因此我知道如何移动地图。我可以使用这些值作为当前偏移量,并且如果有人保存游戏,我只需存储这些值并重新使用它们。不需要方程式,我只需存储累积偏移量。
2个回答

1
取模运算(worldX*tileWidth % screenWidth)导致其重置。取模(%)会给出整数除法操作的余数;因此,如果worldX * tileWidth大于screenWidth,则它将给出(worldX * tileWidth) / screenWidth的余数;如果worldX * tileWidth是screenWidth+1,则余数为1:它从该行开头重新开始。
如果您消除了取模运算,它将继续在屏幕边缘绘制瓷砖。如果您的绘图缓冲区与屏幕大小相同,则需要添加一个检查以确保仅绘制可见的瓷砖部分。
如果您想让玩家保持在屏幕中心,您需要通过玩家相对于像素点0,0的偏移量减去半个屏幕宽度来偏移每个瓷砖:
offsetX = (playerWorldX * tileWidth) - (screenWidth / 2);
screenX = (worldX * tileWidth) - offsetX;

-1
x = ((worldX*tileWidth) > screenWidth) ? worldX*tileWidth : (worldX*tileWidth)%screenWidth;

应该可以。不过我建议实现类似接口的东西,让每个瓷砖决定它们想要呈现的位置。就像这样

interface Renderable {


void Render(Graphics2D g)
  ..
}

class Tile implements Renderable{
  int x,y
   //other stuff


  Render(Graphics2D g){
   if (!inScreen()){
     return; 
    }
   //...
   //render
   }


  boolean inScreen(){
    //if the map moves with the player you need to define the boundaries of your current screenblock in terms of the global map coordinates
    //What you can do is store this globally in a singleton somewhere or pass it to the constructor of each tile.
    //currentBlock.x is then player.x - screenWidth/2
    //currentBlock.width is then player.x + screenWidth/2;
    //similar for y


    if(this.x < currentBlock.x || this.x > currentBlock.Width)
      return false;
    if (this.y < currentBlock.y || this.y > currentBlock.height)
      return false;
    return true;


   //If the map are in blocks (think zelda on snes where you go from one screenblock to another) you still need to define the boundaries
   //currentBlock.x = (player.x / screenWidth) (integer division) *screenWidth;
   //currentBlock.width = (player.x /screenWidth) (...) * screenWidth  + screenWidth;
   //same for y
   //Then perform above tests

}

你的解决方案对我来说没有太多意义:如果它在屏幕外,就让它在屏幕外绘制;如果它在屏幕上,那么进行模运算是没有任何作用的,因为你已经证明了worldXtileWidth不会大于screenWidth。三元运算符是无意义的,因为无论哪种情况,你都会得到worldXtileWidth。 - Adrian
这是正确的,但如果你向下滚动两行,你会看到备选方案,他的问题并没有真正回答他的视角是以玩家为中心还是以地图为中心,所以我提供了两种选择。 - arynaq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接