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

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

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 24, средняя оценка - 4.71
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
17.02.2014, 00:43     Создание игр в текстовом режиме #1
Привет всем! Тут занялся написанием игрушек в текстовом режиме, типа змейки, тетриса и т.п. Суть в том, что я хочу как можно более правильно написать код, со стороны рефакторинга, со стороны выделения и освобождения памяти, и многих других аспектов. Думаю эта тема поможет многим новичкам, в написание чего-либо подобного, поэтому буду потихоньку выкладывать свои исходники и ждать ваших комментариев.Долго думал куда все-таки отнести эту тему, но решил остановиться здесь.
Итак, сейчас я хочу выложить класс интерфейса(менюшка), и данный класс будет использоваться в любой мной написанной игре.

Файл _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)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
programina
22.02.2014, 00:49     Создание игр в текстовом режиме
  #21

Не по теме:

Цитата Сообщение от Bretbas Посмотреть сообщение
еще будут мнения или на этом остановимся?
Говорят, что утро вечера мудренее. Половина России, Украина, Белорусия, Казахстан и др. уже спят.

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
23.02.2014, 00:42  [ТС]     Создание игр в текстовом режиме #22
Так, наконец нашел время все поправить в лучшую сторону. По вашим комментарием собрал вот это:

Файл 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
42
43
44
45
#ifndef INTERFACE_H_
#define INTERFACE_H_
 
#include <iostream>
#include <vector>
#include <string>
 
#include "msoftcon.h"
 
 
/* ## Cтруктура списка интерфейса ## */
struct ListMenu 
{
    vector<wstring> item;
};
 
 
/* ## Абстрактный класс интерфейса ## */
class Interface
{
protected:
    int current_menu() const;                       // Получение текущего списка меню
    int current_cursor() const;                     // Получение каретки текущего пункта меню
    static void next_menu();                        // Следующий список меню
    static void back_menu();                        // Предыдущий список меню
    void add_list_menu(wstring);                    // Добавить пункт в список меню
    void clear_list_menu();                         // Очистить список меню
    int size_list_menu() const;                         // Размер списка меню
    void draw_menu();                               // Прорисовка списка меню
 
private:
    static int number_current_menu_;                // Текущий список меню
    int current_cursor_;                            // Каретка текущего пункта меню
    int x_, y_;                                     // Координаты прорисовки списка на экране
    static ListMenu *menu_;                         // Структура списка меню
 
public:
    Interface(int,int);                             // Конструктор
    virtual ~Interface() = 0;                       // Деструктор
 
    virtual void run() = 0;                         // Запуск статической системы меню
    virtual void run(ListMenu*) = 0;                // Запуск динамической системы меню
};
 
#endif  INTERFACE_H_

Файл Inteface.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
130
131
132
133
#include "Interface.h"
 
 
int Interface :: number_current_menu_ = 1;
ListMenu* Interface :: menu_ = NULL;
 
 
/* ## Конструктор ## */
Interface :: Interface(int x,int y) : x_(x),y_(y)
{ 
    init_graphics();
    menu_ = new ListMenu;
}
 
 
/* ## Деструктор ## */
Interface :: ~Interface()
{ 
    delete menu_;
}
 
 
/* ## Следующий список меню ## */
void Interface :: next_menu()
{
    number_current_menu_++;
}
 
 
/* ## Предыдущий список меню ## */
void Interface :: back_menu()
{
    number_current_menu_--;
}
 
 
/* ## Получение текущего списка меню ## */
int Interface :: current_menu() const
{
    return number_current_menu_;
}
 
 
/* ## Получение каретки текущего пункта меню ## */
int Interface :: current_cursor() const
{
    return current_cursor_;
}
 
 
/* ## Добавить пункт в список меню ## */
void Interface :: add_list_menu(wstring item)
{
    menu_ -> item.push_back(item);
}
 
 
/* ## Очистить список меню ## */
void Interface :: clear_list_menu()
{
    menu_ -> item.clear();
}
 
 
/* ## Размер списка меню ## */
int Interface :: size_list_menu() const
{
    return menu_ -> item.size();
}
 
 
/* ## Прорисовка списка меню ## */
void Interface :: draw_menu()
{
    if ( (menu_ == nullptr) || (menu_ -> item.empty()) )
    {
        clear_screen();
        cout << "Check your list menu!It is empty!";
        _getch();
        exit(0);
    }
 
    set_color(cWHITE,cBLACK);
    clear_screen();
 
    for(unsigned 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 < size_list_menu(); 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_--; } break;
        case 80: if(current_cursor_ != size_list_menu()) { current_cursor_++; } break;
        }
    }
    while(c != 13);
 
    clear_list_menu();
}
 
 
/* ## Запуск динамической системы меню ## */
void Interface :: run(ListMenu *list)
{
    if ( (list == nullptr) || (list -> item.empty()) )
    {
        clear_screen();
        cout << "Check your list menu!It is empty!";
        _getch();
        exit(0);
    }
}

Файл InterfaceChild.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef INTERFACECHILD_H_
#define INTERFACECHILD_H_
 
#include "Interface.h"
 
 
/* ## Производный класс от класса интерфейса ## */
class InterfaceChild : public Interface
{
public:
    InterfaceChild(int,int);        // Конструктор
    ~InterfaceChild();              // Деструктор
 
    void run();                     // Запуск статической системы меню
    void run(ListMenu*);            // Запуск динамической системы меню
};
 
#endif INTERFACECHILD_H_

Файл InterfaceChild.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
#include "InterfaceChild.h"
 
 
/* ## Конструктор ## */
InterfaceChild :: InterfaceChild(int x,int y) : Interface(x,y)
{ }
 
 
/* ## Деструктор ## */
InterfaceChild :: ~InterfaceChild()
{ }
 
 
/* ## Запуск системы ## */
void InterfaceChild :: run()
{
    set_color(cWHITE,cBLACK);
 
    switch(current_menu())
    {
    case 1: // Первое меню - START  OPTION  EXIT
        {
            add_list_menu(L"START");
            add_list_menu(L"OPTION");
            add_list_menu(L"EXIT");
 
            draw_menu();
 
            switch(current_cursor())
            {
            case 1:
                {
                    clear_screen();
                    cout << "hello world";
                    _getch();
                }
            break;
 
            case 2:
                {
                    next_menu();
                }
            break;
 
            case 3:
                {
                    exit(0);
                }
            break;
            }
        }
    break;
 
    case 2: // Второе меню - DINAMIC CREATE MENU   MESSAGE   BACK
        {
            add_list_menu(L"DINAMIC CREATE MENU");
            add_list_menu(L"MESSAGE");
            add_list_menu(L"BACK");
 
            draw_menu();
 
            switch(current_cursor())
            {
            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();
                    back_menu();
                }
            break;
 
            case 3:
                {
                    back_menu();
                }
            break;
            }
        }
    break;
 
    }
 
    run(); // Рекурсивно вызываем эту же функцию
}
 
 
void InterfaceChild :: run(ListMenu *list)
{
    Interface :: run(list);
    set_color(cWHITE,cBLACK);
 
    for(unsigned int i = 0; i < list -> item.size(); i++)
    {
        add_list_menu(list -> item[i]);                 // Инициализируем список с формальным параметром
    }
 
    draw_menu();                                        // Прорисовка списка меню
 
    switch(current_cursor())
    {
    case 1: back_menu(); break;
    case 2: back_menu(); break;
    case 3: back_menu(); break;
    }
}

Ну и конечно же сам main.cpp
C++
1
2
3
4
5
6
7
8
9
10
#include "InterfaceChild.h"
 
 
int main()
{
    InterfaceChild *inter = new InterfaceChild(38,10);
    inter -> run();
 
    return 0;
}

Вроде все, ничего не забыл) Ну теперь жду ваших новых комментариев по новому "улучшенному коду". Что скажете? Так оставлять или можно что-то еще изменить?)
XRuZzz
Антикодер
577 / 478 / 23
Регистрация: 15.09.2012
Сообщений: 2,429
23.02.2014, 01:11     Создание игр в текстовом режиме #23
Название класса Interface не несёт в себе никакой сущности, вы также не определяете пространств имен для класса.
В больших проектах это грозит тем, что на использование класса Interface будут претендовать совершенно разные по назначению классы, и в конечном счете заставит разделить вас класс Interface на несколько. Этой ситуации можно избежать, определив на ранних этапах сущности предметной области, что я и пытался объяснить в статье на которую давал ссылку. Думаю Страуструп также относит ваш подход к "overabstract"

Поэтому дальше названия класса проверять не интересно.
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
23.02.2014, 01:29  [ТС]     Создание игр в текстовом режиме #24
XRuZzz, я не понял, какой сущности нет в названии моего класса?Если я переименую его в AbstractInterface то будет у него сущность?или я вас не правильно понял?объясните пожалуйста.
а про какие пространства имен идет речь?у меня в классе используется только одно пространство имен std и больше ничего.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
23.02.2014, 08:24     Создание игр в текстовом режиме #25
Для такой простой задачи написать такой сложный класс - это, конечно, надо было постараться.
Не будем зарываться в реализацию, а посмотрим на класс с точки зрения пользователя.

По идее, должно быть достаточно посмотреть на интерфейс класса, чтобы стало ясно как его использовать. А что у нас в интерфейсе?
C++
1
2
    virtual void run() = 0;                         // Запуск статической системы меню
    virtual void run(ListMenu*) = 0;                // Запуск динамической системы меню
Два метода для какой-то статической системы и какой-то динамической. О чем это вообще?
Ок, второй метод я еще могу понять - передаем список пунктов, которые следует отобразить. А первый? Откуда он возьмет этот список? Интерфейс не дает ответов на эти вопросы.

А теперь главный фейл - метод run чисто виртуальный. Т.е. я, как пользователь, обязан каждый раз для каждого меню писать свой дочерний класс и каждый раз реализовывать логику выбора пункта и отрисовки меню? Вот уж чего мне точно хочется меньше всего. Скорее всего в большинстве случаев логика будет одна: выбрали пункт - вызвали его обработчик - отрисовали меню.
В данном случае эта логика уже реализована в дочернем классе, и тут возникает вопрос - это пример использования или этот класс является частью библиотеки?

Если это пример использования, то он отлично показывает насколько плох базовый класс - 120+ строк кода, да еще и с не пойми зачем появившейся рекурсией. В моей маленькой голове не укладывается зачем методу run() может потребоваться вызывать себя.

Если же этот класс предоставляется библиотекой, то не ясно на каких правах в нем захардкожены какие-то пункты меню. Мне могут понадобиться совсем другие.

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

Еще класс навязывает свой способ отрисовки. У меня, например, нет заголовочного файла msoftcon.h (я так понимаю, функции для работы с псевдографикой объявлены в нем).

В общем, напишите для начала простое текстовое меню... Тут еще есть какие-то списки менюшек - не надо. Пусть будет один уровень.
XRuZzz
Антикодер
577 / 478 / 23
Регистрация: 15.09.2012
Сообщений: 2,429
23.02.2014, 09:40     Создание игр в текстовом режиме #26
Цитата Сообщение от Bretbas Посмотреть сообщение
XRuZzz, я не понял, какой сущности нет в названии моего класса?Если я переименую его в AbstractInterface то будет у него сущность?или я вас не правильно понял?объясните пожалуйста.
а про какие пространства имен идет речь?у меня в классе используется только одно пространство имен std и больше ничего.
ну скажем если поместить Interface в пространство имен gui, становится несколько понятнее. Однако вы используете текстовый режим, поэтому это скорее не gui, а view.
Класс относится к сущности представления главного окна программы. в MVC паттерне я бы назвал его как то вроде MainFormViews.
Я к тому что по названию класса Interface нельзя догадаться относится ли он к главному окну, либо у вас он нужен для какого нить протокола, либо ещё какой-нить интерфейс для работы с реализациями абстрактных классов, который никак не относится к выводу в консоль.
Впрочем еслu вам не нравumcя мой подход, вы можеmе проuгнорuроваmь моё сообщенuе.

Во многом согласен c 0x10.
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
23.02.2014, 22:39  [ТС]     Создание игр в текстовом режиме #27
XRuZzz, я не хочу игнорировать никакое сообщение, ибо дальше я буду выкладывать уже сами игрушки с использованием этого класса меню.Я хочу преслушиваться к каждому мнению, чтобы добиться как можно идеальной техники кода.
Итак,снова я вас не понимаю, мне нужно мой класс переименовать в MainFormViews для лучшего представления того,что данный класс делает?)
А с пространством имен снова не понял(
Вы можете,если вам не сложно, изменить мой код и выложить мне?
XRuZzz
Антикодер
577 / 478 / 23
Регистрация: 15.09.2012
Сообщений: 2,429
24.02.2014, 09:40     Создание игр в текстовом режиме #28
Цитата Сообщение от Bretbas Посмотреть сообщение
Итак,снова я вас не понимаю, мне нужно мой класс переименовать в MainFormViews для лучшего представления того,что данный класс делает?)
в данном случае слово Form я использую когда есть графический интерфейс, Views если применяется паттерн MVC(о нём можно почитать где угодно)
К вашему коду естественно такое название мало подходит. Техника зависит от опыта, опыта вряд ли вам в форуме за пару дней сильно улучшить технику программирования.
Чтоб углубится в мои подходы к программированию. Нужно потратить значительное время на изучение сайта www.uml2.ru.
вот что пишет Страуструп:
The question ‘‘How does one write good programs in C++?’’ is very similar to the question ‘‘How
does one write good English prose?’’ There are two answers: ‘‘Know what you want to say’’ and
‘‘Practice. Imitate good writing.’’ Both appear to be as appropriate for C++ as they are for English
– and as hard to follow.
Но при это с "Imitate" я не очень согласен.
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
25.02.2014, 00:30  [ТС]     Создание игр в текстовом режиме #29
XRuZzz,вы можете сказать,кроме как названия класса,что нибудь нужно менять еще?может в самом классе нужно изменить что нибудь?или все как надо там?
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
26.02.2014, 02:47  [ТС]     Создание игр в текстовом режиме #30
ммммм?)
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
27.02.2014, 22:06  [ТС]     Создание игр в текстовом режиме #31
Надеюсь вы не отписались от моей темы,потому что я продолжаю!)
В этот раз я выкладываю прикладное приложение для создания карт моих будущих игр)Класс интерфейса(меню) использован тот же,что я и выкладывал)
Итак жду снова ваших мнений и предложений!
Вложения
Тип файла: 7z CreatorMaps_v.beta.7z (364.2 Кб, 7 просмотров)
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
01.03.2014, 00:25  [ТС]     Создание игр в текстовом режиме #32
неужели все отписались от темы?)
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
01.03.2014, 01:58     Создание игр в текстовом режиме #33
Цитата Сообщение от Bretbas Посмотреть сообщение
неужели все отписались от темы?)
Создание игр в текстовом режиме
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
01.03.2014, 02:30  [ТС]     Создание игр в текстовом режиме #34
0x10, хм...странно,я ваш комментарий почему-то пропустил.Вот что значит сидеть с мобильного в интернете(

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

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

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

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

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

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

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

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

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

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

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

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

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

Ну а класс Map - это просто свалка. Тут и редактирование, и доступ к файловой системе, все вперемешку.
Миниатюры
Создание игр в текстовом режиме  
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
03.03.2014, 02:19  [ТС]     Создание игр в текстовом режиме #38
0x10, слушайте,по вашим комментарием хочется все взять и удалить нафиг,и не делать ничего больше...но надо,надо учиться)на счет сущностей,что каждому классу делать,а что не делать,это вы про MVC наверное?)Если да,то есть какая нибудь хорошая книга по MVC с примерами на C++?Не подскажете?
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
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 - хорошая, но опять же надо без фанатизма.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.03.2014, 00:04     Создание игр в текстовом режиме
Еще ссылки по теме:

C++ Нарисовать мышью прямоугольник в текстовом режиме экрана
C++ Работа с экраном в текстовом режиме (вывод всех цветов фона, разделяя цвета паузой)
Создание конструкторов игр C++

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

Или воспользуйтесь поиском по форуму:
Bretbas
22 / 17 / 1
Регистрация: 05.08.2013
Сообщений: 467
Завершенные тесты: 1
06.03.2014, 00:04  [ТС]     Создание игр в текстовом режиме #40
0x10, слушайте...я читаю данные вами статьи про MVC,но не могу понять как разделить данные...мне до сих пор кажется,что они разделены( Я на счет "создания карт"
Вы можете мне словами рассказать,что именно нужно разделить,и к примеру каким образом выводить сообщение об ошибки,если я введу слишком большие размеры матрицы...Ведь манипуляции с матрицей это и есть МОДЕЛЬ,так?Передача размеров матрицы происходит в ПРЕДСТАВЛЕНИИ,которое в свою очередь передает эти размеры КОНТРОЛЛЕРУ на проверку,так?И взависимости прааильные ли они или нет,идем дальше к МОДЕЛИ или ПРЕДСТАВЛЕНИЮ для отображения соответствующего сообщения.Значит мне нужно делать 3 класса - МОДЕЛЬ,ПРЕДСТАВЛЕНИЕ,КОНТРОЛЛЕР для осуществления работы с матрицей?И так нужно и для класса Map и остальных классов?так чтоли?
Yandex
Объявления
06.03.2014, 00:04     Создание игр в текстовом режиме
Ответ Создать тему
Опции темы

Текущее время: 18:09. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru