| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C++ Builder > Помогите сделать игру "змейка" |
| Автор: Lehon 7.10.2009, 19:13 | ||
| Добрый день. Подскажите пожалуйста, как сделать так, что бы при нажатии стрелок обьект (например обычная кнопка) перемещался по форме? И вообще как назначать приложению кнопки? (Если нажата W то, если -> то...). (Гугл не рулит. Точнее рулит под dos приложения. Исходники обычной тупой змейки даже под консоль...) +вопрос который я задавал ранее, но мне не ответили... Не могу задать переменные сразу на всю программу. Вот:
[C++ Error] Unit1.cpp(11): E2451 Undefined symbol 'Edit1' [C++ Error] Unit1.cpp(12): E2451 Undefined symbol 'Edit2' [C++ Error] Unit1.cpp(17): E2303 Type name expected [C++ Error] Unit1.cpp(17): E2238 Multiple declaration for 'z' [C++ Error] Unit1.cpp(13): E2344 Earlier declaration of 'z' [C++ Error] Unit1.cpp(18): E2303 Type name expected и т.д. однотипные ошибки, затем [C++ Warning] Unit1.cpp(46): W8004 'z3' is assigned a value that is never used [C++ Warning] Unit1.cpp(46): W8004 'z2' is assigned a value that is never used [C++ Warning] Unit1.cpp(46): W8004 'z1' is assigned a value that is never used и тд |
| Автор: Lehon 7.10.2009, 19:30 |
| Внутрь кнопки? Так потому и хочу сразу задать глобальные переменные - слишком неэкономично в каждой кнопке писать переменные. |
| Автор: Anikmar 7.10.2009, 19:42 | ||
Можно создать класс для глобальных переменных. И глобальным сделать один его экземпляр.
Вы сначала попробуйте змейку написать хоть под ДОС. Поверьте двигать кнопку намного проще, чем написать змейку. |
| Автор: Lehon 7.10.2009, 20:03 |
| "Вы сначала попробуйте змейку написать хоть под ДОС. Поверьте двигать кнопку намного проще, чем написать змейку." Ну, мне кнопка и нужна ) А не змейка. Я не понимаю ничего в консольном программировании, пусть это и один и тот же с++, мне именно приложение нужно ) С кнопкой двигающийся стрелками. "Можно создать класс для глобальных переменных. И глобальным сделать один его экземпляр." Попробую... |
| Автор: Usper 8.10.2009, 11:06 | ||||
Переменные можно объявить и глобально вне класса, однако присваивать им значения надо в конструкторе формы:
А двигать кнопку так: Разместить на форме кнопку, свойство формы KeyPreview установить в true, в обработчик FormKeyDown формы написать код:
|
| Автор: Lehon 8.10.2009, 15:42 |
| Благодарю, Помогло! ) ПС Вроде бы движение кнопки билдер нереализует. Шейпы двигаются, баттоны нет. |
| Автор: Anikmar 8.10.2009, 15:49 |
Посмотрите - не включено ли в кнопках автовыравнивание и привязка к родительскому контролу. Добавлено через 55 секунд Бедный русский язык. Был бы он реальным монстром - первым делом сожрал бы всех программистов. |
| Автор: Usper 8.10.2009, 16:02 |
| В примере было почему-то Key==0; надо, конечно же, Key=0; и вообще эту строчку можно выкинуть А кнопка нормально двигается. |
| Автор: Lehon 8.10.2009, 16:02 | ||
| Еще вопрос! Вот код. Компилятор ругается (и правильно делает) на то что я вписал кеи в таймер, а так же не понимает что на месте x как раз должно быть имя члена Тшейп. Вопрос в том как правильно написать что б все работало? А именно: 1. Если жмем кнопку *** то на месте х в Shape1->x; Ставиться Top либо Left; Следовательно, в зависимости от того какую кнопку мы нажали, шейп раз в **милисекунд сдвигается в ту сторону какую кнопку мы нажали. 2. Как сдвигать не на ++ а на +20 к примеру? (У меня такое не работает...).
[C++ Error] Unit1.cpp(34): E2451 Undefined symbol 'Key' [C++ Error] Unit1.cpp(38): E2316 'x' is not a member of 'TShape' |
| Автор: Anikmar 8.10.2009, 16:26 |
| Ох... Лучше скажите, что вы хотите при помощи таймера сделать? Добавлено через 3 минуты и 40 секунд Если я правильно понял, то заведите 2 переменные в классе: DirectionX и DirectionY По перехвату соответствующей кнопки заносите в них значение сдвига, например: нажата кнопка влево - DirectionX=-1, кнопка вправо - DirectionX = 1 и т.п. Можно еще фичу сделать: Нажали кнопку влево - уменьшили DirectX на 1, а вправо - увеличили. Тогда скорость движения менять будем. А по таймеру - просто прибавляем к Left - DirectionX, а к Top DirectionY |
| Автор: Lehon 8.10.2009, 16:49 |
| Вообще я хотел научиться управлять клавишами обьектом, а теперь уже захотел написать змейку ) Таймер - обеспечение постоянного движения с постоянной скоростью, желательно так: каждые 0,5 или 1 секунду (пока не решил) происходит сдвиг на 1 длину сегмента змейки ( в моем случае 20). А стрелками теперь я задаю лишь направление движения по идее... Про DirectionX и Y непонял, но попробую... |
| Автор: Anikmar 8.10.2009, 17:05 |
Если не поняли, то как вы собираетесь пробовать? Лучше скажите что непонятно - дабы не плодить лишнего кода. |
| Автор: Lehon 8.10.2009, 17:38 |
| "Если не поняли, то как вы собираетесь пробовать? На вкус? Лучше скажите что непонятно - дабы не плодить лишнего кода. " Да, ни на вкус ни на цвет не получилось ) Гугл вообще мне директх предлагает ))) Мне непонятно что за переменные такие DirectionX и Y и как вообще это запрогать. Я работал раньше тока с дабле и инт... Прогаю 3или 4ый день всего ) |
| Автор: Usper 8.10.2009, 17:59 |
| Anikmar, предлагает создать переменные DirectionX и DirectionY и в обработчике FormKeyDown присваивать им соответствующие значения. А по таймеру, в соответствии со значениями в этих переменных, делать соответствующий сдвиг. Я в своё время при написании змейки тоже руководствовался похожим принципом, только у меня была одна переменная (см. вложение). За код прошу не пинать, писалось всё на заре программерской деятельности |
| Автор: Lehon 8.10.2009, 18:52 | ||
У меня родилась идея как сделать. Компилируется, работает, но само не двигается. вообще. только нажатием кнопки...
|
| Автор: Anikmar 8.10.2009, 19:55 | ||
Оххх. Еще бы вам немного синтаксис языка изучить.... В Cи операция сравнения на равенство кодируется как == |
| Автор: Lehon 8.10.2009, 20:56 |
| Спасибо ) Заработало ) |
| Автор: Lehon 11.10.2009, 11:22 | ||
| Всем привет! У меня опять вопрос ) Вот код. Проблема в последнем блоке. Вроде как синтаксическая ошибка, хотя не понимаю почему, вроде как взял инфу из книги... Ошибки выделил жирным. Что я пытался сделать? Создать случайное число от 0 до 9 (к сож не знаю как сделать от 1 до 9 (ну это только для сотен) - если кто знает тоже подскажите плз), и к нему прибавить 0, ну, т.е. из допустим 3х сделать 30, т.к. мне нужны десятки и сотни. Но! Есть еще момент который я не реализовал - десятки мне нужны через 20. т.е. 00, 20, 40, 60, 80. Все это должно перемещать яблоко по случайным координатам. И еще момент - у меня яблоко перемещается каждые n секунд и быстро скрывается из виду. Да, это из за того что я все вписал в таймер, но нигде больше перемещение не работает. Может как то можно создать отдельное событие о пересечении координат головы змеи и яблока?
[C++ Error] Unit1.cpp(74): E2188 Expression syntax [C++ Error] Unit1.cpp(75): E2188 Expression syntax [C++ Error] Unit1.cpp(76): E2188 Expression syntax Дальше варнинги о обьявленых но неиспользованных переменных. |
| Автор: Usper 11.10.2009, 16:17 |
| А что вы пытаетесь сделать в этих строках? Фактически получается прибавление строки к числу. А это недопутимо. Да ещё и знак "+" зачем-то перед ";" стоит. Нужно справа добавить нулей к числу? Можно просто умножить число на 10^n, где n - необходимое число нулей. |
| Автор: Lehon 11.10.2009, 16:40 |
| Умножить на 10? Не подумал даже... действительно простейший выход ) Да, я хотел к числу которое выдал рандом добавить нули. А ошибка как я понял в том что я не написал StrToFloat. Попробую умножением... А что насчет других вопросов? |
| Автор: Lehon 11.10.2009, 17:27 |
| Получилось, но с ошибочкой. Все вроде как верно, но! Посмотрите на код: if (u==i, l==d) {Shape2->Top=a; Shape2->Left=f;}; Когда по Топ перемещаемся, все норм работает, но когда пересекаем Лефт, на котором лежит яблоко, оно перемещается - хотя я до него еще и не доехал. Т.е. Если я иду к яблоку по Топ, то оно перемещается когда совпадают обе координаты, а когда по Лефт, то сразу. И вот я не пойму в чем дело... Может где ошибка, или я не так указал? Нужно ведь что бы if выполнялся когда совпадают ОБА условия. |
| Автор: Anikmar 11.10.2009, 20:27 |
| Может надо if ((u==i)&& (l==d)) |
| Автор: Lehon 11.10.2009, 22:50 | ||
| Спасибо! Начало работать. И у меня еще вопросы назрели ))) Вот я создаю новый шейп, такой же как и голова змеи, прямо рядом с ней. Все хорошо, но! С какой бы я стороны не зашел, голова змеи при сьедании яблока меняет свое направление на "вниз", и новый сегмент змеи образуется так же только с одной стороны. И конечно же главный вопрос - как сделать так что бы сегменты перемещались за головой, новый возникали за последними сегментами, и повторяли движение головы по очереди?
Билдер выдает на этот код много варнингов такого вида: [C++ Warning] Unit1.cpp(94): W8060 Possibly incorrect assignment Хотя, к счастью, ни одного еррора. |
| Автор: xvr 12.10.2009, 13:39 |
| Правильно выдает - у тебя опять куча присваиваний в if'ах, вместо сравнений |
| Автор: Lehon 12.10.2009, 14:58 |
| Хы, ну да ) Исправил, теперь голова продолжает движение в заданном направлении при сьедании яблока. Но новые сегменты змеи стелятся по верхнему и левому краю ) И опять же, неясно что делать что бы образовывалась змейка а не набор разбросаных шейпов ) |
| Автор: xvr 12.10.2009, 17:58 |
| Для 'змейки' у тебя неправильная логика всей программы. Тело змейки состоит из НАБОРА шейпов, которые надо хранить (например в std::deque). На каждом шаге перемещения создается новая голова змеи на основе координат старой головы (при этом надо вычислять И top И left координаты, а не одну из них). Новая голова добавляется в очередь (deque::push_front). Далее удаляется элемент из хвоста (deque::pop_back). Если змея съедает яблоко, то удаление хвоста блокируется на заданное количество 'тиков' таймера (змея при этом будет расти) Одна оптимизация - если на данном шаге элемент хвоста должен удаляться, то его можно использовать как новую голову, что бы не удалять/создавать TShape. |
| Автор: Lehon 13.10.2009, 16:04 |
| Буду думать... А как создать событие которое происходит через n милисекунд (Речь о вышеописанном "блокируется на заданное количество тиков таймера"). |
| Автор: xvr 13.10.2009, 16:23 | ||
'Тики таймера' имеются в виду вызовы TForm1::Timer1Timer() (по 1 вызову на 1 тик) |
| Автор: Lehon 13.10.2009, 16:55 |
| Не, это у меня уже есть, там описано почти все движения головы и яблока. Мне надо узнать как сделать грубо говоря shp->Top=Shape1->Top через 100 милисекунд; shp->Left=Shape1->Left через 100 милисекунд; С очередью и хранением не разберусь никак. Есть мысль просто хранить шейпы вне поля видимости, а потом вызывать. Но, много кода получается - описывать придется каждый шейп, и не дай бог юзер сможет сьесть 100 яблок, когда я максимум предусмотрел 98... |
| Автор: xvr 13.10.2009, 21:22 | ||||||
Настроить таймер на 100ms и в его OnTimer это и делать
|
| Автор: Anikmar 13.10.2009, 22:05 | ||
Вот вам и обычная змейка. Под консоль или под что еще - но можно было посмотреть в этих исходниках как организован таймер и движение удава. Кстати под ДОС это даже несколько хлопотнее. Под виндами мне кажется намного проще змейку писать. Эта тема переросла из движения кнопки в "Я пишу змейку". |
| Автор: Lehon 13.10.2009, 22:06 | ||||||
Именно так реализовано перемещение шейп1 (голова), но мне не нужно что бы хвост повторял движение головы в тот же миг что голова двигается, мне нужно что бы хвост повторил движение через 1 ход головы (через 100 мс, через 1 тик таймера, именно повторяя движение головы за прошлый "тик"-"ход") Именно потому и пишу - через 100 милисекунд после движения Шейп1. Добавлено через 3 минуты и 1 секунду
Смотрел, читал, сломал мозг ничего не поняв ))) Наверно потому что все было реализовано радикально не так как я это себе представляю ))) |
| Автор: Anikmar 13.10.2009, 22:43 | ||
Ну так в одном тике и двигайте сразу и голову и хвост. В чем проблема? |
| Автор: Usper 14.10.2009, 08:09 |
| А вы мой http://forum.vingrad.ru/index.php?showtopic=275781&view=findpost&p=1989462 на первой странице читали? Там исходники моей реализации змейки, НЕ под ДОС. Размер исходника довольно небольшой, разобраться, как мне кажестя, труда не составит. Там, правда, никаких очередей (я тогда про STL вообще понятия не имел |
| Автор: Anikmar 14.10.2009, 09:31 | ||
Я свою змейку написал в 1989 году на бейсике еще на БК0010 |
| Автор: Lehon 14.10.2009, 15:48 | ||||
Тык нет проблемы - если устраивает змеюга ходящая на хвосте как на ногах, и следовательно растущая вверх ))) Координаты то в таком случае будут одинаковые.
У вас нет файла проекта? Код то из юнит1.кпп я вижу, разобраться пытался, но так и не смог понять что такое DrawQvadrat, azimut, и пара других страшных слов ) ( пытался даже воссоздать форму - одни ерроры ))) Сейчас посмотрел еще раз - что то ясно, что то лес ) В частности я совсем не вижу места реализации создания нового сегмента змеи, и главное - его движения. С головой все ясно, а вот хвост ))) Неясно совсем как его двигать правильно... |
| Автор: Lehon 14.10.2009, 15:48 | ||||
Тык нет проблемы - если устраивает змеюга ходящая на хвосте как на ногах, и следовательно растущая вверх ))) Координаты то в таком случае будут одинаковые.
У вас нет файла проекта? Код то из юнит1.кпп я вижу, разобраться пытался, но так и не смог понять что такое DrawQvadrat, azimut, и пара других страшных слов ) ( пытался даже воссоздать форму - одни ерроры ))) Сейчас посмотрел еще раз - что то ясно, что то лес ) В частности я совсем не вижу места реализации создания нового сегмента змеи, и главное - его движения. С головой все ясно, а вот хвост ))) Неясно совсем как его двигать правильно... А насчет длины - эт разные змейки бывают ) В моем сотовом семилетней давности уровней не было, а макс длина у меня получалась 30 сегментов, но и экранчик был совсем маленький - в компе сотня проблемой не будет думаю ) Уровни это хорошо, и их я тоже хочу сделать, но потом, не все сразу ) От простого к сложному. Только вот простое какое то непростое ) |
| Автор: xvr 14.10.2009, 17:17 | ||||
Ну и фиг с ними |
| Автор: Usper 14.10.2009, 20:53 |
| Ой, и правда, вместе с грязной водой выплеснул и ребёнка (вместе с временными файлами из папки удалил и пару нужных) |
| Автор: Anikmar 14.10.2009, 21:55 | ||
А вот и нет. Надо в хвостовом шейпе поменять координаты - и он станет башкой |
| Автор: xvr 15.10.2009, 11:08 | ||||||
Уже предлагал
|
| Автор: Lehon 15.10.2009, 21:41 | ||
Он просит файлы RaizeComponentsVcl.bpi RaizeComponentsVclDb.bpi Пока не совсем понимаю мысль про поменять координаты хвоста и головы - точней как умная собака, понимаю а написать не могу. Что то вырисовывается, попробую но в результате сомневаюсь... |
| Автор: xvr 15.10.2009, 21:51 | ||||||
Смотри:
|
| Автор: Usper 16.10.2009, 07:51 |
| Lehon, это и есть вся папочка. Всё дело в сторонних компонентах, которые установлены у меня. Даже если они не используются, билдер зачем-то при создании нового проекта запихивает в файл проекта ссылку на эти компоненты. Я поправил файл проекта (*.bpr), удалив из него эти ссылки. Надеюсь теперь заработает. Также запихнул в архив исполняемый файл проекта, чтобы можно было посмотреть на результат. В очередной раз поправил http://forum.vingrad.ru/index.php?showtopic=275781&view=findpost&p=1989462. |