Advertisement
blazinghorizon

Untitled

Dec 15th, 2019
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.74 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 6
  17. #define VYD 6
  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_mission_status(game* g, const int mode);
  131.  
  132.  
  133. /**
  134. * Основная программа
  135. */
  136. int main()
  137. {
  138. /* Инициализация генератора псевдослучайных чисел */
  139. srand(time(NULL));
  140.  
  141. /* Инициализируем игру */
  142. game* g = init();
  143.  
  144. /* Запускаем цикл обработки событий игры */
  145. run(g);
  146.  
  147. return 0;
  148. }
  149.  
  150.  
  151. /**
  152. * Инициализирует игру
  153. * @returns g указатель на структуру состояния игры
  154. */
  155. game* init()
  156. {
  157. /* Создаем структуру представления состояния игры */
  158. game* g;
  159. g = (game*)malloc(sizeof(game));
  160. if (g == NULL) {
  161. fprintf(stderr, "Not enough memory!\n");
  162. exit(EXIT_FAILURE);
  163. }
  164.  
  165. /* Инициализируем библиотеку SDL, используем только видеоподсистему */
  166. if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  167. fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
  168. exit(EXIT_FAILURE);
  169. }
  170.  
  171. /* Регистрируем обработчик завершения программы */
  172. atexit(SDL_Quit);
  173.  
  174. /* Инициализируем библиотеку SDL_ttf и загружаем шрифт */
  175. TTF_Init();
  176. g->font = TTF_OpenFont("AbrilFatface-Regular.ttf", 44);
  177.  
  178. /* Выделяем память для структуры представления экрана */
  179. g->screen = (gamescreen*)malloc(sizeof(gamescreen));
  180. if (g->screen == NULL) {
  181. fprintf(stderr, "Not enough memory!\n");
  182. exit(EXIT_FAILURE);
  183. }
  184.  
  185. /* Инициализируем видеорежим */
  186. g->screen->sprite =
  187. SDL_SetVideoMode(1024, 768, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
  188. if (g->screen->sprite == NULL) {
  189. fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError());
  190. exit(EXIT_FAILURE);
  191. }
  192.  
  193. /* Выделяем память для структуры представления фона */
  194. g->background = (gamebackground*)malloc(sizeof(gamebackground));
  195. if (g->background == NULL) {
  196. fprintf(stderr, "Not enough memory!\n");
  197. exit(EXIT_FAILURE);
  198. }
  199.  
  200. g->background->sprite = SDL_LoadBMP("background.bmp");
  201. if (g->background->sprite == NULL) {
  202. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  203. exit(EXIT_FAILURE);
  204. }
  205.  
  206. /* Выделяем память для структуры представления корабля */
  207. g->ship = (spaceship*)malloc(sizeof(spaceship));
  208. if (g->ship == NULL) {
  209. fprintf(stderr, "Not enough memory!\n");
  210. exit(EXIT_FAILURE);
  211. }
  212.  
  213. g->ship->sprite = SDL_LoadBMP("ship.bmp");
  214. if (g->ship->sprite == NULL) {
  215. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  216. exit(EXIT_FAILURE);
  217. }
  218.  
  219. /* Выделяем память для структуры представления астероидов */
  220. g->asteroid = (obstacle*)malloc(sizeof(obstacle));
  221. if (g->asteroid == NULL) {
  222. fprintf(stderr, "Not enough memory!\n");
  223. exit(EXIT_FAILURE);
  224. }
  225.  
  226. g->asteroid->sprite = SDL_LoadBMP("asteroid.bmp");
  227. if (g->asteroid->sprite == NULL) {
  228. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  229. exit(EXIT_FAILURE);
  230. }
  231.  
  232. /* Выделяем память для структуры представления ресурса */
  233. g->resource = (gameresources*)malloc(sizeof(gameresources));
  234. if (g->resource == NULL) {
  235. fprintf(stderr, "Not enough memory!\n");
  236. exit(EXIT_FAILURE);
  237. }
  238.  
  239. g->resource->sprite = SDL_LoadBMP("bitcoin.bmp");
  240. if (g->resource->sprite == NULL) {
  241. fprintf(stderr, "Couldn't load a bitmap: %s\n", SDL_GetError());
  242. exit(EXIT_FAILURE);
  243. }
  244.  
  245. /* Выделяем память для структуры представления характеристик астероидов */
  246. for (int i = 0; i < N; i++) {
  247. /* Для каждого астероида отдельно */
  248. g->asteroid->pos[i] = (position*)malloc(sizeof(position));
  249. if (g->asteroid->pos[i] == NULL) {
  250. fprintf(stderr, "Not enough memory!\n");
  251. exit(EXIT_FAILURE);
  252. }
  253. }
  254.  
  255. /* Помещаем корабль в начальную позицию */
  256. g->ship->x = (g->screen->sprite->w - g->ship->sprite->w) / 2;
  257. g->ship->y = g->screen->sprite->h - g->ship->sprite->h;
  258.  
  259. /* Помещаем астероиды в начальную позицию */
  260. for (int i = 0; i < N; i++) {
  261. /* Для каждого астероида */
  262. g->asteroid->pos[i]->x = rand() % (g->screen->sprite->w - g->asteroid->sprite->w);
  263. g->asteroid->pos[i]->y = -(g->asteroid->sprite->h);
  264.  
  265. g->asteroid->pos[i]->vx = rand() % 10 - 5;
  266. g->asteroid->pos[i]->vy = rand() % 10 + 1;
  267. }
  268.  
  269. /* Помещаем ресурс в начальную позицию */
  270. g->resource->x = rand() % (g->screen->sprite->w - g->resource->sprite->w);
  271. g->resource->y = rand() % (g->screen->sprite->h * 2 / 3 - g->resource->bitcoin->h) + g->screen->sprite->h / 3;
  272. g->resource->count = 0;
  273.  
  274. /* Устанавливаем заголовок окна */
  275. SDL_WM_SetCaption("Space Explore", NULL);
  276.  
  277. return g;
  278. }
  279.  
  280.  
  281. /**
  282. * Инициализирует игру
  283. * @param g указатель на структуру состояния игры
  284. */
  285. void run(game* g)
  286. {
  287. /* Флажок выхода */
  288. int done = 0;
  289.  
  290. int left_ship_border = 0;
  291. int upper_ship_border = (g->screen->sprite->h) / 3;
  292. int right_ship_border = g->screen->sprite->w - g->ship->sprite->w;
  293. int lower_ship_border = g->screen->sprite->h - g->ship->sprite->h;
  294.  
  295. int left_border = -(g->asteroid->sprite->w);
  296. int right_border = g->screen->sprite->w;
  297. int lower_border = g->screen->sprite->h;
  298.  
  299. /* Продолжаем выполнение, пока не поднят флажок */
  300. while (!done) {
  301.  
  302. for (int i = 0; i < N; i++) {
  303. if (asteroid_crash(g->ship, g->asteroid, i))
  304. done = 1;
  305. }
  306.  
  307. /* Структура описания события */
  308. SDL_Event event;
  309.  
  310. /* Извлекаем и обрабатываем все доступные события */
  311. while (SDL_PollEvent(&event)) {
  312. switch (event.type) {
  313. /* Если клавишу нажали */
  314. case SDL_KEYDOWN:
  315. switch (event.key.keysym.sym) {
  316. case SDLK_LEFT:
  317. g->ship->vx += -VXD;
  318. break;
  319. case SDLK_RIGHT:
  320. g->ship->vx += VXD;
  321. break;
  322. case SDLK_UP:
  323. g->ship->vy += -VYD;
  324. break;
  325. case SDLK_DOWN:
  326. g->ship->vy += VYD;
  327. break;
  328. case SDLK_ESCAPE:
  329. done = 1;
  330. break;
  331. }
  332. break;
  333. /* Если клавишу отпустили */
  334. case SDL_KEYUP:
  335. switch (event.key.keysym.sym) {
  336. case SDLK_LEFT:
  337. g->ship->vx += VXD;
  338. break;
  339. case SDLK_RIGHT:
  340. g->ship->vx += -VXD;
  341. break;
  342. case SDLK_UP:
  343. g->ship->vy += VYD;
  344. break;
  345. case SDLK_DOWN:
  346. g->ship->vy += -VYD;
  347. break;
  348. default:
  349. break;
  350. }
  351. break;
  352. /* Если закрыли окно */
  353. case SDL_QUIT:
  354. done = 1;
  355. break;
  356. default:
  357. break;
  358. }
  359. }
  360.  
  361. /* Проверка выхода корабля за границу */
  362. if (g->ship->x + g->ship->vx >= left_ship_border &&
  363. g->ship->x + g->ship->vx <= right_ship_border)
  364. g->ship->x += g->ship->vx;
  365. if (g->ship->y + g->ship->vy >= upper_ship_border &&
  366. g->ship->y + g->ship->vy <= lower_ship_border)
  367. g->ship->y += g->ship->vy;
  368.  
  369. /* Проверка выхода астероида за границу */
  370. for (int i = 0; i < N; i++) {
  371. if (g->asteroid->pos[i]->y + g->asteroid->pos[i]->vy > lower_border ||
  372. g->asteroid->pos[i]->x + g->asteroid->pos[i]->vx < left_border ||
  373. g->asteroid->pos[i]->x + g->asteroid->pos[i]->vx > right_border)
  374. {
  375. g->asteroid->pos[i]->x = rand() % (g->screen->sprite->w + left_border);
  376. g->asteroid->pos[i]->y = -(g->asteroid->sprite->h);
  377. g->asteroid->pos[i]->vx = rand() % 10 - 5;
  378. g->asteroid->pos[i]->vy = rand() % 10 + 1;
  379. }
  380.  
  381. g->asteroid->pos[i]->x += g->asteroid->pos[i]->vx;
  382. g->asteroid->pos[i]->y += g->asteroid->pos[i]->vy;
  383. }
  384.  
  385. draw(g);
  386.  
  387. SDL_Delay(10);
  388.  
  389. }
  390. }
  391.  
  392.  
  393. /**
  394. * Отрисовывает объекты в новой позиции
  395. * @param g указатель на структуру состояния игры
  396. */
  397. void draw(game* g)
  398. {
  399. /* Прямоугольники, определяющие зону отображения */
  400. SDL_Rect src, dest;
  401.  
  402. /* Фон отображаем целиком */
  403. src.x = 0;
  404. src.y = 0;
  405. src.w = g->background->sprite->w;
  406. src.h = g->background->sprite->h;
  407.  
  408. /* Выполняем отображение */
  409. SDL_BlitSurface(g->background->sprite, &src, g->screen->sprite, &src);
  410.  
  411. for (int i = 0; i < N; i++) {
  412. /* Астероид отображаем целиком */
  413. src.x = 0;
  414. src.y = 0;
  415. src.w = g->asteroid->sprite->w;
  416. src.h = g->asteroid->sprite->h;
  417.  
  418. /* в новую позицию */
  419. dest.x = g->asteroid->pos[i]->x;
  420. dest.y = g->asteroid->pos[i]->y;
  421. dest.w = g->asteroid->sprite->w;
  422. dest.h = g->asteroid->sprite->h;
  423.  
  424. /* Выполняем отображение */
  425. SDL_SetColorKey(g->asteroid->sprite, SDL_SRCCOLORKEY, 0x000000);
  426. SDL_BlitSurface(g->asteroid->sprite, &src, g->screen->sprite, &dest);
  427. }
  428.  
  429. /* Корабль отображаем целиком */
  430. src.x = 0;
  431. src.y = 0;
  432. src.w = g->ship->sprite->w;
  433. src.h = g->ship->sprite->h;
  434.  
  435. /* в новую позицию */
  436. dest.x = g->ship->x;
  437. dest.y = g->ship->y;
  438. dest.w = g->ship->sprite->w;
  439. dest.h = g->ship->sprite->h;
  440.  
  441. /* Выполняем отображение */
  442. SDL_SetColorKey(g->ship->sprite, SDL_SRCCOLORKEY, 0x000000);
  443. SDL_BlitSurface(g->ship->sprite, &src, g->screen->sprite, &dest);
  444.  
  445. if (bitcoin_get(g->ship, g->resource)) {
  446. /* Проверка столкновения с ресурсом */
  447. g->resource->x = rand() % (g->screen->sprite->w - g->resource->sprite->w);
  448. g->resource->y = rand() % (2 * (g->screen->sprite->h) / 3 - g->resource->sprite->h);
  449. g->resource->y += (g->screen->sprite->h) / 3;
  450. /* Инкрементируем счетчик ресурсов */
  451. g->resource->count++;
  452. }
  453.  
  454. /* Ресурс отображаем целиком */
  455. src.x = 0;
  456. src.y = 0;
  457. src.w = g->resource->sprite->w;
  458. src.h = g->resource->sprite->h;
  459.  
  460. /* в новую позицию */
  461. dest.x = g->resource->x;
  462. dest.y = g->resource->y;
  463. dest.w = g->resource->sprite->w;
  464. dest.h = g->resource->sprite->h;
  465.  
  466. /* Выполняем отображение */
  467. SDL_SetColorKey(g->resource->sprite, SDL_SRCCOLORKEY, 0x000000);
  468. SDL_BlitSurface(g->resource->sprite, &src, g->screen->sprite, &dest);
  469.  
  470. /* Отрисовываем обновленный экран */
  471. SDL_Flip(g->screen->sprite);
  472. }
  473.  
  474. /**
  475. * Проверяет столкновение корабля с объектом
  476. * @returns true (1) если, обнаружено столкновение
  477. * В противном случае - false (0)
  478. */
  479. int asteroid_crash(spaceship* ship, obstacle* asteroid, int i)
  480. {
  481. int ship_left, obj_left;
  482. int ship_top, obj_top;
  483. int ship_right, obj_right;
  484. int ship_bottom, obj_bottom;
  485.  
  486. int offset = 10;
  487.  
  488. /* Получение координат сторон объектов */
  489. ship_left = ship->x + offset;
  490. obj_left = asteroid->pos[i]->x + offset;
  491.  
  492. ship_top = ship->y + offset;
  493. obj_top = asteroid->pos[i]->y + offset;
  494.  
  495. ship_right = ship->x + ship->sprite->w - 1 - offset;
  496. obj_right = asteroid->pos[i]->x + asteroid->sprite->w - 1 - offset;
  497.  
  498. ship_bottom = ship->y + ship->sprite->h - 1 - offset;
  499. obj_bottom = asteroid->pos[i]->y + asteroid->sprite->h - 1 - offset;
  500.  
  501. /* Проеверка столкновения объектов */
  502. if (ship_bottom < obj_top) return 0;
  503. if (ship_top > obj_bottom) return 0;
  504.  
  505. if (ship_right < obj_left) return 0;
  506. if (ship_left > obj_right) return 0;
  507.  
  508. return 1;
  509. }
  510.  
  511. /**
  512. * Проверяет столкновение корабля с ресурсом
  513. * @returns true (1) если, обнаружено столкновение
  514. * В противном случае - false (0)
  515. */
  516. int bitcoin_get(spaceship* ship, gameresources* resource)
  517. {
  518. int ship_left, obj_left;
  519. int ship_top, obj_top;
  520. int ship_right, obj_right;
  521. int ship_bottom, obj_bottom;
  522.  
  523. int offset = 10;
  524.  
  525. /* Получение координат сторон объектов */
  526. ship_left = ship->x + offset;
  527. obj_left = resource->x + offset;
  528.  
  529. ship_top = ship->y + offset;
  530. obj_top = resource->y + offset;
  531.  
  532. ship_right = ship->x + ship->sprite->w - 1 - offset;
  533. obj_right = resource->x + resource->sprite->w - 1 - offset;
  534.  
  535. ship_bottom = ship->y + ship->sprite->h - 1 - offset;
  536. obj_bottom = resource->y + resource->sprite->h - 1 - offset;
  537.  
  538. /* Проеверка столкновения объектов */
  539. if (ship_bottom < obj_top) return 0;
  540. if (ship_top > obj_bottom) return 0;
  541.  
  542. if (ship_right < obj_left) return 0;
  543. if (ship_left > obj_right) return 0;
  544.  
  545. return 1;
  546. }
  547.  
  548. void show_counter(game* g, const int counter, const int mode)
  549. {
  550. char text[5] = "";
  551.  
  552. /* Переводим int счетчик в char */
  553. if (sprintf(text, "%d", counter) == 0) {
  554. ;
  555. }
  556. SDL_Surface* fontSurface;
  557. SDL_Color fColor = { 0xff, 0x00, 0x00, 0xff };
  558. SDL_Color bColor = { 0x00, 0x00, 0x00, 0xff };
  559. fontSurface = TTF_RenderUTF8_Shaded(g->font, text, fColor, bColor);
  560.  
  561. int w, h;
  562. TTF_SizeUTF8(g->font, text, &w, &h);
  563.  
  564. SDL_Rect fontRect;
  565. if (mode == 1) {
  566. fontRect.x = 0;
  567. }
  568. else {
  569. fontRect.x = g->screen->sprite->w - w;
  570. }
  571. fontRect.y = 0;
  572. SDL_SetColorKey(fontSurface, SDL_SRCCOLORKEY, 0x000000);
  573. SDL_BlitSurface(fontSurface, NULL, g->screen->sprite, &fontRect);
  574. }
  575.  
  576. void show_mission_status(game* g, const int mode)
  577. {
  578.  
  579. SDL_Surface* status;
  580. if (mode == 0) {
  581. char text[] = "Mission complete!";
  582. SDL_Color fColor = { 0x00, 0xff, 0x00, 0xff };
  583. }
  584. else {
  585. char text[] = "Mission failed!";
  586. SDL_Color fColor = { 0xff, 0x00, 0x00, 0xff };
  587. }
  588. SDL_Color bColor = { 0x00, 0x00, 0x00, 0xff };
  589. status = TTF_RenderUTF8_Shaded(g->font, text, fColor, bColor);
  590.  
  591. int w, h;
  592. TTF_SizeUTF8(g->font, text, &w, &h);
  593.  
  594. SDL_Rect statusRect;
  595. statusRect.x = g->screen->sprite->w / 2 - w / 2;
  596. statusRect.y = g->screen->sprite->h / 2 - h / 2;
  597. SDL_SetColorKey(status, SDL_SRCCOLORKEY, 0x000000);
  598. SDL_BlitSurface(status, NULL, g->screen->sprite, &statusRect);
  599. SDL_Flip(g->screen->sprite);
  600. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement