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

Тетрис на c++ - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 14, средняя оценка - 4.93
Gomg
5 / 5 / 0
Регистрация: 28.06.2013
Сообщений: 116
03.08.2013, 21:13     Тетрис на c++ #1
Я решил проверить свои скудные знания языка и написать всем известную игру тетрис. Вот что получилось.
Кликните здесь для просмотра всего текста
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
#include <iostream>
#include <locale.h>
#include <conio.h>
#include <Windows.h>
 
using namespace std;
 
static char field[10][10] = {"         ",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#########" }; //y x
bool Run = true;
float timer;
 
void Draw(){
    system("cls");
    for (int i =0; i<10;i++){
        cout << field[i] << endl;
    }
}
 
class Block{
public:
    Block(char imag, int x, int y){
        xP = x; yP = y; image = imag;
    }
    char image;
    int xP, yP;
 
    void Block::Input();
 
    static void Turn(Block block){
        switch(field[block.yP+1][block.xP]){
            case ' ':
                field[block.yP][block.xP] = ' ';
                block.yP += 1;
                field[block.yP][block.xP] = block.image;
            break;
        }
    }
};
 
void Block::Input(){
    for (int i =0; i < 10; i++){
        for (int j =0 ; j< 10; j++){
            switch(field[j][i]){
                case 'O':
                    if (GetAsyncKeyState(VK_LEFT) != 0){
                        int j2 = j++;
                        switch (field[i][j2]){
                            case ' ':
                                field[i][j] = ' ';
                                j = j2;
                                field[i][j] = 'O';
                                break;
                        }
                    }
                    if (GetAsyncKeyState(VK_RIGHT) != 0){
                        int j2 = j--;
                        switch (field[i][j2]){
                            case ' ':
                                field[i][j] = ' ';
                                j = j2;
                                field[i][j] = 'O';
                                break;
                        }
                    }
                break;
            }
        }
    }
}
 
 
 
int main(){
    setlocale(LC_ALL,"RUS");
    static Block block1('H',5,0);
    {
    while (Run){
        timer += 0.01f;
        if (timer >= 150000){
            Block::Turn(block1);
            Draw();
            timer =0;
        }
    }
    }
    return 0;
}

Но только она не работает должным образом. То есть не падает блок. нельзя двигать его по бокам.
В чем ошибка? и насколько правильнен код? и как написать лучше?

Добавлено через 7 минут
да и как можно записать без static, а то это меня напрягает, все таки статик для всех параметры одинаковы, а мне надо будет сделать для каждого объекта копию его класса, чтобы как бы параметры типа координаты и значка были лично для этого объекта. все таки надо сделать спавн блоков
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.08.2013, 21:13     Тетрис на c++
Посмотрите здесь:

C++ Тетрис
Тетрис C++
C++ Тетрис: начало
Игра тетрис C++
C++ Тетрис на C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
04.08.2013, 03:25     Тетрис на c++ #2
Цитата Сообщение от Gomg Посмотреть сообщение
Но только она не работает должным образом. То есть не падает блок. нельзя двигать его по бокам.
В чем ошибка? и насколько правильнен код? и как написать лучше?
Блок перемещать нужно. У тебя есть поле 10 на 10, блок у тебя вверху появляется проверяй возможно ли его опустить на клетку вниз делаешь опускание, затем делаешь задержку на секунду или больше потом снова опускание, что бы оно плавно двигалось, просто в цикле изменяй координаты блока по вертикальной оси на -1. Что бы в бок перемещать по горизонтальной оси изменяй координаты на -1 или +1.
Повороты наверно делаются просто для какждого блока в зависимости от формы там ге, квадрат или палка программируешь как она будет отображатся после поворота, короче как изменит свое состояния не знаю но похоже самое тяжолое это сделать поворот хотя кто его знает, да тут наверно каждый блок должен хранить состояние поля.

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

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

Добавлено через 2 минуты
Gomg, Ты тут написал 90 строк кода и спрашиваешь почему оно не работает, когда там должно быть строк примерно 1.5к
Gomg
5 / 5 / 0
Регистрация: 28.06.2013
Сообщений: 116
04.08.2013, 08:44  [ТС]     Тетрис на c++ #3
так почему-то не назначается массиву символ по измененной y++ координате
C++
1
2
3
4
5
6
7
8
9
static void Turn(Block block){
        switch(field[block.yP+1][block.xP]){
            case ' ':
                field[block.yP][block.xP] = ' ';
                block.yP += 1;
                field[block.yP][block.xP] = block.image;
            break;
        }
    }
так и я все-таки не узнал ответы на вопросы про статик и т.д. Да и мне кажется делая классы намного удобнее будет и проще. Да и вообще я еще не задумываюсь о поворотах, я делаю только блок из одного элемента.

Добавлено через 1 час 5 минут
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
#include <iostream>
#include <locale.h>
#include <conio.h>
#include <Windows.h>
 
using namespace std;
 
static char field[10][10] = {"         ",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#       #",
                             "#########" }; //y x
bool Run = true;
float timer;
 
void Draw(){
    system("cls");
    for (int i =0; i<10;i++){
        cout << field[i] << endl;
    }
}
 
class Block{
public:
    Block(char imag, int x, int y){
        xP = x; yP = y; image = imag;
    }
    char image;
    int xP, yP;
};
void Turn(Block &block){
        switch(field[block.yP+1][block.xP]){
            case ' ':
                field[block.yP][block.xP] = ' ';
                block.yP += 1;
                field[block.yP][block.xP] = block.image;
            break;
        }
}
 
void Input(Block block){
    int i2 = 0;
    for (int i =0; i < 10; i++){
        for (int j =0 ; j< 10; j++){
            switch(field[j][i]){
                case 'O':
                    if (GetAsyncKeyState(VK_LEFT) != 0){
                    i2 = i++;
                        switch (field[j][i2]){
                            case ' ':
                                field[j][i2] = block.image;
                                field[j][i] = ' ';
                                i = i2;
                                Draw();
                                break;
                            default: break;
                        }
                    }
                    if (GetAsyncKeyState(VK_RIGHT) != 0){
                        int i2 = i--;
                        switch (field[j][i2]){
                            case ' ':
                                field[j][i2] = block.image;
                                field[j][i] = ' ';
                                i = i2;
                                Draw();
                                break;
                            default: break;
                        }
                    }
                break;
            }
        }
    }
}
 
 
 
int main(){
    setlocale(LC_ALL,"RUS");
    Block block1('O',5,0);
    {
    while (Run){
        timer += 0.01f;
        if (timer >= 150000){
            Turn(block1);
            Draw();
            Input(block1);
            //if (
            timer =0;
        }
    }
    }
    return 0;
}
вот я написал код ,но блок только падает. не сдвигается
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11841 / 6820 / 771
Регистрация: 27.09.2012
Сообщений: 16,911
Записей в блоге: 2
Завершенные тесты: 1
04.08.2013, 08:47     Тетрис на c++ #4
Во-первых, так никогда не делают:
C++
1
2
        timer += 0.01f;
        if (timer >= 150000){
Это У Вас не таймер получается, а счетчик итераций какой-то...
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
04.08.2013, 12:24     Тетрис на c++ #5
Цитата Сообщение от Gomg Посмотреть сообщение
вот я написал код ,но блок только падает. не сдвигается
Выведи на экран после cдвига поле и сделай exit(1); и посмотри что у тебя произошло с блоком. Я честно не люблю в чужой код разбирать.
Gomg
5 / 5 / 0
Регистрация: 28.06.2013
Сообщений: 116
04.08.2013, 16:46  [ТС]     Тетрис на c++ #6
Цитата Сообщение от Croessmah Посмотреть сообщение
Во-первых, так никогда не делают:
а как делают то?
Цитата Сообщение от ninja2 Посмотреть сообщение
Выведи на экран после cдвига поле и сделай exit(1);
просто выключается программа и все.
jorik567
1 / 1 / 0
Регистрация: 23.06.2013
Сообщений: 13
04.08.2013, 17:12     Тетрис на c++ #7
Цитата Сообщение от Gomg Посмотреть сообщение
а как делают то?
Например так:

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
#define TIME_GAME_TIK   0.03f   //величина игрового тика времени в абсолютном выражении, лучше сделать через конст, но для консольки и так пойдёт.
//глобальные переменные
float currTime  = 0.0f;         //(float)timeGetTime(); - для получения текущего времени
static float lastTime = 0.0f;   //значение времени в предидущей итерации (т.е. lastTime = старое значение currTime)
float timeDelta = 0.0f;         //вычисляется так: timeDelta=(currTime - lastTime)*0.001f; разница времени между итерациями
float timeElapsedGame = 0.0f;   //счётчик игрового дискрета времени
 
//функция обработки дискрета времени
inline void Timing() //но можно и не инлайнить
{
    currTime  = (float)timeGetTime();           //получение текущего времени
    timeDelta = (currTime - lastTime)*0.001f;   //вычисление прошедшего между проходами цикла. 0.001f - перевод милисекунд в секунды
    timeElapsedGame+=timeDelta;                 //счётчик игрового дискрета времени
}
 
...
 
...main...
{
....
    lastTime = (float)timeGetTime();        //начальное значение времени на предидущей итерации будет совпадать с  текущим, что очевидно
    while(true) //Главный цикл. только не забудь описать условия выхода ;)
    {
        Timing();   //формировани игрового времени timeElapsedGame
        if(timeElapsedGame>=TIME_GAME_TIK) //если прошёл 1 тик игрового времени, то :
        {
             //всё, что должно происходить в игре
             timeElapsedGame = 0.0f;    //обнуление счётчика игрового дискрета времени - важно, иначе только первая итерация будет по таймеру
        }
        lastTime = currTime;    //запись устаревшего значения текущего времени currTime в lastTime
 
    }
}
У меня работае эта конструкция давно и надёжно. Позволяет делать параллельно несколько независимых таймеров, считать FPS, моделировать тики ИИ и прочее.
rizr
1 / 1 / 0
Регистрация: 13.01.2013
Сообщений: 71
04.08.2013, 17:12     Тетрис на c++ #8
да с поворотами и проверкой на столкновения фигур тут заморочки
jorik567
1 / 1 / 0
Регистрация: 23.06.2013
Сообщений: 13
04.08.2013, 17:34     Тетрис на c++ #9
извини, забыл сказать: надо подключить ctime перед использованием timeGetTime
#include <ctime>
Gomg
5 / 5 / 0
Регистрация: 28.06.2013
Сообщений: 116
05.08.2013, 08:39  [ТС]     Тетрис на c++ #10
1>main.obj : error LNK2019: ссылка на неразрешенный внешний символ __imp__timeGetTime@0 в функции "void __cdecl Time(void)" (?Time@@YAXXZ)

вот что выходит после этого. и define почему-то не работает. пишет что что-то пустое, хотя значение есть. Пришлось писать просто const float TIME_TICK

Добавлено через 27 секунд
<ctime> есть
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.08.2013, 22:57     Тетрис на c++
Еще ссылки по теме:

Тетрис на С++ C++
Тетрис на mvc C++
Оцените тетрис C++

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

Или воспользуйтесь поиском по форуму:
jorik567
1 / 1 / 0
Регистрация: 23.06.2013
Сообщений: 13
06.08.2013, 22:57     Тетрис на c++ #11
Gomg, извини,что не отвечал (не мог добраться к инету...)
на самом деле надо подключать не <ctime> а <Windows.h> и подключить в Project / ... Propertes / Configuration propertes / Linker / Input в строке Additional Dependences библиотеку winmm.lib. В этой строке перечислены библиотеки, кот. подключаются по умолчанию. Судя по всему winmm.lib у тебя там не записан.

Вот код простого примерчика использования этой функции. Программа отмеряет время между вводами данных с клавиатуры и выводит на экран
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "stdafx.h"    //у меня это лепится визардом автоматически
#include <locale>     // чтобы работала локализация (русские буквы в консоли были норм.)
#include <iostream> // ввод вывод
#include <Windows.h> // согласно хелпу по этой функции
 
using namespace std;            //включаем всё пространство имён std. (не очень хорошо, но для теста терпимо)
 
int main()
{
    setlocale(LC_ALL,"russian");    //включает русский шрифт в консоли. Требует locale.h
    float currTime  =(float)timeGetTime();
    float lasttime = currTime;
    char key = ' ';
    while (key!='q')
    {
        currTime  =(float)timeGetTime();
        cout << "для продолжения - любая клавиша           q - выход, ";
        cin >> key;
        cout << "Пауза = " << (currTime-lasttime)*0.001 << endl;
        lasttime = currTime;
    }
    return 0;
}
вот фрагмент хелпа по функции

timeGetTime Function
The timeGetTime function retrieves the system time, in milliseconds. The system time is the time elapsed since Windows was started.
Syntax
DWORD timeGetTime(void);
Parameters
This function has no parameters.
Return Value
Returns the system time, in milliseconds.
Remarks
The only difference between this function and the timeGetSystemTime function is that timeGetSystemTime uses the MMTIME structure to return the system time. The timeGetTime function has less overhead than timeGetSystemTime.
Note that the value returned by the timeGetTime function is a DWORD value. The return value wraps around to 0 every 2^32 milliseconds, which is about 49.71 days. This can cause problems in code that directly uses the timeGetTime return value in computations, particularly where the value is used to control code execution. You should always use the difference between two timeGetTime return values in computations.

Requirements
Minimum supported client Windows 2000 Professional
Minimum supported server Windows 2000 Server
Header Mmsystem.h (include Windows.h)
Library Winmm.lib
DLL Winmm.dll

See Also
Multimedia Timers
Multimedia Timer Functions
Send comments about this topic to Microsoft
Build date: 10/9/2009

[/SPOILER]
Yandex
Объявления
06.08.2013, 22:57     Тетрис на c++
Ответ Создать тему
Опции темы

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