- PVSM.RU - https://www.pvsm.ru -
Идея выучить C появилась у меня довольно давно. Я пробовал писать в Arduino IDE, но мне не хватало чего-то более масштабного — такого проекта, где можно наделать кучу ошибок, но при этом видеть результат и двигаться дальше.
Я наткнулся в Play Market на ASCII-RPG под названием Stone Story. Сам формат меня зацепил: минимализм, но при этом ощущение полноценной игры. Поэтому я решил сделать нечто похожее, но со своими механиками.
Мне показалось, что сочетание моего ника и RPG звучит вполне нормально. Так и появилось название MerRPG [1].
Первым делом я сразу решил использовать структуры, а именно:
typedef struct
{
char Name[15];
int Hp;
int Attack;
} Player;
typedef struct
{
char Name[15];
int Hp;
int min_attack;
int max_attack;
int type;
} Monster;
typedef struct
{
int min_heal;
int max_heal;
} Heal;
Структура игрока
Структура монстров
Структура лечения
С этими аспектами мне понравилось рабоать больше всего. Я использовал void функции (за исключением главной функции main)
Разделю на несколько аспектов:
Инициализация игрока и монстров:
void init_player(Player* player) {
printf("Send Nickname: ");
scanf("%14s", player->Name);
player->Hp = 20;
}
Сделал ограничение для имени персонажа
Сделал ограничение хп игрока
void init_monster(Monster* monster) {
Monster monster_list[3] = {
{"Amogus",30,3,6,0},
{"Slime",20,1,3,1},
{"Spider",25,2,4,2}
};
int id = rand() %3;
*monster = monster_list[id];
}
Добавил несколько монстров
Сделал случайный выбор одного из трех
2. Вывод модельки игрока и монстра:
void print_status(Player player,Monster monster){
printf("n--- MerRPG ---n");
if (monster.type == 0) {
printf(" 0 (AMOGUS)n");
printf("/|\ (00)n");
printf("/ \ /__\n");
} else if (monster.type == 1) {
printf(" 0 (SLIME)n");
printf("/|\ (00)n");
printf("/ \ /~~~\n");
} else if (monster.type == 2) {
printf(" 0 (SPIDER)n");
printf("/|\ //\(oo)/\\n");
printf("/ \ // \\n");
}
printf("%s HP: %dn",player.Name, player.Hp);
printf("%s HP: %dn", monster.Name,monster.Hp);
}
Почему здесь я не использовал указатель? Т.к программа лишь выводит значения, но не изменяет их.
3 Атака игрока и монстра:
void player_attack(Player* player,Monster* monster){
int damage_player= rand() % 5 +1;
monster ->Hp -= damage_player;
printf("You caused %d damagen",damage_player);
if (monster ->Hp < 0) {
monster ->Hp =0;
}
}
На этом моменте я решил отказаться от взятия атаки из структуры игрока и сделал отдельную переменную в самой функции.
void monster_attack(Player* player,Monster* monster){
int damage_monster = rand() % (monster ->max_attack - monster ->min_attack +1) + monster ->min_attack;
player ->Hp -= damage_monster;
printf("Emeny caused %d damagen",damage_monster);
if (player ->Hp < 0) {
player ->Hp =0;
}
}
По сути две эти функции не отличаются функционалом, однако специально для монстров я сделал и использовал понятия минимального и максимального урона.
4 Функция лечения игрока
void player_heal(Player* player, Heal* heal) {
int heal_player = rand() % (heal ->max_heal - heal ->min_heal + 1) + heal->min_heal;
player ->Hp += heal_player;
printf("You have restored %d Hpn", heal_player);
if (player ->Hp > 20) {
player ->Hp = 20;
}
}
Здесь я добавил ограничение, чтобы лечение не превышало максимальное HP.
5 Самая большая функция - функция старта игры:
void start_game() {
Player player;
Monster monster;
Heal heal = {1,6};
init_player(&player);
init_monster(&monster);
while(player.Hp > 0 && monster.Hp > 0 ) {
print_status(player,monster);
printf("[0] - Exitn");
printf("[1] - Attackn");
printf("[2] - Healingn");
scanf("%d", &choice);
if (choice == 1) {
player_attack(&player,&monster);
if ( monster.Hp > 0) {
monster_attack(&player,&monster);
}
} else if (choice == 2) {
player_heal(&player,&heal);
monster_attack(&player,&monster);
}
else if (choice == 0) {
printf("You are out of the gamen");
break;
} else {
break;
}
}
if (player.Hp == 0) {
printf("You Lose...n");
} else if (monster.Hp == 0){
printf("You Win!n");
}
printf("Press any button to return to menun");
char tmp;
getchar();
scanf("%s",&tmp);
}
Основной цикл боя
Обработка действий игрока
Проверка победы или поражения
6 Уже в отдельном файле была перенесена функция начального меню игры:
void menu_game(void) {
while (1) {
printf(" __ __ ____ ____ ____ n");
printf("| \/ | ___ _ __| _ \| _ \ / ___| n");
printf("| |\/| |/ _ \ '__| |_) | |_) | | _ n");
printf("| | | | __/ | | _ <| __/| |_| |n");
printf("|_| |_|\___|_| |_| \_\_| \____|n");
printf("=== MerRPG ===n");
printf("1 - Start gamen");
printf("2 - Exitn");
scanf("%d", &choice);
if (choice == 1) {
start_game();
}
else if (choice == 2) {
break;
}
}
}
В будущем планирую сюда добавить настройки.
7 Ну и последняя, но немало важная функция - главная функция main:
int main() {
srand(time(NULL));
menu_game();
return 0;
}
srand() в данном случае делает так, что бы при каждом запуске игры:
Монстры
Урон
Лечение
Были случайными.
Хочу вынести парочку интересных для меня костлкй.. А именно:
printf("Press any button to return to menun");
char tmp;
getchar();
scanf("%s",&tmp);
}
Я хотел, чтобы игрок мог нажать любую кнопку для возврата в меню. Но при использовании кириллицы программа начинала вести себя странно и могла зациклиться. Насколько я понял, это связано с тем, что %c читает один байт, а кириллица занимает больше. В итоге я заменил %c на %s.
Еще один костыль в этом же куске... Без getchar() игра просто не даст пользователю нажать на любую кнопку и сразу же перекинет его в главное меню. Поэтому пришлось вручную очищать буфер ;)
Костыль с ограничением количество хп, которое дает лечение:
void start_game() {
Player player;
Monster monster;
Heal heal = {1,6};
Мне не удалось сделать это по аналогии с минимальным и максимальным уроном монстров. Поэтому я нашел более "легкий" способ.
Как только мне понадобилось вынести меню в отдельный файл, так сразу этот файл мне помог это сделать.. А точнее 2 файла. Т.к в меню используется данный кусок, вызывающий функцию start_game():
if (choice == 1) {
start_game();
}
Нужно было создать два файла .h - game.h и menu.h
#ifndef GAME_H
#define GAME_H
void start_game(void);
#endif
#ifndef MENU_H
#define MENU_H
void menu_game(void);
#endif
В каждом из которых нужно было вызывать требуемые функции.
В целом мне нравится заниматься данными вещами. Игра будет развиваться, будут появляться новые фичи ( и костыли).
Я буду вам очень признателен за помощь в исправлении моих ошибок. Выслушаю любую критику.
Автор: Meronto
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/448098
Ссылки в тексте:
[1] MerRPG: https://github.com/Meronto/MerRPG
[2] Источник: https://habr.com/ru/articles/1016516/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1016516
Нажмите здесь для печати.