├── README.md └── temple_run.c /README.md: -------------------------------------------------------------------------------- 1 | # temple_run_ascii 2 | compile with 3 | `gcc temp.c -lX11 -lm` 4 | 5 | use arrows as controls 6 | 7 | only tested on ubuntu 20.04 8 | -------------------------------------------------------------------------------- /temple_run.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "X11/keysym.h" 7 | #include 8 | #include 9 | 10 | 11 | #define X_PIX 500 12 | #define Y_PIX 200 13 | #define WIDTH 1 14 | #define HEIGHT 0.7 15 | 16 | 17 | typedef struct Vector{ 18 | float x; 19 | float y; 20 | float z; 21 | } vect; 22 | 23 | typedef struct Vector2{ 24 | float x; 25 | float y; 26 | } vect2; 27 | 28 | vect vect_scale(float s, vect v) { 29 | vect res = {s*v.x, s*v.y, s*v.z}; 30 | return res; 31 | } 32 | 33 | vect vect_add(vect v1, vect v2) { 34 | vect res; 35 | res.x = v1.x + v2.x; 36 | res.y = v1.y + v2.y; 37 | res.z = v1.z + v2.z; 38 | return res; 39 | } 40 | 41 | vect vect_sub(vect v1, vect v2) { 42 | vect v3 = vect_scale(-1, v2); 43 | return vect_add(v1, v3); 44 | } 45 | 46 | 47 | vect vect_normalize(vect v) { 48 | float len = sqrt(v.x * v.x + v.y * v.y + v.z * v.z); 49 | v.x /= len; 50 | v.y /= len; 51 | v.z /= len; 52 | return v; 53 | } 54 | 55 | float vect_dot(vect v1, vect v2) { 56 | return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; 57 | } 58 | 59 | vect vect_cross(vect v1, vect v2) { 60 | return (vect) {v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x}; 61 | } 62 | 63 | void vect_print(vect v) { 64 | printf("x=%f, y=%f, z=%f\n", v.x, v.y, v.z); 65 | } 66 | 67 | vect2 vect2_add(vect2 v1, vect2 v2) { 68 | return (vect2) {v1.x+v2.x, v1.y+v2.y}; 69 | } 70 | 71 | vect2 vect2_sub(vect2 v1, vect2 v2) { 72 | return (vect2) {v1.x-v2.x, v1.y-v2.y}; 73 | } 74 | 75 | vect2 vect2_scale(float a, vect2 v) { 76 | return (vect2) {a*v.x, a*v.y}; 77 | } 78 | 79 | float vect2_dot(vect2 v1, vect2 v2) { 80 | return v1.x*v2.x + v1.y*v2.y; 81 | } 82 | 83 | void vect2_print(vect2 v) { 84 | printf("%f %f\n", v.x, v.y); 85 | } 86 | 87 | 88 | int key_is_pressed(KeySym ks) { 89 | Display *dpy = XOpenDisplay(0); 90 | char keys_return[32]; 91 | XQueryKeymap(dpy, keys_return); 92 | KeyCode kc2 = XKeysymToKeycode(dpy, ks); 93 | int isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7))); 94 | XCloseDisplay(dpy); 95 | return isPressed; 96 | } 97 | 98 | 99 | vect2 project_point(vect dir, vect point) { 100 | float alpha = vect_dot(point, dir) / (1 + vect_dot(point, dir)); 101 | // project onto plane orthogonal to dir through -dir 102 | vect p1 = vect_add(vect_scale(-alpha, dir), vect_scale(1-alpha, point)); 103 | // turn into 2 coordinates 104 | vect x = vect_normalize((vect) {-dir.y, dir.x, 0}); 105 | vect y = vect_cross(dir, x); 106 | float x_coord = vect_dot(p1, x); 107 | float y_coord = vect_dot(p1, y); 108 | return (vect2) {x_coord, y_coord}; 109 | } 110 | 111 | 112 | void put_point(vect2 projected, char c, char **picture) { 113 | int x_coord = (int) ((-projected.x + WIDTH)/(2*WIDTH)*X_PIX); 114 | int y_coord = (int) ((-projected.y + HEIGHT)/(2*HEIGHT)*Y_PIX); 115 | if (x_coord < 0 || x_coord >= X_PIX || y_coord < 0 || y_coord >= Y_PIX) { 116 | return; 117 | } 118 | else { 119 | picture[y_coord][x_coord] = c; 120 | } 121 | } 122 | 123 | void draw_point(vect dir, vect point, char c, char **picture) { 124 | // can't see points behind you 125 | if (vect_dot(dir, point) <= 0) { 126 | return; 127 | } 128 | vect2 projected = project_point(dir, point); 129 | put_point(projected, c, picture); 130 | } 131 | 132 | void draw_line(vect dir, vect v_from, vect v_to, char c, char **picture) { 133 | // remove the part of the line that is behind the viewer 134 | float scale_from = vect_dot(v_from, dir); 135 | float scale_to = vect_dot(v_to, dir); 136 | if (scale_from < 0 && scale_to < 0) { 137 | return; 138 | } 139 | if (scale_from < 0) { 140 | scale_from = -scale_from; 141 | v_from = vect_add(vect_scale(scale_from/(scale_from+scale_to), v_to), vect_scale(scale_to/(scale_from+scale_to), v_from)); 142 | } 143 | if (scale_to < 0) { 144 | scale_to = -scale_to; 145 | v_to = vect_add(vect_scale(scale_to/(scale_to+scale_from), v_from), vect_scale(scale_from/(scale_to+scale_from), v_to)); 146 | } 147 | // now draw the line 148 | vect2 proj_from = project_point(dir, v_from); 149 | vect2 proj_to = project_point(dir, v_to); 150 | vect2 diff = vect2_sub(proj_to, proj_from); 151 | int steps = (X_PIX * (fabs(diff.x)/WIDTH) + Y_PIX * (fabs(diff.y)/HEIGHT))/2 + 1; 152 | vect2 step = vect2_scale(1.0/steps, diff); 153 | for (int i = 0; i <= steps; ++i) { 154 | put_point(proj_from, c, picture); 155 | proj_from = vect2_add(proj_from, step); 156 | } 157 | } 158 | 159 | 160 | void draw_ascii(char **picture) { 161 | printf("\033[0;0H"); // jump to position 0 0 to overwrite current picture 162 | for (int i = 0; i < Y_PIX; ++i) { 163 | for (int j = 0; j < X_PIX; ++j) { 164 | printf("%c", picture[i][j]); 165 | } 166 | printf("\n"); 167 | } 168 | } 169 | 170 | char **empty_picture(char empty_char) { 171 | char **pic; 172 | pic = malloc(sizeof(char *) * Y_PIX); 173 | for (int i = 0; i < Y_PIX; ++i) { 174 | pic[i] = malloc(sizeof(char *) * X_PIX); 175 | for (int j = 0; j < X_PIX; ++j) { 176 | pic[i][j] = empty_char; 177 | } 178 | } 179 | return pic; 180 | } 181 | 182 | float random_float() 183 | { 184 | float r = (float)rand()/(float)RAND_MAX; 185 | return r; 186 | } 187 | 188 | int *init_obstacles(int size) { 189 | /* 190 | 0 = no obstacle 191 | 1 = right thing 192 | 2 = left thing 193 | 3 = down thing 194 | 4 = up thing 195 | */ 196 | int *res = calloc(size, sizeof(int)); 197 | for (int i = 0; i < size; ++i) { 198 | res[i] = rand()%5; 199 | if (res[i] != 0) { 200 | i += 2; 201 | } 202 | } 203 | res[0] = 0; 204 | res[1] = 0; 205 | res[size-1] = 0; 206 | return res; 207 | } 208 | 209 | int min(int a, int b) { 210 | if (a < b) { 211 | return a; 212 | } 213 | return b; 214 | } 215 | 216 | 217 | #define PATH_WIDTH 1 218 | #define Y_BORDER 0.7 219 | #define SIGHT 10 // how far you can see (roughly) 220 | #define GRAVITY 30 221 | #define JUMP_SPEED 8 222 | #define SPEED_INCREASE 0.1 223 | 224 | int main(void) { 225 | START: 226 | srand(time(NULL)); 227 | 228 | vect dir = (vect) {1, 0, 0}; 229 | float speed = 3; 230 | float tstep = 0.03; 231 | int turn_dist_orig = 5 + rand()%10; 232 | float turn_dist = turn_dist_orig; 233 | int next_turn_dist = 5 + rand()%10; 234 | // next_turn: -1 for right, 1 for left 235 | int next_turn = (rand()%2)*2 - 1; 236 | float cam_height = 1; 237 | float y_move_speed = 3; 238 | float duckspeed = 4; 239 | float zpos = 0; 240 | float ypos = 0; 241 | float zspeed = 0; 242 | 243 | int *obstacles = malloc(sizeof(int)*100); 244 | for (int i = 0; i < 100; ++i) { 245 | obstacles[i] = 0; 246 | } 247 | int *next_obstacles = init_obstacles(next_turn_dist+1); 248 | 249 | // main game loop 250 | int i = 0; 251 | while (1) { 252 | // keyboard stuff 253 | // move left/right 254 | if (key_is_pressed(XK_Right)) { 255 | ypos = fmax(ypos-y_move_speed*tstep, -Y_BORDER); 256 | } 257 | else if (key_is_pressed(XK_Left)) { 258 | ypos = fmin(ypos + y_move_speed*tstep, Y_BORDER); 259 | } 260 | else { 261 | if (ypos > 0) { 262 | ypos = fmax(0, ypos-y_move_speed*tstep); 263 | } 264 | else if (ypos < 0) { 265 | ypos = fmin(0, ypos + y_move_speed*tstep); 266 | } 267 | } 268 | // jump 269 | if (zpos == 0 && key_is_pressed(XK_Up)) { 270 | // initiate jump 271 | zspeed = JUMP_SPEED; 272 | } 273 | zpos += zspeed*tstep; 274 | zspeed -= GRAVITY*tstep; 275 | if (zpos < 0) { 276 | zspeed = 0; 277 | } 278 | // duck 279 | if (key_is_pressed(XK_Down)) { 280 | zpos -= duckspeed*tstep; 281 | zpos = fmax(zpos, -0.5); 282 | } 283 | else if (zpos < 0) { 284 | zpos += duckspeed*tstep; 285 | if (zpos >= 0) { 286 | zpos = 0; 287 | } 288 | } 289 | // lost 290 | if (turn_dist < -2) { 291 | draw_ascii(empty_picture('-')); 292 | break; 293 | } 294 | // turn 295 | else if (turn_dist < 0) { 296 | if ((next_turn == -1 && key_is_pressed(XK_Right)) || (next_turn == 1 && key_is_pressed(XK_Left))) { 297 | turn_dist = next_turn_dist; 298 | turn_dist_orig = next_turn_dist; 299 | next_turn_dist = 5 + rand()%10; 300 | next_turn = (rand()%2)*2 - 1; 301 | obstacles = next_obstacles; 302 | next_obstacles = init_obstacles(next_turn_dist+1); 303 | } 304 | } 305 | char **pic = empty_picture(' '); 306 | for (float d = turn_dist; d > 0; d -= 1) { 307 | draw_line(dir, (vect){d, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){d, PATH_WIDTH-ypos, -(cam_height+zpos)}, 'o', pic); 308 | } 309 | 310 | // check for collision 311 | float real_pos = turn_dist_orig - turn_dist; 312 | int int_pos = trunc(real_pos); 313 | // printf("\n%f %f %d %f\n", next_turn_dist, real_pos, int_pos, fabs(int_pos-real_pos)); 314 | if (fabs(int_pos - real_pos) < tstep*speed*5) { 315 | // check for collision 316 | if (obstacles[int_pos] == 1 && ypos < 0.1) { 317 | break; 318 | } 319 | else if (obstacles[int_pos] == 2 && ypos > -0.1) { 320 | break; 321 | } 322 | else if (obstacles[int_pos] == 3 && zpos < 0.5) { 323 | break; 324 | } 325 | else if (obstacles[int_pos] == 4 && zpos > -0.2) { 326 | break; 327 | } 328 | } 329 | 330 | // draw path and next path 331 | if (turn_dist > SIGHT) { 332 | draw_line(dir, (vect){0, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){SIGHT, PATH_WIDTH-ypos, -(cam_height+zpos)}, 'x', pic); 333 | draw_line(dir, (vect){0, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){SIGHT, -PATH_WIDTH-ypos, -(cam_height+zpos)}, 'x', pic); 334 | } 335 | else { 336 | if (next_turn == -1) { 337 | draw_line(dir, (vect){0, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){turn_dist+2*PATH_WIDTH, PATH_WIDTH-ypos, -(cam_height+zpos)}, 'x', pic); 338 | draw_line(dir, (vect){0, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){turn_dist, -PATH_WIDTH-ypos, -(cam_height+zpos)}, 'x', pic); 339 | draw_line(dir, (vect){turn_dist+2*PATH_WIDTH, PATH_WIDTH-ypos, -(cam_height+zpos)}, 340 | (vect){turn_dist+2*PATH_WIDTH, -SIGHT, -(cam_height+zpos)}, 'x', pic); 341 | draw_line(dir, (vect){turn_dist, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){turn_dist, -SIGHT, -(cam_height+zpos)}, 'x', pic); 342 | } 343 | else { // next_turn = 1 344 | draw_line(dir, (vect){0, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){turn_dist+2*PATH_WIDTH, -PATH_WIDTH-ypos, -(cam_height+zpos)}, 'x', pic); 345 | draw_line(dir, (vect){0, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){turn_dist, PATH_WIDTH-ypos, -(cam_height+zpos)}, 'x', pic); 346 | draw_line(dir, (vect){turn_dist+2*PATH_WIDTH, -PATH_WIDTH-ypos, -(cam_height+zpos)}, 347 | (vect){turn_dist+2*PATH_WIDTH, SIGHT, -(cam_height+zpos)}, 'x', pic); 348 | draw_line(dir, (vect){turn_dist, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){turn_dist, SIGHT, -(cam_height+zpos)}, 'x', pic); 349 | } 350 | for (float i = 1-next_turn*ypos; i < SIGHT; i += 1) { 351 | draw_line(dir, (vect){turn_dist, i*next_turn, -(cam_height+zpos)}, 352 | (vect){turn_dist+2*PATH_WIDTH, i*next_turn, -(cam_height+zpos)}, 'x', pic); 353 | } 354 | } 355 | 356 | // draw obstacles 357 | for (int i = 0; i <= turn_dist; ++i) { 358 | int obst = obstacles[turn_dist_orig - i]; 359 | float pos = turn_dist - i; 360 | if (obst == 1) { 361 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, -PATH_WIDTH-ypos, -zpos+0.5}, 'o', pic); 362 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, -ypos, -zpos+0.5}, 'o', pic); 363 | draw_line(dir, (vect){pos, -ypos, -(cam_height+zpos)}, (vect){pos, -ypos, -zpos+0.5}, 'o', pic); 364 | draw_line(dir, (vect){pos, -ypos, -(cam_height+zpos)}, (vect){pos, -PATH_WIDTH-ypos, -zpos+0.5}, 'o', pic); 365 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, -ypos, -zpos+0.5}, 'o', pic); 366 | 367 | } 368 | else if (obst == 2) { 369 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, PATH_WIDTH-ypos, -zpos+0.5}, 'o', pic); 370 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, -ypos, -zpos+0.5}, 'o', pic); 371 | draw_line(dir, (vect){pos, -ypos, -(cam_height+zpos)}, (vect){pos, -ypos, -zpos+0.5}, 'o', pic); 372 | draw_line(dir, (vect){pos, -ypos, -(cam_height+zpos)}, (vect){pos, PATH_WIDTH-ypos, -zpos+0.5}, 'o', pic); 373 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, -ypos, -zpos+0.5}, 'o', pic); 374 | } 375 | else if (obst == 3) { 376 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, PATH_WIDTH-ypos, -zpos-0.5}, 'o', pic); 377 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -zpos-0.5}, (vect){pos, -PATH_WIDTH-ypos, -zpos-0.5}, 'o', pic); 378 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, -PATH_WIDTH-ypos, -zpos-0.5}, 'o', pic); 379 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, PATH_WIDTH-ypos, -zpos-0.5}, 'o', pic); 380 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -(cam_height+zpos)}, (vect){pos, -PATH_WIDTH-ypos, -zpos-0.5}, 'o', pic); 381 | } 382 | else if (obst == 4) { 383 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, PATH_WIDTH-ypos, -zpos-0.2}, 'o', pic); 384 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -zpos-0.2}, (vect){pos, -PATH_WIDTH-ypos, -zpos-0.2}, 'o', pic); 385 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, -PATH_WIDTH-ypos, -zpos-0.2}, 'o', pic); 386 | draw_line(dir, (vect){pos, -PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, PATH_WIDTH-ypos, -zpos-0.2}, 'o', pic); 387 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, -PATH_WIDTH-ypos, -zpos-0.2}, 'o', pic); 388 | draw_line(dir, (vect){pos, PATH_WIDTH-ypos, -zpos+0.5}, (vect){pos, -PATH_WIDTH-ypos, -zpos+0.5}, 'o', pic); 389 | } 390 | } 391 | // draw next obstacles 392 | if (turn_dist < SIGHT) { 393 | for (int i = 0; i <= min(SIGHT, next_turn_dist); ++i) { 394 | int obst = next_obstacles[i]; 395 | float obst_y = -ypos+(i+PATH_WIDTH)*next_turn; 396 | float right_x = turn_dist + (next_turn+1)*PATH_WIDTH; 397 | float left_x = turn_dist + (next_turn*(-1)+1)*PATH_WIDTH; 398 | if (obst == 1) { 399 | draw_line(dir, (vect){right_x, obst_y, -(cam_height+zpos)}, (vect){right_x, obst_y, -zpos+0.5}, 'o', pic); 400 | draw_line(dir, (vect){turn_dist+PATH_WIDTH, obst_y, -(cam_height+zpos)}, (vect){turn_dist+PATH_WIDTH, obst_y, -zpos+0.5}, 'o', pic); 401 | draw_line(dir, (vect){right_x, obst_y, -zpos+0.5}, (vect){turn_dist+PATH_WIDTH, obst_y, -zpos+0.5}, 'o', pic); 402 | draw_line(dir, (vect){turn_dist+PATH_WIDTH, obst_y, -(cam_height+zpos)},(vect){right_x, obst_y, -zpos+0.5}, 'o', pic); 403 | draw_line(dir, (vect){turn_dist+PATH_WIDTH, obst_y, -zpos+0.5}, (vect){right_x, obst_y, -(cam_height+zpos)}, 'o', pic); 404 | 405 | } 406 | else if (obst == 2) { 407 | draw_line(dir, (vect){left_x, obst_y, -(cam_height+zpos)}, (vect){left_x, obst_y, -zpos+0.5}, 'o', pic); 408 | draw_line(dir, (vect){turn_dist+PATH_WIDTH, obst_y, -(cam_height+zpos)}, (vect){turn_dist+PATH_WIDTH, obst_y, -zpos+0.5}, 'o', pic); 409 | draw_line(dir, (vect){left_x, obst_y, -zpos+0.5}, (vect){turn_dist+PATH_WIDTH, obst_y, -zpos+0.5}, 'o', pic); 410 | draw_line(dir, (vect){turn_dist+PATH_WIDTH, obst_y, -(cam_height+zpos)},(vect){left_x, obst_y, -zpos+0.5}, 'o', pic); 411 | draw_line(dir, (vect){turn_dist+PATH_WIDTH, obst_y, -zpos+0.5}, (vect){left_x, obst_y, -(cam_height+zpos)}, 'o', pic); 412 | } 413 | else if (obst == 3) { 414 | draw_line(dir, (vect){left_x, obst_y, -(cam_height+zpos)}, (vect){left_x, obst_y, -zpos-0.5}, 'o', pic); 415 | draw_line(dir, (vect){right_x, obst_y, -(cam_height+zpos)}, (vect){right_x, obst_y, -zpos-0.5}, 'o', pic); 416 | draw_line(dir, (vect){left_x, obst_y, -zpos-0.5}, (vect){right_x, obst_y, -zpos-0.5}, 'o', pic); 417 | draw_line(dir, (vect){right_x, obst_y, -(cam_height+zpos)},(vect){left_x, obst_y, -zpos-0.5}, 'o', pic); 418 | draw_line(dir, (vect){right_x, obst_y, -zpos-0.5}, (vect){left_x, obst_y, -(cam_height+zpos)}, 'o', pic); 419 | } 420 | else if (obst == 4) { 421 | draw_line(dir, (vect){left_x, obst_y, -zpos+0.5}, (vect){left_x, obst_y, -zpos-0.2}, 'o', pic); 422 | draw_line(dir, (vect){right_x, obst_y, -zpos+0.5}, (vect){right_x, obst_y, -zpos-0.2}, 'o', pic); 423 | draw_line(dir, (vect){left_x, obst_y, -zpos-0.2}, (vect){right_x, obst_y, -zpos-0.2}, 'o', pic); 424 | draw_line(dir, (vect){right_x, obst_y, -zpos+0.5},(vect){left_x, obst_y, -zpos-0.2}, 'o', pic); 425 | draw_line(dir, (vect){right_x, obst_y, -zpos-0.2}, (vect){left_x, obst_y, -zpos+0.5}, 'o', pic); 426 | draw_line(dir, (vect){right_x, obst_y, -zpos+0.5}, (vect){left_x, obst_y, -zpos+0.5}, 'o', pic); 427 | } 428 | } 429 | } 430 | turn_dist -= tstep*speed; 431 | draw_ascii(pic); 432 | // printf("%f %d \n", turn_dist, next_turn); 433 | // printf("%d\n", key_is_pressed(XK_Right)); 434 | speed += SPEED_INCREASE*tstep; 435 | y_move_speed += SPEED_INCREASE*tstep*0.5; 436 | duckspeed += SPEED_INCREASE*tstep*0.5; 437 | printf("%d\n", i++); 438 | usleep(1000000*tstep); 439 | } 440 | 441 | // game finished 442 | for (int i = 0; i < 2; ++i) { 443 | draw_ascii(empty_picture(' ')); 444 | usleep(150000); 445 | draw_ascii(empty_picture('X')); 446 | usleep(150000); 447 | } 448 | for (int i = 0; i < 200; ++i) { 449 | if (key_is_pressed(XK_Up) || key_is_pressed(XK_Down) || key_is_pressed(XK_Left) || key_is_pressed(XK_Right)) { 450 | goto START; 451 | } 452 | usleep(10000); 453 | } 454 | draw_ascii(empty_picture(' ')); 455 | } 456 | --------------------------------------------------------------------------------