Automatisches Indexieren von Sprites in einem Array (autotiling x47)

      Automatisches Indexieren von Sprites in einem Array (autotiling x47)

      Vorwort
      Dieses Tutorial befasst sich mit dem automatischen indexieren von Sprites in, z.B. einem Spiel wie Terraria.
      Zu erwähnen ist, dass dies nicht über gm-objekte geschieht sondern über einen Array. Ansonsten ist es ihr herkömmlicher autotiler.

      Notiz1: Der Code ist lange und sieht sehr Performance-unfreundlich aus, ist er aber nicht.
      Notiz2: Funktioniert nicht direkt mit Objekten, kann aber ohne zu grossen Aufwand angepasst werden. (Ich schliesse aber Empfehlungen aus)
      Notiz3: Dieser Autotiler funktioniert nicht in bit-weise, da Game Maker if-statements gegenüber normalen Berechnungen bevorzugt.
      So soll es im Normalfall eine bessere Performance zeigen. (Nicht getestet für den Worst-case!)

      Das Template
      Als erstes muss ein Template erstellt werden. Damit meine ich den Sprite mit seinen Sub-images. Für das Tutorial ist ein Sprite mit 47 Sub-images zu verwenden, Index 0 bis 46.
      Die Anordnung spielt eine grosse Rolle, sie sollte dem Beispiel entsprechen (Anti-kopier Qualität, aber hoffentlich erkennbar) der Abbildung unten:


      Das Setup
      Da es ein Script ist, muss es zuerst aufgerufen werden. Es soll in jeder Zelle des Arrays ausgeführt werden.

      Der Algorithmus
      Nun zum Code der diese Bildchen am richtigen Ort einsetzen soll:Der Algorithmus schaut alle Werte im Array um sich herum nach und vergleicht diese mit dem eigenen Wert. Der Algorithmus dieser Sache ist die Reihenfolge bei der diese Array-positionen angeschaut werden.Zur Zeit ist das der schnellste Weg ans Ziel:

      Quellcode

      1. ///scr_get_index(tile,x,y)
      2. var zero = argument0;
      3. var xpos = argument1;
      4. var ypos = argument2;
      5. var left = xpos-1;
      6. var right = xpos+1;
      7. var above = ypos-1;
      8. var below = ypos+1;
      9. //1+
      10. if (global.tiles[@ xpos, below] != zero)
      11. {
      12. //1-2+
      13. if (global.tiles[@ right, ypos] != zero)
      14. {
      15. //1-2-4+
      16. if (global.tiles[@ xpos, above] != zero)
      17. {
      18. //1-2-4-8
      19. if (global.tiles[@ left, ypos] != zero)
      20. {
      21. return (15);
      22. }
      23. else return (7);
      24. }
      25. else
      26. {
      27. //1-2-8
      28. if (global.tiles[@ left, ypos] != zero)
      29. {
      30. return (11);
      31. }
      32. else
      33. {
      34. //1-2-64
      35. if (global.tiles[@ left, above] != zero)
      36. {
      37. return (27);
      38. }
      39. else return (3);
      40. }
      41. }
      42. }
      43. else
      44. {
      45. //1-4+
      46. if (global.tiles[@ xpos, above] != zero)
      47. {
      48. //1-4-8
      49. if (global.tiles[@ left, ypos] != zero)
      50. {
      51. return (13);
      52. }
      53. else return (5);
      54. }
      55. else
      56. {
      57. //1-8+
      58. if (global.tiles[@ left, ypos] != zero)
      59. {
      60. //1-8-32
      61. if (global.tiles[@ right, above] != zero)
      62. {
      63. return (23);
      64. }
      65. else return (9);
      66. }
      67. else
      68. {
      69. //1-32
      70. if (global.tiles[@ right, above] != zero)
      71. {
      72. //1-32-64
      73. if (global.tiles[@ left, above] != zero)
      74. {
      75. return (43);
      76. }
      77. else return (21);
      78. }
      79. else
      80. {
      81. //1-64
      82. if (global.tiles[@ left, above] != zero)
      83. {
      84. return (25);
      85. }
      86. else return (1);
      87. }
      88. }
      89. }
      90. }
      91. }
      92. else
      93. {
      94. //2+
      95. if (global.tiles[@ right, ypos] != zero)
      96. {
      97. //2-4
      98. if (global.tiles[@ xpos, above] != zero)
      99. {
      100. //2-4-8
      101. if (global.tiles[@ left, ypos] != zero)
      102. {
      103. return (14);
      104. }
      105. else
      106. {
      107. //2-4-128
      108. if (global.tiles[@ left, below] != zero)
      109. {
      110. return (31);
      111. }
      112. else return (6);
      113. }
      114. }
      115. else
      116. {
      117. //2-8
      118. if (global.tiles[@ left, ypos] != zero)
      119. {
      120. return (10);
      121. }
      122. else
      123. {
      124. //2-64
      125. if (global.tiles[@ left, above] != zero)
      126. {
      127. //2-64-128
      128. if (global.tiles[@ left, below] != zero)
      129. {
      130. return (44);
      131. }
      132. else return (26);
      133. }
      134. else
      135. {
      136. //2-128
      137. if (global.tiles[@ left, below] != zero)
      138. {
      139. return (29);
      140. }
      141. else return (2);
      142. }
      143. }
      144. }
      145. }
      146. else
      147. {
      148. //4+
      149. if (global.tiles[@ xpos, above] != zero)
      150. {
      151. //4-8
      152. if (global.tiles[@ left, ypos] != zero)
      153. {
      154. //4-8-16
      155. if (global.tiles[@ right, below] != zero)
      156. {
      157. return (18);
      158. }
      159. else return (12);
      160. }
      161. else
      162. {
      163. //4-16
      164. if (global.tiles[@ right, below] != zero)
      165. {
      166. //4-16-128
      167. if (global.tiles[@ left, below] != zero)
      168. {
      169. return (37);
      170. }
      171. else return (17);
      172. }
      173. else
      174. {
      175. //4-128
      176. if (global.tiles[@ left, below] != zero)
      177. {
      178. return (30);
      179. }
      180. else return (4);
      181. }
      182. }
      183. }
      184. else
      185. {
      186. //8+
      187. if (global.tiles[@ left, ypos] != zero)
      188. {
      189. //8-16
      190. if (global.tiles[@ right, below] != zero)
      191. {
      192. //8-16-32
      193. if (global.tiles[@ right, above] != zero)
      194. {
      195. return (33);
      196. }
      197. else return (19);
      198. }
      199. else
      200. {
      201. //8-32)
      202. if (global.tiles[@ right, above] != zero)
      203. {
      204. return (22);
      205. }
      206. else return (8);
      207. }
      208. }
      209. //ONLY CORNERS
      210. else
      211. {
      212. //16+
      213. if (global.tiles[@ right, below] != zero)
      214. {
      215. //16-32
      216. if (global.tiles[@ right, above] != zero)
      217. {
      218. //16-32-64
      219. if (global.tiles[@ left, above] != zero)
      220. {
      221. //16-32-64-128
      222. if (global.tiles[@ left, below] != zero)
      223. {
      224. return (39);
      225. }
      226. else return (35);
      227. }
      228. else
      229. {
      230. //16-32-128
      231. if (global.tiles[@ left, below] != zero)
      232. {
      233. return (42);
      234. }
      235. else return (32);
      236. }
      237. }
      238. else
      239. {
      240. //16-64
      241. if (global.tiles[@ left, above] != zero)
      242. {
      243. //16-64-128
      244. if (global.tiles[@ left, below] != zero)
      245. {
      246. return (41);
      247. }
      248. else return (34);
      249. }
      250. else
      251. {
      252. //16-128
      253. if (global.tiles[@ left, below] != zero)
      254. {
      255. return (36);
      256. }
      257. else return (16);
      258. }
      259. }
      260. }
      261. else
      262. {
      263. //32+
      264. if (global.tiles[@ right, above] != zero)
      265. {
      266. //32-64
      267. if (global.tiles[@ left, above] != zero)
      268. {
      269. //32-64-128
      270. if (global.tiles[@ left, below] != zero)
      271. {
      272. return (40);
      273. }
      274. else return (46);
      275. }
      276. else
      277. {
      278. //32-128
      279. if (global.tiles[@ left, below] != zero)
      280. {
      281. return (38);
      282. }
      283. else return (20);
      284. }
      285. }
      286. else
      287. {
      288. //64+
      289. if (global.tiles[@ left, above] != zero)
      290. {
      291. //64-128
      292. if (global.tiles[@ left, below] != zero)
      293. {
      294. return (45);
      295. }
      296. else return (24);
      297. }
      298. else
      299. {
      300. //128+
      301. if (global.tiles[@ left, below] != zero)
      302. {
      303. return (28);
      304. }
      305. else return (0);
      306. }
      307. }
      308. }
      309. }
      310. }
      311. }
      312. }


      Bei Fragen und Feedback unbedingt melden.

      Brodi schrieb:

      Sieht interessant aus.
      Wie benutzt man das?

      Hallo Brodi,
      Das Script muss man in einer doppel for-Schleife benutzen.
      Wenn du jetzt z.B. ein 2D Array hast und alle 1en im Array bedeuten das da ein Block ist und alle 0en bedeuten das da Luft ist.
      Wenn du den Sprite hast (spr_tileset_1), kannst du so vorgehen:

      GML-Quellcode

      1. surface_set_target(my_surface);
      2. draw_clear_alpha(0, 0);
      3. for (var i = 99; i >= 0; i--)
      4. {
      5. for (var j = 99; j >= 0; j--)
      6. {
      7. var cell = my_array[i, j];
      8. if (cell != 0)
      9. {
      10. var index = scr_get_index(cell, i, j);
      11. draw_sprite(spr_tileset_1, index, i * 16, j * 16);
      12. }
      13. }
      14. }
      15. surface_reset_target();

      Etwa so siehts bei mir aus.
      Natürlich gehört da noch viel mehr dazu, wie z.B. das Managen von Chunks oder das Entscheiden welcher Sprite in die Zelle geört usw.
      Hoffe das ist in irgend einer Art nützlich.

      Brodi schrieb:

      Oh hoppla. Ehm, das übersteigt mein Verständnis. Aber ich bin sehr interessiert, dass auszuprobieren.
      Wie wäre es mit einem Tutorial von deinem Tutorial ;)


      Ich glaub das ist noch ein wenig zu früh für ein GML Novize. Das wird extrem kompliziert.

      Brodi schrieb:

      ;(



      Oh je,
      aber wenn du unbedingt ein 5-seitiges überkompliziertes Tutorial lesen möchtest kann ich das schon machen.
      kleine Einsicht des Inhalts, es
      kommen vor:
      - Enums
      - Arrays
      - ds_lists
      - Buffer
      - For-Schleifen
      - Surfaces
      - Bitweise
      - Cellular Automata
      - noise Funktionen
      - Speichern und Laden
      - Grid Kollisionen
      - Shader

      vielleicht ändert das deine Einstellung ein wenig

      Brodi schrieb:

      Ooh ja voll dabei und motiviert. :)
      Und das meiste von dem was du da Auflist ist nicht unbedingt Neuland - das kriege ich hin ;)


      Könnt aber ne Weile dauern bis ich dieses Tutorial geschrieben habe. Und es sind auch noch Bugs im Projekt selber die ich beheben muss.
      Viele Tutorials kann man auch als ein eigenes schreiben, damit man alles nicht zig Mal wiederholen muss.
      Ich helfe dir bei anderen Tutorials gerne, wenn du möchtest :)
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe
      Ich arbeite gerade an einem neuen Auto-tiler, welcher auch Verbindungen mit anderen array-werten unterstützt. Daher kann es sein (bei Erfolg) das ich ein neues Tutorial schreiben muss. Das gilt auch fürs andere Tutorial mit den Binären Konstellationen. Dort gibt es auch schon eine neue Technik.