简体   繁体   English

基于网格的游戏中的负坐标

[英]Negative coordinates in a grid based game

I have written a small 2D game in javascript that uses a grid where the player starts at position [0,0] and can move an almost infinite distance in either direction. 我已经用JavaScript编写了一个小型2D游戏,它使用一个网格,玩家在位置[0,0]处开始,可以在任一方向上移动几乎无限的距离。

Now I want to implement A* pathfinding, but I'm having some problems finding the best way to store the world with all it's different obstacles, enemies and terrain. 现在,我想实现A *寻路,但是在寻找一种最佳的存储世界的方式时遇到了一些问题,该世界具有所有不同的障碍,敌人和地形。 This is what I have tried or thought about so far. 到目前为止,这是我尝试过或考虑过的。

Array of arrays 数组数组

Here I store the world in an array of arrays [x][y] . 在这里,我将世界存储在数组[x][y]

var world = [[]];
world[312][11] = 0;
world[312][12] = 0;
world[312][13] = 1;
world[312][14] = 1;
...

This works great with A* pathfinding! 这对于A *寻路非常有用! It's easy and very fast to access a specific coordinate and populate the world. 访问特定坐标并填充世界非常容易且非常快捷。 In the example above I just store passable (0) or impassable (1) terrain, but I can store pretty much whatever I want there. 在上面的示例中,我仅存储通行(0)或不通行(1)地形,但是我可以在此处存储几乎任何内容。 However, this doesn't work very well with negative coordinates like if my players is at [-12][-230] . 但是,这对于负坐标不太适用,例如我的玩家在[-12][-230] Negative keys in a javascript array isn't actually part of the array, they won't be included in world.length or world[3].length and from what I understand, it's overall bad practice and might have some impact on the performance as well. javascript数组中的负键实际上不是数组的一部分,它们不会包含在world.lengthworld[3].length ,据我所知,这是一个整体不良做法,可能会对性能产生一些影响也一样 I read somewhere that if you are using negative keys in your array, you are doing it wrong. 我在某处读到,如果您在数组中使用否定键,那么您做错了。 I would still not pass the entire world into the A* function for obvious reasons. 由于明显的原因,我仍然不会将整个世界传递给A *函数。 Just a small part close to my player, but the coordinates would correspond to the positions in the array which is easy to work with. 只是靠近玩家的一小部分,但坐标将对应于数组中易于使用的位置。

A separate array of arrays just for A* pathfinding 单独的数组数组,仅用于A *寻路

This is where I'm at right now. 这就是我现在所在的位置。 I have a separate 50x50 grid called pathMap = [[]] , that is only used for pathfinding. 我有一个单独的50x50网格,称为pathMap = [[]]用于寻路。

var pathMap = [[]];
pathMap[0][0] = 0;
pathMap[0][1] = 0;
pathMap[0][2] = 1;
pathMap[0][3] = 1;
...

It starts at pathMap[0][0] and goes to pathMap[50][50] and is working as an overlay on my current position where I (as the player) will always be in the center position. 它从pathMap[0][0]开始, pathMap[0][0] pathMap[50][50]并作为我当前位置的叠加层,我(作为玩家)将始终位于中心位置。 My real coordinates may be something like [-5195,323] , but it translates to pathMap[25][25] and everything close to me is put on the pathMap in relation to my position. 我的真实坐标可能类似于[-5195,323] ,但是它转换为pathMap[25][25] ,与我近的一切都与我的位置有关。 Now this works, but it's a huge mess. 现在可以用了,但是很乱。 All the translations from one coordinate to another back and forth makes my brain hurt. 从一个坐标到另一个坐标的所有翻译都使我的大脑受伤。 Also, when I get the path back from A*, I have to translate each step of it back to the actual position my element should move to in the real world. 另外,当我从A *获得路径时,我必须将其每一步都转换回我的元素在现实世界中应该移动到的实际位置。 I also have to populate the same object into 2 different grids every update which hurts performance a bit as well. 每次更新时,我还必须将同一对象填充到2个不同的网格中,这同样会损害性能。

Array of objects 对象数组

I think this is where I want to be, but I have some issues with this as well. 我认为这是我想要的地方,但是与此同时我也有一些问题。

var world = [];
world[0] = { x: -10, y: 3, impassable: 0 };
world[1] = { x: -10, y: 4, impassable: 0 };
world[2] = { x: -10, y: 5, impassable: 1 };
world[3] = { x: -10, y: 6, impassable: 1 };
...

Works great with negative x or y values! 负x或y值非常有用! However, it's not as easy to find for instance [10,3] in this array. 但是,在此数组中查找例如[10,3]并不容易。 I have to loop through the entire array to look for an object where x == 10 and y == 3 instead of the very easy and fast approach world[10][3] in the first example. 我必须遍历整个数组以查找x == 10y == 3的对象,而不是第一个示例中非常简单快速的方法world[10][3] Also, I can't really rely on the coordinates being in the right order using this version, sorting becomes harder, as does other things that was a lot easier with the array of arrays. 另外,使用此版本时,我不能真正依靠正确的坐标来进行排序,因此排序变得更加困难,因为使用数组数组,其他事情要容易得多。

Rebuild the game to always be on the positive side 重建游戏,使其始终处于积极的一面

I would prefer not to do this, but I have considered placing the players starting position at something like [1000000,1000000] instead, and making negative coordinates off limits. 我不希望这样做,但是我已经考虑过将玩家的起始位置放在[1000000,1000000]类的位置,并使负坐标超出限制。 It seems like a failure if I have to remove the vision I have of endlessness just to make the pathfinding work with less code. 如果我不得不删除我无休止的愿景只是为了用更少的代码来使寻路工作看起来似乎是一个失败。 I know there will always be some upper or lower limits anyways, but I just want to start at [0,0] and not some arbitrary coordinate for array related reasons. 我知道总会有一些上限或下限,但是出于数组相关的原因,我只想从[0,0]开始,而不是一些任意坐标。

Other? 其他?

In javascript, is there another option that works better and is not described above? 在javascript中,还有没有更好的选择,并且上面没有描述? I'm very open to suggestions! 我很乐意提出建议!

Is there a best practice for similar cases? 是否有针对类似案例的最佳实践?

You have three coordinates system you must distinguish : 您必须区分三个坐标系:

  • the world coordinates. 世界坐标。
  • the world model / path-finding (array) coordinates. 世界模型/寻路(数组)坐标。
  • the screen coordinates. 屏幕坐标。

The screen coordinates system depends upon : 屏幕坐标系取决于:

  • the viewport = the canvas. 视口=画布。 (width, height in pixels). (宽度,高度(以像素为单位))。
  • a camera = (x,y) center in world coordinates + a viewWidth (in world coordinates). 摄像头=(x,y)在世界坐标中的中心+ viewWidth(在世界坐标中)。

To avoid headaches, build a small abstraction layer that will do the math for you. 为避免头痛,请构建一个小的抽象层来为您做数学。

You might want to use Object.defineProperty to define properties, that will provide a fluent interface. 您可能要使用Object.defineProperty定义属性,以提供一个流畅的界面。

var canvas = ... ;
var canvasWidth = canvas.width;
var canvasHeigth = canvas.heigth;


var world = {
              width  : 1000,  // meters
              height : 1000,  // meters
              tileSize : 0.5,   // height and width of a tile, in meter
              model  : null,  // 2D array sized ( width/tileSize, XtileSize )
             };
// possibles world coordinates range from -width/2 to width/2 ; - height/2 height/2.

 var camera = {
                 x : -1,
                 y : -1,
                 viewWidth : 10, // we see 10 meters wide scene
                 viewHeight : -1 // height is deduced from canvas aspect ratio
              };
camera.viewHeight = camera.viewWidth * canvasWidth / canvasHeight ;

Then your character looks like : 然后您的角色看起来像:

// (x,y) is the center of the character in centered world coordinates
// here (0,0) means (500,500) world coords
//                  (1000,1000) array coords
//                  (320, 240) screen coords in 640X480
function /*Class*/ Character(x, y) {
     var _x=x;
     var _y=y;
     var _col=0;
     var _row=0;
     var _sx=0.0;
     var _sy=0.0;         
     var dirty = true;
     Object.defineProperty(this,'x', 
                              { get : function() {return _x; } 
                                set : function(v) { _x=v; 
                                                    dirty=true; } });
     Object.defineProperty(this,'x', 
                              { get : function() {return _y; } 
                                set : function(v) { _y=v; 
                                                    dirty=true; } });
     Object.defineProperty(this,'col', 
                              { get : function() {
                                               if (dirty) updateCoords();
                                               return _col; }  });
     Object.defineProperty(this,'row', 
                              { get : function() {
                                               if (dirty) updateCoords();
                                               return _row; }  });
     Object.defineProperty(this,'sx', 
                              { get : function() {
                                               if (dirty) updateCoords();
                                               return _sx; }  });
     Object.defineProperty(this,'sy', 
                              { get : function() {
                                               if (dirty) updateCoords();
                                               return _sy; }  });
     function updateCoords() {
        _row = ( ( _x + 0.5 * world.width )/ world.tileSize ) | 0 ;
        _col = ( ( _x + 0.5 * world.height )/ world.tileSize ) | 0 ;
        _sx =  canvasWidth  * ( 0.5 + ( _x - camera.x ) / camera.viewWidth ) ;
        _sy =  canvasHeight * ( 0.5 + ( _y - camera.y ) / camera.viewHeight ) ;
        dirty = false;            
     }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM