змейка в блокноте код
DosTips.com
A Forum all about DOS Batch
Moderator: DosItHelp
#1 Post by dbenham » 13 Jul 2013 13:43
For a while now I’ve been messing around with the concept of creating an arcade style game using only pure native batch. I ran across an interesting implementation of the classic SNAKE game (BATCHSNAKE.BAT) at http://www.youtube.com/watch?v=RblizDDxaBA
EDIT: I updated the link to point to the original author’s YouTube post. The prior link was by an impostor claiming credit
BATCHSNAKE.BAT uses an interesting technique to emulate the ability to detect a key press without pausing the game. The main game runs in one console window, and it launches a controller batch process in a new window that uses CHOICE to read keys. The controller process writes the key presses to a file, and the main game has stdin redirected to the file, so it can read the keys using SET /P. The nice feature is that SET /P reads the next key if available, but immediately moves on with no input if currently at the end of the file. What I don’t like is the reliance on two windows, it is confusing. Also, the implementation seems to sometimes drop key presses. BATCHSCRIPT.BAT also uses multiple batch scripts.
BATCHSNAKE.BAT works fairly well, and has a lot of nice features. But the screen has a lot of flicker, and the maximum speed is severely limited by the number of CALL statements, as well as to a lesser extent by the complexity of some logic and dependence of randomly finding a free space to locate the next piece of food. Performance on XP running via Win 7 Virtual PC is abysmal, and the controller process is somehow broken on the virtual PC (it launches but then closes).
I decided to create my own version of SNAKE using pure batch, concentrating on performance and controller reliability and ease of use. I chose not to implement features like high score, user defined maps, rocks, etc. Those features could easily be added.
Controller improvements
I put all code within one batch script (SNAKE.BAT). I launch the controller process using START /B so the controller runs in the same console window. The controller has various modes to allow the game to detect individual key presses, as well as to prompt and wait for input. The game communicates with the controller by writing commands to a command file that the controller then reads. Getting the correct behavior within a shared console window requires carefully constructed output redirection for the controller, as well as input redirection for the game.
The controller requires the CHOICE command. Unfortunately, the CHOICE command is not standard for XP. But XP users can still use the game if they download a port of the CHOICE command. SNAKE.BAT detects if the CHOICE command is available, and displays URLs where it may be downloaded if it is not available. The calling syntax for CHOICE varies depending on the version of CHOICE. SNAKE.BAT detects which version is available and sets up a simple «macro» to account for the version.
Speed improvements
This is a BIG topic. There are a number of important basic design principles.
1) Minimize use of GOTO
The main game loop is an infinite FOR /L loop. The infinite loop is exited via the EXIT command. The main game is launched from SNAKE.BAT via a new CMD.EXE so that necessary cleanup actions can take place after the loop exits. Use of GOTO for the main loop would slow down the program.
2) Minimize use of CALL
CALLed Batch «functions» with arguments are convenient, but the CALL mechanism is comparatively very slow. SNAKE.BAT dramatically improves speed via extensive use of batch «macros» with arguments. See Batch «macros» with arguments for more info on how to use macros. The link gives a good background on the macro concept. It provides a link to a more recent thread with major macro enhancements by jeb that more closely resemble the macros used in SNAKE.BAT, as well as a link to the initial thread where Ed Dyreen introduced the macro with arguments concept.
3) Encapsulate logic in data structures.
4) Efficiently «plot» characters as «pixels»
The screen is composed of a set of environment variables holding fixed length strings that are ECHOed, one string per graphic line. Each character in a string represents a graphic «pixel». The variable name specifies the Y coordinate, and the position within the string the X coordinate. All «graphic» lines are created pixel by pixel just once upon initialization. From then on, a Plot macro uses simple SET substring operations to set the value of individual «pixels» as needed. There is no need to recompose the entire screen.
5) Snake definition
The snake is represented as variables containing a string of coordinates, one variable for X, and another for Y. The beginning of the string is the head, and the end is the tail. As the snake «moves» forward, simple SET substring operations are used to place a new coordinate at the front, and remove a coordinate from the rear.
6) Random food placement
A list of empty coordinates is maintained in a string variable so that food can be randomly placed without fear of colliding with an already occupied pixel. A random number between 0 and the count of available pixels is generated, and a SET substring operation is used to extract the available position. Then a SET search and replace is used to remove the newly occupied coordinates from the empty list. When the snake tail moves, the newly vacated pixel coordinates are appended to the end of the empty list.
7) Collision detection
Classic pixel probing is used to detect collisions. When the snake head is moving, a Test macro probes the value of the new position using a SET substring operation. The macro compares the current value against a list of allowable values. Disallowed values represent a collision.
A fixed delay between each main loop iteration can result in jerky movement because the amount of work required by an iteration varies depending on context. More work equates to more time. Instead of introducing a fixed delay between each iteration, I note the time the previous movement ended, and then continuously check how much time has elapsed since the last movement. I only initiate movement when the delay time is exceeded. As long as the time spent on any one iteration is always less then the delay time, then the motion will always be smooth.
The game even works well when I run it on an XP virtual machine within Windows 7. There is much more flicker, but it still remains fairly smooth.
Possible Enhancements
Obviously things like high score lists, user defined maps, rocks, etc. that are available in the original BATCHSNAKE.BAT could be imlemented.
The following ideas interest me more. At one point I was considering implementing the following ideas, but I ran out of steam.
1) Increased play field size
The empy pixel list is maintained in a variable with a max string length of 8191 bytes. That restricts the total area of the play field. The snake definition variables also restrict the size, but they support a larger area then the empty list. Maximum playfield size could be increased by splitting the empty list and snake definition over multiple variables. But that complicates the management of those lists.
2) Introduce enemy snakes
If the food is not eaten within a time limit, then it can spawn into an enemy snake. The enemy snake(s) can eat food or chase you. Shorter snakes move faster than longer snakes. A small snake can nibble at the tail of a large snake. A large snake can swallow a small snake whole if eaten head first. Running into the side of a snake results in a collision (death). This sounds complicated, but the logic need not be all that complex. And I believe there is plenty of performance bandwidth left to handle the added complexity without hurting the animation quality.
So, here at last is the code for SNAKE.BAT
Embedded in a comment at the top are instructions for how to disable the awfull beep that occurs when an invalid key is pressed.
EDIT: Added /C: option to the test for CHOICE to account for some internationalization issues
EDIT2: Added comma to DELIMS option when parsing time to support European decimal point
EDIT3: Changed 2nd CHOICE test to wait 1 second to support downloaded 16 bit version and fixed disappearing food
bug
EDIT4: One more CHOICE test change to account for fact that 16 bit version returns 0 if invalid arguments
Простейшая змейка на Python менее, чем в 100 строчек кода
На самом деле строчек кода с логикой игры будет гораздо меньше, добрую половину скрипта занимает подготовка игрового поля, рисование новорождённой змеи, назначение клавиш управления и ещё парочка мелочей. Публикация может быть полезна для таких же начинающих, как и я сам. И да, в коде могут быть ошибки, которые я в настоящий момент не вижу в силу своего небольшого опыта программирования, заканчивающегося на прочтении Марка Лутца и пока ещё недописанном телеграм боте, но змейка работает исправно и делает всё, что было задумано. Писать буду с использованием модуля turtle. Погнали.
Импортируем необходимые модули и задаём глобальную переменную. Модуль time понадобится для установки паузы в основном бесконечном цикле программы, turtle будет отвечать за графику в игре, из модуля random возьмём один метод randrange для генерации координат еды для нашей змеи. С помощью переменной BREAK_FLAG будем останавливать игру при укусе змейки самой себя, подробнее об этом позже.
Следующим шагом создаём окно игры, назначаем название, задаём цвет фона и размеры окна. Строка screen.tracer(0) отключает анимацию, рисовать кадры будем сами в основном цикле программы. Если этого не сделать вновь созданный сегмент змейки и новый элемент еды, после поедания добычи, будет появляться в центре поля и только потом перемещаться в заданные координаты и весь этот процесс мы будем видеть. Это особенность библиотеки turtle, каждый новый объект всегда появляется в центре координат.
Для наглядности нарисуем границы игрового поля. Создаём объект черепашки border = turtle.Turtle(), делаем его невидимым border.hideturtle(), так как от него нам понадобится только линия, которую он чертит при перемещении. И опуская и поднимая перо border.penup(), border.pendown() перемещаем нашу черепашку по строго заданным координатам. На выходе получаем чёрный квадрат, границы которого нельзя будет пересекать нашей змее.
Создадим змейку. Наша вновь рождённая змея будет состоять из трёх сегментов каждый из которых будет являться новым экземпляром класса Turtle. Другими словами змея будет состоять из множества черепашек. Надеюсь контекст слова «черепашка» в этой публикации понятен всем без объяснений. Хранить змейку целиком будем в виде списка в переменной snake. Создаём змею в цикле for, который прогоняем три раза. Создаём новый сегмент snake_segment = turtle.Turtle(), задаём форму snake_segment.shape(‘square’) и поднимаем перо snake_segment.penup() так, как нам не надо, чтобы змейка оставляла после себя след. Условие if необходимо для окраски сегментов в серый цвет. Красятся все кроме первого, голова остаётся чёрной. В конце каждой итерации добавляем сегмент в список хранящий всю змею целиком snake.append(snake_segment).
В этом блоке кода создаём объект еды, задаём ему круглую форму, генерируем координаты и перемещаем еду на определённое для неё место.
Управлять змейкой будем кнопками навигации со стрелками. За привязку клавиш отвечает метод screen.onkeypress(). Методу необходимо передать в качестве аргументов функцию и имя кнопки, которая будет вызывать функцию. Метод setheading() задаёт направление движения объекта черепашки. Использовать его будем в таком виде snake[0].setheading(90), то есть голову змейки повернуть на 90 градусов относительно направления по умолчанию. Для нас это значит вверх. Оборачиваем метод в лямбда выражение, это отложит его вызов до момента нажатия на клавишу. Имя кнопки передаём в виде строки ‘Up’ повторяем процедуру для остальных направлений. Начинаем слушать события с клавиатуры screen.listen()
Ну и наконец самое интересное. Логика игры будет обрабатываться в бесконечном цикле. Для наглядности положу его полностью здесь под
А теперь по порядку. Если расстояние от головы змеи до еды меньше 10 if snake[0].distance(food)
Змейка в блокноте код
HTML5 Canvas позволяет создавать 2D приложения любой сложности. Удобство этой технологии заключается в её кроссплатформенности, ибо любое устройство, где есть современный браузер, может запустить подобное приложение.
В этой статье я покажу как создать игру-змейку, на примере своей реализации этой игры (демо, GitHub).
Подготовка
Для начала создадим файловую структуру проекта, в моём случае она выглядит таким образом:
Информация о файлах:
index.html
Здесь всё просто, обычный HTML код с подключением всех JavaScript файлов.
client/app.js — приложение
Файл приложения — это файл, в котором инициализируется приложение и запускается бесконечный таймер.
Инициализация
Код инициализации приложения выглядит следующим образом:
Здесь мы инициализируем объект Game и создаём функцию init(), в которой запускается метод game.init() и запускается бесконечный таймер.
Бесконечный таймер
Функция main() — это функция которая будет вызываться постоянно, выглядит она следующим образом:
Здесь мы вызываем методы игры — метод обновления, а потом метод для рендеринга.
Обработка клавиш
Добавляем обработчик события keydown, который будет вызывать метод game.handleInput(e);
Запуск
Здесь всё просто — в самом конце мы вызываем функцию init(), что повлечёт за собой запуск всего приложения.
Полный код client/app.js выглядит так:
client/input.js — определение нажатой клавиши
Эта маленькая библиотека была создана для удобного определения нажатых клавиш.
Функция isKey(key) проверяет наличие key в объекте keys, чтобы заменить слово на код клавиши и если его там нет, то считается, что была введена какая-то буква. Потом полученный код сравнивается с введённым.
Для удобства здесь создаётся метод объекта window — input, который позволяет использовать библиотеку следующим образом: input.isKey(‘SPACE’).
client/game.js — тело игры
В этом файле объединяются все части игры, создаётся Canvas, обновляются и перерисовываются данные.
Объект Game создаётся следующим образом:
В блоке // default settings определяются параметры игры по умолчанию, создаются константы, которые будут использовать остальные файлы.
Далее мы создаём объект Canvas стандартными методами Javascript и располагаем его по центру страницы. Настраиваем его ширину и высоту, задаём стиль рамке.
Потом, на основе параметров высоты, ширины и размера ячейки мы высчитываем количество ячеек на поле в ширину и высоту.
И в самом конце мы подключаем объекты Snake и Apple, чтобы использовать их в методах объекта Game.
Сброс игры
Функция сброса игры нужна для её первоначальной инициализации и сброса игры, если игрок пожелает сыграть заново.
Функция reset выглядит таким образом:
Здесь мы заново инициализируем объекты Snake и Apple для сброса их значений в Game и обнуляем переменную this.score.
Инициализация игры
Приложение должно запускать функцию инициализации, поэтому объявим её:
Как сделать игру змейку (snake) в простом блокноте
Показать панель управления
Комментарии • 38
почему меня перекидывает по этой ссылке на сайт гос услуг.
@DEAF Game скинь мне
Сайт был продлен если хочешь код пиши мне в ВК vk.com/id647607085
А на каком языке она написана?
народ вот код
@echo off
setlocal enabledelayedexpansion
if «%
nx0″ control
echo.Press any key in control window
if exist sn.cntrl erase sn.cntrl
:wait
if not exist sn.cntrl goto wait
call :clear
call :cepos
set «snake[0]X=1»
set «snake[0]Y=1»
set «snake.length=0»
set «dir=D»
:game
::cscript //nologo //e:jscript «%
nx0″ 20
for /L %%A IN (1 1 %pause%) DO (set «a=»)
cls
call :clear
call :move
if «%errorlevel%»==»1» exit /b
call :draw
goto game
:move
set /p dir=sn.cntrl
if «%dir%»==»Q» (erase sn.cntrl & exit /b 1)
set «tmpX=%snake[0]X%»&set «tmpY=%snake[0]Y%»
if «%dir%»==»D» set /a snake[0]X+=1
if «%dir%»==»W» set /a snake[0]Y-=1
if «%dir%»==»S» set /a snake[0]Y+=1
if «%dir%»==»A» set /a snake[0]X-=1
if defined err[%snake[0]X%][%snake[0]Y%] goto gameover
for /L %%A IN (1 1 %snake.length%) DO (
set «tmp2X=!snake[%%A]X!»&set «tmp2Y=!snake[%%A]Y!»
set «err[!tmp2X!][!tmp2Y!]=»
set «snake[%%A]X=!tmpX!»&set «snake[%%A]Y=!tmpY!»
set «err[!tmpX!][!tmpY!]=1»
set «tmpX=!tmp2X!»&set «tmpY=!tmp2Y!»
)
if «%snake[0]X%»==»%eatX%» (
if «%snake[0]Y%»==»%eatY%» (
call :cepos
set /a snake.length+=1
)
)
if %snake[0]X% LEQ 0 goto gameover
if %snake[0]X% GEQ 14 goto gameover
if %snake[0]Y% LEQ 0 goto gameover
if %snake[0]Y% GEQ 14 goto gameover
exit /b 0
:control
@echo on
mode con cols=50 lines=5
:control[0]
choice /C «wasdq» /N >nul
:control[1]
if «%errorlevel%»==»1» echo.W>sn.cntrl 2>nul|| goto control[1]
if «%errorlevel%»==»2» echo.A>sn.cntrl 2>nul|| goto control[1]
if «%errorlevel%»==»3» echo.S>sn.cntrl 2>nul|| goto control[1]
if «%errorlevel%»==»4» echo.D>sn.cntrl 2>nul|| goto control[1]
if «%errorlevel%»==»5» echo.Q>sn.cntrl 2>nul|| goto control[1]
goto control[0]
:gameover
echo.GAME OVER | msg *
erase sn.cntrl
exit
:cepos
set /a eatX=(%RANDOM% %% 13) + 1
set /a eatY=(%RANDOM% %% 13) + 1
if defined err[%eatX%][%eatY%] goto cepos
exit /b
Пишем игру змейка с помощью JavaScript + Canvas
Подготовка
Пожалуй, стоит вообще начать с подготовки к созданию игры и написанию кода. Мы будем использовать простой редактор Sublime Text. Впрочем, это не важно. Все делаем в одном документе, чтобы было быстрее.
Первым делом, напишем сам код для встраивания canvas в документ. Напомню, что canvas поддерживается только в HTML5.
Подготовка завершена, теперь мы можем приступать к созданию самой игры.
Начинаем
Для начала, я хотел бы вам вообще объяснить как будет работать змейка, так будет гораздо понятнее. Наша змейка — это массив. Массив элементов, элементы — это ее части, на которые она делиться. Это всего лишь квадратики, которые имеют координаты X и Y. Как вы знаете, X — горизонталь, Y — вертикаль. В обычном виде мы представляем себе координатную плоскость вот так:
Она абсолютно правильная, в этом нет сомнения, но на мониторе компьютера (в частности, canvas) она выглядит по-другому, вот так:
Это нужно знать, если вы вдруг в первый раз столкнулись с canvas. Я, когда столкнулся с этим, сначала вообще не понял где точка (0,0), благо я быстро разобрался. Надеюсь и у вас проблем не возникло.
Вернемся к элементам змейки, ее частям. Представим, что каждый элемент имеет свои координаты, но одинаковую высоту и одинаковую ширину. Это квадратики, не более. А теперь представим, что мы вот нарисовали змейку, все квадратики, они идут друг за другом, одинаковые такие. И тут мы решили, что нам нужно подвинуть змейку вправо. Как бы вы поступили?
Некоторые люди ответили бы, что нам нужно первый элемент подвинуть вправо, затем второй, затем третий и так далее. Но для меня этот вариант не является правильным, так как в случае, если вдруг змейка огромная, а компьютер слабый, мы можем заметить, что змейка иногда разрывается, что вообще не должно быть. Да и вообще, данный способ требует слишком много команд, когда можно обойтись гораздо меньшим количеством, не потеряв качество. А теперь мой способ: Мы берем последний элемент змейки, и ставим его в начало, изменяя его координаты так, чтобы он был после головы. Теперь этот элемент — голова. Всего-то! И да, эффект движения будет присутствовать, а на компьютере вообще не будет заметно, как мы спрятали хвост, а потом его поставили в начало. именно так мы и будем поступать во время создания движения змейки.
Вот тут точно начинаем
Сначала нам нужно объявить некоторые переменные, которые мы в дальнейшем будем использовать.
И так, вообще, нужно чуть-чуть пояснить зачем нам нужно в функции возвращения случайного числа, умножать и делить на переменную s, которая хранит в себе ни что иное, как ширину, по совместительству и высоту элементов змейки. На самом деле, это нужно, чтобы не было смещений во время движения, так как у нас ширина элемента — 30, то если мы хотим двигать ее без разрывов, то все координаты должны делиться на 30 без остатка. Именно поэтому я делю на число, округляю, а потом умножаю. Таким образом, число возвращается таким, что его можно разделить без остатка на 30.
Вы могли бы возразить, сказав, что ты мог бы просто холсту сделать ширину и высоту, кратную 30. Но на самом деле, это не лучший вариант. Так как я лично привык использовать всю ширину экрана. И в случае, если ширина = 320, то мне пришлось бы аж целых 20 пикселей забирать у пользователя, что могло бы доставить дискомфорт. Именно поэтому в нашей змейки все координаты объектов делятся на 30, чтобы не было никаких неожиданных моментов. Было бы даже правильнее вынести это как отдельную функцию, так как она достаточно часто используется в коде. Но к этому выводу я пришел поздно. (Но возможно это даже не нужно).
Теперь сделаем так, чтобы картинка имела четкое качество отображения. По ходу статьи, я буду дописывать код, в некоторых местах возвращаться к началу, так что при себе имейте полную картину кода.
Если что, то переменные innerWidth и innerHeight хранятся в глобальном пространстве имен.
Поэтому к ним можно обратиться именно так. Правда, я не знаю правильно ли так делать.
Ну что же, теперь начинаем писать код змейки.
Чтобы было движение, нам нужна анимация, мы будем использовать функцию setInterval, вторым параметром которой будет число 60. Можно чуть больше, 75 на пример, но мне нравится 60. Функция всего на всего каждые 60 мс. рисует змейку «заново». Дальнейшее написание кода — это только этот интервал.
Покажу вообще простую отрисовку нашей змейки, пока что без движения.
Чтобы проверить, что наша змейка не сталкивается сама с собой, нам нужно сделать некоторую проверку для каждого элемента, кроме последнего. Мы будем проверять, не равны ли координаты последнего элемента (головы) змейки любым из… То есть проще говоря: не произошло ли столкновение. Эта строчка кода была единой строкой, но вам сделал ее понятной. Напоминаю, что все это добавляется в функцию интервала.
А теперь, вы наверное заметили, что во время того, как мы изменяем координаты, мы вечно что-то «сохраняем», сначала поделив, а потом округлив и умножив на число s. Это все тот же самый способ выравнивания змейки относительно яблока. Движение в данном случае строгое, простое, поэтому и есть змейка яблоко может строго по определенным правилам, которые задан в самом начале интервала. И если бы координаты головы змейки хоть на 1px сместились бы, то яблоко нельзя было бы съесть. И да, это простой вариант, поэтому все так сильно ограничено.
Ну а нам же осталось что сделать? Правильно, удалить из массива хвост (первый элемент), добавить новый элемент в самый конец и отрисовать всю змейку. Сделаем это, добавив в конец интервала вот такие строчки кода.
В добавок к отрисовке змейки, я добавил код, который делает ощущение, что конец экрана — это его начало. И если змейка выходит за границы, то она потом выходит из начала, на погибая.
Вы можете заменить обнуление координат, на пример, на сбрасывание игры, если у вас все очень жестко. Но мне нравится больше так. Ну а теперь, осталось только по нажатию кнопок изменять направление змейки. Делает за считанные секунды. Нужно лишь написать этот код сразу после setInterval. Примерно так:
Тут мы сделали так, что если змейка двигается вправо, то она не может изменить направление налево. Это логично, на самом деле.
Вот и все, друзья. Моя первая статья, написанная новичком для новичков. Надеюсь, все было понятно и кому-то это пригодилось. Змейку можно усовершенствовать, добавив на пример, счетчик очков, рекорды, дополнительные фишки, но это все уже дополнения, которые вы можете сделать сами. На этом все, всем удачи!