{"id":48083458,"url":"https://github.com/L4zzur/minecraft-on-ursina","last_synced_at":"2026-04-20T00:01:50.578Z","repository":{"id":188528382,"uuid":"678867358","full_name":"L4zzur/minecraft-on-ursina","owner":"L4zzur","description":"Прототип Minecraft на языке Python и движке Ursina","archived":false,"fork":false,"pushed_at":"2023-10-27T16:20:01.000Z","size":17482,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-07T16:19:55.841Z","etag":null,"topics":["minecraft","python","tutorial","ursina-engine"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/L4zzur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-08-15T15:10:06.000Z","updated_at":"2026-01-31T14:08:36.000Z","dependencies_parsed_at":"2023-08-15T19:23:27.280Z","dependency_job_id":null,"html_url":"https://github.com/L4zzur/minecraft-on-ursina","commit_stats":null,"previous_names":["l4zzur/minecraft-on-ursina"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/L4zzur/minecraft-on-ursina","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/L4zzur%2Fminecraft-on-ursina","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/L4zzur%2Fminecraft-on-ursina/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/L4zzur%2Fminecraft-on-ursina/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/L4zzur%2Fminecraft-on-ursina/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/L4zzur","download_url":"https://codeload.github.com/L4zzur/minecraft-on-ursina/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/L4zzur%2Fminecraft-on-ursina/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32027234,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["minecraft","python","tutorial","ursina-engine"],"created_at":"2026-04-04T15:00:21.516Z","updated_at":"2026-04-20T00:01:50.569Z","avatar_url":"https://github.com/L4zzur.png","language":"Python","funding_links":[],"categories":["Проекты"],"sub_categories":["Aiogram"],"readme":"# 0. Ресурсы, используемые модули\n[Minecraft — Википедия (wikipedia.org)](https://ru.wikipedia.org/wiki/Minecraft)\n\n[Minecraft: история создания, описание - CQ](https://cq.ru/articles/gaming/istoriia-sozdaniia-minecraft)\n\n[История Minecraft и её создателя. Кто и когда сделал легендарную игру — Игромания (igromania.ru)](https://www.igromania.ru/article/31609/Istoriya_Minecraft_i_eyo_sozdatelya._Kto_i_kogda_sdelal_legendarnuyu_igru.html)\n\n[Как Minecraft устроена за кадром — Minecraft на DTF](https://dtf.ru/s/minecraft/202337-kak-minecraft-ustroena-za-kadrom)\n\n\n[ursina engine](https://www.ursinaengine.org/index.html)\n\n[ursina engine samples](https://www.ursinaengine.org/samples.html)\n\n```\nursina\nperlin_noise\nmatplotlib\nnumpy\n```\n# 1. Почему именно Python?\n**Программирование** - это процесс создания инструкций для компьютера, чтобы он мог выполнять различные задачи. Компьютер - это устройство, которое умеет работать только с числами и буквами, поэтому нам нужен специальный язык, чтобы общаться с ним. Такой язык называется языком программирования.\n\nСуществует много разных языков программирования, каждый из которых имеет свои особенности и применение. Например, есть языки, которые используются для создания веб-сайтов, мобильных приложений, игр, анимации и т.д. Один из самых популярных и универсальных языков программирования - это **Python**.\n\n**Python** - это язык программирования высокого уровня, то есть он близок к естественному человеческому языку и легко читается. Python также имеет много готовых библиотек и модулей, которые расширяют его возможности и позволяют решать разнообразные задачи. Например, с помощью Python можно создавать игры, анализировать данные, обрабатывать изображения и звук, работать с искусственным интеллектом и машинным обучением и многое другое.\n\n- Множество  обучающего материала  и большое сообщество  \n- Легкость и понятность кода  \n- Большое количество библиотек для разных задач  \n- Кроссплатформенность\n\nВот пример кода на Python:\n\n```python\n# Это комментарий. Он не влияет на работу программы, но помогает понять ее лучше.\n# Комментарии начинаются с символа #\n\n# Импортируем модуль random, который позволяет генерировать случайные числа\nimport random\n\n# Создаем переменную number и присваиваем ей случайное число от 1 до 10\nnumber = random.randint(1, 10)\n\n# Выводим сообщение на экран\nprint(\"Я загадал число от 1 до 10. Попробуй угадать!\")\n\n# Создаем бесконечный цикл\nwhile True:\n    # Запрашиваем у пользователя ввод числа\n    guess = input(\"Введи свой вариант: \")\n    # Преобразуем введенное значение в целое число\n    guess = int(guess)\n    # Сравниваем введенное число с загаданным\n    if guess == number:\n        # Если числа равны, то выводим сообщение об успехе и выходим из цикла\n        print(\"Ура, ты угадал!\")\n        break\n    # Иначе, если введенное число меньше загаданного, то выводим подсказку\n    elif guess \u003c number:\n        print(\"Нет, мое число больше.\")\n    # Иначе, если введенное число больше загаданного, то выводим подсказку\n\telse:\n        print(\"Нет, мое число меньше.\")\n```\nКак ты думаешь, что делает эта программа? Попробуй запустить ее и поиграть в нее. Это простая игра, в которой ты должен угадать число, которое загадал компьютер. Компьютер дает тебе подсказки, если ты не угадал с первого раза. Эта игра демонстрирует некоторые основные элементы программирования на Python, такие как переменные, функции, циклы, условия и операторы.\n\n# 2. Почему именно Minecraft?\nMinecraft - это компьютерная игра в жанре песочницы, созданная шведским программистом Маркусом Перссоном и выпущенная его студией Mojang. Игроки могут свободно строить и разрушать блоки, создавать различные предметы и взаимодействовать с другими игроками в многопользовательском режиме.\n![](images/minecraft.jpg)\n- Minecraft был создан шведским программистом Маркусом Перссоном, известным под псевдонимом Notch.![](images/markus.jpg)\n- Перссон начал работу над игрой в мае 2009 года, вдохновившись такими играми, как Dwarf Fortress, Dungeon Keeper и Infiniminer.\n- Первая версия игры, называемая Classic, была опубликована на официальном сайте в июне 2009 года. Она была бесплатной и позволяла игрокам строить из разных блоков в режиме креатива.\n\n**Cave Game**\n![](images/mine1.jpg)\n![](images/mine2.jpg)\n# 3. Игровые движки и знакомство с Ursina\nИгровой движок - это набор программного обеспечения, необходимый для работы компьютерных игр и не привязанный жестко к какой-либо из них. Игровой движок облегчает создание игр, предоставляя разработчикам готовые решения для таких задач, как отрисовка графики, обработка физики, управление звуком, вводом и сетью. Игровой движок также позволяет переносить игры на разные платформы, такие как ПК, консоли, мобильные устройства и т.д.\n\nСуществует много разных игровых движков, каждый из которых имеет свои особенности и применение. Например, есть игровые движки, которые специализируются на создании 2D-игр, 3D-игр, VR-игр и т.д. Один из самых популярных и универсальных игровых движков - это Unity. Unity поддерживает множество платформ и жанров, имеет удобный редактор сцен и ассетов, а также мощный язык программирования C#.\n\nМы будем использовать другой игровой движок, который называется Ursina. Ursina Engine — это полноценный движок под Windows, Linux и Mac, написанный на Panda3D, Pillow. Его можно использовать для создания 2D- и 3D-игр. В комплекте библиотеки — готовые шейдеры, геометрические примитивы и анимации. Ursina имеет следующие преимущества:\n- Ursina работает на Python.\n- Ursina имеет современный дизайн и интерфейс. Ursina также имеет встроенные элементы управления для камеры, мыши и клавиатуры.\n- Ursina бесплатна и открыта для изменений. Ursina распространяется под лицензией MIT, которая позволяет использовать Ursina для любых целей.\n\nДля того, чтобы начать работать с Ursina, нам нужно установить несколько программ на наш компьютер.\n```python\n# Импортируем модуль ursina, который содержит все необходимые классы и функции для работы с игровым движком\nfrom ursina import *\n\n# Создаем объект app, который представляет собой приложение Ursina\napp = Ursina()\n\n# Создаем объект cube, который представляет собой сущность (Entity) - основной класс для создания игровых объектов\n# Указываем параметры сущности, такие как модель (model), текстура (texture), цвет (color), размер (scale)\ncube = Entity(\n\tmodel=\"cube\",\n\ttexture=\"white_cube\",\n\tcolor=color.red,\n\tscale=2,\n)\n\n# Создаем функцию spin, которая будет вызываться при клике на куб\ndef spin():\n\t# Анимируем поворот куба по оси Y на 360 градусов за 2 секунды с помощью метода animate\n\tcube.animate(\n\t\t\"rotation_y\",\n\t\tcube.rotation_y + 360,\n\t\tduration=2,\n\t\tcurve=curve.in_out_expo,\n\t)\n\n# Привязываем функцию spin к событию on_click куба с помощью оператора присваивания\ncube.on_click = spin\n\n# Создаем объект camera, который представляет собой камеру редактора (EditorCamera) - специальный класс для управления камерой в режиме разработки\ncamera = EditorCamera()\n\n# Запускаем приложение Ursina с помощью метода run объекта app\napp.run()\n```\n\u003eРезультат:\n\u003e![](images/0.png)\n\u003e*Чтобы управлять камерой зажми правую кнопку мыши и тяни мышь в разные стороны!*\n\n\nЭто простая демонстрация возможностей Ursina. Ты увидишь красный куб в центре экрана. Ты можешь управлять камерой с помощью мыши и клавиатуры. Ты можешь кликнуть на куб левой кнопкой мыши и он начнет вращаться. Эта программа демонстрирует некоторые основные элементы работы с Ursina, такие как создание сущностей, анимация, ввод и коллизия.\n\n# 4. Начало разработки своего Minecraft\nНиже представлен шаблон кода для любого проекта на Ursina\n```python\n# Необходимые импорты\nfrom ursina import *\n\n# Инициализация окна игры\napp = Ursina() \n\n# здесь будет описана игровая логика\n\n# Запускаем проект\napp.run()\n```\n\n\u003eРезультат:\n\u003e![](images/1.png)\n\nДавай прежде чем переходить к работе с игровыми объектами сделаем так, чтобы исчезла кнопка закрытия окна, но при этом мы могли закрывать игру при помощи клавиши Q или ESC. Добавим в код функцию `input`, которая позволяет считывать вводимые в игре клавиши и реагировать на них как нам нужно.\nКод примет следующий вид:\n```python\n# Необходимые импорты\nfrom ursina import *\n\n# Инициализация окна игры\napp = Ursina()\n\n# Убираем кнопку закрытия окна\nwindow.exit_button.visible = False\n\n# Определяем функцию input с одним параметром key\ndef input(key):\n    # Проверяем, равна ли переменная key строке \"q\" или \"escape\"\n    if key == \"q\" or key == \"escape\":\n        # Если да, то вызываем функцию quit, которая завершает работу приложения Ursina\n        quit()\n\n# Запускаем проект\napp.run()\n```\n\n## 4.1. Entity\nОбъект **Entity** - это основа для всех сущностей в игре. С его помощью можно создавать разные элементы игрового мира, например, фигуры (кубы, сферы, пирамиды и т.д.) или модели (персонажи, предметы и т.д.). Для наполнения карты воспользуемся им.\nДальше будем приводить только новые фрагменты кода, но с пояснением, куда его необходимо вставлять.\n```python\n# Прошлый код\n...\n\n# Создаем двойной цикл for, который повторяется 16 раз по переменным x и z\nfor x in range(16): \n\tfor z in range(16):\n\t    # Создаем сущность в виде куба с белой текстурой и задаем ей позицию в пространстве по координатам x, 0 и z\n\t    Entity(model=\"cube\", texture=\"white_cube\", position=Vec3(x,0,z))\n\n# Запускаем проект\napp.run()\n```\n\u003eРезультат:\n\u003e![](images/2.png)\n\n## 4.2. FirstPersonController\nПрограмма покажет на экране плоское изображение. Для просмотра блочной сцены в 3D нужен наблюдатель. Его можно создать с помощью готового объекта FirstPersonController.\n\nПолный код представлен ниже:\n```python\n# Необходимые импорты\nfrom ursina import *\n# импортируем объект игрока\nfrom ursina.prefabs.first_person_controller import FirstPersonController\n\n# Инициализация окна игры\napp = Ursina()\n\n# Убираем кнопку закрытия окна\nwindow.exit_button.visible = False\n\n# Определяем функцию input с одним параметром key\ndef input(key):\n    # Проверяем, равна ли переменная key строке \"q\" или \"escape\"\n    if key == \"q\" or key == \"escape\":\n        # Если да, то вызываем функцию quit, которая завершает работу приложения Ursina\n        quit()\n\n# Создаем двойной цикл for, который повторяется 16 раз по переменным x и z\nfor x in range(16): \n\tfor z in range(16):\n\t    # Создаем сущность в виде куба с белой текстурой и задаем ей позицию в пространстве по координатам x, 0 и z\n\t    Entity(model=\"cube\", texture=\"white_cube\", position=Vec3(x,0,z))\n\n# Создаем объект player, который представляет собой контроллер от первого лица (FirstPersonController) - специальный класс для управления персонажем в 3D-играх\nplayer = FirstPersonController()\n\n# Устанавливаем свойство gravity объекта player равным 0.0, что означает, что персонаж не подвержен гравитации и не падает вниз\nplayer.gravity = 0.0\n\n# Запускаем проект\napp.run()\n```\n\n\u003e[!info] Важно!\n\u003eИгроком по умолчанию можно управлять с помощью мышки и кнопок W, A, S, D. Но есть особенность: если переключиться на русскую раскладку, то при нажатии кнопки возникнет ошибка. Не забудь переключить раскладку!\n\n\u003eРезультат:\n\u003e![](images/3.png)\n\nПрограмма покажет тебе базовую сцену из блоков. Она еще не очень интересная, но ты уже можешь по ней ходить!\n\n## 4.3. Текстурирование\nUrsina Engine дает возможность использовать свои текстуры и модели, а не только стандартные.\n\n### 4.3.1. Текстурирование блоков\nДля начала стоит создать и раскрасить блоки. Нужно сначала сделать модель в Blender, потом подготовить текстуру и затем импортировать объект в программу. \nМы же возьмем уже готовые объект и текстуру.\n\nМодель блока находится в папке `models` под названием `block.obj`, а текстура травы для него - в папке `textures` под названием `grass.png`. Если хочешь, можешь взять и другую текстуру из находящихся в этой папке, кроме `arm.png`.\n\nДля начала создадим переменную с нашей загруженной текстурой, а затем будет использовать её и нашу модель `block` при создании объектов `Entity` в циклах.\n\n```python\n# Прошлый код\n...\n\n# загружаем текстуру\ngrass_texture = load_texture('assets/grass.png')\n\n# Создаем двойной цикл for, который повторяется 16 раз по переменным x и z\nfor x in range(16): \n\tfor z in range(16):\n\t    # Создаем сущность в виде БЛОКА с НАШЕЙ текстурой и задаем ей позицию в пространстве по координатам x, 0 и z\n\t    Entity(model='models/block', scale=0.5, texture=grass_texture, position=(x, 0, z))\n\n...\n# Прошлый код\n```\n\n\u003eРезультат:\n\u003e!![](images/4.png)\n\n### 4.3.2. Текстурирование персонажа\nТак же можно сделать и руку персонажа. Сперва — подготовить текстуру для модели в Blender, потом — привести ее в программу через Entity. Чтобы прикрепить руку к камере персонажа, нужно настроить параметры — положение и угол.\nМы же снова воспользуемся готовыми объектом и текстурой руки.\n\nКак и раньше, модель руки находится `models/arm.obj`, а текстура - `textures/arm.png`.\n\n```python\n# Прошлый код\n...\n\n# ЗДЕСЬ ФУНКЦИЯ input\n\n# Загружаем текстуру для руки\narm_texture = load_texture(\"textures/arm.png\")\n\n# Создаем сущность в виде руки и присваиваем ее переменной hand\nhand = Entity(\n\t# Указываем камеру, чтобы рука всегда была видна на экране\n\tparent=camera.ui,\n\t# Указываем модель\n\tmodel=\"models/arm\",\n\t# Указываем текстуру\n\ttexture=arm_texture,\n\t# Указываем масштаб сущности как 0.2, чтобы рука не была слишком большой или маленькой\n\tscale=0.2,\n\t# Указываем поворот, чтобы рука имела правильную ориентацию\n\trotation=Vec3(150, -10, 0),\n\t# Указываем позицию, чтобы рука была в нижнем правом углу\n\tposition=Vec2(0.6, -0.6),\n)\n\n...\n# Прошлый код\n```\n\n\u003eРезультат:\n\u003e![](images/5.png)\n\n### 4.3.3. Текстурирование неба\nEntity поможет тебе сделать небо — достаточно создать модель сферы с текстурой неба и ее использовать.\n\nКак и раньше, текстура неба - `textures/sky.png`.\n\n```python\n# Прошлый код\n...\n\n# ЗДЕСЬ КОД ДЛЯ РУКИ HAND\n\n# Загружаем текстуру\nsky_texture = load_texture(\"textures/sky.png\")\n\n# Создаем сущность в виде неба и присваиваем ее переменной sky\nsky = Entity(\n\t# Указываем модель сферы\n\tmodel=\"sphere\",\n\t# Указываем текстуру\n\ttexture=sky_texture,\n\t# Указываем масштаб, чтобы небо было достаточно большим\n\tscale=1000,\n\t# Указываем, чтобы текстура неба была видна с обеих сторон сферы\n\tdouble_sided=True,\n)\n\n...\n# Прошлый код\n```\n\n\u003eРезультат:\n\u003e![](images/6.png)\n\u003e*Получаем красивое небо!*\n\n## 4.4. Включение блоков Button\nНекоторые блоки нельзя «ломать». Чтобы сделать игру интерактивной, нужен особый объект Button. Он умеет работать с функцией input и методом destroy, которые помогают разбивать блоки. Создадим свой собственный класс таких блоков на основе Button. Добавим так же звуковое сопровождение для установки и удаления блока.\n\nУбираем из кода прошлый цикл!\n```python\n# Прошлый код\n...\n\n# Загружаем текстуру для травы\ngrass_texture = load_texture(\"textures/grass.png\") # Эта строка уже есть!\n\n# Новый код идет дальше\n\n# Загружаем звук\npunch_sound = Audio(\"sounds/punch.wav\", loop=False, autoplay=False)\n\n# Создаем класс Voxel, специальный класс для создания интерактивных объектов\nclass Voxel(Button):\n\t# Определяем конструктор\n\tdef __init__(self, position=(0, 0, 0), texture=grass_texture):\n\t\tsuper().__init__(\n\t\t\t# Указываем сцену, чтобы объект был виден в игре\n\t\t\tparent=scene,\n\t\t\t# Указываем модель объекта\n\t\t\tmodel=\"models/block\",\n\t\t\t# Указываем масштаб объекта\n\t\t\tscale=0.5,\n\t\t\t# Указываем текстуру объекта\n\t\t\ttexture=texture,\n\t\t\t# Указываем позицию объекта\n\t\t\tposition=position,\n\t\t\t# Указываем точку опоры объекта\n\t\t\torigin_y=0.5,\n\t\t\t# Указываем цвет объекта как случайный оттенок зеленого\n\t\t\tcolor=color.color(0, 0, random.uniform(0.9, 1)),\n\t\t)\n\t# Определяем метод input класса, который принимает один параметр: key\n\tdef input(self, key):\n\t\t# Проверяем, наведен ли курсор мыши на объект\n\t\tif self.hovered:\n\t\t\t# Проверяем, нажата ли правая кнопка мыши\n\t\t\tif key == \"right mouse down\":\n\t\t\t\t# Воспроизводим звук\n\t\t\t\tpunch_sound.play()\n\t\t\t\t# Создаем объект Voxel с текстурой и позицией\n\t\t\t\tVoxel(position=self.position + mouse.normal, texture=grass_texture)\n\t\t\t\t\n\t\t\t# Проверяем, нажата ли левая кнопка мыши\n\t\t\tif key == \"left mouse down\":\n\t\t\t\t# Воспроизводим звук\n\t\t\t\tpunch_sound.play()\n\t\t\t\t# Уничтожаем текущий объект\n\t\t\t\tdestroy(self)\n\n\n# Создаем двойной цикл for, который повторяется 16 раз по переменным x и z\nfor x in range(16):\n\tfor z in range(16):\n\t\t# Создаем объект Voxel с текстурой grass_texture и позицией по координатам x и z\n\t\tVoxel(position=(x, 0, z))\n```\n\n\u003eРезультат:\n\u003e![](images/7.png)\n\u003e*Теперь можно строить!*\n\n\u003e[!info] Чтобы персонаж мог прыгать, убери строку `player.gravity = 0.0`!\n\n## 4.5. Генерация мира\nКогда количество объектов в игровой сцене не ограничено, можно создать мир похожий на Minecraft. Для этого нет готовых функций. Но есть легкий метод — сделать матрицу из шумов Перлина и поочередно «рисовать» ее в игре.\n\n\u003e[!info] Матрица из шумов Перлина\nШум Перлина — это способ процедурной генерации по псевдослучайному алгоритму. Принцип такой: вы вводите число seed, на основе которого создается текстура поверхности.\n![](images/perlin_noise.png)\nПри одинаковом значении seed шум не изменится, если не настроить внутренние параметры алгоритма.\n\nПопробуй сгенерировать различные шумы Перлина! Для этого открой в боковой панели файл `perlin_test.py` и пробуй запускать код, при этом меняя значение `seed=*твое число*`!\nТак же можно изменять значение `terrain_width` (размер шума) и `octaves` (насколько часто меняется высота).\n\u003eПример работы программы:\n\u003e`octaves = 2, seed = 2023, terrain_width = 64`\n\u003e![](images/perlin_test.png)\n\nИспользуем такой алгоритм в генерации сложного ландшафта.\nВ основе шума Перлина лежит двумерный массив с гладкими возвышениями и углублениями по оси y. Его легко внедрить в игру.\n\nСоздадим шум Перлина перед двойным циклом. Перед этим добавим важную строку в самом начале.\n\n```python\n# Необходимые импорты\nfrom ursina import * # ЭТОТ ИМПОРТ УЖЕ ЕСТЬ В КОДЕ!\nfrom numpy import floor # НЕОБХОДИМО ДОБАВИТЬ!\nfrom perlin_noise import PerlinNoise # НЕОБХОДИМО ДОБАВИТЬ!\n\n...\n# Прошлый код\n...\n\nClass Voxel(Button):\n\t...\n\n# Создаем объект noise, который представляет собой шум Перлина\n# Указываем параметры шума, такие как количество октав (octaves) - уровней детализации шума, и зерно (seed) - начальное значение для генерации\nnoise = PerlinNoise(octaves=2, seed=2023)\n# Создаем переменную am которая определяет амплитуду шума - максимальное отклонение от среднего значения\namp = 6\n# Создаем переменную, которая определяет частоту шума - количество повторений шума на единицу длины\nfreq = 24\n# Указываем ширину и длину \nterrain_width = 30\n\n# Создаем двумерный список landscale, который будет хранить высоты блоков по координатам x и z\n# Инициализируем список нулевыми значениями размером terrain_width на terrain_width\nlandscale = [[0 for i in range(terrain_width)] for i in range(terrain_width)]\n\n# Создаем цикл for, который перебирает все позиции блоков\nfor position in range(terrain_width**2):\n    # Вычисляем координату x \n    x = floor(position / terrain_width)\n    # Вычисляем координату z \n    z = floor(position % terrain_width)\n    # Вычисляем координату y\n    # Для получения значения шума Перлина используем метод noise\n    y = floor(noise([x / freq, z / freq]) * amp)\n\n    # Присваиваем значение y в списке landscale по индексам x и z\n    landscale[int(x)][int(z)] = int(y)\n\n\n# Создаем двойной цикл for, который перебирает все координаты x и z\nfor x in range(terrain_width):\n    for z in range(terrain_width):\n        # Создаем объект block класса Voxel, который представляет собой интерактивный блок в игре\n        # Указываем параметры блока, такие как позицию по трем осям (x, y и z), используя значение y из списка landscale по индексам x и z\n        block = Voxel(position=(x, landscale[x][z], z))\n\n...\n# Прошлый код\n```\n\n\u003eРезультат:\n\u003e![](images/8.png)\n\u003e*Теперь мир не просто плоский!*\n\n\u003e[!info]\n\u003e Таким же способом можно создавать не только поверхности, но и, скажем, рудники. Только для них применяются черви Перлина. Больше информации о разнообразных алгоритмах и основах генерации мира есть [здесь](https://habr.com/ru/articles/673268/).\n\n## 4.6. Последние штрихи\nСтроить одним видом блоком, конечно же, неинтересно, поэтому давай добавим ещё 4 разных вида блоков: земля, камень, кирпичи и доски.\n\nДля этого создадим переменную `block_pick`, в которой будет содержаться номер того предмета, который мы будем устанавливать. Изменять значение будем с помощью цифр от 1 до 5.\n\nКроме того, необходимо загрузить текстуры для других блоков.\n\nИзменяем функцию `input`, чтобы она выглядела следующим образом, а так же добавим перед ней переменную, отвечающую за выбранный блок:\n\n```python\n# Прошлый код\n...\n\n# Создаем глобальную переменную block_pick, которая хранит номер выбранного блока\nblock_pick = 1\n\n\n# Определяем функцию input с одним параметром key\ndef input(key):\n\t# Объявляем, что мы будем использовать глобальную переменную block_pick внутри функции\n\tglobal block_pick\n\t# Проверяем, равна ли переменная key строке \"q\" или \"escape\"\n\tif key == \"q\" or key == \"escape\":\n\t\t# Если да, то вызываем функцию quit, которая завершает работу приложения Ursina\n\t\tquit()\n\t\t\n\t# Трава\n\tif key == \"1\":\n\t\tblock_pick = 1\n\t# Земля\n\tif key == \"2\":\n\t\tblock_pick = 2\n\t# Камень\n\tif key == \"3\":\n\t\tblock_pick = 3\n\t# Кирпичи\n\tif key == \"4\":\n\t\tblock_pick = 4\n\t# Доски\n\tif key == \"5\":\n\t\tblock_pick = 5\n\n...\n# Прошлый код\n```\n\nЧтобы ставить выбранный блок изменим функцию `update` внутри класса `Voxel`. Она будет выглядеть вот так:\n\u003e Поскольку она находится внутри класса, единичный отступ на всех строках обязателен!\n```python\n# Создаем класс Voxel, специальный класс для создания интерактивных объектов\nclass Voxel(Button):\n\t# Определяем конструктор\n\tdef __init__(self, position=(0, 0, 0), texture=grass_texture):\n\t\tsuper().__init__(\n\t\t\t# Указываем сцену, чтобы объект был виден в игре\n\t\t\tparent=scene,\n\t\t\t# Указываем модель объекта\n\t\t\tmodel=\"models/block\",\n\t\t\t# Указываем масштаб объекта\n\t\t\tscale=0.5,\n\t\t\t# Указываем текстуру объекта\n\t\t\ttexture=texture,\n\t\t\t# Указываем позицию объекта\n\t\t\tposition=position,\n\t\t\t# Указываем точку опоры объекта\n\t\t\torigin_y=0.5,\n\t\t\t# Указываем цвет объекта как случайный оттенок зеленого\n\t\t\tcolor=color.color(0, 0, random.uniform(0.9, 1)),\n\t\t)\n\t# Определяем метод input класса, который принимает один параметр: key\n\tdef input(self, key):\n\t\t# Проверяем, наведен ли курсор мыши на объект\n\t\tif self.hovered:\n\t\t\t# Проверяем, нажата ли правая кнопка мыши\n\t\t\tif key == \"right mouse down\":\n\t\t\t\t# Воспроизводим звук\n\t\t\t\tpunch_sound.play()\n\t\t\t\t# Создаем объект Voxel с нужной текстурой и позицией\n\t\t\t\tif block_pick == 1:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=grass_texture)\n\t\t\t\tif block_pick == 2:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=dirt_texture)\n\t\t\t\tif block_pick == 3:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=stone_texture)\n\t\t\t\tif block_pick == 4:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=brick_texture)\n\t\t\t\tif block_pick == 5:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=wood_texture)\n\t\t\t\t\t\n\t\t\t\t# Проверяем, нажата ли левая кнопка мыши\n\t\t\t\tif key == \"left mouse down\":\n\t\t\t\t\t# Воспроизводим звук\n\t\t\t\t\tpunch_sound.play()\n\t\t\t\t\t# Уничтожаем текущий объект\n\t\t\t\t\tdestroy(self)\n```\n\n\u003eРезультат:\n\u003e![](images/9.png)\n\u003e*Готово!*\n\n\n# 5. Код игры\n```python\n# Необходимые импорты\nfrom ursina import *\nfrom perlin_noise import PerlinNoise\n  \n# импортируем объект игрока\nfrom ursina.prefabs.first_person_controller import FirstPersonController\n\n# Инициализация окна игры\napp = Ursina()\n\n\n# Убираем кнопку закрытия окна\nwindow.exit_button.visible = False\n\n# Создаем глобальную переменную block_pick, которая хранит номер выбранного блока\nblock_pick = 1\n\n\n# Определяем функцию input с одним параметром key\ndef input(key):\n\t# Объявляем, что мы будем использовать глобальную переменную block_pick внутри функции\n\tglobal block_pick\n\t# Проверяем, равна ли переменная key строке \"q\" или \"escape\"\n\tif key == \"q\" or key == \"escape\":\n\t\t# Если да, то вызываем функцию quit, которая завершает работу приложения Ursina\n\t\tquit()\n\t\t\n\t# Трава\n\tif key == \"1\":\n\t\tblock_pick = 1\n\t# Земля\n\tif key == \"2\":\n\t\tblock_pick = 2\n\t# Камень\n\tif key == \"3\":\n\t\tblock_pick = 3\n\t# Кирпичи\n\tif key == \"4\":\n\t\tblock_pick = 4\n\t# Доски\n\tif key == \"5\":\n\t\tblock_pick = 5\n\n# Загружаем текстуру для руки\narm_texture = load_texture(\"textures/arm.png\")\n\n# Создаем сущность в виде руки и присваиваем ее переменной hand\nhand = Entity(\n\t# Указываем камеру, чтобы рука всегда была видна на экране\n\tparent=camera.ui,\n\t# Указываем модель\n\tmodel=\"models/arm\",\n\t# Указываем текстуру\n\ttexture=arm_texture,\n\t# Указываем масштаб сущности как 0.2, чтобы рука не была слишком большой или маленькой\n\tscale=0.2,\n\t# Указываем поворот, чтобы рука имела правильную ориентацию\n\trotation=Vec3(150, -10, 0),\n\t# Указываем позицию, чтобы рука была в нижнем правом углу\n\tposition=Vec2(0.6, -0.6),\n)\n\n  \n  \n\n# Загружаем текстуру\nsky_texture = load_texture(\"textures/sky.png\")\n\n# Создаем сущность в виде неба и присваиваем ее переменной sky\nsky = Entity(\n\t# Указываем модель сферы\n\tmodel=\"sphere\",\n\t# Указываем текстуру\n\ttexture=sky_texture,\n\t# Указываем масштаб, чтобы небо было достаточно большим\n\tscale=1000,\n\t# Указываем, чтобы текстура неба была видна с обеих сторон сферы\n\tdouble_sided=True,\n)\n  \n  \n\n# Загружаем текстуру для травы\ngrass_texture = load_texture(\"textures/grass.png\")\n# Загружаем текстуры для остальных блоков\nstone_texture = load_texture(\"textures/stone.png\")\nbrick_texture = load_texture(\"textures/brick.png\")\ndirt_texture = load_texture(\"textures/dirt.png\")\nwood_texture = load_texture(\"textures/wood.png\")\n\n# Загружаем звук\npunch_sound = Audio(\"sounds/punch.wav\", loop=False, autoplay=False)\n\n\n# Создаем класс Voxel, специальный класс для создания интерактивных объектов\nclass Voxel(Button):\n\t# Определяем конструктор\n\tdef __init__(self, position=(0, 0, 0), texture=grass_texture):\n\t\tsuper().__init__(\n\t\t\t# Указываем сцену, чтобы объект был виден в игре\n\t\t\tparent=scene,\n\t\t\t# Указываем модель объекта\n\t\t\tmodel=\"models/block\",\n\t\t\t# Указываем масштаб объекта\n\t\t\tscale=0.5,\n\t\t\t# Указываем текстуру объекта\n\t\t\ttexture=texture,\n\t\t\t# Указываем позицию объекта\n\t\t\tposition=position,\n\t\t\t# Указываем точку опоры объекта\n\t\t\torigin_y=0.5,\n\t\t\t# Указываем цвет объекта как случайный оттенок зеленого\n\t\t\tcolor=color.color(0, 0, random.uniform(0.9, 1)),\n\t\t)\n\t# Определяем метод input класса, который принимает один параметр: key\n\tdef input(self, key):\n\t\t# Проверяем, наведен ли курсор мыши на объект\n\t\tif self.hovered:\n\t\t\t# Проверяем, нажата ли правая кнопка мыши\n\t\t\tif key == \"right mouse down\":\n\t\t\t\t# Воспроизводим звук\n\t\t\t\tpunch_sound.play()\n\t\t\t\t# Создаем объект Voxel с нужной текстурой и позицией\n\t\t\t\tif block_pick == 1:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=grass_texture)\n\t\t\t\tif block_pick == 2:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=dirt_texture)\n\t\t\t\tif block_pick == 3:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=stone_texture)\n\t\t\t\tif block_pick == 4:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=brick_texture)\n\t\t\t\tif block_pick == 5:\n\t\t\t\t\tVoxel(position=self.position + mouse.normal, texture=wood_texture)\n\t\t\t\t\t\n\t\t\t# Проверяем, нажата ли левая кнопка мыши\n\t\t\tif key == \"left mouse down\":\n\t\t\t\t# Воспроизводим звук\n\t\t\t\tpunch_sound.play()\n\t\t\t\t# Уничтожаем текущий объект\n\t\t\t\tdestroy(self)\n\n\n# Создаем объект noise, который представляет собой шум Перлина\n# Указываем параметры шума, такие как количество октав (octaves) - уровней детализации шума, и зерно (seed) - начальное значение для генерации\nnoise = PerlinNoise(octaves=2, seed=2023)\n# Создаем переменную am которая определяет амплитуду шума - максимальное отклонение от среднего значения\namp = 6\n# Создаем переменную, которая определяет частоту шума - количество повторений шума на единицу длины\nfreq = 24\n# Указываем ширину и длину \nterrain_width = 30\n\n# Создаем двумерный список landscale, который будет хранить высоты блоков по координатам x и z\n# Инициализируем список нулевыми значениями размером terrain_width на terrain_width\nlandscale = [[0 for i in range(terrain_width)] for i in range(terrain_width)]\n\n# Создаем цикл for, который перебирает все позиции блоков\nfor position in range(terrain_width**2):\n    # Вычисляем координату x \n    x = floor(position / terrain_width)\n    # Вычисляем координату z \n    z = floor(position % terrain_width)\n    # Вычисляем координату y\n    # Для получения значения шума Перлина используем метод noise\n    y = floor(noise([x / freq, z / freq]) * amp)\n\t\n    # Присваиваем значение y в списке landscale по индексам x и z\n    landscale[int(x)][int(z)] = int(y)\n\n\n# Создаем двойной цикл for, который перебирает все координаты x и z\nfor x in range(terrain_width):\n    for z in range(terrain_width):\n        # Создаем объект block класса Voxel, который представляет собой интерактивный блок в игре\n        # Указываем параметры блока, такие как позицию по трем осям (x, y и z), используя значение y из списка landscale по индексам x и z\n        block = Voxel(position=(x, landscale[x][z], z))\n\n  \n  \n\n# Создаем объект player, который представляет собой контроллер от первого лица (FirstPersonController) - специальный класс для управления персонажем в 3D-играх\nplayer = FirstPersonController()\n\n\n# Запускаем проект\napp.run()\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FL4zzur%2Fminecraft-on-ursina","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FL4zzur%2Fminecraft-on-ursina","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FL4zzur%2Fminecraft-on-ursina/lists"}