Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 24, средняя оценка - 4.71
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
#1

Создание игр в текстовом режиме - C++

17.02.2014, 00:43. Просмотров 3231. Ответов 67
Метки нет (Все метки)

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

Файл _interface.h

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include "msoftcon.h"
using namespace std;
 
 
/* ## Cтруктура списка интерфейса ## */
struct ListMenu 
{
    vector<wstring> item;
};
 
 
/* ## Абстрактный класс интерфейса ## */
class _interface
{
protected:
    int CurrentMenu();                              // Получение текущего списка меню
    int CurrentCursor();                            // Получение каретки текущего пункта меню
    static void NextMenu();                         // Следующий список меню
    static void BackMenu();                         // Предыдущий список меню
    void AddListMenu(wstring);                      // Добавить пункт в список меню
    void ClearListMenu();                           // Очистить список меню
    int SizeListMenu();                             // Размер списка меню
    void DrawMenu();                                // Прорисовка списка меню
 
private:
    static int current_menu;                        // Текущий список меню
    int current_cursor;                             // Каретка текущего пункта меню
    int x,y;                                        // Координаты прорисовки списка на экране
    ListMenu *menu;                                 // Структура списка меню
 
public:
    _interface(int,int);                            // Конструктор
    ~_interface();                                  // Деструктор
 
    virtual void Run() = 0;                         // Запуск статической системы меню
    virtual void Run(ListMenu*) = 0;                // Запуск динамической системы меню
};
Ну что могу сказать по поводу этого класса. Ну первое, это абстрактный класс, то есть создание экземпляров от этого класса будет невозможно.

У меня есть 8 методов в области видимости protected, которые будут доступны соответственно классу - потомку. Сейчас распишу примерно, что каждый метод делает:
Кликните здесь для просмотра всего текста
int CurrentMenu() - Соответственно получает номер текущего меню. При создании первого экземпляра класса - потомка номер текущего меню равен 0.
static void NextMenu() - Изменяет номер текущего меню на следущее +1.
static void BackMenu(); - Изменяет номер текущего меню на предыдущее -1.
int CurrentCursor() - Получаем номер текущего пункта меню, где в данное время находится каретка указателя.
void AddListMenu(wstring) - Так мы можем добавить пункт меню в список меню.
void ClearListMenu() - Соответсвенно, что видно из название - очищаем список меню.
int SizeListMenu() - Размер текущего списка меню(Количество пунктов меню данного списка).
void DrawMenu() - Метод прорисовки списка меню и выбора определенного пункта меню.


Теперь расскажу про область видимости private. Там находятся поля класса. Про них особо нечего рассказывать, практически все методы, которые были описаны выше, просто манипулируют этими полями и все:
Кликните здесь для просмотра всего текста
static int current_menu - Номер текущего меню. Причем сколько бы экземпляров класса - потомка не было, это значение для всех общее.
int current_cursor - Номер текущего пункта меню, где в данное время находится каретка указателя.
int x,y - Координаты вывода списка меню на экране.
ListMenu *menu - Ну и конечно структура самого списка меню, состоящая из одного всего поля - вектора библиотеки STL, где хранятся все пункты меню.


Ну и public:
Кликните здесь для просмотра всего текста
_interface(int,int) - Конструктор как вы поняли.
~_interface() - Деструктор соответственно.
virtual void Run() = 0 - Вот это самое интересное.Это чисто виртуальная функция, которая будет заводить всю систему меню. Она должна обязательно быть перегружена в классе - потомке, и все меню и события по нажатию на определенные пункты меню должны создаваться в ней. То есть все что связано с меню, должно выполняться именно в этой функции.
virtual void Run(ListMenu*) = 0 - Метод Run(), это статическое управление списками меню, то есть я не могу создавать, изменять, удалять меню программно. Для этого я создал функцию Run(ListMenu*), которая делает все тоже самое что и Run(), только принимает в качестве формального параметра список меню, что следовательно,что я могу создать меню программно, что иногда очень бывает нужно.


Выкладываю определение всех методов данного класса. Файл _interface.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "_interface.h"
 
 
int _interface :: current_menu = 0;
 
 
/* ## Конструктор ## */
_interface :: _interface(int x1,int y1) : x(x1),y(y1)
{ 
    init_graphics();
    menu = new ListMenu;
}
 
 
/* ## Деструктор ## */
_interface :: ~_interface()
{ }
 
 
/* ## Следующий список меню ## */
void _interface :: NextMenu()
{
    current_menu++;
}
 
 
/* ## Предыдущий список меню ## */
void _interface :: BackMenu()
{
    current_menu--;
}
 
 
/* ## Получение текущего списка меню ## */
int _interface :: CurrentMenu()
{
    return current_menu;
}
 
 
/* ## Получение каретки текущего пункта меню ## */
int _interface :: CurrentCursor()
{
    return current_cursor;
}
 
 
/* ## Добавить пункт в список меню ## */
void _interface :: AddListMenu(wstring item)
{
    menu -> item.push_back(item);
}
 
 
/* ## Очистить список меню ## */
void _interface :: ClearListMenu()
{
    menu -> item.clear();
}
 
 
/* ## Размер списка меню ## */
int _interface :: SizeListMenu()
{
    return menu -> item.size();
}
 
 
/* ## Прорисовка списка меню ## */
void _interface :: DrawMenu()
{
    set_color(cWHITE,cBLACK);
    clear_screen();
 
    for(int i = 0; i < menu -> item.size(); i++)
    {
        set_cursor_pos(x + 4,y + i);
        wcout << menu -> item[i] << endl;
    }
 
    set_cursor_pos(x,y);
    current_cursor = 1;
    char c;
 
    do
    {
        for(int i = 0; i < SizeListMenu(); i++)
        {
            if(i == current_cursor - 1)
            { set_color(cBLACK,cYELLOW); }
            else
            { set_color(cBLACK,cBLUE); }
 
            set_cursor_pos(x,y + i);
            cout << "->";
        }
 
        c = _getch();
 
        switch(c)
        {
        case 72: if(current_cursor != 1) { current_cursor = current_cursor - 1; } break;
        case 80: if(current_cursor != SizeListMenu()) { current_cursor = current_cursor + 1; } break;
        }
    }
    while(c != 13);
}
Ну если все понятно, можно теперь создать собственно меню.) Создаем вначале класс - потомок. Файл ___interface.h

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
#include "_interface.h"
using namespace std;
 
 
/* ## Производный класс от класса интерфейса ## */
class ___interface : public _interface
{
public:
    ___interface(int,int);      // Конструктор
    ~___interface();            // Деструктор
 
    void Run();                 // Запуск статической системы меню
    void Run(ListMenu*);        // Запуск динамической системы меню
};
Здесь вроде все понятно, теперь соответственно определяем функции Run() и Run(ListMenu*). Но прежде чем их определить, нужно придумать меню).
Давайте создадим меню из списка: START, OPTION, EXIT.
По нажатию на START - Выводится сообщение "hello world"
По нажатию на OPTION - Создается второе меню - DINAMIC CREATE MENU, MESSAGE, BACK
По нажатию на EXIT - Выходим из программы

Теперь распишем что будет делать второе меню,созданное по нажатию на OPTION.
По нажатию на DINAMIC CREATE MENU - Создается динамическое меню, из 6 пунктов, если нажмем на один из первых трех - вернемся назад на второе меню, если нажмем на один из трех следующих - вернемся на START, ...
По нажатию на MESSAGE - Выводится сообщение "I Love CyberForum" и возвращаемся на меню START, ...
По нажатию на BACK - Возвращаемся назад на первое меню

Ну вот более менее подходящее меню, чтобы задействовать всю мощь моего написанного класса)
Реализовываем. Файл ___interface.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "___interface.h"
 
 
/* ## Конструктор ## */
___interface :: ___interface(int x,int y) : _interface(x,y)
{ }
 
 
/* ## Деструктор ## */
___interface :: ~___interface()
{ }
 
 
/* ## Запуск системы ## */
void ___interface :: Run()
{
    set_color(cWHITE,cBLACK);
 
    ClearListMenu();
 
    switch(CurrentMenu())
    {
    case 0: // Первое меню - START  OPTION  EXIT
        {
            AddListMenu(L"START");
            AddListMenu(L"OPTION");
            AddListMenu(L"EXIT");
 
            DrawMenu();
 
            switch(CurrentCursor())
            {
            case 1:
                {
                    clear_screen();
                    cout << "hello world";
                    getch();
                }
            break;
 
            case 2:
                {
                    NextMenu();
                }
            break;
 
            case 3:
                {
                    exit(0);
                }
            break;
            }
        }
    break;
 
    case 1: // Второе меню - DINAMIC CREATE MENU   MESSAGE   BACK
        {
            AddListMenu(L"DINAMIC CREATE MENU");
            AddListMenu(L"MESSAGE");
            AddListMenu(L"BACK");
 
            DrawMenu();
 
            switch(CurrentCursor())
            {
            case 1:
                {
                    clear_screen();
                    ListMenu* DinamicMenu = new ListMenu;
                    wstring item;
 
                    for(int i = 0; i < 6; i++)
                    {
                        cout << "Input item of menu";
                        wcin >> item;
                        DinamicMenu -> item.push_back(item);
                    }
 
                    Run(DinamicMenu); // Создаем новое меню динамически
                }
            break;
 
            case 2:
                {
                    clear_screen();
                    cout << "I Love CyberForum";
                    getch();
                    BackMenu();
                }
            break;
 
            case 3:
                {
                    BackMenu();
                }
            break;
            }
        }
    break;
 
    }
 
    Run(); // Рекурсивно вызываем эту же функцию
}
 
 
void ___interface::Run(ListMenu *list)
{
    set_color(cWHITE,cBLACK);
    NextMenu();
    ClearListMenu();                                // Очищаем список
 
    for(int i = 0; i < list -> item.size(); i++)
    {
        AddListMenu(list -> item[i]);               // Инициализируем список с формальным параметром
    }
 
    DrawMenu();                                     // Прорисовка списка меню
 
    switch(CurrentCursor())
    {
    case 1: BackMenu(); break;
    case 2: BackMenu(); break;
    case 3: BackMenu(); break;
    case 4: { BackMenu(); BackMenu(); } break;
    case 5: { BackMenu(); BackMenu(); } break;
    case 6: { BackMenu(); BackMenu(); } break;
    }
}
В main.cpp можно вызвать меню таким способом:

C++
1
2
3
4
5
6
7
8
9
#include "___interface.h"
 
 
void main()
{
    ___interface *inter = new ___interface(38,10);
 
    inter -> Run();
}
Постепенно я буду выкладывать и остальные части игр, и буду слушать ваше мнение по написанному. Почему я начал с меню? Потому что это главный класс, который заводит всю игру, и его нужно написать на сколько можно правильно. Поэтому жду ваших комментариев,критик по поводу написанного, может что то нужно изменить, добавить, убрать. Я прислушаюсь к любому мнению)
1
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.02.2014, 00:43
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Создание игр в текстовом режиме (C++):

Создание интерфейса пользователя в текстовом режиме - C++
Создание интерфейса пользователя в текстовом режиме. Библиотека PDCurses. (С++) Задание: В текстовом режиме экрана реализуйте...

Работа с экраном в текстовом режиме - C++
Ниже дана программа которая до нажатия Esc повторяет действия: случайным образом выбирает размеры (соотношение 25х80) и положение окна ...

Работа с экраном в текстовом режиме - C++
В меню с выбором пунктов Функциональными Клавишами по программе с клавиатуры в 1-е окно вводится текст с цифрами. Во 2-м окне...

Нарисовать мышью прямоугольник в текстовом режиме экрана - C++
Помогите разобраться.. Нужно нарисовать прямоугольник (любыми символами) в текстовом режиме экрана с помощью мышки. Ну я пытался...

ООП иерархия классов с выводом в текстовом режиме - C++
Помогите с решением &quot;Дана иерархия классов числа-числа кратные 5-числа кратные 25. Написать программу с выводом объектов указанных классов...

Как сделать прокрутку (в текстовом режиме) и менюшку в turbo c - C++
(Turbo c)Если прогамма выводит на экран большое кол-во информации, то некоторая её часть становится недоступной, как же сделать прокрутку...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
27.02.2014, 22:06  [ТС] #31
Надеюсь вы не отписались от моей темы,потому что я продолжаю!)
В этот раз я выкладываю прикладное приложение для создания карт моих будущих игр)Класс интерфейса(меню) использован тот же,что я и выкладывал)
Итак жду снова ваших мнений и предложений!
0
Вложения
Тип файла: 7z CreatorMaps_v.beta.7z (364.2 Кб, 7 просмотров)
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
01.03.2014, 00:25  [ТС] #32
неужели все отписались от темы?)
0
Jupiter
Каратель
Эксперт С++
6554 / 3975 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
01.03.2014, 01:58 #33
Цитата Сообщение от Bretbas Посмотреть сообщение
неужели все отписались от темы?)
Создание игр в текстовом режиме
0
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
01.03.2014, 02:30  [ТС] #34
0x10, хм...странно,я ваш комментарий почему-то пропустил.Вот что значит сидеть с мобильного в интернете(

Мой класс Interface является библиотекой,пользователь должен будет создать дочерний класс,чтобы начать использовать и создавать меню.Его нужно создавать только в функции run(),если пользователь хочет создать меню еще до компиляции,тоесть статически,ну или использовать run(ListMenu*),для того,чтобы создать меню уже динамически.Только за этим я разделил эти две функции.
Рекурсия использована,для перехода между списками иерархии меню и не больше.
120 строк...я согласен,но что убрать тогда,чтобы сделать базовый класс меньше?
объясните плизз

Добавлено через 2 минуты
Jupiter,а что вы скажете по поводу "создания карт"?)
0
0x10
2464 / 1636 / 238
Регистрация: 24.11.2012
Сообщений: 4,031
01.03.2014, 06:43 #35
Цитата Сообщение от Bretbas Посмотреть сообщение
Его нужно создавать только в функции run(),если пользователь хочет создать меню еще до компиляции,тоесть статически,ну или использовать run(ListMenu*),для того,чтобы создать меню уже динамически.Только за этим я разделил эти две функции.
Вопрос: а на каком основании класс, который по идее должен быть не более чем контейнером с минимальной логикой, делает предположения о том, на каком этапе у пользователя есть данные? Второго метода вполне достаточно - в него пользователь может передать как список, сформированный на этапе выполнения, так и зашитый жестко в код.
1
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
02.03.2014, 01:51  [ТС] #36
0x10,я вас понял...все переделаю нафиг)завтра выложу)а что скажете про создание карт?)
0
0x10
2464 / 1636 / 238
Регистрация: 24.11.2012
Сообщений: 4,031
02.03.2014, 08:20 #37
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Было бы желание, а разнести можно за каждую строчку... Я не уверен, имеет ли смысл расписывать или пусть автор дойдет своим умом.

Пробежимся раз по интерфейсам и местами по реализации. Дисклеймер: все сказанное - не прямое руководство к действию.

Посмотрим на интерфейс класса Matrix. В паблике у нас два конструктора: с параметрами и без.
Внимание, вопрос: какой смысл автор вкладывает в конструктор матрицы без параметров? Что должно произойти? Создаться матрица размера 0х0? Как потом с ней работать? По факту выясняется, что этот конструктор не делает ничего. видимо, его и быть не должно.

Смысл конструктора с двумя параметрами интуитивно понятен - создание матрицы размера rows*cols. Забегая вперед, реализация конструктора не соответствует ожиданиям.

В публичном доступе также есть данные: собственно, сама матрица и ее размерности. Причем ни о какой инкапсуляции и речи нет - пользователю навязывается тот факт, что матрица реализована как двумерный массив, что, кстати, может быть и иначе. Более того, массив этот всегда фиксированного размера.
Размерности матрицы также ничем не защищены и могут быть изменены независимо. Т.е. где-то в коде я могу поменять, например, высоту, а в другом месте - вылететь за пределы массива при обходе матрицы.

В общем, интерфейс неудобен, не является универсальным и вообще потенциально опасен в использовании.

Еще интересности в приватной части: некая функция Mod_. Комментарий сообщает, что это проверка четности. Тут надо вспомнить, что есть оператор %, которым можно проверить четность. И вообще: какое отношение обычная операция с двумя целыми числами имеет к матрице?

Посмотрим теперь на реализацию.
Реализация конструктора, как я уже заметил выше, дикая. Внезапно конструктор устанавливает цвета в терминале, выводит сообщения в случае ошибок и, что еще круче, в случае ошибки вызывает exit().
Разделите данные и представление. Матрица - это всего лишь контейнер объектов, никакого отношения к представлению он не имеет. Более того, в нем не должны фигурировать никакие ограничения по размеру матрицы относительно размера окна.

В общем, тут две сущности слились в одну: сама матрица и ее представление в окне.

Метод Mod_ делает странное и не соответствующее комментарию. Проверяет он делимость первого аргумента на второй. Как я уже говорил, тут не нужны циклы, а есть оператор %.

Еще у класса есть производный - MatrixChild, который не расширяет функционал базового ничем. Следовательно, и быть его не должно.

Класс Cursor.
Аналогичная проблема с инкапсуляцией - координаты открыты, доступны для изменения.
Главная неожиданность - курсор ссылается на матрицу. Все ради того, чтобы нельзя было сместить его за пределы матрицы. Опять же странная логика. Матрица - контейнер, не важно как она отображается. Курсор - пассивная структура со своей позицией. Мне видится, что явно не ему принимать решение куда двигаться можно, а куда нельзя.

Ну а класс Map - это просто свалка. Тут и редактирование, и доступ к файловой системе, все вперемешку.
0
Миниатюры
Создание игр в текстовом режиме  
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
03.03.2014, 02:19  [ТС] #38
0x10, слушайте,по вашим комментарием хочется все взять и удалить нафиг,и не делать ничего больше...но надо,надо учиться)на счет сущностей,что каждому классу делать,а что не делать,это вы про MVC наверное?)Если да,то есть какая нибудь хорошая книга по MVC с примерами на C++?Не подскажете?
0
0x10
2464 / 1636 / 238
Регистрация: 24.11.2012
Сообщений: 4,031
03.03.2014, 05:54 #39
Цитата Сообщение от Bretbas Посмотреть сообщение
слушайте,по вашим комментарием хочется все взять и удалить нафиг
Ну это одна из причин, по которой я сомневался: писать или не писать. Как вариант, можно было просто дать реализовать несколько игрушек по этому шаблону, чтобы, если сильно повезет, Вы сами прошлись по граблям.

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

При разработке маленького монолитного приложения, в котором переиспользовать особо нечего (или кажется, что нечего) действительно может показаться, что все это не нужно. Но после написания нескольких таких приложений станет очевидно, что какие-то части кода дублируются во всех практически без изменений. И тогда захочется общие части вынести в библиотеку - и тут уже ее нужно сделать универсальной. Было бы дико, если бы контейнеры стандартной библиотеки в Вашей программе что-то сами писали в stdout, так?

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

Цитата Сообщение от Bretbas Посмотреть сообщение
и не делать ничего больше
Делать надо. Забег по граблям, с кучей шишек и все такое.

Цитата Сообщение от Bretbas Посмотреть сообщение
на счет сущностей,что каждому классу делать,а что не делать,это вы про MVC наверное?
Ну так или иначе всегда все сводится к разделению данных, логики и представления. Прям книга по одному этому паттерну - наверное, слишком жирно. А вот статей погуглить можно. Сходу нашел пару, глянул по диагонали: вроде все по теме:
http://ru.wikiversity.org/wiki/%D0%A...B8%D0%BA%D0%B8
http://rsdn.ru/article/patterns/generic-mvc.xml

Только без фанатизма. Не обязательно всегда слепо следовать паттерну в том виде, в котором он реализован в примере. Подвижки допустимы.

Почитать можно Макконнелла - "Совершенный код". Там в основном капитанство, но некоторые эвристические принципы описаны, лишним не будет. "Паттерны проектирования" GoF - хорошая, но опять же надо без фанатизма.
0
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
06.03.2014, 00:04  [ТС] #40
0x10, слушайте...я читаю данные вами статьи про MVC,но не могу понять как разделить данные...мне до сих пор кажется,что они разделены( Я на счет "создания карт"
Вы можете мне словами рассказать,что именно нужно разделить,и к примеру каким образом выводить сообщение об ошибки,если я введу слишком большие размеры матрицы...Ведь манипуляции с матрицей это и есть МОДЕЛЬ,так?Передача размеров матрицы происходит в ПРЕДСТАВЛЕНИИ,которое в свою очередь передает эти размеры КОНТРОЛЛЕРУ на проверку,так?И взависимости прааильные ли они или нет,идем дальше к МОДЕЛИ или ПРЕДСТАВЛЕНИЮ для отображения соответствующего сообщения.Значит мне нужно делать 3 класса - МОДЕЛЬ,ПРЕДСТАВЛЕНИЕ,КОНТРОЛЛЕР для осуществления работы с матрицей?И так нужно и для класса Map и остальных классов?так чтоли?
0
0x10
2464 / 1636 / 238
Регистрация: 24.11.2012
Сообщений: 4,031
06.03.2014, 05:44 #41
Цитата Сообщение от Bretbas Посмотреть сообщение
Значит мне нужно делать 3 класса
Как я уже говорил - не нужно слепо следовать паттерну. Каждая сущность может быть представлена несколькими классами, их композицией. Или же вообще классов может не быть - если окажется достаточно свободной функции.

Чтобы предложить какое-нибудь решение, расскажите словами что хочется получить в итоге. Что из себя представляет карта, предполагается ли скроллинг, какие элементы уровня должны быть, что вы хотите делать с этой картой (сохранение, загрузка). Чтобы я не навязывал какое-то свое видение.
Понятно, что это может показаться очевидным. "Карта - это набор клеток, каждая из которых может быть своего цвета". Но важно формализовать все детали. Возможно, характеристики объектов: проходимость, триггеры событий. Для какой вообще игры делается редактор. Или это будет семейство игр. Нужно понять что у них общего и в чем различия, чтобы либо принять решение где разделять интерфейс и реализацию, определить наиболее вероятные места изменений и т п.
0
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
07.03.2014, 22:17  [ТС] #42
Короче по максимому изменил мой класс Меню,в лучшую сторону или нет, судить конечно не мне а Вам. А как мне кажется, он ниче так)
Во-первых, теперь он у меня не абстрактный.Потому что, я подумал что это не нужно в принципе.
Во-вторых, я написал библиотеку графики,точнее стащил пол кода с книги Р.Лафоре, и сделал на его "Упрощенном варианте консольной графики" класс. Теперь этот класс я использую везде, где хочу изменить цвет, стереть с экрана что-нибудь, или расположить курсор в нужном мне месте. Думаю это стало более удобнее, чем было раньше. Но меню не будет работать без этого класса, поэтому его нужно таскать всегда с собой.
В-третьих, избавился от функций run вовсе, они мне не нужны) Создаю меню я в главной функции main и все такое)

Итак сами файлы:

Файл Menu.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef MENU_H_
#define MENU_H_
 
#include <iostream>
#include <vector>
#include <string>
#include <conio.h>
 
#include "Grafic.h"
 
 
/* ## Класс интерфейса ## */
class Menu
{
private:
    static int number_current_menu_;                    // Номер текущего списка меню
    int current_cursor_;                                // Каретка текущего пункта меню
    int x_, y_;                                         // Координаты прорисовки списка на экране
    static std :: vector<std :: wstring> list_menu_;    // Список меню
    Grafic *grafic_;                                    // Объект графики
 
public:
    Menu(int,int);                                      // Конструктор
    ~Menu();                                            // Деструктор
 
    void add_list_menu(std :: wstring);                 // Добавить пункт в список меню
    void draw_menu();                                   // Прорисовка списка меню
    int current_menu() const;                           // Получение номера текущего списка меню
    int current_cursor() const;                         // Получение каретки текущего пункта меню
    static void next_menu();                            // Следующий список меню
    static void back_menu();                            // Предыдущий список меню
};
 
#endif  MENU_H_
Файл Menu.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "Menu.h"
 
 
int Menu :: number_current_menu_ = 1;
std :: vector<std :: wstring> Menu :: list_menu_;
 
 
/* ## Конструктор ## */
Menu :: Menu(int x,int y) : x_(x),y_(y)
{ 
    grafic_ = new Grafic;
}
 
 
/* ## Деструктор ## */
Menu :: ~Menu()
{ }
 
 
/* ## Следующий список меню ## */
void Menu :: next_menu()
{
    if(number_current_menu_ != list_menu_.size())
    { number_current_menu_++; }
}
 
 
/* ## Предыдущий список меню ## */
void Menu :: back_menu()
{
    if(number_current_menu_ != 0)
    { number_current_menu_--; }
}
 
 
/* ## Получение текущего списка меню ## */
int Menu :: current_menu() const
{
    return number_current_menu_;
}
 
 
/* ## Получение каретки текущего пункта меню ## */
int Menu :: current_cursor() const
{
    return current_cursor_;
}
 
 
/* ## Добавить пункт в список меню ## */
void Menu :: add_list_menu(std :: wstring item)
{
    list_menu_.push_back(item);
}
 
 
/* ## Прорисовка списка меню ## */
void Menu :: draw_menu()
{
    if (list_menu_.empty())
    {
        grafic_ -> clear_screen();
        std :: cout << "Check your list menu!It is empty!";
        _getch();
        exit(0);
    }
 
    grafic_ -> set_color(cWHITE,cBLACK);
    grafic_ -> clear_screen();
 
    for(unsigned int i = 0; i < list_menu_.size(); i++) 
    {
        grafic_ -> set_cursor_pos(x_ + 4,y_ + i);
        std :: wcout << list_menu_[i] << std :: endl;
    }
 
    grafic_ -> set_cursor_pos(x_,y_);
    current_cursor_ = 1;
    char c;
 
    do
    {
        for(unsigned int i = 0; i < list_menu_.size(); i++)
        {
            if(i == current_cursor_ - 1)
            { grafic_ -> set_color(cBLACK,cYELLOW); }
            else
            { grafic_ -> set_color(cBLACK,cBLUE); }
 
            grafic_ -> set_cursor_pos(x_,y_ + i);
            std :: cout << "->";
        }
 
        c = _getch();
 
        switch(c)
        {
        case 72: if(current_cursor_ != 1) { current_cursor_--; } break;
        case 80: if(current_cursor_ != list_menu_.size()) { current_cursor_++; } break;
        }
    }
    while(c != 13);
 
    list_menu_.clear();
}
Файл Grafic.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef GRAFIC_H_
#define GRAFIC_H_
 
#include <iostream>
#include <windows.h>
 
 
/* ## Список перечисления ## */
enum color
{
    cBLACK=0, cDARK_BLUE=1, cDARK_GREEN=2, DARK_CYAN=3, cDARK_RED=4, cDARK_MAGENTA=5, cBROWN=6, cLIGHT_GRAY=7,
    cDARK_GRAY=8, cBLUE=9, cGREEN=10, cCYAN=11, cRED=12, cMAGENTA=13, cYELLOW=14, cWHITE=15
};
 
 
/* ## Класс графики ## */
class Grafic
{
private:
    static HANDLE h_console_;                       // Дескриптор окна консоли
 
public:
    Grafic();                                       // Конструктор
    ~Grafic();                                      // Деструктор
 
    void set_color(color fg,color bg = cBLACK);     // Установка цвета
    void set_cursor_pos(int x,int y);               // Установка позиции курсора
    void clear_screen();                            // Стирание экрана
};
 
#endif GRAFIC_H_
Файл Grafic.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "Grafic.h"
 
 
HANDLE Grafic :: h_console_ = NULL;
 
 
Grafic :: Grafic()
{
    COORD console_size = {80,25};
 
    h_console_ = CreateFile( L"CONOUT$",
                            GENERIC_WRITE |
                            GENERIC_READ,
                            FILE_SHARE_READ |
                            FILE_SHARE_WRITE,
                            0L,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            0L );
 
    SetConsoleScreenBufferSize(h_console_,console_size);
 
    SetConsoleTextAttribute(h_console_,(WORD)((0<<4) | 15));
 
    clear_screen();
}
 
 
Grafic :: ~Grafic()
{ }
 
 
void Grafic :: set_color(color foreground,color background)
{
    SetConsoleTextAttribute(h_console_,(WORD)((background<<4) | foreground));
}
 
 
void Grafic :: set_cursor_pos(int x,int y)
{
    COORD cursor_pos;
    cursor_pos.X = x - 1;
    cursor_pos.Y = y - 1;
 
    SetConsoleCursorPosition(h_console_,cursor_pos);
}
 
 
void Grafic :: clear_screen()
{
    set_cursor_pos(1,25);
 
    for(int j = 0;j < 25;j++)
    { std :: cout << "\n"; }
 
    set_cursor_pos(1,1);
}
И конечно же сам main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include <conio.h>
 
#include "Menu.h"
#include "Grafic.h"
 
using namespace std;
 
int main()
{
    Grafic *grafic = new Grafic;
    Menu *inter = new Menu(38,10);
    
    for(;;)
    {
        switch(inter -> current_menu())
        {
        case 1: // Первое меню - START  OPTION  EXIT
            {
                inter -> add_list_menu(L"START");
                inter -> add_list_menu(L"OPTION");
                inter -> add_list_menu(L"EXIT");
 
                inter -> draw_menu();
 
                switch(inter -> current_cursor())
                {
                case 1:
                    {
                        grafic -> clear_screen();
                        cout << "hello world";
                        _getch();
                    }
                break;
 
                case 2:
                    {
                        inter -> next_menu();
                    }
                break;
 
                case 3:
                    {
                        exit(0);
                    }
                break;
                }
            }
        break;
 
        case 2: // Второе меню - DINAMIC CREATE MENU   MESSAGE   BACK
            {
                inter -> add_list_menu(L"DINAMIC CREATE MENU");
                inter -> add_list_menu(L"MESSAGE");
                inter -> add_list_menu(L"BACK");
 
                inter -> draw_menu();
 
                switch(inter -> current_cursor())
                {
                case 1:
                    {
                        grafic -> clear_screen();
                        wstring item;
                        vector<wstring> dimanic_menu;
 
                        for(int i = 0; i < 6; i++)
                        {
                            cout << "Input item of menu";
                            wcin >> item;
                            inter -> add_list_menu(item);
                        }
 
                        inter -> draw_menu();
 
                        switch(inter -> current_cursor())
                        {
                        case 1: inter -> back_menu(); break;
                        case 2: inter -> back_menu(); break;
                        case 3: { inter -> back_menu(); } break;
                        }
                    }
                break;
 
                case 2:
                    {
                        grafic -> clear_screen();
                        cout << "I Love CyberForum";
                        _getch();
                        inter -> back_menu();
                    }
                break;
 
                case 3:
                    {
                        inter -> back_menu();
                    }
                break;
                }
            }
        break;
        }
    }
 
    return 0;
}
Жду снова ваших комментариев по поводу написанного. Надеюсь хоть на этот раз более-менее грамотно написано, и можно продолжать дальше)
0
XRuZzz
Антикодер
676 / 577 / 28
Регистрация: 15.09.2012
Сообщений: 2,523
07.03.2014, 23:05 #43
Цитата Сообщение от Bretbas Посмотреть сообщение
grafic_ = new Grafic;
че то deletе-a не вижу.
Цитата Сообщение от Bretbas Посмотреть сообщение
Надеюсь хоть на этот раз более-менее грамотно написано
можно до бесконечности стремиться к идеалу в коде, но намного разумнее почитать что нить новое, или придумать что то новое в архитектуре кода самому.
Я например недавно добавил в свою прогу JSON парсер на основе boost property tree[ поддерживает также XML и INI]. Это позволяет хранить конфигурационный файл проги в удобном виде.
Решение в booste казалось бы красивое, но когда начинаешь рассуждать, оказывается, что можно сделать более универсальный и изящный код. Доходит до того, что хочется переделать весь C++. Раньше я считал, что языков программирования слишком много, терь я считаю, что недостаточно, так как нет подходящего.
0
Bretbas
198 / 57 / 8
Регистрация: 05.08.2013
Сообщений: 869
Завершенные тесты: 1
07.03.2014, 23:06  [ТС] #44
XRuZzz, кроме delete еще есть замечания?)
0
XRuZzz
Антикодер
676 / 577 / 28
Регистрация: 15.09.2012
Сообщений: 2,523
08.03.2014, 00:59 #45
Цитата Сообщение от Bretbas Посмотреть сообщение
XRuZzz, кроме delete еще есть замечания?)
к любой строчке можно придраться, тока смысла не вижу. Но если говорить в позитивном ключе, то хотелось бы увидеть в коде паттерны проектирования[это вы можете легко оспорить, если вы их изучили], полиморфизм, наследование, обобщенное программирование[шаблоны], стиль C++11, перегрузку операторов. Возможно перегрузка вам вовсе не нужна, однако я ожидаю более широкого использования возможностей языка, в тех местах где это действительно необходимо.

Не смотря на то, что помогать разработчикам игр не очень хорошее занятие, дам вам ссылку на пример, который помог мне понять один из паттернов МVC[так как паттерны МVC бывают разные]:
MVC в примере на С++ (консольное приложение)
То что я рекомендую этот паттерн, означает только то, что я мало разбирался[экспериментировал] с другими.
По проекту в целом, меня бы порадовали[многие не признают некоторые пункты]:
-более высокий уровень описания требований к проекту
-сценарии вариантов использования
-UML диаграммы[они используются как дополнение к тексту. Немного порадовала диаграмма классов 0x10]
-система контроля версий[я не сторонник смотреть код проекта в форуме]
и т п
Конечно вы просили оценить только код, но иногда полезно выйти за рамки темы.

Давайте откроем любой участок кода boost [или другой библиотеки C++]:
C++
1
2
3
4
5
6
7
8
9
10
11
12
        /** Insert a copy of the given tree with its key just before the given
         * position in this node. This operation invalidates no iterators.
         * @return An iterator to the newly created child.
         */
        iterator insert(iterator where, const value_type &value);
 
        /** Range insert. Equivalent to:
         * @code
         * for(; first != last; ++first) insert(where, *first);
         * @endcode
         */
        template<class It> void insert(iterator where, It first, It last);
Не будем рассматривать код, посмотрим на комментарии в коде. Они имеют особый формат для автоматической генерации документации.
Это формат doxygen.
Этим я хотел сказать то, что даже в ваших комментариях есть что улучшать.

Всё вышеперечисленное не является фундаментальными знаниями[такими как математика], на которые я вам советую опираться в первую очередь[уделять им больше времени].
1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.03.2014, 00:59
Привет! Вот еще темы с ответами:

Работа с экраном в текстовом режиме (вывод всех цветов фона, разделяя цвета паузой) - C++
Пожалуйста подскажите, как сделать вывод всех цветов фона, разделяя цвета паузой. Задание: Дополнить меню функциональной клавишей F6:...

Создание 2D игр. Начало - C++
Уважаемые форумчане! Помогите: покидайте ссылок на ресурсы, связанные с разработкой 2D игр - платформеров(самых примитивных) на С++ на...

Создание конструкторов игр - C++
Вопрос этот поднимал в теме про xna, но понял что ответа на него там не получу. Всем привет! Решил задать вопрос, как работает 2d игровой...

Создание 2д игр под android на C++ - C++
Доброго времени суток. Очень часто задаюсь мыслью что делаю что либо зря.. и вот такая мысля меня посетила снова, и я решился спросить у...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
08.03.2014, 00:59
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru