Скачиваний:
0
Добавлен:
09.09.2026
Размер:
220 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В. И. Ульянова (Ленина)

Кафедра МО ЭВМ

отчет

по лабораторной работе №4

по дисциплине «Объектно-ориентированное программирование»

Тема: Уровни абстракции

Студентка гр. 2383

Бараева Е. Н.

Преподаватель

Жангиров Т. Р.

Санкт-Петербург

2023

Цель работы.

Создание класса игры, отвечающего за запуск и логику, класса считывания ввода пользователя, отвечающего за контроль пользователем игрока.

Задание.

а) Создать класс игры. Класс игры отвечает за запуск игры (в начале и во время текущей сессии), выход из игры, выбор уровня, а также инициализирующего перемещение игрока. Также класс должен проводить проверку проигрыша или выигрыша игрока и давать возможность начать новую игру или завершить работу программы.

б) Создать класс (или набор классов) считывания ввода пользователя. Данный класс(ы) должен сопоставить ввод пользователя с командой, которую необходимо выполнить. И передать эту информацию в класс игры. Клавиши управления (то на какую клавишу назначено определенное действия) должны считываться из файла. Класс(ы) должен быть разработан так, чтобы:

  • потенциально можно было масштабировать управление с минимальным количеством изменений в коде

  • можно было заменить схему управления, например, заменить ввод команду через терминал на чтение команд из файла или из сети с другого устройства

Примечания:

  • После считывания клавиши, считанный символ должен сразу обрабатываться, и далее работа должна проводить с сущностью, которая представляет команду.

  • Для представления команды можно разработать системы классов или использовать перечисление enum.

  • Хорошей практикой является создание “прослойки” между считыванием/обработкой команды и классом игры, которая сопоставляет команду и вызываемым методом игры. Существуют альтернативные решения без явной “прослойки”

  • При считывании управления необходимо делать проверку, что на все команды назначена клавиша, что на одну клавишу не назначено две команды, что на одну команду не назначено две клавиши.

  • При работе с файлом используйте идиому RAII.

Выполнение работы.

Class ReadingFromConsole

В данном классе был переопределен оператор (), который отвечает за считывание клавиш пользователя с консоли без нажатия на Enter. Для него была подключена библиотека windows.h, и использованы из данной библиотеки функции. Таже у этого класса есть деструктор, в котором закрывается файл с ключами клавиш. В добавок этот класс является дочерним к классу Reading.

Class Reading

Данный класс считывает команды пользователя. Имеет два поля – файл, откуда считываются пользовательские ключи, и словарь численных представлений символов клавиш и команд. Конструктор класса Reading() считывает клавиши из файла "keys.txt" и сопоставляет им команды из enum commands. В случае, если клавиш меньше должного количества и есть повторения, то клавиши задаются по умолчанию. Также был переопределен оператор () для объектов данного класса. Еще у этого класса есть деструктор, в котором закрывается файл с ключами клавиш.

Class Game

Класс, создающий все элементы игры. Имеет 3 поля – игровое поле, игрок, контроллер и указатель на объект класса считывания. В конструкторе класса генерируется поле игры и присваивается field. Метод меню игры считывает команды игрока с помощью функционального класса Reading и позволяет либо продолжить игру, либо начать игру сначала, либо выйти из игры. Death_menu() – метод меню смерти персонажа, считывающий команды игрока с помощью функционального класса Reading и позволяющая либо начать игру сначала, либо выйти из игры. Game_play() – метод, считывающий команды и передвигающий игрока в соответствующих направлениях или вызывающий меню. Run() – основной метод игры, устанавливающий игрока на начальные координаты, запускающий Game_play(), завершающий свою работу в случае, если Game_play() вернул 0, и создающий второй уровень и снова запускающий Game_play() в обратном.

Тестирование.

Результаты тестирования представлены в табл. 1.

Таблица 1 – Результаты тестирования

№ п/п

Входные данные

Выходные данные

Комментарии

1.

wsddwpq

Проверка передвижения.

Верно.

2.

prprq

Проверка меню.

Верно.

Вывод.

Был создан класс игры, отвечающий за запуск и логику всей игры, также реализован класс считывания ввода пользователя клавиш с консоли, отвечающего за контроль пользователем игрока. В классе считывания ввода были созданы методы, которые в дальнейшем будут использованы для меню игры.

ПРИЛОЖЕНИЕ А ИСХОДНЫЙ КОД ПРОГРАММЫ

Название файла: Game.h

#ifndef OOP_GAME_H

#define OOP_GAME_H

#include "CreationLevels.h"

#include "Controller.h"

#include "Reading.h"

#include <thread>

class Game {

private:

Field field;

Player player;

Controller controller;

Reading* reader;

protected:

public:

explicit Game(class Reading* reader);

bool Menu();

bool Death_menu();

int Game_play();

void Run();

~Game();

};

#endif //OOP_GAME_H

Название файла: Game.cpp

#include "Game.h"

Game::Game(class Reading * reader) : field(), player(), controller(player, field, {0, 0}), reader(reader) {

CreationLevels creator;

field = creator.GetLevel1();

}

bool Game::Menu(){

command action = reader->operator()();

std::cout << "Menu" << '\n';

while (action != restart && action != pause && action != quit)

action = reader->operator()();

// go on

if (action == pause)

return true;

// play again

if (action == restart) {

player.Revive();

Run();

return false;

}

// exit

if (action == quit)

exit(0);

return false;

}

bool Game::Death_menu(){

command action = reader->operator()();

while (action != restart && action != quit)

action = reader->operator()();

// play again

if (action == restart) {

player.Revive();

Run();

return false;

}

// exit

if (action == quit)

exit(0);

return false;

}

int Game::Game_play(){

while (controller.Alive()) {

command action = reader->operator()();

switch (action) {

case move_down:

std::cout << "Down" << '\n';

controller.Move(down);

break;

case move_up:

std::cout << "Up" << '\n';

controller.Move(up);

break;

case move_right:

std::cout << "Right" << '\n';

controller.Move(right);

break;

case move_left:

std::cout << "Left" << '\n';

controller.Move(left);

break;

case pause:

std::cout << "Pause" << '\n';

if (Menu())

break;

else

return 0;

case restart:

break;

case quit:

break;

}

Coordinates cur_cords = controller.GetCoordinates();

if (cur_cords.x == field.GetExit().x && cur_cords.y == field.GetExit().y)

return 1;

}

if (!controller.Alive())

return Death_menu();

return -1;

}

void Game::Run(){

controller.SetCoordinates({field.GetEntry().x, field.GetEntry().y});

if (Game_play() == 0)

return;

CreationLevels creator;

field = creator.GetLevel2();

if (Game_play() == 0)

return;

}

Game::~Game() {

delete reader;

reader = nullptr;

}

Название файла: Reading.h

#ifndef OOP_READING_H

#define OOP_READING_H

#include <fstream>

#include <iostream>

#include <vector>

#include <map>

#define COMMAND_LEN 7

enum command {move_up, move_down, move_right, move_left, pause, restart, quit};

class Reading {

protected:

std::ifstream user_keys;

std::map<int, command> commands;

public:

Reading();

virtual command operator()() = 0;

virtual ~Reading();

};

#endif //OOP_READING_H

Название файла: Reading.cpp

#include "Reading.h"

Reading::Reading() : user_keys("keys.txt") {

if (!user_keys.is_open())

throw std::invalid_argument("User keys file do not open!");

std::vector<int> keys(COMMAND_LEN);

bool ok = true;

// checking for the correct number of commands

int ind = 0;

while (ind != COMMAND_LEN && !user_keys.eof()) {

int intBuf;

user_keys >> intBuf;

keys[ind] = intBuf;

ind += 1;

}

if (ind != COMMAND_LEN)

ok = false;

else { // checking for repetitions of commands

int counter = 0;

for (int i = 0; i < COMMAND_LEN; i++) {

counter = 0;

for (int j = 0; j < COMMAND_LEN; j++) {

if (keys[i] == keys[j])

counter += 1;

}

if (counter > 1) {

ok = false;

break;

}

}

}

if (ok) {

commands[keys[0]] = move_up;

commands[keys[1]] = move_down;

commands[keys[2]] = move_right;

commands[keys[3]] = move_left;

commands[keys[4]] = pause;

commands[keys[5]] = restart;

commands[keys[6]] = quit;

}

else {

commands[119] = move_up; // w

commands[115] = move_down; // s

commands[100] = move_right; // d

commands[97] = move_left; // a

commands[112] = pause; // p

commands[114] = restart; // r

commands[113] = quit; // q

}

}

Reading::~Reading(){

user_keys.close();

}

Название файла: ReadingFromConsole.h

#ifndef OOP_READINGFROMCONSOLE_H

#define OOP_READINGFROMCONSOLE_H

#include "Reading.h"

class ReadingFromConsole : public Reading {

public:

command operator()() final;

~ReadingFromConsole() final;

};

#endif //OOP_READINGFROMCONSOLE_H

Название файла: ReadingFromConsole.cpp

#include "ReadingFromConsole.h"

#include <windows.h>

command ReadingFromConsole::operator()(){

HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);

DWORD mode;

GetConsoleMode(hConsole, &mode);

SetConsoleMode(hConsole, mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));

int ch = getchar();

while(true){

if (commands.count(ch)){

SetConsoleMode(hConsole, mode);

return commands[ch];

}

ch = getchar();

}

}

ReadingFromConsole::~ReadingFromConsole(){

user_keys.close();

}

10

Соседние файлы в папке Лабы по ООП 2023