Template_-_Map_BreathFdist_Smooth.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. //
  2. // Template topdown smooth movement player.
  3. // Map setup through array.
  4. // Agents, BreathFirst distance map.
  5. #include "raylib.h"
  6. #include <math.h>
  7. #define MAX_PATH 1024
  8. #define MAX_AGENT 32 // Maximum number of ai entities
  9. #define SPEED 1
  10. enum terrain{TREE=1,GROUND=0,PLAYER=2,AIPLAYER=3,GOAL=4,GOALREACHED=5};
  11. enum flag{UP,DOWN,LEFT,RIGHT,WAIT};
  12. //
  13. // You can set any number of 3 and 2 on the map. more 4's untested. keep the borders(1) intact(memory errors)
  14. //
  15. //1=border(TREE),2=PLAYER,3=AIPLAYER,4=Path finding objective(GOAL)
  16. int map1[10][10] = { {1,1,1,1,1,1,1,1,1,1},
  17. {1,0,0,0,0,1,0,0,3,1},
  18. {1,0,0,0,0,1,0,0,0,1},
  19. {1,3,0,0,0,1,0,0,0,1},
  20. {1,0,0,0,0,1,1,0,1,1},
  21. {1,0,0,0,0,1,0,0,0,1},
  22. {1,1,1,0,1,1,0,0,0,1},
  23. {1,0,0,0,0,0,2,0,0,1},
  24. {1,0,0,0,0,0,0,0,0,1},
  25. {1,1,1,1,1,1,1,1,1,1}
  26. };
  27. int map[10][10] = {0};
  28. int dijkstramap[10][10]={0};
  29. typedef struct pathnode{
  30. int x;
  31. int y;
  32. }pathnode;
  33. typedef struct agent{
  34. bool active;
  35. Vector2 position;
  36. Vector2 size;
  37. }agent;
  38. static struct agent arr_agent[MAX_AGENT];
  39. typedef struct player{
  40. Vector2 position;
  41. Vector2 size;
  42. }player;
  43. player myPlayer = {0};
  44. void makedijkstramap();
  45. static float distance(float x1,float y1,float x2,float y2);
  46. static float edistance(float x1,float y1,float x2,float y2);
  47. //Unit collide with solid blocks true/false
  48. bool recttilecollide(int x, int y, int w, int h, int offsetx,int offsety);
  49. // Our rectsoverlap function. Returns true/false.
  50. static bool rectsoverlap(int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2);
  51. void updateplayer();
  52. int topdijkstralen=0;
  53. int screenWidth;
  54. int screenHeight;
  55. int tileWidth,tileHeight,mapWidth,mapHeight;
  56. int main(void)
  57. {
  58. // Initialization
  59. //--------------------------------------------------------------------------------------
  60. screenWidth = 800;
  61. screenHeight = 600;
  62. mapWidth = 10;
  63. mapHeight = 10;
  64. tileWidth = ceil((float)screenWidth/(float)mapWidth);
  65. tileHeight = ceil((float)screenHeight/(float)mapHeight);
  66. InitWindow(screenWidth, screenHeight, "raylib example.");
  67. SetTargetFPS(200); // Set our game to run at 60 frames-per-second
  68. //--------------------------------------------------------------------------------------
  69. //makedijkstramap(); // The 4 = the goal that gets flooded from...
  70. //
  71. // Copy our original map into the active map...
  72. for(int y=0;y<mapHeight;y++){
  73. for(int x=0;x<mapHeight;x++){
  74. map[y][x]= map1[y][x];
  75. }}
  76. // set our player up..
  77. for(int y=0;y<mapHeight;y++){
  78. for(int x=0;x<mapHeight;x++){
  79. if(map[y][x]==PLAYER){
  80. myPlayer.position = (Vector2){x*tileWidth,y*tileHeight};
  81. myPlayer.size = (Vector2){tileWidth/2,tileHeight/2};
  82. map[y][x]=GROUND;
  83. }
  84. }}
  85. // set our agents(ai) up..
  86. int agentcount=0;
  87. for(int y=0;y<mapHeight;y++){
  88. for(int x=0;x<mapHeight;x++){
  89. if(map[y][x]==AIPLAYER){
  90. arr_agent[agentcount].active=true;
  91. arr_agent[agentcount].position = (Vector2){x*tileWidth,y*tileHeight};
  92. arr_agent[agentcount].size = (Vector2){tileWidth/2,tileHeight/2};
  93. map[y][x]=GROUND;
  94. agentcount++;
  95. }
  96. }}
  97. // Main game loop
  98. while (!WindowShouldClose()) // Detect window close button or ESC key
  99. {
  100. // Update
  101. //----------------------------------------------------------------------------------
  102. updateplayer();
  103. //----------------------------------------------------------------------------------
  104. // Draw
  105. //----------------------------------------------------------------------------------
  106. BeginDrawing();
  107. ClearBackground(RAYWHITE);
  108. //drawmap (tile positions)
  109. for(int y=0;y<10;y++){
  110. for(int x =0;x<10;x++){
  111. int m=map[y][x];
  112. if(m==TREE){
  113. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,(Color){40,90,20,255});
  114. DrawCircle(x*tileWidth+tileWidth/1.5,y*tileHeight+tileHeight/1.5,tileWidth/5,(Color){20,50,20,255});
  115. DrawRectangle(x*tileWidth+tileWidth/2.2,y*tileHeight+tileHeight/2,tileWidth/8,tileHeight/3,BROWN);
  116. DrawCircle(x*tileWidth+tileWidth/2,y*tileHeight+tileHeight/3,tileWidth/4,(Color){120,250,20,255});
  117. DrawCircle(x*tileWidth+tileWidth/2.2,y*tileHeight+tileHeight/4,tileWidth/9,(Color){220,255,220,155});
  118. }
  119. if(m==GROUND){
  120. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,DARKGREEN);
  121. DrawRectangle(x*tileWidth+5,y*tileHeight+10,2,1,GREEN);
  122. DrawRectangle(x*tileWidth+tileWidth/6,y*tileHeight+tileHeight/6,2,1,GREEN);
  123. DrawRectangle(x*tileWidth+tileWidth/1.5,y*tileHeight+tileHeight/1.5,2,1,GREEN);
  124. DrawRectangle(x*tileWidth+tileWidth/2,y*tileHeight+tileHeight/2,2,1,GREEN);
  125. }
  126. if(m==PLAYER){
  127. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,BLUE);
  128. DrawText("Player",x*tileWidth,y*tileHeight+tileHeight/4,16,BLACK);
  129. }
  130. if(m==AIPLAYER){
  131. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,RED);
  132. DrawText("Ai_Player",x*tileWidth,y*tileHeight+tileHeight/4,16,WHITE);
  133. }
  134. if(m==GOAL){
  135. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,WHITE);
  136. DrawText("City",x*tileWidth+tileWidth/4,y*tileHeight+tileHeight/4,26,BLACK);
  137. }
  138. if(m==GOALREACHED){
  139. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,YELLOW);
  140. DrawText("Captured",x*tileWidth+4,y*tileHeight+tileHeight/4,16,BLACK);
  141. }
  142. DrawText(FormatText("%i",dijkstramap[y][x]),x*tileWidth+tileWidth/2-10,y*tileHeight+tileHeight/2-10,20,BLACK);
  143. }
  144. }
  145. // Draw our agents..
  146. for(int i=0;i<MAX_AGENT;i++){
  147. int x = arr_agent[i].position.x;
  148. int y = arr_agent[i].position.y;
  149. int w = arr_agent[i].size.x;
  150. int h = arr_agent[i].size.y;
  151. DrawRectangle(x,y,w,h,RED);
  152. DrawText(FormatText("Agent %i",i),x,y+h/8,h/8,WHITE);
  153. }
  154. // Draw our player..
  155. int x = myPlayer.position.x;
  156. int y = myPlayer.position.y;
  157. int w = myPlayer.size.x;
  158. int h = myPlayer.size.y;
  159. DrawRectangle(x,y,w,h,BLUE);
  160. DrawText("Player",x,y+h/8,h/4,BLACK);
  161. DrawText("Cursors U/D/L/R",10,10,26,BLACK);
  162. DrawText("Cursors U/D/L/R",9,9,26,WHITE);
  163. EndDrawing();
  164. //----------------------------------------------------------------------------------
  165. }
  166. // De-Initialization
  167. //--------------------------------------------------------------------------------------
  168. CloseWindow(); // Close window and OpenGL context
  169. //--------------------------------------------------------------------------------------
  170. return 0;
  171. }
  172. void updateplayer(){
  173. for(int sp=0;sp<SPEED;sp++){ // our movement speed (makes to check collision every step)
  174. Vector2 oldpos = myPlayer.position;
  175. if(IsKeyDown(KEY_LEFT)){
  176. myPlayer.position.x-=1;
  177. }
  178. if(IsKeyDown(KEY_RIGHT)){
  179. myPlayer.position.x+=1;
  180. }
  181. if(recttilecollide(myPlayer.position.x,myPlayer.position.y,tileWidth/2,tileHeight/2,0,0)){
  182. myPlayer.position = oldpos;
  183. }
  184. oldpos = myPlayer.position;
  185. if(IsKeyDown(KEY_UP)){
  186. myPlayer.position.y-=1;
  187. }
  188. if(IsKeyDown(KEY_DOWN)){
  189. myPlayer.position.y+=1;
  190. }
  191. if(recttilecollide(myPlayer.position.x,myPlayer.position.y,tileWidth/2,tileHeight/2,0,0)){
  192. myPlayer.position = oldpos;
  193. }
  194. }
  195. }
  196. void makedijkstramap(){
  197. int startx;
  198. int starty;
  199. // First make sure every map value is 0.
  200. for(int y=0;y<mapHeight;y++){
  201. for(int x=0;x<mapWidth;x++){
  202. dijkstramap[y][x] = 0;
  203. if(map1[y][x]==1)dijkstramap[y][x]=-1;
  204. if(map1[y][x]==4){
  205. startx = x;
  206. starty = y;
  207. }
  208. }}
  209. //
  210. //
  211. // Flood the map with distances from the start.
  212. //
  213. // We store the distance on each map cell if there is no wall there.
  214. //
  215. struct pathnode list[MAX_PATH];
  216. dijkstramap[starty][startx]=1;
  217. int listlen=0;
  218. list[listlen].x=startx;
  219. list[listlen].y=starty;
  220. listlen+=1;
  221. int failed=0;
  222. // 4 way search! left/up/down/right
  223. int dx[8]={ -1,0,1,-1,1,-1,0,1};
  224. int dy[8]={-1,-1,-1,0,0,1,1,1};
  225. // While we have a list to work with
  226. while(listlen>0){
  227. // Take the first value from the array.
  228. int x1=list[0].x;
  229. int y1=list[0].y;
  230. // shift all up.
  231. for(int i=0;i<listlen;i++){
  232. list[i].x = list[i+1].x;
  233. list[i].y = list[i+1].y;
  234. }
  235. // Decrease list length
  236. listlen-=1;
  237. //
  238. // Here we check around our current position.
  239. for(int i=0;i<8;i++){
  240. int nx = x1+dx[i];
  241. int ny = y1+dy[i];
  242. if(nx<0 || ny<0 || nx>= mapWidth || ny>= mapHeight)continue;
  243. // If we can get there then put the new distance there and add this position
  244. // to the list.
  245. if(dijkstramap[ny][nx]==0 && map[ny][ny]!=1){
  246. dijkstramap[ny][nx]=dijkstramap[y1][x1]+1;
  247. if(dijkstramap[ny][nx]>topdijkstralen)topdijkstralen=dijkstramap[ny][nx];
  248. // add to last
  249. //
  250. list[listlen].x = nx;
  251. list[listlen].y = ny;
  252. listlen++;
  253. //
  254. }
  255. }
  256. // Error?
  257. failed+=1;
  258. if(failed>160000)return;
  259. }
  260. }
  261. // Manhattan Distance (less precise)
  262. float distance(float x1,float y1,float x2,float y2){
  263. return (float)abs(x2-x1)+abs(y2-y1);
  264. }
  265. // Euclidean distance (more precise)
  266. float edistance(float x1,float y1,float x2,float y2){
  267. return sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) );
  268. }
  269. //Unit collide with solid blocks true/false
  270. bool recttilecollide(int x, int y,int w, int h, int offsetx,int offsety){
  271. //y+=abs(mapy);//for scrolling
  272. int cx = (x+offsetx)/tileWidth;
  273. int cy = (y+offsety)/tileHeight;
  274. for(int y2=cy-1; y2<cy+2;y2++){//Note that the - and + are to be set differently with differently sized players
  275. for(int x2=cx-1; x2<cx+2;x2++){
  276. if(x2>=0 && x2<mapWidth && y2>=0 && y2<mapHeight){
  277. if(map[y2][x2] == 1){
  278. int x3 = (x2)*tileWidth;
  279. int y3 = (y2)*tileHeight;
  280. if(rectsoverlap(x+offsetx,y+offsety,w,h,x3,y3,tileWidth,tileHeight)){
  281. return true;
  282. }
  283. }
  284. }
  285. }}
  286. return false;
  287. }
  288. // Rectangles overlap
  289. bool rectsoverlap(int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2){
  290. if(x1 >= (x2 + w2) || (x1 + w1) <= x2) return false;
  291. if(y1 >= (y2 + h2) || (y1 + h1) <= y2) return false;
  292. return true;
  293. }