ECS
-
Публикации
533 -
Зарегистрирован
-
Посещение
-
Победитель дней
203
Сообщения, опубликованные пользователем ECS
-
-
42 минуты назад, WheatComp сказал:Выдает ошибку:
Символ "s" поставил лишний, сорян. Я тебе сам принцип хотел показать, что нужно сначала пройтись по всем имеющимся танкам, а затем уже обращаться к их полям.
Если нужен самодельный сериализатор для любого типа таблиц, то можно написать что-то вроде
tank1 = {amount = 222, capacity = 333, nestedTable = {1, 2, 3}} tank2 = {amount = 452, capacity = 349, nestedTable = {4, 5, 6}} tankTable = {tank1, tank2} local function printTableContents(source, name, indentator) indentator = indentator or "" name = name or "" print(indentator .. name .. "{") for key, value in pairs(source) do if type(value) == "table" then printTableContents(value, tostring(key) .. " = ", (indentator or "") .. " ") else print(indentator .. " " .. tostring(key) .. " = " .. tostring(value)) end end print(indentator .. "}") end printTableContents(tankTable)
В результате выведется
-
1
-
1
-
-
3 часа назад, WheatComp сказал:tank1 = {amount = 222, capacity = 333} tank2 = {amount = 452, capacity = 349} tankTable = {tank1, tank2} for key, value in pairs(tankTable) do print(value) print(tankTable[1][key]) end
Выводит nil nil.
tank1 = {amount = 222, capacity = 333} tank2 = {amount = 452, capacity = 349} tankTable = {tank1, tank2} -- Сначала перебираем танки for tankIndex, tank in ipairs(tanksTable) do -- Затем все поля танка for key, value in pairs(tank) do print(key, value) end end
-
13 часа назад, WheatComp сказал:Можно поподробнее, где хранится этот буфер энергии? И где смотреть "алмазность", или "железность" робота?
Хранится в роботе, получить объем буфера можно через computer.maxEnergy(), а смотреть "алмазность" можно либо через experience.level(), либо визуально, т.к. с накоплением опыта робот меняет свой цвет сначала на золотой, а затем на алмазный:
13 часа назад, WheatComp сказал:А если просто выкидывать мусор? Прописать названия, если == то дропнуть.
А выкидывание никто не отменял, его нужно грамотно комбинировать с упаковкой. Например, если робот накопал 9 стаков реда, их можно упаковать в стак блоков, освободив целых 8 слотов под другие ресурсы. Это в любом случае быстрее, чем перемещаться на базу, сбрасывать инвентарь, возвращаться на раскопки и продолжать работу
В случае с мусором - да, только выкидывать по черному/белому списку или заправлять апгрейд генератора, если ресурс сжигаемый. Однако мусора много, сканить инвентарь придётся часто, а этот процесс не слишком быстрый. В теории его можно ускорить, реализовав RAM-кеш содержимого инвентаря - но придётся сильно попотеть и учесть тысячу и один нюанс
-
1
-
-
22 часа назад, WheatComp сказал:Нужна ли эта строчка в send.lua? В этом файле ничего не принимается, вроде.
Не нужна, это задел на дальнейшую разработку с анализом входящих сообщений. Бывают ситуации, когда робот застрял в приватной зоне или бедроке, когда села батарея или сломался инструмент - в этом случае имеет смысл отослать статусное сообщение с координатами робота относительно хоста, а затем отключить питание
Вообще роботы с дронами, имхо, самая балдёжная часть мода. Тут и автоматизация рутины, и распределенное выполнение задач, и сетевой код, и инфо-безопасность. Когда кодил аналогичную систему контроля в сурве, то сформулировал для себя несколько рекомендейшнов:
- Метод modem.setWakeMessage() - имба. Когда робот выполнил все задачи, можно смело его выключать, оставляя где-то на глубине в границах привата. Когда необходимо продолжить работу, шлём сетевой пакет на включение - профит. И энергия сохранена, и нажимать кнопку Power не надо
- Широковещательные пакеты через modem.broadcast() опасны на публичных серверах, и в 100% случаев станут причиной угона робота. В идеале, когда все машинки скрафчены, необходимо внести адреса их модемов в конфиг на хосте, а впоследствии общаться приватными пакетами через modem.send(). Либо захардкодить в роботах адрес хоста и доверять лишь ему одному, как в примере выше
- Дополнительные батареи - мусор. Вместо них лучше установить апгрейд опыта, построить ферму кобблы и позволить роботу фармить экспу. Спустя 2-4 реальных часа у тебя раскачается "алмазный" робот с колоссальным буфером энергии
- Апгрейд навигации для вычисления позиции/поворота - мусор. Вместо него куда дешевле и интереснее накодить софтверную триангуляцию, основанную на перемещениях робота и расстоянии, которое "пролетел" сетевой пакет. А поворот можно определить с помощью геоанализатора, ломания/установки блоков и вращения робота
- Софтверное позиционирование - имба. Вычисляешь единожды координаты/поворот робота - и корректируешь их при вызове move/turn. Взамен появляется возможность автоматизировать перемещение в любую указанную точку. При отключении питания имеет смысл сохранять эти данные на диске, либо определять их автоматически при включении
- Геоанализатор - легальный чит. Однако использовать его в штатном режиме, сканируя вертикальными "столбцами" - выстрел в ногу, т.к. точность результатов на расстоянии в 10+ блоков будет отвратная. Вместо этого стоит заюзать опциональные аргументы scan(), анализируя небольшие горизонтальные плоскости 8х8 блоков вокруг робота, постепенно прокапывая вниз. Точность при этом станет как советском станке
- Экран/клавиатура/дисковод и полноценная ОС - штуки ситуативные, т.к. стоимость сборки улетает в космос, а выхлоп сомнительный. Мнение не навязываю, но я предпочитаю ставить больше апгрейдов инвентаря/крафтинг/редстоун-плату/etc., делая машинку универсальнее и контролируя её по сети
- Апгрейд крафтинга очень недооценён. Каким бы большим ни был инвентарь, он гарантированно заполнится всякими андезитами/мусоритами. Эту проблему в соло решает крафтинг, упаковывающий ресурсы в стаки, особенно на серверах с модами типа экстраутилит, позволяющими "сжимать" кобблу
- Жёсткий диск 1 тира - топ за свои деньги. Всегда приятно иметь возможность сохранять/загружать координаты робота или довольно объёмные "снимки" местности с геоанализатора
-
5
-
16 часов назад, WheatComp сказал:Пытался проверить, будет ли 3-х секундная задержка (computer.pullSignal(3)), нет задержки
Эта штука ждёт каких-либо сигналов в течение 3 секунд. Если сигнал получен - pullSignal вернёт информацию о нём досрочно. Если сигналов не было - pullSignal будет честно ждать 3 секунды, а затем вернет nil
Вообще, как я понял, тебе нужен некий аналог os.sleep(3) из OpenOS, который реализован как раз на чистом pullSignal. Можно скопировать его из исходников
16 часов назад, WheatComp сказал:upd: оказалось, pullSignal() относится к api. Есть ли "компонентная" альтернатива?
На самом деле не относится, это на вики мешанина. Суперглобалки component/computer/robot/unicode/bit32, а также штатные библиотеки Lua доступны отовсюду. Все остальное - софтверные фичи OpenOS
-
2 часа назад, WheatComp сказал:Это странно, почему filesystem.exists() смотрит в /, а не в /home, где обычно стартует терминал при включении игрового компа
Библиотека filesystem абстрагируется от действий текущего юзера и рабочей директории, предоставляя более "сырой" доступ к файловой системе без высокоуровневых проверок. Для поддержки поиска по раб. директории следует обратиться к методу shell.resolve(path), который используется большинством штатных скриптов в /bin/. Посмотри на отправляющий код с пред. сообщения - там я как раз добавил эту фичу для удобства
2 часа назад, WheatComp сказал:Почему-то arg[1] выводит send. Вчера, когда пытался разобраться с аргументами, читал, что в Lua-интерпретаторах обычно args[0] выводит имя файла. Попытался в игре - выводит nil
Всё верно. В десктопном Lua ты получил бы что-то наподобие:
А в OpenComputers уже нет, т.к. глобальной переменной arg вовсе не существует:
Все входные аргументы мы получаем вручную через args = {...}, создавая при этом самую обычную переменную. Она не какая-то магическая, не системная. Её и назвать можно как угодно, хоть someWeirdDots = {...}, тут уж воля фантазии
2 часа назад, WheatComp сказал:Робота удалось заставить шевелиться, но возникает некоторая путаница с командами. В ОpenOS же вперед - это forward(), а тут move(side). Придется изменить много кода и ошибки, чувствую, неизбежны
Согласен, хотя это скорее дело привычки. Всегда можно скопировать таблицу направлений из исходников Sides API, и воспользоваться ей для движения робота в нужную сторону, если вводить непонятные цифры а-ля robot.move(1/2/3/4) дискомфортно
2 часа назад, WheatComp сказал:К тому же на сайте игры не написано, каковы же остальные "низкоуровневые" команды. Описаны move, turn, swing, а back, up, down не описаны
Как раз по этой ссылке и перечислены все остальные "низкоуровневые" команды, других попросту не существует в компоненте robot. Пикча для наглядности:
Например, back/up/down реализуются софтверно средствами OpenOS. При этом robot.back() из OpenOS эквивалентен компонентному вызову robot.move(2). Вообще крайне рекомендую чекнуть исходники по пред. ссылке - там много всего интересного, и на деле окажется, что работа с "чистым" роботом ничуть не сложнее, чем с библиотекой из OpenOS. Непривычно и неочевидно - да, есть такое
-
1
-
-
11 час назад, WheatComp сказал:Попытался запустить и так и сяк, не получилось (прикрепил фото)
Проверяй наличие файлов и корректность вводимых путей. Интереса ради загрузил майн, проверил - всё сработало, как и задумано:
Управляющий скрипт /home/send.lua:
Скрытый текст-- Подключаем библиотеки local component = require("component") local filesystem = require("filesystem") local shell = require("shell") local io = require("io") local event = require("event") -- Получаем и анализируем входные аргументы local args = {...} if #args < 1 then print("Usage: send <filename>") return end local path = shell.resolve(args[1]) -- Проверяем, существует ли файл, содержимое которого -- мы будем отсылать по сети if not filesystem.exists(path) then print("Specified file doesn't exist") return -- Проверяем, не директория ли это elseif filesystem.isDirectory(path) then print("It's a directory, not file") return end -- Читаем содержимое файла local file = assert(io.open(args[1], "rb")) local data = file:read("*a") file:close() -- Получаем компонент модема, вставленный в хост, и -- открываем любой порт. Он обязан быть таким же, что и у -- всех подконтрольных роботов local modem = component.modem local port = 123 modem.open(port) -- Отсылаем прочтённое содержимое всем роботам на выполнение -- Если файл будет слишком большим, чтобы уместиться -- в пакет модема - нужно будет писать отдельную -- систему для разбивки на пакеты. Но это уже выходит за -- рамки текущего примера modem.broadcast(port, "execute", data) -- Далее можно реализовать приёмку сообщений об ошибках, -- визуализировать их, логировать и т.п.
Микропрограмма-ресивер для робота /home/eeprom.lua:
Скрытый текст-- Получаем компонент модема, вставленный в робота, и -- открываем любой порт по вкусу local modem = component.proxy(component.list("modem")()) local port = 123 modem.open(port) -- Анализируем сигналы в бесконечном цикле while true do local data = {computer.pullSignal()} -- Если пришло сообщение по модему, и адрес модема отправителя -- совпадает с адресом хоста, т.е. если мы можем доверять -- содержимому сообщения if data[1] == "modem_message" then -- Анализируем содержимое сообщения. В этом примере мы -- будем выполнять код, присланный хостом, и отсылать ему -- обратно информацию в случае неудачи if data[6] == "execute" and data[7] then -- Пытаемся загрузить присланную строку в виде Lua-кода local result, reason = load(data[7]) -- Если код загружен - выполняем его if result then result, reason = xpcall(result, debug.traceback) end -- Если загрузка/выполнение не удались - отсылаем -- причину хосту. В принципе это тоже необязательный -- шаг, но при контроле большого кол-ва дронов/роботов -- будет разумно визуализировать все проблемы на хосте if not result and reason then modem.send(serverModemAddress, port, "executeFailed", tostring(reason)) end end end end
Исполняемый код, отсылаемый роботам по сети /home/robot.lua:
Скрытый текстlocal robot = component.proxy(component.list("robot")()) for i = 1, 4 do robot.turn(true) end
Команда для отсылки:
send robot.lua
Результат:
11 час назад, WheatComp сказал:Кстати про require("robot"). Без него же робот не поднимется, т.к. у него нет OpenOS
Движение робота реализуется самим роботом, а не OpenOS. Как правило, любая ОС в OpenComputers - это софтверная оболочка, функционирующая поверх аппаратной части, и предоставляющая набор библиотек, упрощающих разработку софта. Например, в случае с роботами OpenOS оборачивает компонент robot в библиотеку robot, предоставляющую набор шорткатов. То же самое и с глобальной функцией require - её попросту нет в "голых" роботах, управляемых из-под EEPROM
Использовать ОС крайне удобно, когда речь идет об одном роботе, хранящем пользовательские скрипты и управляемом напрямую через экран/клавиатуру. Однако в случае с роем такое решение контр-продуктивно, т. к. любая ОС потребляет ресурсы и требует крафта более дорогостоящих компонентов - в частности, планок памяти и жёстких дисков. Это всё равно что ставить Debian на сеть устройств для капельного полива домашних растений - ну то есть да, это возможно, а зачем?
Разумнее прибегнуть к концепции микропрограмм на EEPROM, которые относительно дёшевы в плане крафта, а профит в виде освободившихся слотов под компоненты существенный. Заодно можно получить интересный опыт по "низкоуровневой" разработке под опенкомпы:
-- Робот с OpenOS local robot = require("robot") robot.moveUp() robot.turnRight() robot.swing() -- Робот с EEPROM local robot = component.proxy(component.list("robot")()) robot.move(1) robot.turn(true) robot.swing(3)
11 час назад, WheatComp сказал:а в начале файла-ресивера нет запроса библиотеки "computer". Сработает ли скрипт
Таблицы component/computer/robot/unicode/bit32 являются суперглобальными и доступны сразу при запуске микропрограммы EEPROM, однако во время инициализации OpenOS они маскируются из соображений консистентности кода. Поэтому при работе из-под EEPROM вызов require не требуется, а из-под OpenOS уже требуется
11 час назад, WheatComp сказал:Вот для них прямо необходима общая папка, поскольку внутри них будут всякие улучшения (верстаки, контроллеры инвентаря и емкости, а они же требуют OpenOS)
Верстаки, контроллеры инвентаря и ёмкости - это аппаратные компоненты, функционирующие самостоятельно и не требующие OpenOS. Любая ОС - это просто средство доступа к компонентам, причём одно из многих:
-- Робот с OpenOS local component = require("component") local sides = require("sides") local crafting = component.crafting local inventoryController = component.inventory_controller local tankController = component.tank_controller crafting.craft(10) inventoryController.dropIntoSlot(sides.front, 10) tankController.drain() -- Робот с EEPROM local crafting = component.proxy(component.list("crafting")()) local inventoryController = component.proxy(component.list("inventory_controller")()) local tankController = component.proxy(component.list("tank_controller")()) crafting.craft(10) inventoryController.dropIntoSlot(3, 10) tankController.drain()
Как видно, разница в коде несущественна, отличие лишь в способе получения доступа к ним и в наличии упрощающих библиотек типа sides
10 часов назад, WheatComp сказал:В дополнение. По-моему, пропущены end-ы после return в скрипте для хоста?:
Чтобы прояснить ситуацию: никто не призывает тебя использовать голый EEPROM вместо классического подхода с HDD/OpenOS. Разрабатывай так, как считаешь комфортным и оптимальным для себя - я лишь указал один из способов решения поставленной задачи, который использовал при выживании, и который сам считаю оптимальным
Если тебе требуется весь богатый функционал, поставляемый OpenOS для роботов, ничто не мешает модифицировать скрипт-ресивер таким образом, чтобы он работал из-под OpenOS:
Скрытый текст-- Подключаем библиотеки local component = require("component") local event = require("event") -- Получаем компонент модема, вставленный в робота, и -- открываем любой порт по вкусу local modem = component.modem local port = 123 modem.open(port) -- Задаём адрес модема, вставленного в компьютер-хост -- Вообще это опциональная штука, необходимая для защиты от -- атак на роботов на публичных серверах. В локальной игре -- это не имеет особого смысла local serverModemAddress = "eafaff-fae-faefaefa-fafe" -- Ждем сообщений по модему в бесконечном цикле while true do local data = {event.pull("modem_message")} -- Если адрес модема отправителя совпадает с адресом хоста, -- т.е. если мы можем доверять содержимому сообщения if data[3] == serverModemAddress then -- Анализируем содержимое сообщения. В этом примере мы -- будем выполнять код, присланный хостом, и отсылать ему -- обратно информацию в случае неудачи if data[6] == "execute" and data[7] then -- Пытаемся загрузить присланную строку в виде Lua-кода local result, reason = load(data[7]) -- Если код загружен - выполняем его if result then result, reason = xpcall(result, debug.traceback) end -- Если загрузка/выполнение не удались - отсылаем -- причину хосту. В принципе это тоже необязательный -- шаг, но при контроле большого кол-ва дронов/роботов -- будет разумно визуализировать все проблемы на хосте if not result and reason then modem.send(serverModemAddress, port, "executeFailed", tostring(reason)) end end end end
-
2
-
-
2 минуты назад, Anon сказал:не опечатка ли это
Ага, опечатка, поправил, спсибо
-
1
-
-
@WheatComp Если по-читерски, то можно сдюпнуть жёсткий диск одного робота, вставить его в остальные и работать в одной общей папке
Если по-честному, то имеет смысл дать возможность каждому роботу выполнять произвольный код, присылаемый компьютером-хостом по беспроводной сети. Это позволит избавиться от OpenOS, жёсткого диска и упростить сборку робота за счёт более дешёвых компонентов:
1) Крафтим 20 чистых EEPROM и беспроводных модемов
2) Прошиваем их скриптом-ресивером:
Скрытый текст-- Получаем компонент модема, вставленный в робота, и -- открываем любой порт по вкусу local modem = component.proxy(component.list("modem")()) local port = 123 modem.open(port) -- Задаём адрес модема, вставленного в компьютер-хост -- Вообще это опциональная штука, необходимая для защиты от -- атак на роботов на публичных серверах. В локальной игре -- это не имеет особого смысла local serverModemAddress = "eafaff-fae-faefaefa-fafe" -- Анализируем сигналы в бесконечном цикле while true do local data = {computer.pullSignal()} -- Если пришло сообщение по модему, и адрес модема отправителя -- совпадает с адресом хоста, т.е. если мы можем доверять -- содержимому сообщения if data[1] == "modem_message" and data[3] == serverModemAddress then -- Анализируем содержимое сообщения. В этом примере мы -- будем выполнять код, присланный хостом, и отсылать ему -- обратно информацию в случае неудачи if data[6] == "execute" and data[7] then -- Пытаемся загрузить присланную строку в виде Lua-кода local result, reason = load(data[7]) -- Если код загружен - выполняем его if result then result, reason = xpcall(result, debug.traceback) end -- Если загрузка/выполнение не удались - отсылаем -- причину хосту. В принципе это тоже необязательный -- шаг, но при контроле большого кол-ва дронов/роботов -- будет разумно визуализировать все проблемы на хосте if not result and reason then modem.send(serverModemAddress, port, "executeFailed", tostring(reason)) end end end end
3) Вставляем прошитые EEPROM с модемами в роботов
4) Пишем управляющий скрипт для компьютера-хоста. Предполагаю, что на нём будет использоваться OpenOS:
Скрытый текст-- Подключаем библиотеки local component = require("component") local filesystem = require("filesystem") local shell = require("shell") local io = require("io") local event = require("event") -- Получаем и анализируем входные аргументы local args = {...} if #args < 1 then print("Usage: send <filename>") return end local path = shell.resolve(args[1]) -- Проверяем, существует ли файл, содержимое которого -- мы будем отсылать по сети if not filesystem.exists(path) then print("Specified file doesn't exist") return -- Проверяем, не директория ли это elseif filesystem.isDirectory(path) then print("It's a directory, not file") return end -- Читаем содержимое файла local file = assert(io.open(args[1], "rb")) local data = file:read("*a") file:close() -- Получаем компонент модема, вставленный в хост, и -- открываем любой порт. Он обязан быть таким же, что и у -- всех подконтрольных роботов local modem = component.modem local port = 123 modem.open(port) -- Отсылаем прочтённое содержимое всем роботам на выполнение -- Если файл будет слишком большим, чтобы уместиться -- в пакет модема - нужно будет писать отдельную -- систему для разбивки на пакеты. Но это уже выходит за -- рамки текущего примера modem.broadcast(port, "execute", data) -- Далее можно реализовать приёмку сообщений об ошибках, -- визуализировать их, логировать и т.п.
5) Запускаем всех роботов и отсылаешь им любой файл с жёсткого диска на исполнение командой send robots/example.lua
Единственный нюанс - работоспособность кода выше чекнуть не могу, т.к. майна под рукой нет, но общий концепт, думаю, понятен
-
1
-
1
-
1
-
-
1 час назад, WheatComp сказал:В package.lua, что в папке lib папки жесткого диска робота, добавил конце строку "/D:/23/?.lua"
Это не возымеет эффекта, т.к. библиотека package реализована средствами OpenOS, а не мода. То есть ей доступны те же данные, что и игровому жёсткому диску. А ему в свою очередь доступны только данные в рамках директории игрового сейва - это захардкожено из соображений серверной безопасности, и обойти не получится
Вероятно, package задумывалась как полный аналог одноименной библиотеки в "реальной" версии Lua - отсюда и путаница-
2
-
-
8 минут назад, Bumer_32 сказал:а почему нельзя отключить только определённую кнопку
Можно, button.disabled = false. Но оно меняет визуальный стиль ¯\_(ツ)_/¯
По идее каждая кнопка имеет таблицу .colors, где можно кастомизировать все цвета. Так что можно заюзать что-то наподобие
button.colors.disabled = button.colors.default
Но с окнами это не прокатит, т.к. "общего" решения для отключения обработки событий не предусмотрено. Кстати, его не особенно сложно имплементировать, буду рад PR, если захочется покопаться
-
Увы, нет, это не было предусмотрено "из коробки". Как я понял, речь идёт о неком аналоге IsHitTestVisible, когда система должна игнорировать touch-ивенты, но без смены визуального стиля элементов. Причём глобально, а не только для кнопок.
На текущий момент это можно реализовать лишь с помощью перегрузки:
window.isEventHandlingEnabled = true local originalWindowEventHandler = window.eventHandler window.eventHandler = function(workspace, window, ...) if window.isEventHandlingEnabled then originalWindowEventHandler(workspace, window, ...) end end
-
15 часов назад, Oleshe сказал:Есть таблица которую оно может запринтить, но не может записать аля не хватает памяти
Для print заданы ограничения сериализатора, которые отсутствуют в writeTable
15 часов назад, Oleshe сказал:Объясняйся
А какие именно - не скажу, сам думай. Не люблю приказной формат дискуссий)0
-
2
-
1
-
-
Хост маркета располагается на домашней OrangePI и пару недель не отвечает на пинги. Может быть, умерла загрузочная SD-карта, которая родилась с нокией le papan 15 лет назад и давно на ладан дышит. Или, что более вероятно, сработало реле в распред. щитке, и питание полностью отключилось (прощай, заморозка в холодосе). Или вообще роутер с алика самопроизвольно перепрошился и устал работать. Сложно сказать. Бекапы валяются на внешнем диске на пыльных антресолях, а сам я за тридевять земель от дома, вернусь ориентировочно к концу лета - примерно тогда и гляну, что там случилось
-
1
-
1
-
1
-
1
-
-
19 часов назад, Oleshe сказал:gui.workspace(160,50)
Workspace создается за пределами экрана, первые два параметра - это x и y. Подробнее в доке
19 часов назад, Oleshe сказал:a = vector.new(10,10)
a = vector.add(a,1,1,'square',10,10,0xFFFFFF)
a = vector.add(a,1,1,'line',10,10,0xFFFFFF)
Переменная "a" переопределена, из-за чего теряется объект, созданный в vector.new(). Т.е. каждая новая фигура добавляется не в родительский object, а в предыдущую фигуру
Фиксим, радуемся:
Это что касалось логики. Теперь по коду: осмелюсь прогнать его через Lua Beautifier, оформить ООП и дать человеческие названия переменным, т.к. "a", "what" или "toendobject" имеют сомнительную информативность. Использовать его или нет - дело, офк, твоё
Приложение:
Скрытый текстlocal vector = require("vectorImage") local gui = require("gui") ----------------------------------------------------- local workspace = gui.workspace() -- Создаем фоновую панель для заливки цветом workspace:addChild(gui.panel(1, 1, workspace.width, workspace.height, 0x262626)) -- Создаем холст, на котором будут располагаться фигуры local canvas = workspace:addChild(vector.newCanvas(3, 2, 20, 10)) -- Добавляем фигуры на холст canvas:addShape(1, 1, "rectangle", 20, 10, 0x444444) canvas:addShape(3, 2, "line", 18, 9, 0xFF0000) canvas:addShape(10, 5, "ellipse", 6, 3, 0xFFFFFF) ----------------------------------------------------- workspace:draw() workspace:start()
Либа:
Скрытый текстlocal gui = require("gui") local screen = require("screen") local fs = require("filesystem") local compress = require("compressor") ----------------------------------------------------- local vectorImage = {} local function unpack(type) return compress.unpack(type, "/Temporary/lib") end local function pack(type) return compress.pack("/Temporary/lib", type) end function vectorImage.new(width, heigth) return {width = width, heigth = heigth} end function vectorImage.load(path) if fs.exists(path) then unpack(path) return fs.readTable("/Temporary/lib") else return nil, "File does not exists" end end function vectorImage.save(type, path) fs.writeTable(type, "/Temporary/lib") return pack(path) end local function canvasAddShape(canvas, x, y, type, ...) local args = {...} if type == "line" then table.insert(canvas.shapes, { type = type, x = x, y = y, x1 = args[1], y1 = args[2], color = args[3] }) elseif type == "rectangle" then table.insert(canvas.shapes, { type = type, x = x, y = y, width = args[1], height = args[2], color = args[3] }) elseif type == "ellipse" then table.insert(canvas.shapes, { type = type, x = x, y = y, radiusX = args[1], radiusY = args[2], color = args[3] }) end return canvas end local function canvasDraw(canvas) local x, y = canvas.x, canvas.y local shapes = canvas.shapes local shape for i = 1, #shapes do shape = shapes[i] if shape.type == "line" then screen.drawLine( x + shape.x - 1, y + shape.y - 1, x + shape.x1 - 1, y + shape.y1 - 1, shape.color, 0x0, " " ) elseif shape.type == "rectangle" then screen.drawRectangle( x + shape.x - 1, y + shape.y - 1, shape.width, shape.height, shape.color, 0xFFFFFF, " " ) elseif shape.type == "ellipse" then screen.drawEllipse( x + shape.x - 1, y + shape.y - 1, shape.radiusX, shape.radiusY, shape.color, 0xFFFFFF, " " ) end end end function vectorImage.newCanvas(x, y, width, height) local canvas = gui.object(x, y, width, height) canvas.shapes = {} canvas.draw = canvasDraw canvas.addShape = canvasAddShape return canvas end return vectorImage
-
2
-
-
Исходники не полные, инфы о создании элементов фигур в what нет, поэтому чёрт его знает. На текущий момент в глаза бросается лишь использование глобальных экранных координат вместо локальных координат объекта в методе отрисовки. Все методы либы screen работают с экраном, а не с объектом toendobject, у которого есть свои собственные координаты. Поэтому для корректной отрисовки фигур нужно будет юзать конструкцию вида
screen.drawRectangle( toendobject.x + what[i].x, toendobject.y + what[i].y, toendobject.x + what[i].x1, toendobject.y + what[i].y1, what[i].color, 0xFFFFFF, 'R' )
Ещё мб ты не вызываешь метод workspace:draw() после добавления всех элементов в него, поэтому никаких новых данных на экране и не появляется
И напоследок, вполне может быть, что x/y/x1/y1 не округлены, что выливается в ошибки экранной либы. Но опять же, без полных сырцов что-либо дельное сказать сложно
-
-- Копируем переменную what в toendobject toendobject.what = what -- Определяем метод отрисовки toendobject toendobject.draw = function(toendobject) -- Обращаемся к скопированной ранее переменной for i = 1, #toendobject.what do if toendobject.what[i] == "line" then ... end end end
-
1
-
-
Вновь ничего не понятно, но
16 часов назад, Oleshe сказал:только на том мониторе с которого это началось
-
А питания хватает? Была похожая ситуация, когда некоторые мониторы отключались из-за подключения лишь одного энерговхода
-
Капец, я еле понял, о чём речь. Bзмени второй аргумент gpu.bind на false, т.к. по умолчанию разрешение автоматически сбрасывается на maxResolution. Из документации:
bind(address: string[, reset: boolean=true])
-
1
-
-
22 часа назад, Oleshe сказал:Я использовал цикл потому-что нужно было что-бы когда мы зажимали клавишу, мы ходили без остановки, только потом я догадался сделать isKeyDown, который можно встроить в eventHandler. Я использовал для начала, остатки это текст, но потом нужда в непрерывной ходьбе
Дык его попросту нельзя использовать. Либа сама делает всю работу, обрабатывая ивенты по-своему и творя внутреннюю магию. Если используешь - получаешь "unexpected behaviour" со всеми вытекающими. Поэтому либо повторяй в точности всю "магию", либо присоединяй eventHandler как положено и не парься
22 часа назад, Oleshe сказал:Что-бы цикл не стопорил все на 2 минуты по кастомному конфигу. Иногда мне нужно обработать огромный цикл, это занимает больше секунды и оно вылетает.
Для твоей задачи это не требуется, т.к. удержание клавиш нажатыми в любом случае генерирует бесконечный поток событий key_down, позволяя персонажу двигаться ходить непрерывно. Авто-пуллинг событий впустую нагружает компьютер, обрабатывая их через либу. Иногда это действительно необходимо (пример с опросом реакторов), но чаще всего нет
22 часа назад, Oleshe сказал:В чем отличие? Как и описывалось в коде список "игрок" описывает его, он не является контейнером, либо я не правильно понял ответ (или вопрос). Или имелось в виду что если используем контейнер. Из-за этого и пошла ошибка отрисовки, при перемещений контейнера на фоне пластины оно и закрашивало.
localX/localY отвечают за положение элемента внутри родительского контейнера, а x/y - за позицию на экране во время отрисовки. При этом x/y рассчитываются автоматически и используются только во время операций отрисовки. Вообще все подробности имеются в доке, которую было бы неплохо чекнуть
22 часа назад, Oleshe сказал:Это было сделано потому-что мы просто ставили новый объект, другого способа поменять координату я не знаю.
localX/localY
22 часа назад, Oleshe сказал:Хотелось-бы что-бы каждый граф. элемент имел динамические координаты, кнопка, картинка, текст, ползунок и т.д., не только контейнеры
Дык имеют же. Читай доку!!11
-
Вполне вероятно, что смещение белого прямоугольника - это баг отрисовки. А, может быть, и нет, т.к. либа юзается не по доке:
1) Обработка событий встроена, workspace.start() сам по себе запускает бесконечный цикл пуллинга событий, и делать это вручную через while true нет смысла:
wk.eventHandler = function(e1, e2, e3, e4, e5, e6) ... end wk:start(0.01)
2) Непонятно, зачем конкретно в твоём случае используется таймаут поллинга в 0.01 сек. Эта фича используется в довольно редких ситуациях, когда нужно делать что-то с заданным интервалом. Например, опрашивать внешние компоненты типа реакторов или перемещать визуальные элементы в играх раз в N сек. Если тебе требуется лишь анализ нажатия клавиш, то:
bg.eventHandler = function(e1, e2, e3, e4, e5, e6) if e1 == "key_down" then -- A if e3 == 30 then ... wk:draw() -- D else if e3 == 32 then ... wk:draw() end end end wk:start(0.01)
3) Изменять экранные координаты объекта бесполезно, т.к. они рассчитываются автоматически и используются только во время вызова метода draw(). Чтобы изменить позицию элемента в родительском контейнере, используй localX/localY:
-- Нельзя player.x = player.x - 2 -- Можно player.localX = player.localX - 2
4) Нет смысла удалять и пересоздавать объекты картинок при каждом ивенте. Если тебе нужно попросту заменить картинку в существующем виджете, то:
local playerpic = wk:addChild(gui.image(50,25,images['Man Right'])) bg.eventHandler = function(e1, e2, e3, e4, e5, e6) if e1 == "key_down" then -- A if e3 == 30 then player.facing = 'Left' playerpic.image = images['Man ' .. player.facing] wk:draw() end end end
5) Можно вообще создать собственный виджет "player", определив ему метод отрисовки и не собирать его из GUI.image. Он и работать будет быстрее, и все поля будут храниться в одном месте, и любой кастом можно будет оформить за пару строк кода:
local player = wk:addChild(gui.object(50, 25, 8, 4)) player.facing = 'Left' player.draw = function(player) screen.drawImage(player.x, player.y, images['Man ' .. player.facing] end
-
4
-
-
13 часа назад, Oleshe сказал:Почему они летают? у координата = 0 ставим стенку на 0-ой корде с высотой в 2. у = у + 2, ставим стенку на 2-й высоте, но, мне кажется, он ставит её не там
Ничего не понял, кроме того, что они летают :p
Код писался в докембрийскую эпоху, и сейчас уже не вспомнить, как там что было устроено. И тем более не пофиксить, так что увы
-
1
-
-
6 часов назад, eu_tomat сказал:@ECS, объясни, пожалуйста, что хочет этот товарищ?
А чего я-то, это все он! Видимо, хочет поставить старую оську, исходники которой уже давно утеряны, а пастбин акк заблочен из-за санкций
-
1
-
1
-

Почему package.lua не видит модуль?
в Общие
Опубликовано:
tankTable[1].amount