Вот есть мой старый код, ну скажем алгоритм на Jass, который вполне себе исправно работает
Jass код
//передаточная функция я просто вызываю её далее по коду если хочу что либо куда либо передвинуть ForceUnit( юнит, угол ,дистанция, скорость за тик 0,04, флаг (дополнительный параметр))
function ForceUnit takes unit u,real a,real d,real s,integer flag returns nothing
if GetUnitMoveSpeed(u) >= 1 and IsUnitType(u, UNIT_TYPE_STRUCTURE) == false then
call GroupAddUnit(gforce, u)
call SaveReal(udg_hash, GetHandleId(u), StringHash("a"), a)
call SaveReal(udg_hash, GetHandleId(u), StringHash("d"), d)
call SaveReal(udg_hash, GetHandleId(u), StringHash("s"), s)
call SaveInteger(udg_hash, GetHandleId(u), StringHash("flag"), flag)
endif
endfunction

//далее просто перебирается группа и делаются действия
function MainForce takes nothing returns nothing
local unit u=GetEnumUnit()
local real a=LoadReal(udg_hash, GetHandleId(u), StringHash("a"))
local real d=LoadReal(udg_hash, GetHandleId(u), StringHash("d"))
local real s=LoadReal(udg_hash, GetHandleId(u), StringHash("s"))
local integer flag=LoadInteger(udg_hash, GetHandleId(u), StringHash("flag"))
local real x=GetUnitX(u)
local real y=GetUnitY(u)
call SaveReal(udg_hash, GetHandleId(u), StringHash("d"), d - s)
//call BJDebugMsg(R2S(s))
//////ДОПОЛНИТЕЛЬНЫЕ флаги при движении
if flag == 1 then // босс эффект воды
//call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetUnitX(u),GetUnitY(u)))
endif

if flag == 2 then // стоп
call IssueImmediateOrder(u, "stop")
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl", GetUnitX(u), GetUnitY(u)))
//call BJDebugMsg("2")
endif

////Условия прекращения движения
if d <= 0 or Out(MoveX(x , s * 2 , a) , MoveY(y , s * 2 , a)) == false or GetPointZ(x , y) <= GetPointZ(MoveX(x , s * 2 , a) , MoveY(y , s * 2 , a)) - 30 then
if IsUnitType(u, UNIT_TYPE_HERO) == false then
call FlushChildHashtable(udg_hash, GetHandleId(u))
//call BJDebugMsg("BREAK")
endif

call GroupRemoveUnit(gforce, u)
endif //конец условий прекращения движения

// движение выполняется всегда за исключением условий прекращения движения
call SetUnitX(u, MoveX(x , s , a))
call SetUnitY(u, MoveY(y , s , a))
//call killtree(u,x,y,70)
//call BJDebugMsg("3")
set u=null
endfunction
Код можно не смотреть особо там крутится группа на таймере, в группе у юнита извлекаются на хештаблицах параметры для движения, но ОНB висят НА ЮНИТЕ
Как сделать что-то подобное на LUA?
Как сделать каждое толкание на отдельном таймере я понял, а как крутить группу на 1 таймере? (это тоже в принципе понятно)
Но что щас выступает аналогом load*handle?

Принятый ответ


А еще у меня там местами xpcall отладочный висит, там где я ловил косяки и не убрал его потом, без него код чуть проще становится, он нужен только для отлова ошибок и в моем случае вывода их на экран.

Это печально, новые костыли, а я уже обрадовался, что ничего обнулять и чистить не нужно =(
Не нужно обнулять локалки в функциях и все что ограниченного срока жизни, но всякие системы хранения данных они же либо глобальные либо в "локальном" скопе всей карты и, соответственно, живут пока загружена карта - там вручную подчищать надо, естественно. Можно делать это полу-автоматически как у меня, можно вручную когда становится известно что данные уже не нужны. Можно было бы использовать таблицу со слабыми ключами, но тогда возникает вопрос что использовать в качестве ключей - можно прямо на самого юнита вешать, чтобы когда игра его удалит из памяти, таблица почистилась сборщиком мусора, но нет гарантии что это будет работать и не будет вызывать десинки т.к. сборщику мусора синхронизация не указ.
Bergi_Bear:
но мне можно себе такой вариант забрать или надо ещё что-то дополнительно записать?
У меня библиотека отгорожена только ради того чтобы автоматизировать сборку мусора и создание новых таблиц при обращении по хендлу на который ничего нет.
Минимальный вариант, наверно, такой:
local HandleData = {} -- я использую локальные переменные в скопе карты, при этом важен порядок но доступ к ним идет чуть быстрее чем в глобальном скопе

function ForceUnit (u,a,d,s,flag)
  local data = HandleData[GetHandleId(u)]
  if (data==nil) then data = {} HandleData[GetHandleId(u)] = data end
  data.a = a
  data.d = d
  data.s = s
  data.flag = flag
  GroupAddUnit(gforce, u)
end
-- --------------
ForGroup(gforce, function()
  local u=GetEnumUnit()
  local h=GetHandleId(u)
  local data = HandleData[h]
  local a=data.a
  local d=data.d
  local s=data.s
  local flag=data.flag
  ...
end
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
1
24
5 лет назад
Отредактирован prog
1
Два варианта
1 - массив-таблица с индексами по хендлу и еще одной таблицей в качестве значений
2 - передача переменных через кложуры (не твой случай ведь тебе на юнита данные вязать надо т.к. таймер один на всех)
Оба способа есть в примере ниже, если сможеш разобраться в том что там происходит.
немного моего сырого кода из тестовой карты
--========== Common Utils start ====================

local function RAW(id) --есть более эффективный вариант, но пока и так сойдет
  return id:byte(1) * 0x1000000 + 
         id:byte(2) * 0x10000 + 
         id:byte(3) * 0x100 +
         id:byte(4)
end

local function ehandler( err )
  print( "ERROR:", err )
end

--========== Common Utils end ====================
--========= Libraries start ==============

local Libraries = {libs = {}}

function Libraries:Init()
  print("Libraries Init")
  for id,lib in ipairs(self.libs) do
    if (lib.Init) then
      print("Pre Init "..lib.name)
--      lib:Init()
      xpcall(function() lib:Init() end,ehandler)
      print("Post Init "..lib.name)
    else
      print("Skip Init "..lib.name)
    end
  end
  for id,lib in ipairs(self.libs) do
    if (lib.Final) then
      print("Pre Final "..lib.name)
--    lib:Final()
      xpcall(function() lib:Final() end,ehandler)
      print("Post Final "..lib.name)
    else
      print("Skip Final "..lib.name)
    end
  end
end

function Libraries:new(name,dep)
  local lib = {}
  lib.name = name
  lib.dep = dep
  table.insert( self.libs, lib )
  self[name] = lib
  return lib
end

--========= Libraries end ==============
--============ CustomDataLibrary start ============

local DataStorage = Libraries:new("DataStorage",{})
function DataStorage:Reset(h)
  print("data reset "..h)
  self[x] = {}
  return self[x]
end
function DataStorage:Purge(h)
  print("data purge "..h)
  self[h] = nil
end
function DataStorage:new (o)
  o = o or {}
  o.Reset = DataStorage.Reset
  o.Purge = DataStorage.Purge
  setmetatable(o, DataStorage)
  DataStorage.__index = function (table, key) table[key] = {} return table[key] end
  return o
end

local HandleData
local ProtoData

function DataStorage:Init()
    HandleData = DataStorage:new()
    ProtoData = DataStorage:new()
end

function DataStorage:Final()
  local clean = Libraries.CleanUp
  table.insert( clean.DeathHandlers,function(u,h) HandleData:Purge(h) end)
  table.insert( clean.RemoveHandlers,function(u,h) HandleData:Purge(h) end)
end

--============ CustomDataLibrary end ==============
--============ CleanUpLib start ===============

local CleanUp =  Libraries:new("CleanUp",{})
CleanUp.DeathHandlers={}
CleanUp.RemoveHandlers={}
CleanUp.RemoveUnitBase=nil

function CleanUp.OnDeath()
  local unit u = GetTriggerUnit()
  local id = GetHandleId(u)
  for n,h in ipairs(CleanUp.DeathHandlers) do h(u,id) end
end

function CleanUp.OnRemove(u)
  local id = GetHandleId(u)
  for n,h in ipairs(CleanUp.RemoveHandlers) do h(u,id) end
  return CleanUp.RemoveUnitBase(u)
end

function CleanUp:Init()
  local trig = CreateTrigger()
  TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_DEATH )
  TriggerAddAction( trig, CleanUp.OnDeath )

  self.RemoveUnitBase=RemoveUnit
  RemoveUnit = self.OnRemove
end

function CleanUp:Final()
  table.insert( self.DeathHandlers,function(u,h) print("Final Unit Death Handler "..GetUnitName(u)) end)
  table.insert( self.RemoveHandlers,function(u,h) print("Final Unit Remove Handler "..GetUnitName(u)) end)
end

--============ CleanUpLib end ===============
--============ TestLib start ===============

local TestLib = Libraries:new("TestLib",{})

function TestLib.TestGroup(g)
  print("group test start")
  xpcall(function()
    local a = 42
    local i = 0
    ForGroup(g, function()
      xpcall(function()
        local u = GetEnumUnit()
        print('i='..i..' a='..a.." "..GetHandleId(u).." "..GetUnitName(u))
        i = i +1
      end,ehandler)
    end)
  end,ehandler)
  print("group test end")
end

TestLib.TimerCounter=0
function TestLib.TestTimers()
  local t1 = CreateTimer()
  local i = 0
  local a = 42
  local x = TestLib.TimerCounter
  print('start timer '..x)
  TimerStart(t1, 1, true, function()
    print('timer '..x..' tick '..i..' a='..a)
    i = i +1
  end)
  TestLib.TimerCounter = TestLib.TimerCounter+1
end

function TestLib.TestUnit(u)
  print("unit test start")
  print(u)
  local h = GetHandleId(u)
  print("handle "..h)
  local data = HandleData[h]
  if (data.num==nil)then
    data.num=0
  end
  data.num = data.num+1
  BlzSetUnitRealField(u, UNIT_RF_DEFENSE, data.num)

  print("unit test end")
end

--============ TestLib end ===============
0
32
5 лет назад
0
prog, спасибо сам тоже только что до этого дошёл, даже всё работает
prog:
1 - массив-таблица с индексами по хендлу и еще одной таблицей в качестве значений
примерно так сделал:
------ новая толкалка
do
af={}
df={}
sf={}
flagf={}
gforce=CreateGroup()

function ForceUnit (u,a,d,s,flag)
GroupAddUnit(gforce, u)
af[GetHandleId(u)]=a
df[GetHandleId(u)]=d
sf[GetHandleId(u)]=s
flagf[GetHandleId(u)]=flag
end


TimerStart(CreateTimer(), 0.04, true, function()
ForGroup(gforce, function()
local u=GetEnumUnit()
local h=GetHandleId(u)
local a=af[h]
local d=df[h]
local s=sf[h]
local flag=flagf[h]
--action
local x=GetUnitX(u)
local y=GetUnitY(u)


df[h]=d-s
--Условия прекращения движения
if d <= 0 or Out(MoveX(x , s * 2 , a) , MoveY(y , s * 2 , a)) == false or IsUnitDeadBJ(u) then --or GetPointZ(x , y) <= GetPointZ(MoveX(x , s * 2 , a) , MoveY(y , s * 2 , a)) - 30
 GroupRemoveUnit(gforce, u)
if flag==0 then
KillUnit(u)
end
end 

-- движение выполняется всегда за исключением условий прекращения движения
SetUnitX(u, MoveX(x , s , a))
SetUnitY(u, MoveY(y , s , a))



---------
end)--group    
end)--timer
end
0
24
5 лет назад
0
Bergi_Bear, у тебя по таблице под каждое значение, а в моем варианте одна таблица в которой внутри по таблице на каждый хендл на который что-то прикручено. Мой вариант удобней в использовании т.к. все что связано с одним юнитом собрано в одном месте.
0
32
5 лет назад
0
prog, в любом случае свой вариант я хотя бы понимаю и это его главный плюс, но в понял тебя, можно же сделать многомерный массив
prog:
одна таблица в которой внутри по таблице на каждый хендл
Насчет удобства я пока не могу оценить ибо вообще ничего не понимаю, что происходит, но очищать ничего не надо? юнит умер, его записи остались в таблице, сборщик мусора все сделает?
тот самый сборщик о котором все говорят?
0
24
5 лет назад
0
На примере твоего кода - в моем варианте работа с данными будет выглядеть примерно так:
function ForceUnit (u,a,d,s,flag)
  local data = HandleData[GetHandleId(u)]
  data.a = a
  data.d = d
  data.s = s
  data.flag = flag
  GroupAddUnit(gforce, u)
end
-- --------------
ForGroup(gforce, function()
  local u=GetEnumUnit()
  local h=GetHandleId(u)
  local data = HandleData[h]
  local a=data.a
  local d=data.d
  local s=data.s
  local flag=data.flag
  ...
end

Насчет удобства я пока не могу оценить ибо вообще ничего не понимаю, что происходит, но очищать ничего не надо? юнит умер, его записи остались в таблице, сборщик мусора все сделает?
Сборщик сам не настолько крут, поэтому у меня там есть функции Purge и Reset для сноса данных из таблицы, а также целая либа CleanUp для перехвата смертей и удаления юнита, на которую либа хранения данных вешает свой хук в котором и подчищаются данные для таких юнитов.
0
32
5 лет назад
0
prog, ну да, через точку писать более удобней, чем через [скобочки], но мне можно себе такой вариант забрать или надо ещё что-то дополнительно записать?
пошёл пробовать
prog:
Сборщик сам не настолько крут, поэтому у меня там есть функции Purge и Reset для сноса данных из таблицы, а также целая либа CleanUp для перехвата смертей и удаления юнита, на которую либа хранения данных вешает свой хук в котором и подчищаются данные для таких юнитов.
Это печально, новые костыли, а я уже обрадовался, что ничего обнулять и чистить не нужно =(
2
24
5 лет назад
Отредактирован prog
2

А еще у меня там местами xpcall отладочный висит, там где я ловил косяки и не убрал его потом, без него код чуть проще становится, он нужен только для отлова ошибок и в моем случае вывода их на экран.

Это печально, новые костыли, а я уже обрадовался, что ничего обнулять и чистить не нужно =(
Не нужно обнулять локалки в функциях и все что ограниченного срока жизни, но всякие системы хранения данных они же либо глобальные либо в "локальном" скопе всей карты и, соответственно, живут пока загружена карта - там вручную подчищать надо, естественно. Можно делать это полу-автоматически как у меня, можно вручную когда становится известно что данные уже не нужны. Можно было бы использовать таблицу со слабыми ключами, но тогда возникает вопрос что использовать в качестве ключей - можно прямо на самого юнита вешать, чтобы когда игра его удалит из памяти, таблица почистилась сборщиком мусора, но нет гарантии что это будет работать и не будет вызывать десинки т.к. сборщику мусора синхронизация не указ.
Bergi_Bear:
но мне можно себе такой вариант забрать или надо ещё что-то дополнительно записать?
У меня библиотека отгорожена только ради того чтобы автоматизировать сборку мусора и создание новых таблиц при обращении по хендлу на который ничего нет.
Минимальный вариант, наверно, такой:
local HandleData = {} -- я использую локальные переменные в скопе карты, при этом важен порядок но доступ к ним идет чуть быстрее чем в глобальном скопе

function ForceUnit (u,a,d,s,flag)
  local data = HandleData[GetHandleId(u)]
  if (data==nil) then data = {} HandleData[GetHandleId(u)] = data end
  data.a = a
  data.d = d
  data.s = s
  data.flag = flag
  GroupAddUnit(gforce, u)
end
-- --------------
ForGroup(gforce, function()
  local u=GetEnumUnit()
  local h=GetHandleId(u)
  local data = HandleData[h]
  local a=data.a
  local d=data.d
  local s=data.s
  local flag=data.flag
  ...
end
Принятый ответ
0
32
5 лет назад
0
гарантии что это будет работать и не будет вызывать десинки т.к. сборщику мусора синхронизация не указ
я конечно лишь примерно представляю как это всё работает, но скорее всего не должно быть десинхов, если данные не использются больше, вроде бы как даже это логично, но будет десинх, если кривым кодом куда-то не туда обратится и попытаться получить какие либо данные
Такс, prog, не получается =(
HandleData={}
gforce=CreateGroup()

function ForceUnit (u,a,d,s,flag)
    print("start")
GroupAddUnit(gforce, u)
local datan = HandleData[GetHandleId(u)]
datan.a = a
datan.d = d
datan.s = s
datan.flag = flag
end


TimerStart(CreateTimer(), 0.04, true, function()
ForGroup(gforce, function()
local u=GetEnumUnit()
local h=GetHandleId(u)
local data = HandleData[h]
local a=data.a
local d=data.d
local s=data.s
local flag=data.flag
print("period")
Дебага с надписью период нет, значит даже таймер не стартует =(
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.