WaveFunctionCollapse_var2.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. //
  2. // Wave Function Collapse - sort of...
  3. //
  4. // I barely understand how this works. It has taken me a number of tries and a whack load of hours
  5. // top get to this current point. The tutorials and explanations on the internet are not that clear and easy
  6. // to understand.
  7. //
  8. // In the example here I have a number of tiles. I pick a random tile from the valid ones and place it on the grid.
  9. // I then fix the neighbour tiles to fit this current position. Connected/unconnected. I keep placing random tiles
  10. // for a x amount of times.
  11. // There is a array that contains a list of all possible tiles. There are functions that check if a position on the grid
  12. // has connections to another position on the grid. This is used to unflag the tiles that are on the list to get
  13. // selected(one random) as a tile to be placed.
  14. // note: the array(x,y,slot) has one slot for every possible tile. when tile x,y has no left sided connection then
  15. // the array position on the left of that one will have all right sided connection tiles unflagged.
  16. //
  17. // The MAX_TILES is the amount of tiles that I have created to create the map with. I check the middle top/left/right/bottom
  18. // tile value to see if there is a connection(1). Experiment with making different tiles.
  19. //
  20. // I might(should) add comments to the code later.
  21. //
  22. #include "raylib.h"
  23. #define MAP_WIDTH 10
  24. #define MAP_HEIGHT 10
  25. #define MAX_TILES 15
  26. static void newmap(void);
  27. static void resetmap(void);
  28. static bool domainhasleftsidedconnections(int x,int y);
  29. static bool domainhasrightsidedconnections(int x,int y);
  30. static bool domainhastopsidedconnections(int x,int y);
  31. static bool domainhasbottomsidedconnections(int x,int y);
  32. static void removeleftsidedconnections(int x,int y);
  33. static void removerightsidedconnections(int x,int y);
  34. static void removetopsidedconnections(int x,int y);
  35. static void removebottomsidedconnections(int x,int y);
  36. static void setrandomtile(int x,int y);
  37. static void updatedomain(int x,int y);
  38. static void finishmap(void);
  39. static int tile[3][3][MAX_TILES] = {0};
  40. static int map[MAP_WIDTH][MAP_HEIGHT][MAX_TILES] = {0};
  41. static int tilemap[MAP_WIDTH][MAP_HEIGHT] = {0};
  42. int main(void)
  43. { // Initialization
  44. //--------------------------------------------------------------------------------------
  45. const int screenWidth = 800;
  46. const int screenHeight = 450;
  47. InitWindow(screenWidth, screenHeight, "raylib example.");
  48. int tile1[3][3] = { {0,1,0},
  49. {0,1,0},
  50. {0,1,0}};
  51. int tile2[3][3] = { {0,0,0},
  52. {1,1,1},
  53. {0,0,0}};
  54. int tile3[3][3] = { {1,1,1},
  55. {1,1,1},
  56. {1,1,1}};
  57. int tile4[3][3] = { {0,1,0},
  58. {1,1,1},
  59. {0,1,0}};
  60. int tile5[3][3] = { {0,1,0},
  61. {1,1,0},
  62. {0,0,0}};
  63. int tile6[3][3] = { {0,1,0},
  64. {0,1,1},
  65. {0,0,0}};
  66. int tile7[3][3] = { {0,0,0},
  67. {1,1,0},
  68. {0,1,0}};
  69. int tile8[3][3] = { {0,0,0},
  70. {0,1,1},
  71. {0,1,0}};
  72. int tile9[3][3] = { {0,1,0},
  73. {1,1,1},
  74. {0,0,0}};
  75. int tile10[3][3] = { {0,1,0},
  76. {0,1,1},
  77. {0,1,0}};
  78. int tile11[3][3] = { {0,0,0},
  79. {1,1,1},
  80. {0,1,0}};
  81. int tile12[3][3] = { {0,1,0},
  82. {1,1,0},
  83. {0,1,0}};
  84. int tile13[3][3] = { {1,1,0},
  85. {1,1,0},
  86. {1,1,0}};
  87. int tile14[3][3] = { {0,1,1},
  88. {0,1,1},
  89. {0,1,1}};
  90. int tile15[3][3] = { {0,0,0},
  91. {1,1,1},
  92. {1,1,1}};
  93. // int tile[3][3][4] = {0};
  94. for(int i=0;i<MAX_TILES;i++){
  95. for(int y=0;y<3;y++){
  96. for(int x=0;x<3;x++){
  97. switch (i){
  98. case 0:
  99. tile[x][y][i] = tile1[x][y];
  100. break;
  101. case 1:
  102. tile[x][y][i] = tile2[x][y];
  103. break;
  104. case 2:
  105. tile[x][y][i] = tile3[x][y];
  106. break;
  107. case 3:
  108. tile[x][y][i] = tile4[x][y];
  109. break;
  110. case 4:
  111. tile[x][y][i] = tile5[x][y];
  112. break;
  113. case 5:
  114. tile[x][y][i] = tile6[x][y];
  115. break;
  116. case 6:
  117. tile[x][y][i] = tile7[x][y];
  118. break;
  119. case 7:
  120. tile[x][y][i] = tile8[x][y];
  121. break;
  122. case 8:
  123. tile[x][y][i] = tile9[x][y];
  124. break;
  125. case 9:
  126. tile[x][y][i] = tile10[x][y];
  127. break;
  128. case 10:
  129. tile[x][y][i] = tile11[x][y];
  130. break;
  131. case 11:
  132. tile[x][y][i] = tile12[x][y];
  133. break;
  134. case 12:
  135. tile[x][y][i] = tile13[x][y];
  136. break;
  137. case 13:
  138. tile[x][y][i] = tile14[x][y];
  139. break;
  140. case 14:
  141. tile[x][y][i] = tile15[x][y];
  142. break;
  143. }
  144. }
  145. }
  146. }
  147. newmap();
  148. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  149. //--------------------------------------------------------------------------------------
  150. // Main game loop
  151. while (!WindowShouldClose()) // Detect window close button or ESC key
  152. {
  153. // Update
  154. //----------------------------------------------------------------------------------
  155. //---------------------------------------------------------------------------------
  156. if(IsKeyReleased(KEY_SPACE)){
  157. newmap();
  158. }
  159. // Draw
  160. //----------------------------------------------------------------------------------
  161. BeginDrawing();
  162. ClearBackground(RAYWHITE);
  163. for (int y = 0; y< MAP_HEIGHT ; y++)
  164. {
  165. for (int x = 0; x< MAP_WIDTH ; x++)
  166. {
  167. int x3 = x*48;
  168. int y3 = y*32;
  169. for(int y2=0;y2<3;y2++){
  170. for(int x2=0;x2<3;x2++){
  171. if( tile[x2][y2][tilemap[x][y]]==1 )DrawRectangle(x3+x2*16,y3+y2*12,16,12,BLACK);
  172. }
  173. }
  174. }
  175. }
  176. DrawText("Press space for new map.", 100, screenHeight-40, 40, LIGHTGRAY);
  177. EndDrawing();
  178. //----------------------------------------------------------------------------------
  179. }
  180. // De-Initialization
  181. //--------------------------------------------------------------------------------------
  182. CloseWindow(); // Close window and OpenGL context
  183. //--------------------------------------------------------------------------------------
  184. return 0;
  185. }
  186. void newmap(){
  187. resetmap();
  188. int depth=GetRandomValue(10,100);
  189. for(int i=0;i<depth;i++){
  190. setrandomtile(GetRandomValue(0,MAP_WIDTH-1),GetRandomValue(0,MAP_HEIGHT-1));
  191. }
  192. finishmap();
  193. // test
  194. for(int y=0;y<MAP_HEIGHT;y++){
  195. for(int x=0;x<MAP_WIDTH;x++){
  196. updatedomain(x,y);
  197. }}
  198. };
  199. void finishmap(){
  200. for(int y=0;y<MAP_HEIGHT;y++){
  201. for(int x=0;x<MAP_WIDTH;x++){
  202. for(int i=0;i<MAX_TILES;i++){
  203. if(map[x][y][i]>-1){
  204. tilemap[x][y] = i;
  205. }
  206. }
  207. }}
  208. };
  209. void resetmap(){
  210. for(int y=0;y<MAP_HEIGHT;y++){
  211. for(int x=0;x<MAP_WIDTH;x++){
  212. for(int i=0;i<MAX_TILES;i++){
  213. map[x][y][i] = 1;
  214. }
  215. }
  216. }
  217. };
  218. bool domainhasleftsidedconnections(int x,int y){
  219. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  220. for(int i=0;i<MAX_TILES;i++){
  221. if(map[x][y][i]==1 && tile[0][1][i]==1){
  222. return true;
  223. }
  224. }
  225. return false;
  226. };
  227. bool domainhasrightsidedconnections(int x,int y){
  228. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  229. for(int i=0;i<MAX_TILES;i++){
  230. if(map[x][y][i]==1 && tile[2][1][i]==1){
  231. return true;
  232. }
  233. }
  234. return false;
  235. };
  236. bool domainhastopsidedconnections(int x,int y){
  237. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  238. for(int i=0;i<MAX_TILES;i++){
  239. if(map[x][y][i]==1 && tile[1][0][i]==1){
  240. return true;
  241. }
  242. }
  243. return false;
  244. };
  245. bool domainhasbottomsidedconnections(int x,int y){
  246. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  247. for(int i=0;i<MAX_TILES;i++){
  248. if(map[x][y][i]==1 && tile[1][2][i]==1){
  249. return true;
  250. }
  251. }
  252. return false;
  253. };
  254. void removeleftsidedconnections(int x,int y){
  255. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  256. for(int i=0;i<MAX_TILES;i++){
  257. if(map[x][y][i]==1 && tile[0][1][i]==1){
  258. map[x][y][i]=-1;
  259. }
  260. }
  261. };
  262. void removerightsidedconnections(int x,int y){
  263. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  264. for(int i=0;i<MAX_TILES;i++){
  265. if(map[x][y][i]==1 && tile[2][1][i]==1){
  266. map[x][y][i]=-1;
  267. }
  268. }
  269. };
  270. void removetopsidedconnections(int x,int y){
  271. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  272. for(int i=0;i<MAX_TILES;i++){
  273. if(map[x][y][i]==1 && tile[1][0][i]==1){
  274. map[x][y][i]=-1;
  275. }
  276. }
  277. };
  278. void removebottomsidedconnections(int x,int y){
  279. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return false;
  280. for(int i=0;i<MAX_TILES;i++){
  281. if(map[x][y][i]==1 && tile[1][2][i]==1){
  282. map[x][y][i]=-1;
  283. }
  284. }
  285. };
  286. void setrandomtile(int x,int y){
  287. bool exitloop=false;
  288. int count=0;
  289. while(exitloop==false){
  290. count++;
  291. int val=GetRandomValue(0,MAX_TILES-1);
  292. if(map[x][y][val]>-1){
  293. for(int i=0;i<MAX_TILES;i++){
  294. map[x][y][i]=-1;
  295. }
  296. map[x][y][val]=1;
  297. exitloop = true;
  298. }
  299. if(count>500)exitloop=true;
  300. }
  301. updatedomain(x-1,y);
  302. updatedomain(x+1,y);
  303. updatedomain(x,y-1);
  304. updatedomain(x,y+1);
  305. };
  306. void updatedomain(int x,int y){
  307. if(x<0 || y<0 || x>=MAP_WIDTH || y>=MAP_HEIGHT)return;
  308. for(int i=0;i<MAX_TILES;i++){
  309. map[x][y][i]=1;
  310. }
  311. if(domainhasbottomsidedconnections(x,y-1)==false)removetopsidedconnections(x,y);
  312. if(domainhastopsidedconnections(x,y+1)==false)removebottomsidedconnections(x,y);
  313. if(domainhasleftsidedconnections(x+1,y)==false)removerightsidedconnections(x,y);
  314. if(domainhasrightsidedconnections(x-1,y)==false)removeleftsidedconnections(x,y);
  315. };