Advertisement
Guest User

Untitled

a guest
Dec 16th, 2019
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.59 KB | None | 0 0
  1. /**
  2. * spacexplore.c -- прототип игры управления звездолетом
  3. *
  4. * Copyright (c) 2019, Nikita Semenov <ndsemeno@cs.mail.petrsu.ru>
  5. *
  6. * This code is licensed under a MIT-style license.
  7. */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <time.h>
  13. #include <SDL.h>
  14. #include <SDL_ttf.h>
  15.  
  16. #define VXD 8
  17. #define VYD 8
  18.  
  19. #define N 5
  20.  
  21.  
  22. /* Описание экрана игры */
  23. typedef struct _gamescreen {
  24. /* Поверхность отрисовки */
  25. SDL_Surface* sprite;
  26. } gamescreen;
  27.  
  28.  
  29. /* Описание фона */
  30. typedef struct _gamebackground {
  31. /* Поверхность отрисовки */
  32. SDL_Surface* sprite;
  33. } gamebackground;
  34.  
  35.  
  36. /* Описание управляемого пользователем корабля */
  37. typedef struct _spaceship {
  38. /* Поверхность отрисовки */
  39. SDL_Surface* sprite;
  40. /* Координаты корабля */
  41. int x;
  42. int y;
  43. /* Проекции скорости корабля */
  44. int vx;
  45. int vy;
  46. } spaceship;
  47.  
  48. /* Описание характеристик астероидов */
  49. typedef struct _position {
  50. /* Координаты астероида */
  51. int x;
  52. int y;
  53. /* Проекции скорости астероида */
  54. int vx;
  55. int vy;
  56. } position;
  57.  
  58. /* Описание астероидов */
  59. typedef struct _obstacle {
  60. /* Поверхность отрисовки */
  61. SDL_Surface* sprite;
  62. /* Физические характеристики */
  63. position *pos[N];
  64. } obstacle;
  65.  
  66. /* Описание ресурса */
  67. typedef struct _gameresources {
  68. /* Поверхность отрисовки */
  69. SDL_Surface* sprite;
  70. /* Количество собранных ресурсов */
  71. int count;
  72. /* Координаты ресурса */
  73. int x;
  74. int y;
  75. } gameresources;
  76.  
  77.  
  78. /* Ресурсы и состояние игры */
  79. typedef struct _game {
  80. /* Экран игры */
  81. gamescreen* screen;
  82. /* Корабль пользователя */
  83. spaceship* ship;
  84. /* Фон */
  85. gamebackground* background;
  86. /* Астероиды */
  87. obstacle* asteroid;
  88. /* Ресурс */
  89. gameresources* resource;
  90. TTF_Font* font;
  91. int timer;
  92. } game;
  93.  
  94. /**
  95. * Инициализирует игру
  96. * @returns g указатель на структуру состояния игры
  97. */
  98. game* init();
  99.  
  100. /**
  101. * Инициализирует игру
  102. * @param g указатель на структуру состояния игры
  103. */
  104. void run(game* g);
  105.  
  106. /**
  107. * Отрисовывает объекты в новой позиции
  108. * @param g указатель на структуру состояния игры
  109. */
  110. void draw(game* g);
  111.  
  112. /**
  113. * Проверяет столкновение корабля с объектом
  114. * @returns true (1) если, обнаружено столкновение
  115. * В противном случае - false (0)
  116. */
  117. int asteroid_crash(spaceship* ship, obstacle* asteroid, int i);
  118.  
  119. /**
  120. * Проверяет столкновение корабля с ресурсом
  121. * @returns true (1) если, обнаружено столкновение
  122. * В противном случае - false (0)
  123. */
  124. int bitcoin_get(spaceship* ship, gameresources* resource);
  125.  
  126. /* Отображает таймер и счетчик ресурсов */
  127. void show_counter(game* g, const int counter, const int mode);
  128.  
  129. /* Отображает статус прохождения игры */
  130. void show_text(game* g);
  131.  
  132. /**
  133. * Основная программа
  134. */
  135. int main()
  136. {
  137. /* Инициализация генератора псевдослучайных чисел */
  138. srand(time(NULL));
  139.  
  140. /* Инициализируем игру */
  141. game* g = init();
  142.  
  143. /* Запускаем цикл обработки событий игры */
  144. run(g);
  145.  
  146. return 0;
  147. }
  148.  
  149.  
  150. /**
  151. * Инициализирует игру
  152. * @returns g указатель на структуру состояния игры
  153. */
  154. game* init()
  155. {
  156. /* Создаем структуру представления состояния игры */
  157. game* g;
  158. g = (game*)malloc(sizeof(game));
  159. if (g == NULL) {
  160. fprintf(stderr, "Not enough memory!\n");
  161. exit(EXIT_FAILURE);
  162. }
  163.  
  164. /* Инициализируем библиотеку SDL, используем только видеоподсистему */
  165. if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  166. fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
  167. exit(EXIT_FAILURE);
  168. }
  169.  
  170. /* Регистрируем обработчик завершения программы */
  171. atexit(SDL_Quit);
  172.  
  173. /* Инициализируем библиотеку SDL_ttf и загружаем шрифт */
  174. TTF_Init();
  175. g->font = TTF_OpenFont("AbrilFatface-Regular.ttf", 44);
  176.  
  177. /* Выделяем память для структуры представления экрана */
  178. g->screen = (gamescreen*)malloc(sizeof(gamescreen));
  179. if (g->screen == NULL) {
  180. fprintf(stderr, "Not enough memory!\n");
  181. exit(EXIT_FAILURE);
  182. }
  183.  
  184. /* Инициализируем видеорежим */
  185. g->screen->sprite =
  186. SDL_SetVideoMode(1024, 768, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
  187. if (g->screen->sprite == NULL) {
  188. fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError());
  189. exit(EXIT_FAILURE);
  190. }
  191.  
  192. /* Выделяем память для структуры представления фона */
  193. g->background = (gamebackground*)malloc(sizeof(gamebackground));
  194. if (g->background == NULL) {
  195. fprintf(stderr, "Not enough memory!\n");
  196. exit(EXIT_FAILURE);
  197. }
  198.  
  199. g->background->sprite = SDL_LoadBMP("background.bmp");
  200. if (g->background->sprite == NULL) {
  201. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  202. exit(EXIT_FAILURE);
  203. }
  204.  
  205. /* Выделяем память для структуры представления корабля */
  206. g->ship = (spaceship*)malloc(sizeof(spaceship));
  207. if (g->ship == NULL) {
  208. fprintf(stderr, "Not enough memory!\n");
  209. exit(EXIT_FAILURE);
  210. }
  211.  
  212. g->ship->sprite = SDL_LoadBMP("ship.bmp");
  213. if (g->ship->sprite == NULL) {
  214. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  215. exit(EXIT_FAILURE);
  216. }
  217.  
  218. /* Выделяем память для структуры представления астероидов */
  219. g->asteroid = (obstacle*)malloc(sizeof(obstacle));
  220. if (g->asteroid == NULL) {
  221. fprintf(stderr, "Not enough memory!\n");
  222. exit(EXIT_FAILURE);
  223. }
  224.  
  225. g->asteroid->sprite = SDL_LoadBMP("asteroid.bmp");
  226. if (g->asteroid->sprite == NULL) {
  227. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  228. exit(EXIT_FAILURE);
  229. }
  230.  
  231. /* Выделяем память для структуры представления ресурса */
  232. g->resource = (gameresources*)malloc(sizeof(gameresources));
  233. if (g->resource == NULL) {
  234. fprintf(stderr, "Not enough memory!\n");
  235. exit(EXIT_FAILURE);
  236. }
  237.  
  238. g->resource->sprite = SDL_LoadBMP("bitcoin.bmp");
  239. if (g->resource->sprite == NULL) {
  240. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  241. exit(EXIT_FAILURE);
  242. }
  243.  
  244. /* Выделяем память для структуры представления характеристик астероидов */
  245. for (int i = 0; i < N; i++) {
  246. /* Для каждого астероида отдельно */
  247. g->asteroid->pos[i] = (position*)malloc(sizeof(position));
  248. if (g->asteroid->pos[i] == NULL) {
  249. fprintf(stderr, "Not enough memory!\n");
  250. exit(EXIT_FAILURE);
  251. }
  252. }
  253.  
  254. /* Помещаем корабль в начальную позицию */
  255. g->ship->x = (g->screen->sprite->w - g->ship->sprite->w) / 2;
  256. g->ship->y = g->screen->sprite->h - g->ship->sprite->h;
  257.  
  258. /* Помещаем астероиды в начальную позицию */
  259. for (int i = 0; i < N; i++) {
  260. /* Для каждого астероида */
  261. g->asteroid->pos[i]->x = rand() % (g->screen->sprite->w - g->asteroid->sprite->w);
  262. g->asteroid->pos[i]->y = -(g->asteroid->sprite->h);
  263.  
  264. g->asteroid->pos[i]->vx = rand() % 10 - 5;
  265. g->asteroid->pos[i]->vy = rand() % 10 + 1;
  266. }
  267.  
  268. /* Помещаем ресурс в начальную позицию */
  269. g->resource->x = rand() % (g->screen->sprite->w - g->resource->sprite->w);
  270. g->resource->y = rand() % (g->screen->sprite->h * 2 / 3 - g->resource->sprite->h) + g->screen->sprite->h / 3;
  271. g->resource->count = 0;
  272.  
  273. /* Устанавливаем заголовок окна */
  274. SDL_WM_SetCaption("Space Explore", NULL);
  275.  
  276. return g;
  277. }
  278.  
  279.  
  280. /**
  281. * Инициализирует игру
  282. * @param g указатель на структуру состояния игры
  283. */
  284. void run(game* g)
  285. {
  286. /* Флажок выхода */
  287. int done = 0;
  288.  
  289. unsigned int start_time = SDL_GetTicks();
  290.  
  291. int left_ship_border = 0;
  292. int upper_ship_border = (g->screen->sprite->h) / 3;
  293. int right_ship_border = g->screen->sprite->w - g->ship->sprite->w;
  294. int lower_ship_border = g->screen->sprite->h - g->ship->sprite->h;
  295.  
  296. int left_border = -(g->asteroid->sprite->w);
  297. int right_border = g->screen->sprite->w;
  298. int lower_border = g->screen->sprite->h;
  299.  
  300. char text1[] = "Mission complete!";
  301. char text2[] = "Mission failed :(";
  302. char text3[] = "Press ESC to exit or SPACE to restart";
  303.  
  304. /* Продолжаем выполнение, пока не поднят флажок */
  305. while (!done) {
  306.  
  307. for (int i = 0; i < N; i++) {
  308. if (asteroid_crash(g->ship, g->asteroid, i)) {
  309. done = 1;
  310. show_text(g);
  311. SDL_Delay(2500);
  312. }
  313. }
  314.  
  315. /* Структура описания события */
  316. SDL_Event event;
  317.  
  318. /* Извлекаем и обрабатываем все доступные события */
  319. while (SDL_PollEvent(&event)) {
  320. switch (event.type) {
  321. /* Если клавишу нажали */
  322. case SDL_KEYDOWN:
  323. switch (event.key.keysym.sym) {
  324. case SDLK_LEFT:
  325. g->ship->vx += -VXD;
  326. break;
  327. case SDLK_RIGHT:
  328. g->ship->vx += VXD;
  329. break;
  330. case SDLK_UP:
  331. g->ship->vy += -VYD;
  332. break;
  333. case SDLK_DOWN:
  334. g->ship->vy += VYD;
  335. break;
  336. case SDLK_ESCAPE:
  337. done = 1;
  338. break;
  339. }
  340. break;
  341. /* Если клавишу отпустили */
  342. case SDL_KEYUP:
  343. switch (event.key.keysym.sym) {
  344. case SDLK_LEFT:
  345. g->ship->vx += VXD;
  346. break;
  347. case SDLK_RIGHT:
  348. g->ship->vx += -VXD;
  349. break;
  350. case SDLK_UP:
  351. g->ship->vy += VYD;
  352. break;
  353. case SDLK_DOWN:
  354. g->ship->vy += -VYD;
  355. break;
  356. default:
  357. break;
  358. }
  359. break;
  360. /* Если закрыли окно */
  361. case SDL_QUIT:
  362. done = 1;
  363. break;
  364. default:
  365. break;
  366. }
  367. }
  368.  
  369. /* Проверка выхода корабля за границу */
  370. if (g->ship->x + g->ship->vx >= left_ship_border &&
  371. g->ship->x + g->ship->vx <= right_ship_border)
  372. g->ship->x += g->ship->vx;
  373. if (g->ship->y + g->ship->vy >= upper_ship_border &&
  374. g->ship->y + g->ship->vy <= lower_ship_border)
  375. g->ship->y += g->ship->vy;
  376.  
  377. /* Проверка выхода астероида за границу */
  378. for (int i = 0; i < N; i++) {
  379. if (g->asteroid->pos[i]->y + g->asteroid->pos[i]->vy > lower_border ||
  380. g->asteroid->pos[i]->x + g->asteroid->pos[i]->vx < left_border ||
  381. g->asteroid->pos[i]->x + g->asteroid->pos[i]->vx > right_border)
  382. {
  383. g->asteroid->pos[i]->x = rand() % (g->screen->sprite->w + left_border);
  384. g->asteroid->pos[i]->y = -(g->asteroid->sprite->h);
  385. g->asteroid->pos[i]->vx = rand() % 10 - 5;
  386. g->asteroid->pos[i]->vy = rand() % 10 + 1;
  387. }
  388.  
  389. g->asteroid->pos[i]->x += g->asteroid->pos[i]->vx;
  390. g->asteroid->pos[i]->y += g->asteroid->pos[i]->vy;
  391. }
  392.  
  393. unsigned int current_time = SDL_GetTicks();
  394. g->timer = (current_time - start_time) / 1000;
  395.  
  396. if (g->timer <= 60) {
  397. draw(g);
  398. } else {
  399. show_text(g);
  400. SDL_Delay(2500);
  401. done = 1;
  402. }
  403. SDL_Delay(10);
  404.  
  405. }
  406. }
  407.  
  408.  
  409. /**
  410. * Отрисовывает объекты в новой позиции
  411. * @param g указатель на структуру состояния игры
  412. */
  413. void draw(game* g)
  414. {
  415. /* Прямоугольники, определяющие зону отображения */
  416. SDL_Rect src, dest;
  417.  
  418. /* Фон отображаем целиком */
  419. src.x = 0;
  420. src.y = 0;
  421. src.w = g->background->sprite->w;
  422. src.h = g->background->sprite->h;
  423.  
  424. /* Выполняем отображение */
  425. SDL_BlitSurface(g->background->sprite, &src, g->screen->sprite, &src);
  426.  
  427. for (int i = 0; i < N; i++) {
  428. /* Астероид отображаем целиком */
  429. src.x = 0;
  430. src.y = 0;
  431. src.w = g->asteroid->sprite->w;
  432. src.h = g->asteroid->sprite->h;
  433.  
  434. /* в новую позицию */
  435. dest.x = g->asteroid->pos[i]->x;
  436. dest.y = g->asteroid->pos[i]->y;
  437. dest.w = g->asteroid->sprite->w;
  438. dest.h = g->asteroid->sprite->h;
  439.  
  440. /* Выполняем отображение */
  441. SDL_SetColorKey(g->asteroid->sprite, SDL_SRCCOLORKEY, 0xffffff);
  442. SDL_BlitSurface(g->asteroid->sprite, &src, g->screen->sprite, &dest);
  443. }
  444.  
  445. /* Корабль отображаем целиком */
  446. src.x = 0;
  447. src.y = 0;
  448. src.w = g->ship->sprite->w;
  449. src.h = g->ship->sprite->h;
  450.  
  451. /* в новую позицию */
  452. dest.x = g->ship->x;
  453. dest.y = g->ship->y;
  454. dest.w = g->ship->sprite->w;
  455. dest.h = g->ship->sprite->h;
  456.  
  457. /* Выполняем отображение */
  458. SDL_SetColorKey(g->ship->sprite, SDL_SRCCOLORKEY, 0x000000);
  459. SDL_BlitSurface(g->ship->sprite, &src, g->screen->sprite, &dest);
  460.  
  461. if (bitcoin_get(g->ship, g->resource)) {
  462. /* Проверка столкновения с ресурсом */
  463. g->resource->x = rand() % (g->screen->sprite->w - g->resource->sprite->w);
  464. g->resource->y = rand() % (2 * (g->screen->sprite->h) / 3 - g->resource->sprite->h);
  465. g->resource->y += (g->screen->sprite->h) / 3;
  466. /* Инкрементируем счетчик ресурсов */
  467. g->resource->count++;
  468. }
  469.  
  470. /* Ресурс отображаем целиком */
  471. src.x = 0;
  472. src.y = 0;
  473. src.w = g->resource->sprite->w;
  474. src.h = g->resource->sprite->h;
  475.  
  476. /* в новую позицию */
  477. dest.x = g->resource->x;
  478. dest.y = g->resource->y;
  479. dest.w = g->resource->sprite->w;
  480. dest.h = g->resource->sprite->h;
  481.  
  482. /* Выполняем отображение */
  483. SDL_SetColorKey(g->resource->sprite, SDL_SRCCOLORKEY, 0x000000);
  484. SDL_BlitSurface(g->resource->sprite, &src, g->screen->sprite, &dest);
  485.  
  486. show_counter(g, g->resource->count, 1);
  487. show_counter(g, g->timer, 2);
  488. /* Отрисовываем обновленный экран */
  489. SDL_Flip(g->screen->sprite);
  490. }
  491.  
  492. /**
  493. * Проверяет столкновение корабля с объектом
  494. * @returns true (1) если, обнаружено столкновение
  495. * В противном случае - false (0)
  496. */
  497. int asteroid_crash(spaceship* ship, obstacle* asteroid, int i)
  498. {
  499. int ship_left, obj_left;
  500. int ship_top, obj_top;
  501. int ship_right, obj_right;
  502. int ship_bottom, obj_bottom;
  503.  
  504. int offset = 25;
  505.  
  506. /* Получение координат сторон объектов */
  507. ship_left = ship->x + offset;
  508. obj_left = asteroid->pos[i]->x + offset;
  509.  
  510. ship_top = ship->y + offset;
  511. obj_top = asteroid->pos[i]->y + offset;
  512.  
  513. ship_right = ship->x + ship->sprite->w - 1 - offset;
  514. obj_right = asteroid->pos[i]->x + asteroid->sprite->w - 1 - offset;
  515.  
  516. ship_bottom = ship->y + ship->sprite->h - 1 - offset;
  517. obj_bottom = asteroid->pos[i]->y + asteroid->sprite->h - 1 - offset;
  518.  
  519. /* Проеверка столкновения объектов */
  520. if (ship_bottom < obj_top) return 0;
  521. if (ship_top > obj_bottom) return 0;
  522.  
  523. if (ship_right < obj_left) return 0;
  524. if (ship_left > obj_right) return 0;
  525.  
  526. return 1;
  527. }
  528.  
  529. /**
  530. * Проверяет столкновение корабля с ресурсом
  531. * @returns true (1) если, обнаружено столкновение
  532. * В противном случае - false (0)
  533. */
  534. int bitcoin_get(spaceship* ship, gameresources* resource)
  535. {
  536. int ship_left, obj_left;
  537. int ship_top, obj_top;
  538. int ship_right, obj_right;
  539. int ship_bottom, obj_bottom;
  540.  
  541. int offset = 15;
  542.  
  543. /* Получение координат сторон объектов */
  544. ship_left = ship->x + offset;
  545. obj_left = resource->x + offset;
  546.  
  547. ship_top = ship->y + offset;
  548. obj_top = resource->y + offset;
  549.  
  550. ship_right = ship->x + ship->sprite->w - 1 - offset;
  551. obj_right = resource->x + resource->sprite->w - 1 - offset;
  552.  
  553. ship_bottom = ship->y + ship->sprite->h - 1 - offset;
  554. obj_bottom = resource->y + resource->sprite->h - 1 - offset;
  555.  
  556. /* Проеверка столкновения объектов */
  557. if (ship_bottom < obj_top) return 0;
  558. if (ship_top > obj_bottom) return 0;
  559.  
  560. if (ship_right < obj_left) return 0;
  561. if (ship_left > obj_right) return 0;
  562.  
  563. return 1;
  564. }
  565.  
  566. void show_counter(game* g, const int counter, const int mode)
  567. {
  568. char text[5] = "";
  569.  
  570. /* Переводим int счетчик в char */
  571. if (sprintf(text, "%d", counter) == 0) {
  572. ;
  573. }
  574. SDL_Surface* fontSurface;
  575. SDL_Color fColor = { 0xff, 0x00, 0x00, 0xff };
  576. SDL_Color bColor = { 0x00, 0x00, 0x00, 0xff };
  577. fontSurface = TTF_RenderUTF8_Shaded(g->font, text, fColor, bColor);
  578.  
  579. int w, h;
  580. TTF_SizeUTF8(g->font, text, &w, &h);
  581.  
  582. SDL_Rect fontRect;
  583. if (mode == 1) {
  584. fontRect.x = 0;
  585. }
  586. else {
  587. fontRect.x = g->screen->sprite->w - w;
  588. }
  589. fontRect.y = 0;
  590. SDL_SetColorKey(fontSurface, SDL_SRCCOLORKEY, 0x000000);
  591. SDL_BlitSurface(fontSurface, NULL, g->screen->sprite, &fontRect);
  592. }
  593.  
  594. void show_text(game* g)
  595. {
  596. SDL_Surface* status;
  597. SDL_Color fColor = { 0x00, 0xff, 0x00, 0xff };
  598. SDL_Color bColor = { 0x00, 0x00, 0x00, 0xff };
  599. status = TTF_RenderUTF8_Shaded(g->font, text, fColor, bColor);
  600.  
  601. int w, h;
  602. TTF_SizeUTF8(g->font, text, &w, &h);
  603.  
  604. SDL_Rect statusRect;
  605. statusRect.x = g->screen->sprite->w / 2 - w / 2;
  606. statusRect.y = g->screen->sprite->h / 2 - h / 2;
  607. SDL_SetColorKey(status, SDL_SRCCOLORKEY, 0x000000);
  608. SDL_BlitSurface(status, NULL, g->screen->sprite, &statusRect);
  609. SDL_Flip(g->screen->sprite);
  610. }
  611.  
  612. /* void show_fail(game* g)
  613. {
  614. char text[] = "Mission failed :(";
  615. SDL_Surface* status;
  616. SDL_Color fColor = { 0x00, 0xff, 0x00, 0xff };
  617. SDL_Color bColor = { 0x00, 0x00, 0x00, 0xff };
  618. status = TTF_RenderUTF8_Shaded(g->font, text, fColor, bColor);
  619.  
  620. int w, h;
  621. TTF_SizeUTF8(g->font, text, &w, &h);
  622.  
  623. SDL_Rect statusRect;
  624. statusRect.x = g->screen->sprite->w / 2 - w / 2;
  625. statusRect.y = g->screen->sprite->h / 2 - h / 2;
  626. SDL_SetColorKey(status, SDL_SRCCOLORKEY, 0x000000);
  627. SDL_BlitSurface(status, NULL, g->screen->sprite, &statusRect);
  628. SDL_Flip(g->screen->sprite);
  629. }
  630. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement