You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Structure.js 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import assets from "./assets.js";
  2. import Rect from "./Rect.js";
  3. import Vec2 from "./Vec2.js";
  4. function findBounds(arr, bounds) {
  5. arr.forEach(e => {
  6. let right = (e.x + 1) * assets.tiles.tileWidth;
  7. let bottom = (e.y + 1) * assets.tiles.tileHeight;
  8. if (bounds.size.x < right)
  9. bounds.size.x = right;
  10. if (bounds.size.y < bottom)
  11. bounds.size.y = bottom;
  12. });
  13. }
  14. function rightOrBelow(r1, r2) {
  15. // r2 right of r1
  16. if (
  17. (r1.top === r2.top && r1.bottom == r2.bottom) &&
  18. (r1.right + 1 >= r2.left && r1.left <= r2.left))
  19. return true;
  20. // r2 below r1
  21. if (
  22. (r1.right === r2.right && r1.left == r2.left) &&
  23. (r1.bottom + 1 >= r2.top && r1.top <= r2.top))
  24. return true;
  25. return false;
  26. }
  27. function continuous(r1, r2) {
  28. return rightOrBelow(r1, r2) || rightOrBelow(r2, r1);
  29. }
  30. function findGeometry(bounds, arr, geometry) {
  31. let allBounds = [];
  32. arr.forEach(e => {
  33. let eBounds = new Rect(bounds.pos.clone());
  34. eBounds.pos.pixelX += e.x * assets.tiles.tileWidth;
  35. eBounds.pos.pixelY += e.y * assets.tiles.tileWidth;
  36. eBounds.size.pixelX = assets.tiles.tileWidth;
  37. eBounds.size.pixelY = assets.tiles.tileWidth;
  38. allBounds.push(eBounds);
  39. });
  40. function runPass() {
  41. if (allBounds.lenght === 1) {
  42. geometry.push(allBounds[0]);
  43. allBounds.splice(0, 1);
  44. return;
  45. }
  46. // Find continuous bounds
  47. let changed = false;
  48. geometry.forEach((g, gi) => {
  49. allBounds.forEach((b, bi) => {
  50. if (continuous(g, b)) {
  51. if (b.left < g.left)
  52. g.pixelResizeLeftTo(b.pixelLeft);
  53. if (b.right > g.right)
  54. g.pixelResizeRightTo(b.pixelRight);
  55. if (b.top < g.top)
  56. g.pixelResizeTopTo(b.pixelTop);
  57. if (b.bottom > g.bottom)
  58. g.pixelResizeBottomTo(b.pixelBottom);
  59. allBounds.splice(bi, 1);
  60. changed = true;
  61. }
  62. });
  63. });
  64. // If no continuous blocks were found, we need a new rectangle
  65. if (!changed) {
  66. geometry.push(allBounds[0]);
  67. allBounds.splice(0, 1);
  68. }
  69. }
  70. while (allBounds.length > 0) {
  71. runPass();
  72. }
  73. }
  74. function drawToCanvas(ctx, arr) {
  75. arr.forEach(e => {
  76. assets.tiles.drawTile(ctx, e.tile, e.x, e.y);
  77. });
  78. }
  79. function flattened(arr, newArr = []) {
  80. arr.forEach(e => {
  81. if (e instanceof Array)
  82. flattened(e, newArr);
  83. else
  84. newArr.push(e);
  85. });
  86. return newArr;
  87. }
  88. export default class Structure {
  89. constructor(attrs, nestedArr) {
  90. this.attrs = {
  91. collides: false,
  92. }
  93. for (let a of attrs)
  94. this.setAttr(a);
  95. this.nestedArr = nestedArr;
  96. this.bounds = new Rect();
  97. this.geometry = [];
  98. this.can = document.createElement("canvas");
  99. }
  100. init() {
  101. var arr = flattened(this.nestedArr);
  102. findBounds(arr, this.bounds);
  103. this.can.width = this.bounds.size.x;
  104. this.can.height = this.bounds.size.y;
  105. if (this.attrs.collides) {
  106. findGeometry(this.bounds, arr, this.geometry);
  107. }
  108. let ctx = this.can.getContext("2d");
  109. assets.tiles.whenReady(() => drawToCanvas(ctx, arr));
  110. }
  111. draw(ctx) {
  112. ctx.drawImage(
  113. this.can, this.bounds.pos.pixelX, this.bounds.pos.pixelY,
  114. this.bounds.size.x, this.bounds.size.y);
  115. }
  116. setAttr(attr) {
  117. if (this.attrs[attr] == null)
  118. throw new Error("Invalid attribute:", attr);
  119. this.attrs[attr] = true;
  120. return this;
  121. }
  122. collidesWith(rect) {
  123. if (!this.bounds.intersects(rect))
  124. return null;
  125. for (let bounds of this.geometry) {
  126. if (bounds.intersects(rect))
  127. return bounds;
  128. }
  129. return null;
  130. }
  131. }