簡體   English   中英

如何在2D游戲中對對象進行排序?

[英]How to sort objects in 2d game?

我正在用javascript開發一種基於透視的2d / 3d游戲

我有一個X軸和Y軸,就像我在下面的圖像中顯示的那樣。


我的問題:我的地圖上有一堆對象(標有“1”和“2”),其屬性如下:

  • positionX / positionY
  • sizeX / sizeY

在圖像中,對象“1”確實得到坐標x:3, y:2 ,而對象“2”確實得到坐標x:5, y:4 對於兩個對象,SizeX和sizeY是w:1, h:1

我想用這個信息做的是按升序對所有對象進行排序(基於對象的位置和大小),以便在3d中知道哪些對象來自另一個對象,以便稍后繪制排序到我的畫布中的所有對象(前景/背景中的對象=“圖層”)。


IMG

注意:攝像機必須固定位置 - 假設攝像機具有相同的X和Y值,因此在計算CameraX = CameraY時不得使用攝像機位置。

到目前為止我嘗試過的:

 let objects = [ { name: "objectA", x: 8, y: 12, w: 2, h: 2 }, { name: "objectB", x: 3, y: 5, w: 2, h: 2 }, { name: "objectC", x: 6, y: 2, w: 1, h: 3 } ] let sortObjects = (objects) => { return objects.sort((a, b)=> { let distanceA = Math.sqrt(ax**2 + ay**2); let distanceB = Math.sqrt(bx**2 + by**2); return distanceA - distanceB; }); } let sortedObjects = sortObjects(objects); console.log(sortedObjects); // NOTE in 3d: first Object drawn first, second Object drawn second and so on... 

編輯上面的代碼段:

我試圖根據它們的x / y坐標對對象進行排序,但似乎必須在計算時使用width和height參數以避免錯誤。

我如何利用寬度/高度? Tbh我沒有任何線索,所以任何幫助都會非常感激。

我不確定你的意思是:

注意:攝像機必須固定位置 - 假設攝像機具有相同的X和Y值,因此在計算CameraX = CameraY時不得使用攝像機位置。

所以這是一個通用案例解決方案。

您必須按照距離相機最近的距離對對象進行排序。 這取決於對象的尺寸及其相對位置。

該算法可以在JS中實現如下:

// If e.g. horizontal distance > width / 2, subtract width / 2; same for vertical
let distClamp = (dim, diff) => {
    let dist = Math.abs(diff);
    return (dist > 0.5 * dim) ? (dist - 0.5 * dim) : dist;
}

// Closest distance to the camera
let closestDistance = (obj, cam) => {
    let dx = distClamp(obj.width, obj.x - cam.x);
    let dy = distClamp(obj.height, obj.y - cam.y);
    return Math.sqrt(dx * dx + dy * dy);
}

// Sort using this as the metric
let sortObject = (objects, camera) => {
    return objects.sort((a, b) => {
        return closestDistance(a, camera) - closestDistance(b, camera);
    });
}

編輯此解決方案也不起作用,因為它做出天真的假設,將很快更新或刪除。

好吧,讓我們去吧! 我們不得不按距離訂購這些物體,而是按障礙物。 由此,我的意思是兩個物體A和B,A可以明顯地阻擋B,B可以明顯地阻擋A,或者兩者都不會阻擋另一個。 如果A阻礙B,我們首先要繪制B,反之亦然。 要解決這個問題,我們需要能夠說出A是阻礙B,還是反過來。

這就是我想出的。 我只有有限的測試能力,所以可能仍有缺陷,但思考過程是合理的。

步驟1.將每個對象映射到其邊界,保存原始對象以供以后使用:

let step1 = objects.map(o => ({
  original: o,
  xmin: o.x,
  xmax: o.x + o.w,
  ymin: o.y,
  ymax: o.y + o.h
}));

步驟2.將每個對象映射到兩個角,當它們之間繪制一條線時,形成攝像機視野的最大障礙:

let step2 = step1.map(o => {
  const [closestX, farthestX] = [o.xmin, o.xmax].sort((a, b) => Math.abs(camera.x - a) - Math.abs(camera.x - b));
  const [closestY, farthestY] = [o.ymin, o.ymax].sort((a, b) => Math.abs(camera.y - a) - Math.abs(camera.y - b));

  return {
    original: o.original,
    x1: closestX,
    y1: o.xmin <= camera.x && camera.x <= o.xmax ? closestY : farthestY,
    x2: o.ymin <= camera.y && camera.y <= o.ymax ? closestX : farthestX,
    y2: closestY
  };
});

第3步。對對象進行排序。 從相機到一個對象的每個端點繪制一條線段。 如果另一個對象的端點之間的線段相交,則另一個對象更近,必須在之后繪制。

let step3 = step2.sort((a, b) => {
  const camSegmentA1 = {
    x1: camera.x,
    y1: camera.y,
    x2: a.x1,
    y2: a.y1
  };
  const camSegmentA2 = {
    x1: camera.x,
    y1: camera.y,
    x2: a.x2,
    y2: a.y2
  };
  const camSegmentB1 = {
    x1: camera.x,
    y1: camera.y,
    x2: b.x1,
    y2: b.y1
  };
  const camSegmentB2 = {
    x1: camera.x,
    y1: camera.y,
    x2: b.x2,
    y2: b.y2
  };

  // Intersection function taken from here: https://stackoverflow.com/a/24392281
  function intersects(seg1, seg2) {
    const a = seg1.x1, b = seg1.y1, c = seg1.x2, d = seg1.y2,
          p = seg2.x1, q = seg2.y1, r = seg2.x2, s = seg2.y2;
    const det = (c - a) * (s - q) - (r - p) * (d - b);
    if (det === 0) {
      return false;
    } else {
      lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
      gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
      return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1);
    }
  }

  function squaredDistance(pointA, pointB) {
    return Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2);
  }

  if (intersects(camSegmentA1, b) || intersects(camSegmentA2, b)) {
    return -1;
  } else if (intersects(camSegmentB1, a) || intersects(camSegmentB2, a)) {
    return 1;
  } else {
    return Math.max(squaredDistance(camera, {x: b.x1, y: b.y1}), squaredDistance(camera, {x: b.x2, y: b.y2})) - Math.max(squaredDistance(camera, {x: a.x1, y: a.y1}), squaredDistance(camera, {x: a.x2, y: a.y2}));
  }
});

步驟4.最后一步 - 返回原始對象,按最遠到最近的順序排序:

let results = step3.map(o => o.original);

現在,把它們放在一起:

results = objects.map(o => {
  const xmin = o.x,
        xmax = o.x + o.w,
        ymin = o.y,
        ymax = o.y + o.h;

  const [closestX, farthestX] = [xmin, xmax].sort((a, b) => Math.abs(camera.x - a) - Math.abs(camera.x - b));
  const [closestY, farthestY] = [ymin, ymax].sort((a, b) => Math.abs(camera.y - a) - Math.abs(camera.y - b));

  return {
    original: o,
    x1: closestX,
    y1: xmin <= camera.x && camera.x <= xmax ? closestY : farthestY,
    x2: ymin <= camera.y && camera.y <= ymax ? closestX : farthestX,
    y2: closestY
  };
}).sort((a, b) => {
  const camSegmentA1 = {
    x1: camera.x,
    y1: camera.y,
    x2: a.x1,
    y2: a.y1
  };
  const camSegmentA2 = {
    x1: camera.x,
    y1: camera.y,
    x2: a.x2,
    y2: a.y2
  };
  const camSegmentB1 = {
    x1: camera.x,
    y1: camera.y,
    x2: b.x1,
    y2: b.y1
  };
  const camSegmentB2 = {
    x1: camera.x,
    y1: camera.y,
    x2: b.x2,
    y2: b.y2
  };

  // Intersection function taken from here: https://stackoverflow.com/a/24392281
  function intersects(seg1, seg2) {
    const a = seg1.x1, b = seg1.y1, c = seg1.x2, d = seg1.y2,
          p = seg2.x1, q = seg2.y1, r = seg2.x2, s = seg2.y2;
    const det = (c - a) * (s - q) - (r - p) * (d - b);
    if (det === 0) {
      return false;
    } else {
      lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
      gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
      return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1);
    }
  }

  function squaredDistance(pointA, pointB) {
    return Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2);
  }

  if (intersects(camSegmentA1, b) || intersects(camSegmentA2, b)) {
    return -1;
  } else if (intersects(camSegmentB1, a) || intersects(camSegmentB2, a)) {
    return 1;
  }
  return Math.max(squaredDistance(camera, {x: b.x1, y: b.y1}), squaredDistance(camera, {x: b.x2, y: b.y2})) - Math.max(squaredDistance(camera, {x: a.x1, y: a.y1}), squaredDistance(camera, {x: a.x2, y: a.y2}));
}).map(o => o.original);

如果有效,請告訴我!

這里的問題是你使用歐氏距離來測量物體距離(0, 0)的距離,以嘗試測量距離y = -x線的距離。 這不起作用,但曼哈頓的距離會有所不同。

let sortObjects = (objects) => {
  return objects.sort((a, b)=> {
    let distanceA = a.x + a.y;
    let distanceB = b.x + b.y;
    return distanceA - distanceB;
  });
}

這將在旋轉的坐標系中垂直排序對象。

在您的圖表中,考慮每個單元格的x + y值

每個單元格的X + Y圖表

要從上到下排序單元格,您只需對x+y的值進行排序即可。

也許你可以在這里找到有用的東西 (使用Firefox並查看DEMO

在我的情況下,深度基本上是pos.x + pos.y [assetHelper.js - > get depth(){...],正如第一個答案所描述的那樣。 然后排序是一個簡單的比較[canvasRenderer - > depthSortAssets(){...]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM