Перейти к содержимому

Oleshe

Пользователи
  • Публикации

    155
  • Зарегистрирован

  • Посещение

  • Победитель дней

    12

Сообщения, опубликованные пользователем Oleshe


  1. Да-да, поразмыслив, кажется, использовать буферы на отдельное изображение — оно. Только проблема скорее в динамичности и объёме изображения. Если изменится элемент выше нашего, или, если он прозрачный, под ним, придётся ВСЁ пересчитывать, что как раз-таки очень дорого, даже если отрисовывать только ту область, что изменилась (Что и происходит в примере)
    Тем не менее, со статичной картинкой работать проще... Заранее просчитать и добавить в буфер все варианты спрайтов, а после доставать их на нужное место. Но с динамичной получится слишком много вариантов, из-за чего это увы полный. Что поделать... Пойду действительно попробую реализовать это... Маленький рефакторинг, в третий раз переписать движок рендера...


  2. Шли года... Буксующая разработка продолжалась.. И вот 0.4! Считаю её стабильной и лучшей на данный момент, потому отметим её.
    Забудьте всё, теперь всё по-другому. Разберём попытку перенести одну игру, но провалившеюся по одной причине, которую мы разберём ниже.
    Здесь находится Main.lua. Разберём что же творится!

    Скрытый текст
    
    local scriptPath = string.gsub(require('System').getCurrentScript(),'/LiminalStarwave.app','')
    local args = {...}
    _, args = require('System').parseArguments(table.unpack(args))
    local OE, why = assert(loadfile(scriptPath))() -- Подгрузка библиотеки
    if not OE then print(why) return end
    OE.applicationRoot = string.gsub(require('System').getCurrentScript(),'Main.lua','')
    OE.fileRoot = OE.applicationRoot .. 'Additional_Content/' -- Ставим рут приложения и папки контента
    OE.createScene('Game') -- Создаём основную сцену
    OE.Render.addLayer() -- Main game
    OE.Render.layers[2].y = -16
    OE.Render.addLayer() -- Arrows and fly windows
    OE.Render.setResolution(135,50) -- Добавляем еще 2 слоя к первому, итого 3. 1 - задник, 2 - игра, 3 - UI Ставим разрешение 135 на 50. 
    local sky = OE.createObject('Skybox','Game') -- Задник
    sky:_addScript('MAIN_Panel.lua',"Render") -- Добавляем скрипт панели
    sky.Render.color = 0
    sky.Transform.Scale = {w = 135, h = 50} -- Параметры панели. Её размер и цвет.
    
    local BL = OE.createObject('BottomLine','Game') -- Две чёрные полосы сверху и снизу экрана по такому же принципу, как и задник
    BL:_addScript('MAIN_Panel.lua',"Render")
    BL.Render.color = 0
    BL.Render.layer = 3 -- .. с отличием, что мы ставим ему 3 слой
    BL.Transform.Scale = {w = 135, h = 3}
    BL.Transform.Position = {y=48}
    local UL = OE.createObject('UpperLine','Game')
    UL:_addScript('MAIN_Panel.lua',"Render")
    UL.Render.color = 0
    UL.Render.layer = 3
    UL.Transform.Scale = {w = 135, h = 3}
    
    local BG = OE.createObject('Background','Game') -- Пикча задника игры.
    BG:_addScript('MAIN_Sprite.lua','Render')
    BG.Render.sourceImage = 'Background.pic'
    BG.Render.transperent = true -- Она прозрачна.
    BG.Render.layer = 2
    
    local ENA = OE.createObject('ENA','Game') -- Наш персонаж
    ENA:_addScript('MAIN_Sprite.lua','Render')
    ENA.Render.sourceImage = 'ENAIdle1.pic'
    ENA.Render.transperent = true
    ENA.Render.layer = 2
    ENA:_addScript('CharactersSpriteBehavior.lua','SpriteBehavior') -- Смотреть в следующем файле. Управляет анимацией спрайта.
    ENA:_addScript('PlayerInput.lua','PlayerInput') -- Смотреть в очередном следующем файле. Управляет вводом игрока.
    --ENA:_addScript('SoundManager.lua','Audio') -- Смотреть в третьем файле. Управляет звуком.
    ENA.Transform.Position = {y=32}
    
    OE.Storage.reloadAdditionalFiles(OE.fileRoot) -- Загружаем дополнительные ассеты из нашей папки
    
    OE.log('Project init completed')
    OE.loadScene("Game") -- Загружаем сцену
    OE.log('Scene loaded')
    OE.initWindow() -- И иницилизируем окно

    ./Additional_Content/Scripts/CharactersSpriteBehavior.lua

    
    local currentAnim = "" -- Анимация, что сейчас воспроизводится
    function Idle()
    	currentAnim = "ENAIdle"
    	Object.SpriteBehaviorAnimation.Play(currentAnim)
    end
    
    function Left()
    	currentAnim = "ENALeft"
    	Object.SpriteBehaviorAnimation.Play(currentAnim)
    end
    function Right()
    	currentAnim = "ENARight"
    	Object.SpriteBehaviorAnimation.Play(currentAnim)
    end
    function Down()
    	currentAnim = "ENADown"
    	Object.SpriteBehaviorAnimation.Play(currentAnim)
    end
    function Up()
    	currentAnim = "ENAUp"
    	Object.SpriteBehaviorAnimation.Play(currentAnim)
    end
    
    function ChangeSprite(index)
    	Object.Render.setImage(currentAnim .. index .. ".pic") -- Сделал универсально. Анимация ENAIdle, индекс 1, .pic > ENAIdle1.pic
    end
    
    function OnEndNotIdle()
    	OE.Script.Invoke(Idle, 0.2) -- В отличий от идле анимаций, другие чуть задержаться на последнем спрайте.
    end
    
    Start = Idle -- Когда сцена загрузится, мы переходим в Idle
    
    function Init()
    	Object:_addScript('MAIN_Animation.lua','SpriteBehaviorAnimation', true) -- При иницилизвации скрипта, добавляем компонент анимации. Просто выполняет функций по таймкоду
    	Object.SpriteBehaviorAnimation.animations["ENAIdle"] = {
    		onEnd = Idle, -- Выполнится, когда кейфреймов не останится
    		frames = {
    			[0] = ChangeSprite,
    			[0.2] = ChangeSprite,
    			[0.4] = ChangeSprite
    		}
    	}
    	Object.SpriteBehaviorAnimation.animations["ENAUp"] = {
    		onEnd = OnEndNotIdle,
    		frames = {
    			[0] = ChangeSprite,
    			[0.1] = ChangeSprite -- У нас только 2 спрайта на каждое действие, в отличий от Idle
    		}
    	}
    	Object.SpriteBehaviorAnimation.animations["ENADown"] = Object.SpriteBehaviorAnimation.animations["ENAUp"] -- Ничем не отличаются, ибо мы уже сделали всё достатачно универсальным
    	Object.SpriteBehaviorAnimation.animations["ENALeft"] = Object.SpriteBehaviorAnimation.animations["ENAUp"]
    	Object.SpriteBehaviorAnimation.animations["ENARight"] = Object.SpriteBehaviorAnimation.animations["ENAUp"]
    end

    ./Additional_Content/Scripts/PlayerInput.lua

    
    local KeyCodes, pauseToggle = OE.Input.keyCodes
    local anims = {[KeyCodes.A] = "Left", [KeyCodes.S] = "Down", [KeyCodes.D] = "Right", [KeyCodes.W] = "Up"} -- Привязываем клавиши к соответствующим названиям функций, что стартуют анимации
    function KeyDown(key) -- Когда клавиша нажата
    	if anims[key] then -- Если клавиша действия, значит
    		Object.SpriteBehavior[anims[key]]() -- запускаем действие
    	elseif key == KeyCodes.SPACE then -- , или же, если это пробел
    		if pauseToggle then -- — ставим на паузу, остарнавливая аудио, или же снимаем с паузы
    			Time.scale = 0
    			Object.Audio.Pause()
    		else
    			Time.scale = 1
    			Object.Audio.Resume()
    		end
    		pauseToggle = not pauseToggle -- Переключаем паузу
    	end
    end

    ./Additional_Content/Scripts/SoundManager.lua

    
    local cmp, getFile,len1,len2 = require('component'), OE.Storage.getFile
    local empty = string.rep("\xAA",8192) -- Заранее подготавливаем пустую для кассет строку
    local listOfTapes = cmp.list('tape_drive') -- Получаем и
    tape1 = cmp.proxy(listOfTapes()) -- ставим прокси для обоих кассетниц
    tape2 = cmp.proxy(listOfTapes())
    local lengts = {} -- Хз зачем
    if not tape1 or not tape2 then -- Если кассетниц менее 2х
    	OE.log("Not enough tapes")
    	return false
    end
    function Start()
    	tape1.play()
    	tape2.play()
    end
    
    function Update() -- Каждый кадр мы проверяем
    	if tape1.getPosition() >= len2 then -- не закончилось ли аудио
    		tape1.stop()
    		tape2.stop()
    		OE.exit() -- И если да — останавливаем звук и выходим
    		-- BSOD picture, sound, crash system
    	end
    end
    
    function Pause()
    	tape1.stop()
    	tape2.stop()
    end
    Resume = Start
    function Wipe()
    	tape1.seek(-math.huge)
    	tape2.seek(-math.huge)
    	local k = tape1.getSize()
    	for i = 1, k + 8191, 8192 do
    		tape1.write(empty)
    		tape2.write(empty)
    	end
    	tape1.seek(-math.huge)
    	tape2.seek(-math.huge)
    end
    function Dissolve()
    	Pause()
    	Wipe()
    end
    onApplicationExit = Dissolve -- При стандартном выходе также останавливаем и очищаем кассету
    
    Dissolve()
    tape1.seek(-math.huge)
    tape2.seek(-math.huge)
    tape1.write(getFile('Inst.dfpwm')) -- Записываем инструментал
    len1 = #getFile('Inst.dfpwm')
    OE.Storage.unloadFile("Inst.dfpwm") -- Выгружаем его из памяти
    
    tape2.write(getFile('Voices.dfpwm')) -- Делаем тоже самое с голосами типо
    len2 = #getFile('Voices.dfpwm')
    OE.Storage.unloadFile("Voices.dfpwm")
    
    tape1.seek(-math.huge)
    tape2.seek(-math.huge)

     

    Получается, все старые проекты работать не будут. Список изменений.. Большой. Если кратко:

    Изменён рендер в очередной раз, тотально. Теперь он быстрей и работает на нашем движке Matrix, который можно выдернуть из движка прям так и использовать в своих сторонних проектах.

    Добавлена поддержка сети, который точно также можно вырвать. У него еще есть OpenOS версия!! Просто измените пару строк в получении евентов и добавлении слушателей.
    Добавлены компоненты: спрайт, кнопка(Как поставить кнопку, можете узнать в Test.app/Main.lua)
    Все модули перенесены в отдельную для этого папку.
    Самое модное: использование скриптов. Вы могли заметить, что мы ставим глобальные переменные и забираем их из, казалось бы, ниоткуда.
    Все скрипты теперь таблица. Глобальные переменные можно получить по ней. Таблицы привязываются к объекту. Следовательно, можно сделать так:

    OE.CurrentScene.Objects[1].Render.setColor(math.random(0,0xFFFFFF))

    Или из самого скрипта:

    Object.Render.setColor(math.random(0xFFFFFF))

    Весь рендер перенесён с screen библиотеки на сырые вызовы гпу. С матриксом это не такая проблема, если рендер стоит в режиме perObject. Следовательно, был исправлен воистину тупой баг, что на прозрачных пикслеях изображения не оставались символы, из-за чего прозрачностью обладал только задник пикселя, а символ оставался пробелом, кушая концепт прозрачности.

    Проблемы:

    Слои в Render.layers никак не связаны, как бы это странно не звучало. Придётся придумать альтернативу дублированию библиотеки и рисовать в иерархии, ибо если, например, изменится 1й слой, пиксели на месте 2го исчезнут, ибо они буквально на другом холсте и не считаются для колайда и он считает, что всё ок.
    Главная проблема: лаги. Из-за отрисовки изображения выяснилось, что рисовать такой большой спрайт даже в буфере — дорого. Очень. Идея для фикса уже есть, но, всё же, исправит ситуацию он не сильно, ибо всё сейчас упирается в скорость цикла.

    Такие пироги.

    Вот видео, например:

     


  3. В 11.01.2025 в 22:00, nonvex сказал:

    Как автоматически при запуске системы монтировать дискету по адресу в /home/storage?

    Создаём файл autorun.lua в / на дискете или желаемом диске:

    require('filesystem').mount(..., '/home/storage')

    Об этом и других методах, таких как изменение названия диска, можно найти тут.


  4. Ответ: никак. Оно смотрит не буквальные комплектующие(Могло бы оно), а их характеристики. Именно: разрешение экрана и глубину цвета. У планшета это 80 на 25, когда у 3 тир компьютера 160 50.
    Можно обойти это собственным щиткодом, но, наверное, не зря там стоит такое ограничение. Картинка будет насколько малой, что кнопки будут наслаиваться.
    Если, кстати, перевести то, что оно от нас просит, оно требует тир 3 видеокарту и экран, коим не обладает ни один планшет.

    • Нравится 1

  5. Да, оставив мою конструкцию с event.listen можно использовать вашу изначальную программу, с мизерными корректировками.

    Оптимизация, применённая мною: вместо перебора каждого пользователя в списке и сравнения его с тем, что дало событие, лучше сделать "Есть ли имя игрока в списке разрешённых? Да- event.timer, который откладывает выполнение кода, отключит только что включённый редстоун."
    Редактируя ваш код ранее, можно прийти к такому решению:

    Скрытый текст
    
    local users = {}
    local userDataFile = '/userdataOpenDoors.txt'
    local configFile = '/configOpenDoors.cfg'
    local event = require('event')
    local setOutput = require('component').redstone.setOutput
    
    local handle = io.open(configFile,'r')
    local config = require('serialization').unserialize(handle:read(math.huge)) or {sleepTime = 1}-- Загружаем конфиг
    handle:close()
    
    local handle = io.open(userDataFile,'r')
    while true do -- Загружаем пользователей
      local name = handle:read()
      if not name then 
        break
      else
        users[name] = true
      end
    end
    handle:close()
    
    local listener = event.listen("motion", function(_, _, _, _, _, username) -- Слушаем в потоке движение
      if users[username] then
        setOutput(1,15)
        event.timer(config.sleepTime, function() setOutput(1,0) end)  -- Откладываем выполнение кода в поток
      end
    end)
    
    print("Введите ники игрока(ов) для доступа к двери или exit - для выхода")
    while true do
        local inp = io.read()
        if inp == "exit" then
            event.cancel(listener)
            os.exit()
        elseif inp == "config" then
            print("Для изменения параметра напишите его название. Чтобы выйти из конфига впишите exit.")
            print("sleepTime - Задержка сигнала: " .. config.sleepTime)
            while true do
                inp = io.read()
                if inp == "exit" then
                    break
                elseif string.sub(inp, 1, 9) == "sleepTime" then -- Если начало вырожения значение одной из переменных в конфиге
                    local num = tonumber(string.sub(inp, 10, #inp)) -- Вырезаем и трансформируем её в цифру
                    if num == nil then
                        print("Введено не число!")
                    elseif num <= 0 then
                        print("Введено число меньше нуля!")
                    else
                        config.sleepTime = num
                        local handle = io.open(configFile,'w')
                        handle:write(require('serialization').serialize(config)) -- Сохраняем конфиг
                        handle:close()
                        print("Значение " .. num .. " сохранено.")
                    end
                else
                    print('Неизветный параметр!')
                end
            end
        else
            users[inp] = true
            print('Добавлен пользователь ' .. inp .. '!')
        end
    end

     

    Не уверен, стоит ли оставлять то, что любой неверный ввод с клавиатуры превратиться в нового пользователя.
    Теперь переменные в конфиг ставить: "sleepTime n", на пример: "sleepTime 12.5". Они так же сохраняются в файл. Сохранять пользователей я не стал, ибо их удалить нельзя из программы напрямую, что может создать геморрой. Тем не менее из старта программы они всё еще зачисляются, что означает, что вы можете не прописывать там себя и ваших союзников каждый раз. Сильно откланяться от вашей программы не стану, поэтому далее, как поступать, смотрите сами


  6. Кхм. Я сказал, что оно черпает конфиг и дата базу пользователей из файла? Вы создали эти файлы? Пропишите к ним путь, он в переменных в первых же строках кода.
    Дата база пользователей- один ник, одна строка. На каждую строку свой ник, суть ясна.

    Username
    Username2
    Thrid_User_Name


    Конфиг- таблица. Сейчас это:

    {sleepTime = 1}

     


  7. Предлагаю такой вариант программы:

    local users = {}
    local userDataFile = '/userdataOpenDoors.txt'
    local configFile = '/configOpenDoors.cfg'
    local event = require('event')
    local setOutput = require('component').redstone.setOutput
    
    local handle = io.open(configFile,'r')
    local config = require('serialization').unserialize(handle:read(16000)) or {sleepTime = 1}-- Загружаем конфиг
    handle:close()
    
    local handle = io.open(userDataFile,'r')
    while true do -- Загружаем пользователей
      local name = handle:read()
      if not name then 
        break
      else
        users[name] = true
      end
    end
    handle:close()
    
    local listener = event.listen("motion", function(_, _, _, _, _, username) -- Слушаем в потоке движение
      if users[username] then
        setOutput(1,1)
        event.timer(config.sleepTime, function() setOutput(1,0) end)  -- Откладываем выполнение кода в поток
      end
    end)
    
    while true do
      local input = io.read() -- Слушаем пользователя
      if input == 'exit' then
        event.cancel(listener)
        return true
      end
    end

    Здесь мы загружаем конфиг и базу пользователей из файла, что исключает потребность каждый раз заново прописывать их.

    Так же здесь используется event.listen, который не будет блокировать io.read, как и event.timer. Каждый таймер считается отдельно


  8. Всё на скриншоте. Код соответственно:

    -- /OpenGames 2/Test.app/Main.lua
    local scriptPath = string.gsub(require('System').getCurrentScript(),'/Test.app','')
    local code = require('filesystem').read(scriptPath)
    local args = {...}
    print(require('System').getCurrentScript(),scriptPath)
    _, args = require('System').parseArguments(table.unpack(args))
    local OE = load(code,scriptPath,args.loadMode or 't')()
    ...
    -- /OpenGames 2/Main.lua
    ...
    local OE = {
        root = string.gsub(System.getCurrentScript(), 'Main.lua', ''),
        Time = {
    ...
    }
    print(OE.root,System.getCurrentScript())
    OE.huge = 2147483647
    ...

    image.png.088ee27917759b551d0093ac90036e95.png

     

    Если запустить точечно скрипт, вызывающий ошибку:
     image.png.3234064bbcc34a7740e4cdc46b894978.png 

    "done!" - запустилось и код дошёл до конца к return


  9. Я говорил выше:

    Цитата

    Если закомментировать удаление сервера

     .. то оно не выдаёт ошибок, а если оставить всё как есть (На первом скриншоте print, 3 строки и server = nil), то ошибка получится.
    Ошибка остаётся как возможная, ибо тот код, который я запускал для её получения уже удалён. Ладно, поработаем, может еще увижу её..


  10. Здравия! В названий всё: когда удаляешь хандлер, он не удаляется сразу, от чего всё портит.

    Сам код. server.timeId и server.eventId создаются ранее методом event.addHandler:

    Скрытый текст

    Создание:

    image.png.518d70e8b96a839a8f94bd64c5f88fdb.png

    Уборка:

    image.png.6392870cb317f32a7bd42909f0fa9b14.png

    То, что выдаёт ошибка:

    Скрытый текст

    image.png.5fe465d944e8939c6d0dea5c6975c2ee.png


    Если закомментировать удаление сервера:

    Скрытый текст

     

    image.png.cac2a6fc21f275bb7b5da4a8010ad99f.png

     

    Ну и как быть? Спрашивал в irc в дискорде, пусто.


  11. Согласен! Будет легче, если по всей местности расставить датчики движения. Или область большая? Просто несколько дронов- лагодром. Если один- медленно. А тут все датчики подключил к одной серверной стойке. Повесить их сверху, радиус у них 8 блоков, код я уже спланировал так, что 99% времени это простой (Ожидание сущности). Вести отчёты, когда кого засекли, статистику как часто какие мобы появляются...
    Редстоун включается дистанционно, на другом краю базы?


  12. Ну в принципе, можно попробовать его написать. Как допишу своё, буду тыкаться в это, если не найдётся. На форуме отрыл IDE-шку, но не уверен в её актуальности и стабильности, да и с таким-же подходом можно и в акелпаде всё верстать.

     


  13. Ладно, потыкав я понял что в executableForFrame я записал еще и системный скрипт для обработки сообщений модема. У него нету объекта, т.к. он и не нужен. А есть наш, ванильный скрипт у которого есть объект. На первом скриншоте видно как там сперва мега-таблица объекта, и после пустое \n. \n и есть системный скрипт, у которого нету объекта. Из-за того что он обрабатывается на ряду с обычными, а у него нету объекта оно нас мгновенно выкидывает, что означает что этот топик летит в корзину из-за намудрённой логики и фатальной ошибки автора(Когда я стирал текст с input-а с 50 кадров спускалось до 14, исправив ошибку таблиц, я обнаружил пустой отладочный print в мета-таблице того самого объекта. Кадры теперь теряются не так фатально, до 30.)..


  14. Привет, в переменной v есть objectThatCalls, и print и if это подтверждают. Но когда мы пытаемся что-либо достать из неё, на пример Scale то оно выдаёт что objectThatCalls вовсе не-было

    Где создаётся:

    table.insert(Scripts.ExecutableForFrame,{Script = script,objectThatCalls = objectThatCalls})

    Где используется:

    ...
        for i,v in  pairs(ExecutableForFrame) do
            print(v.objectThatCalls)
            if v.objectThatCalls then
                System.call(v.Script.Update,v.objectThatCalls,OE)
            end
        end
    ...
    Скрытый текст

    image.png.29549a894c4ad5032ef22c1a982923ca.png

     

    Но..

    ...
        for i,v in  pairs(ExecutableForFrame) do
            print(v.objectThatCalls.Scale)
            if v.objectThatCalls then
    ...

     

    Скрытый текст

    image.thumb.png.a4ab9d9a6dadb52b99da5a17f130dbf2.png

    Тут я вообще в замешательстве, всё везде существует но всё ровно ругается.


  15. 3 минуты назад, BenniShifer919 сказал:

    И да, если не сложно, не знаешь где можно найти таблицу символов и их код для ОС?

    Некоторое уже не актуально, показывает интересные символы.

    На пример человечек: unicode.char(0xEC23)

    На форуме так-же была найдена программа которая процедурно показывает символы, то-есть всегда актуальна.

     


  16. Привет, по поводу ревизий для OpenCompuetrs.

    Она работает, но до определённого условия, либо много уйти в сторону, либо гэйм овер:

    Скрытый текст

    Только по ссылке

    https://youtu.be/whsGVMua5qo

    В общем: Цветовая палитра снизу сливается с текстом. Жёлтый и белый особенно. Так-же было-бы ну прикольно сделать так что-бы та полоска на которой текст уходила вместе со значениями. Меньше значение- меньше полоска, наглядно понимать когда тебе конец. В уникоде есть сплошной символ, закрашенный пиксель, и есть решето (Куча точек). Залить сплошным стены а то что там серое на дороге сделать точками. Не знаю как с этим в СС.

    Почешу репу что можно сделать с ошибками...

    А еще было-бы неплохо начать загружать всё на GitHub т.к. там есть удобный GitHub Desktop (2 кнопки и обновление выкачено), можно посмотреть историю версий да и ссылка будет всегда одинаковая.

    • Одобряю 1
    • Спасибо 1

  17. Короткий вариант в одну строку:

    print(require("serialization").serialize(require("component").me_controller.getItemsInNetwork({"Thanumcraft:ItemWhispEssence"}), math.huge))

    Стерилизация что-бы оно нам показала ту таблицу, которое оно вернёт. Фильтр в методе getItemsInNetwork задаётся таблицей.

    Для того что-бы узнать сколько всех видов эссенций у нас есть:

    local count = #me_controller.getItemsInNetwork({"Thanumcraft:ItemWhispEssence"})

    Посмотрите параметры которые предлагает нам список, на пример там есть count.


  18. Скрытый текст
    
    local users = {
      {"nick1","Admin"},
      {"nick2","Админ"},
      {"ТЕТС","Admin"},
      {"test","Admin"},
      {"Ну за ящиком этим","Admin"},
      {"За ящиком","User"}
    }
     
    local cmp = require("component")
    local computer = require("computer")
    local uni = require("unicode")
    local gpu = cmp.gpu
    local w,h = gpu.getViewport()
    local bridge = cmp.openperipheral_bridge
    bridge.clear()
    
    for i = 1, #users do
      bridge.addText(1,i*10,"[" .. string.rep(" ",uni.len(users[i][2])) .. "] - " .. users[i][1],0xFFFFFF)
      users[i][4] = bridge.addText(4,i*10,users[i][2],0xFFFFFF) 
      users[i][3] = bridge.addText(120,i*10,"SETUP",0x505050)
    end
    bridge.sync()
    
    gpu.setForeground(0xFFFFFF)
    gpu.set(1,1,"Information on glasses")
    
    local function check()
      for ind = 1,#users do
        local name = users[ind][1]
        local rank = users[ind][2]
        local objectStatus = users[ind][3]
        local socialStatusObject = users[ind][4]
    
        if rank == "Admin" then
          socialStatusObject.setColor(0xFF0000)
        elseif rank == "Member" then
          socialStatusObject.setColor(0x0000FF)
        end
    
        if computer.addUser(name) then
          computer.removeUser(name)
          objectStatus.setColor(0x00FF00)
          objectStatus.setText("Online")
        else
          objectStatus.setText("Offline")
          objectStatus.setColor(0x999999)
        end
    
        bridge.sync()
      end
    end
     
    for ind = 1,#users do
      computer.removeUser(users[ind][1])
    end
    gpu.setResolution(22,1)
    
    while true do
      check()
      local e = ({require("event").pull(5,"key_down")})[4]
      if e == 29 or e == 157 then -- Ctrl Выход
        gpu.setResolution(w,h)
        os.exit()
      end
    end

     

    Ну вот как-бы. Убрал вывод на монитор, привинтил всё к окам. Еще можно экономить на бюджетах вызовах, но в данном случаи это не критично. Еще имейте ввиду что у очков возможно(Не проверял) есть потолок виджетов на экране. 1-н пользователь это 3 виджета. Обусловлено окрашиванием текста. Если вам не принципиальны цвета, можно сделать монохромно в 1-н виджет. Ну вот собственно и всё (❁´◡`❁)

    • Нравится 2

  19. 18 часов назад, eu_tomat сказал:

    Тут есть смыл рассказать о возможностях этого движка, зачем он нужен, кому он может пригодиться, и как им пользоваться.

    А, да, извините.
    Итак, для того что-бы им вообще можно было воспользоваться нужно загрузить Main.lua как библиотеку. Это делается примерно так:

    local OE = loadfile("/OpenGames 2/Main.lua")()

    Поскольку он "модульный" можно менять расположение главной папки. Оно будет записано в System.getUserSettings.OpenGames2EnginePath (Если вы устанавливали с установщика).

    Сделаем для примера радужный квадрат который по клику переместиться к курсору.

    Создадим наш квадрат, это панель. Существует множество разных объектов которые подвластны нам, такие как ComboBox, Button, Input, Switch и т.д.

    local obj = OE.createObject() -- Создаём объект которые сам добавляется в сцену.
    obj:setRenderMode(OE.Render.renderTypes.PANEL) -- Рендерить как панель.
    local matID = obj:addComponent(OE.Component.componentTypes.MATERIAL) -- Что-бы у нашего квадрата был цвет
    obj.Transform.Scale.Width = 10 -- Размер длинны
    obj.Transform.Scale.Height = 5 -- Размер высоты, в два раза меньше длинны

    После сделаем окно и покажем пользователю:

    OE.Project.Window.Color = 0x505050
    OE.Project.Window.Width = 160
    OE.Project.Window.Height = 50
    OE.Project.Window.Title = "Это куб"
    OE.initWindow() -- Принять нынешние значения и пересоздать окно с ними

    Создадим файл для нашего скрипта и добавим его к нашему объекту:

    local function update(...)
    	local args = {...}
      	args[1].Components[matID].Color.First = math.random(0x0,0xFFFFFF) -- Именение цвета. Поскольку update вызываеться asap оно бует менять его довольно выстро. Что нам вроде-бы и надо.
    	if args[2].lastEvent[1] == "drag" or args[2].lastEvent[1] == "drop" or args[2].lastEvent[1] == "touch" then -- lastEvent это буквально последнее событие
       		args[1].Transform.Position.x = args[2].lastEvent[3]-math.ceil(args[1].Transform.Scale.Width/2)-args[2].Render.Window.x -- args[1] Это объект от имени которого запустился скрипт. args[2] это OE для вызываемых скриптов. То-есть мы находим середину для x относительно того куда мы кликнули, ..
        	args[1].Transform.Position.y = args[2].lastEvent[4]-math.ceil(args[1].Transform.Scale.Height/2)-args[2].Render.Window.y -- .. как и для y
    	end
    end
    OE.Storage.createFile(OE.CurrentScene.Storage,'Script.lua',{Update=update})
    obj.Components[obj:addComponent(OE.Component.componentTypes.SCRIPT)].file = "Script.lua" -- addComponent вернёт номер компонента в obj.Components, а мы его сразу подхватываем и изменяем значение file для скриптa на наш файл. Оно найдёт его везде, в файлах сцены или файлах проекта.
    OE.Script.Reload() -- Перезагружаем все наши скрипты добовляя наш.

    Добавим нашу милашку к рендеру и готово

    obj:addToRender()

    Итог:

    local OE = loadfile("/OpenGames 2/Main.lua")()
    local obj = OE.createObject()
    obj:setRenderMode(OE.Render.renderTypes.PANEL)
    local matID = obj:addComponent(OE.Component.componentTypes.MATERIAL)
    obj.Transform.Scale.Width = 10 
    obj.Transform.Scale.Height = 5 
    OE.Project.Window.Color = 0x505050
    OE.Project.Window.Width = 160
    OE.Project.Window.Height = 50
    OE.Project.Window.Title = "Это куб"
    OE.initWindow()
    local function update(...)
    	local args = {...}
      	args[1].Components[matID].Color.First = math.random(0x0,0xFFFFFF)
    	if args[2].lastEvent[1] == "drag" or args[2].lastEvent[1] == "drop" or args[2].lastEvent[1] == "touch" then
       		args[1].Transform.Position.x = args[2].lastEvent[3]-math.ceil(args[1].Transform.Scale.Width/2)-args[2].Render.Window.x
        	args[1].Transform.Position.y = args[2].lastEvent[4]-math.ceil(args[1].Transform.Scale.Height/2)-args[2].Render.Window.y
    	end
    end
    OE.Storage.createFile(OE.CurrentScene.Storage,'Script.lua',{Update=update})
    obj.Components[obj:addComponent(OE.Component.componentTypes.SCRIPT)].file = "Script.lua"
    OE.Script.Reload()
    obj:addToRender()

    Теперь давайте сделаем тоже самое в сырую...

    Итог:

    local GUI = require("GUI")
    local System = require('System')
    local wk,win = System.addWindow(GUI.titledWindow(1,1,160,50,'Это куб',true))
    win.backgroundPanel.colors.background = 0x505050
    win.titlePanel.colors.background = 0x505050
    local panel = win:addChild(GUI.panel(1,1,10,5,0x0))
    wk.eventHandler = function(_,_,...)
      local args = {...}
      panel.colors.background = math.random(0,0xFFFFFF)
      if args[1] == 'touch' or args[1] == 'drop' or args[1] == 'drag' then
        panel.localX = args[3]-math.ceil(panel.width/2)-win.localX
        panel.localY = args[4]-math.ceil(panel.height/2)-win.localY
      end
    end
    win:draw()

    По символам он меньше. 

    В обоих OE есть редактор в котором можно наглядно отредактировать расположение объектов, а в сыром запускай кучу раз.

    Минусы и плюсы использование движка:

    + Просто для освоения

    + Наглядно

    - Грамоздко (большие файлы)

    - События медленные (Разница между сырым и движком видна, причём очень сильно. Не знаю с чем это связано.)

    Можно еще сравнить Unity и какой ни-будь pygame. Разница размера файлов колоссальная, но большинство используют юнити т.к. в pygame и я не очень разобрался...

    Я не очень понимаю как находить сильные и слабые стороны в своём-же продукте...

    • Нравится 1

  20. Привет! Последние 2 месяца я разрабатывал OE 2. Это проект очень схожий с Unity имея дочерний замысел с OpenGames где после изменения объекта не надо писать draw()...

    Он еще не готов, я хотел релизнуть после того как я его доделаю, но случилось не предвиденное. Из AppMarket-a была удалена либа opengames, что напрямую убивает весь первый движок т.к. оно в зависимостях, и в зависимостях всех дочерних приложений. Мне удалять это было не зачем, да он был поломанный, там объект кнопки не работал. Но это как-то тупо сносить один элемент из 2-, не так-ли?

     

    "Какая вообще разница?" Этот проект остался не доделанным, движок готов, установщик движка тоже. Не готов только редактор. Мне симпатизирует этот проект, но я прекращу (или сильно дестабилизирую) свою собственную поддержку данного проекта т.к. не исключаю случайное исчезновение моих продуктов в макрете.

     

    Так-же одна из причин это полу-мёртвое комьюнити. За пол года существования первого OpenGames им увлёкся только один человек. И то всё его творчество (хоть и довольно спорное (вирусы(удаление одной папки\файла))) хоть и было довольно спорное, но было удалено самим им. А зачем удалять свой продукт?

    Движок не нашел людей, а зачем разрабатывать предложение, если нету спроса.


    Это репозиторий проекта, в нём есть подробная (имхо) вики которая поясняет как работать в движке из скрипта. Так-же есть 2 примера которые могут перекидываться сообщениями между друг-другом. Там целая куча файлов которая добавляет функций в движок с определённой задачей.

     

    Цель этого поста: сказать что уже есть неплохие(имхо) наработки графического движка, если кто-то уже собрался что-то делать.

     

    Скриншот первой программы для того что-бы разбавить текст:

    Скрытый текст

    image.thumb.png.cabaf52854f2e020c399f0fb56c4c0bc.png

     


  21. Ладно, свою ошибку я так и не понял. Моё решение:

    win:resize(160,50) -- Итоговый размер окна
    win.titleLabel.text = lc.LabelEditor -- Имя окна
    winMask:remove() -- Контейнер для тех элементов которые участвовали в первой части программы, 
    --потому-что если мы удалим чайлды win(основное окно) то оно 
    --удалит ваще всё и оставит прозрачный полиэтиленовый пакет, а строить окно заново мне не очень хочеться. 
    --Проще было-б его пересоздать, но мы выяснели ранее что не можем так сделать(
    win.localX = 1 -- В моём случаи длинна 160, поетому шоб оно влезно на фулскрин ставим его в начало экрана
    win.localY = 1 -- Так-же и с высотой
    itemSettings:remove() -- Шляпа привязанная к menu. Причина почему не removeChildren и почему отдульно каждый 
    --элемент: таже что и с окном
    loadfile(hubPath..'/Editor.lua')(Projects[ChoosedProject], {wk,win,menu}) -- Ну и грузим его. Сам едит тот-же

     


  22. local args = {...}
    print(pcall(function()
      ...
      29 local Project = fs.readTable(fs.removeSlashes(args[1]..'/.Data.dat'))
      ...
      31 local wk, win, menu = System.addWindow(GUI.titledWindow(1,1,160,50,lc.Editor, true))
      32 local contextWindowMenus = menu:addContextMenuItem(lc.createWindows)
      ...
    end))

    image.png.8ae164eebf99a8cb27e5af3a5408c6e4.png

     

    Создал окно, захотел привязать к меню контекст меню, но не получилось. Запускалось через pcall потому-что иначе system fatal error: nil.

    Не знаю что с этим делать. Должно работать, но не работает. Сам этот файл вызывается из другого файла через loadfile:

    local Projects = {'/Applications/New project/'}
    local ChoosedProject = 1
    ...
    loadfile('/Editor.lua')(Projects[ChoosedProject])
    ...

     

×
×
  • Создать...