Guest User

Sand Game by EmeraldGreen

a guest
Mar 19th, 2016
903
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.65 KB | None | 0 0
  1. //gcc sand.c -O3 -o sand `sdl2-config --libs --cflags` -lm
  2. //Sand simulator game
  3. //Controls:
  4. //1: sand, 2: stone, 3: sand generator, 4: eraser, +/-: change brush size, space: pause, L: load, S: save
  5. #include <stdio.h>
  6. #include <SDL2/SDL.h>
  7. #include <stdint.h>
  8. #include <math.h>
  9.  
  10. #define CELL_EMPTY 0
  11. #define CELL_SAND 1
  12. #define CELL_ROCK 3
  13. #define CELL_SOURCE 5
  14.  
  15. uint32_t cellColors[] = {0, 0x00EEAA00, 0, 0x00444444, 0, 0x00BB0000};
  16.  
  17. int worldW = 320;
  18. int worldH = 240;
  19. int scale = 2;
  20. int screenW, screenH;
  21. uint8_t mouseDown = 0;
  22. uint8_t pause = 0;
  23. uint32_t drawColor;
  24. uint32_t drawRadius = 1;
  25. float fps = 50.0;
  26.  
  27. void clearScreen(uint32_t* pixels) {
  28.     int i;
  29.     for (i=0; i<screenW*screenH; i++) {
  30.         pixels[i] = 0x00000000;
  31.     }
  32. }
  33.  
  34. void initState(uint32_t* state) {
  35.     int x, y;
  36.     for (y=0; y<worldH; y++) {
  37.         for (x=0; x<worldW; x++) {
  38.             if (x > worldW/4 && x < 3*worldW/4 && (rand() % 10) < 2)
  39.                 state[y*worldW+x] = 1;
  40.             else
  41.                 state[y*worldW+x] = 0;
  42.         }
  43.     }
  44. }
  45.  
  46. uint8_t inline cellEmpty(uint32_t state) {
  47.     return !(state & 1);
  48. }
  49.  
  50. uint32_t inline cellAt(uint32_t* world, uint32_t x, uint32_t y) {
  51.     return world[y*worldW+x];
  52. }
  53.  
  54. uint32_t inline cellSet(uint32_t* world, uint32_t x, uint32_t y, uint32_t val) {
  55.     world[y*worldW+x] = val;
  56. }
  57.  
  58. void computeCell(uint32_t* state, int x, int y, int* flag) {
  59.  
  60.     int lx, rx;
  61.  
  62.     if (cellAt(state, x, y) == CELL_SOURCE) {
  63.         if ((rand() & 0xFF) < 20 && cellEmpty(cellAt(state, x, y+1)))
  64.             cellSet(state, x, y+1, CELL_SAND);
  65.         }
  66.  
  67.     if (cellAt(state, x, y) == CELL_SAND) {
  68.  
  69.         cellSet(state, x, y, CELL_EMPTY);
  70.  
  71.         if (cellEmpty(cellAt(state, x, y+1))) {
  72.  
  73.             cellSet(state, x, y+1, CELL_SAND);
  74.  
  75.         } else {
  76.             //Swap left and right direction on every decision to mitigate asymmetry
  77.             //if (1) { lx = x-1; rx = x+1; *flag = 0; }
  78.             //else { lx = x+1; rx = x-1; *flag = 1; }
  79.  
  80.             lx = x-1; rx = x+1;
  81.  
  82.             if (cellEmpty(cellAt(state, lx, y+1))) {
  83.  
  84.                 cellSet(state, lx, y+1, CELL_SAND);
  85.  
  86.             } else if (cellEmpty(cellAt(state, rx, y+1))) {
  87.  
  88.                 cellSet(state, rx, y+1, CELL_SAND);
  89.  
  90.             } else {
  91.  
  92.                 cellSet(state, x, y, CELL_SAND);
  93.  
  94.             }
  95.  
  96.         }
  97.     }
  98. }
  99.  
  100.  
  101. void updateState(uint32_t* state) {
  102.     int x, y;
  103.     int flag = 0;
  104.  
  105.     y = worldH-1;
  106.     for (x=1; x<(worldW-1); x++) {
  107.         if (cellAt(state, x, y) == CELL_SAND) {
  108.             cellSet(state, x, y, CELL_EMPTY);
  109.         }
  110.     }
  111.  
  112.     for (y=(worldH-2); y>=0; y--) {
  113.         for (x=1; x<(worldW-1); x++) {
  114.             computeCell(state, 1 + (rand() % (worldW-2)), y, &flag);
  115.             computeCell(state, 1 + (rand() % (worldW-2)), y, &flag);
  116.         }
  117.     }
  118. }
  119.  
  120. void draw(uint32_t* state, uint32_t* pixels, float t) {
  121.     int x, y, offset;
  122.     uint32_t color;
  123.     uint32_t cell;
  124.     for (y=0; y<worldH; y++) {
  125.         offset = y*worldW*scale*scale;
  126.         for (x=0; x<worldW; x++) {
  127.             cell = cellAt(state, x ,y);
  128.             if (!cellEmpty(cell)) {
  129.                 color = cellColors[cell];
  130.                 pixels[offset+x*scale] = color;
  131.                 pixels[offset+x*scale+1] = color;
  132.                 pixels[offset+x*scale+worldW*scale] = color;
  133.                 pixels[offset+x*scale+worldW*scale+1] = color;
  134.             }
  135.         }
  136.     }
  137. }
  138.  
  139. inline uint32_t limitU32(uint32_t umin, uint32_t umax, uint32_t val) {
  140.     if (val < umin) return umin;
  141.     if (val > umax) return umax;
  142.     else return val;
  143. }
  144.  
  145. void drawCell(uint32_t* world, int x, int y) {
  146.     int i,j;
  147.     if (drawRadius == 1) {
  148.         cellSet(world, x, y, drawColor);
  149.     }
  150.     if (drawRadius > 1) {
  151.         for (i=y; i<y+drawRadius; i++)
  152.             for (j=x; j<x+drawRadius; j++)
  153.                 cellSet(world, limitU32(0, worldW-1, j), limitU32(0, worldH-1, i), drawColor);
  154.     }
  155. }
  156.  
  157. void handleMouseDown(SDL_MouseButtonEvent* event, uint32_t* world) {
  158.     mouseDown = 1;
  159.     int x = event->x;
  160.     int y = event->y;
  161.     drawCell(world, x/scale, y/scale);
  162. }
  163.  
  164. void handleMouseUp(SDL_MouseButtonEvent* event) {
  165.     mouseDown = 0;
  166. }
  167.  
  168. void handleMouseMove(SDL_MouseMotionEvent* event, uint32_t* world) {
  169.     int x, y;
  170.     if (mouseDown) {
  171.         x = event->x;
  172.         y = event->y;
  173.         drawCell(world, x/scale, y/scale);
  174.     }
  175. }
  176.  
  177. void handleKeyDown(SDL_KeyboardEvent* event, uint32_t* state) {
  178.     SDL_Keysym key = event->keysym;
  179.     if (key.scancode == SDL_SCANCODE_1) drawColor = CELL_SAND;
  180.     if (key.scancode == SDL_SCANCODE_2) drawColor = CELL_ROCK;
  181.     if (key.scancode == SDL_SCANCODE_3) drawColor = CELL_SOURCE;
  182.     if (key.scancode == SDL_SCANCODE_4) drawColor = CELL_EMPTY;
  183.     if (key.scancode == SDL_SCANCODE_SPACE) pause = !pause;
  184.     if (key.scancode == SDL_SCANCODE_EQUALS) drawRadius++;
  185.     if (key.scancode == SDL_SCANCODE_MINUS) if (drawRadius > 1) drawRadius--;
  186.     if (key.scancode == SDL_SCANCODE_S) {
  187.         FILE* f = fopen("save.bin", "w");
  188.         fwrite(state, sizeof(uint32_t), worldW*worldH, f);
  189.         fclose(f);
  190.     }
  191.     if (key.scancode == SDL_SCANCODE_L) {
  192.         FILE* f = fopen("save.bin", "r");
  193.         int n = fread(state, sizeof(uint32_t), worldW*worldH, f);
  194.         fclose(f);
  195.     }
  196. }
  197.  
  198. int main(int argc, char *argv[]) {
  199.  
  200.     srand(81237);
  201.  
  202.     screenW = worldW*scale;
  203.     screenH = worldH*scale;
  204.  
  205.     SDL_Window *win = NULL;
  206.     SDL_Renderer *renderer = NULL;
  207.     SDL_Texture *screen = NULL;
  208.     int posX = 100, posY = 100, width = screenW, height = screenH;
  209.  
  210.     SDL_Init(SDL_INIT_VIDEO);
  211.  
  212.     win = SDL_CreateWindow("Hello World", posX, posY, width, height, 0);
  213.  
  214.     renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
  215.  
  216.     screen = SDL_CreateTexture(renderer,
  217.                                 SDL_PIXELFORMAT_ARGB8888,
  218.                                 SDL_TEXTUREACCESS_STREAMING,
  219.                                 screenW, screenH);
  220.  
  221.     uint32_t* state = (uint32_t*) malloc(sizeof(uint32_t)*worldW*worldH);
  222.  
  223.     initState(state);
  224.  
  225.     uint32_t* pixels = (uint32_t*) malloc(sizeof(uint32_t)*screenW*screenH);
  226.  
  227.     float t = 0;
  228.  
  229.     uint32_t beforeT, afterT;
  230.  
  231.     while (1) {
  232.  
  233.         beforeT = SDL_GetTicks();
  234.  
  235.         t++;
  236.  
  237.         SDL_Event e;
  238.         if (SDL_PollEvent(&e)) {
  239.             if (e.type == SDL_QUIT) {
  240.                 break;
  241.             }
  242.             if (e.type == SDL_MOUSEBUTTONDOWN) {
  243.                 handleMouseDown(&e.button, state);
  244.             }
  245.             if (e.type == SDL_MOUSEBUTTONUP) {
  246.                 handleMouseUp(&e.button);
  247.             }
  248.             if (e.type == SDL_MOUSEMOTION) {
  249.                 handleMouseMove(&e.motion, state);
  250.             }
  251.             if (e.type == SDL_KEYDOWN) {
  252.                 handleKeyDown(&e.key, state);
  253.             }
  254.         }
  255.  
  256.         if (!pause) {
  257.  
  258.             clearScreen(pixels);
  259.  
  260.             updateState(state);
  261.  
  262.             draw(state, pixels, t);
  263.  
  264.             SDL_UpdateTexture(screen, NULL, pixels, screenW * sizeof (uint32_t));
  265.  
  266.             SDL_RenderClear(renderer);
  267.             SDL_RenderCopy(renderer, screen, NULL, NULL);
  268.             SDL_RenderPresent(renderer);
  269.  
  270.             afterT = SDL_GetTicks();
  271.  
  272.             if (afterT - beforeT < 1000.0/fps) {
  273.                 //SDL_Delay(1000.0/fps - (afterT - beforeT));
  274.                 //printf("delay: %f\n", 1000.0/fps - (afterT - beforeT));
  275.             }
  276.         } else {
  277.             SDL_Delay(20);
  278.         }
  279.     }
  280.  
  281.     SDL_DestroyTexture(screen);
  282.     SDL_DestroyRenderer(renderer);
  283.     SDL_DestroyWindow(win);
  284.  
  285.     SDL_Quit();
  286.  
  287.     return 0;
  288. }
Advertisement
Add Comment
Please, Sign In to add comment