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.0KB

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