Всем привет! Мой вопрос собственно заключается в том, что правильно ли я сделал, если допустим есть способность кровотечение, которая вызывает кровотечение на юнитах. Суть в том, что допустим 10 юнитов получили кровотечение и получают урон, на 5 из них допустим через 2 секунды опять оказало действие кровотечение, а на тех, что не получили изначально получат через 1 секунду. Собственно сделать через один таймер кровотечение на группу юнитов с разными таймера их действия, чтоб кровотечение обновлялось, а не тупо стакалось на 100500 таймеров... Я понимаю, что нужно через переменную проверять и собсвтенно это сделал..Но вопрос в том, пойдет ли данная схема, если допустим несколько игроков запустят таймеры для себя, не будут ли сбиваться переменные передаваемые через функцию и вообще рабочая ли эта схема ? У меня вроде все работает...но хотелось бы узнать мнение экспертов )))
	local PS_DMG_PERC=.25

	local PS_GROUP={}
	local PS_TIMER_BLEED={}
	local PS_TIME_UNIT={}
	
PS_Opgh_FUNC=function(caster,caster_uid,target,target_uid)

		if PS_GROUP[caster_uid]==nil then

			local size
			local fg
			local id
			local damage

			PS_GROUP[caster_uid]=CreateGroup()
			PS_TIMER_BLEED[caster_uid]=CreateTimer()
			PS_TIME_UNIT[caster_uid]={}

			TimerStart(PS_TIMER_BLEED[caster_uid],1,true,function()

				damage=GetHeroStr(caster,true)*PS_DMG_PERC

				size=BlzGroupGetSize(PS_GROUP[caster_uid])

				print("7")
				if size==0 then
					DestroyGroup(PS_GROUP[caster_uid])
					PS_GROUP[caster_uid]=nil
					DestroyTimer(PS_TIMER_BLEED[caster_uid])
					PS_TIMER_BLEED[caster_uid]=nil
					PS_TIME_UNIT[caster_uid]=nil
					return
				elseif size>=1 then
					for i=size-1,0,-1 do

						fg=BlzGroupUnitAt(PS_GROUP[caster_uid],i)
						id=GetHandleId(fg)
						if UnitAlive(fg) and not BlzIsUnitInvulnerable(fg) then

							UnitDamageTarget(caster,fg,damage,false,false,ATTACK_PHYSICAL,DAMAGE_PHYSICAL,nil)

							PS_TIME_UNIT[caster_uid][id]=PS_TIME_UNIT[caster_uid][id]-1

							if PS_TIME_UNIT[caster_uid][id]==0 then
								GroupRemoveUnit(PS_GROUP[caster_uid],fg)
								PS_TIME_UNIT[caster_uid][id]=nil
							end
						else
							GroupRemoveUnit(PS_GROUP[caster_uid],fg)
							PS_TIME_UNIT[caster_uid][id]=nil
						end
					end
				end

				size=BlzGroupGetSize(PS_GROUP[caster_uid])
				if size==0 then
					DestroyGroup(PS_GROUP[caster_uid])
					PS_GROUP[caster_uid]=nil
					DestroyTimer(PS_TIMER_BLEED[caster_uid])
					PS_TIMER_BLEED[caster_uid]=nil
					PS_TIME_UNIT[caster_uid]=nil
				end
			end)
		end

		if PS_GROUP[caster_uid]~=nil then
			if not IsUnitInGroup(target,PS_GROUP[caster_uid])then
				GroupAddUnit(PS_GROUP[caster_uid],target)
				PS_TIME_UNIT[caster_uid][target_uid]=3
			else
				PS_TIME_UNIT[caster_uid][target_uid]=3
			end
		end
	end

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

Прежде всего, зачем по таймеру для каждого игрока, а тем более на каждого кастера, если можно обойтись одним таймером на всех?
Группы я бы тоже не хранил для каждого игрока, а вместо этого хранил бы по хендлу цели сколько осталось тактов кровотечения и от чьего имени наносить урон, а всех юнитов с кровотечением складывал бы в одну группу для всех.
Постоянное создание-удаление групп, в принципе, тоже не лучшая идея, лучше их чистить и повторно использовать.
Ну и я бы не стал использовать анонимную функцию в таймере - она тут не нужна, все отлично передается глобалками.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
1
24
5 лет назад
Отредактирован prog
1
Castiel, ты храниш все по хендлу кастера, а я предлагаю хранить данные по хендлу цели. Ты создаеш по одному таймеру для каждого кастера и по одной группе на каждого кастера и еще и удаляеш их каждый раз когда у кастера заканчиваются цели, я предлагаю использовать один таймер и одну группу на всех, причем без создания-удаления. разве что таймер можно стопать и рестартовать если очень хочется оптимизации, но, опять-же, удалять его нет смысла.

Это может выглядеть примерно так:
  • функция ДобавитьКровотечение (кастер, цель, длительность)
    • проверяет если ли на юните кровотечение от кастера, если есть, то продлевает его, а если нет, то добавляет новое кровотечение в список записаный по хендлу цели (в данных о кровотечении хранится, как минимум, кастер и оставшаяся длительность, но можно хранить и больше данных, например урон за такт чтобы кровотечение не усиливалось магическим образом если кастер прокачался пока идет кровотечение)
    • добавляет цель в группу для перебора
    • если таймер остановлен, то запускает его заново
  • Функция таймера (желательно отдельной именованой функцией, а не анонимной пересоздаваемой при каждом старте таймера)
    • перебирает группу раз в секунду, для каждого юнита в группе перебирает все повешеные на него кровотечения, наносит урон и уменьшает оставшиеся такты кровотечения на 1
    • если прошли все такты кровотечения, то кровотечение убирается из данных записаных по хендлу юнита
    • если по хендлу юнита больше не записано кровотечений, то юнит убирается из группы перебора
    • если в группе перебора не осталось юнитов, то таймер стопается, но не удаляется, группа тоже не удаляется
0
8
5 лет назад
0
как отдельная именная функция узнает юнита который нанносит урон кровотечением ? Допустим через цикл i=0,#GroupCaster.. А если таких юнитов которые вешают кровотечение 5-6 рыл, то получается цикл в цикле....Мне кажется те же яйца только в профиль ! Или так более оптимизированее и быстрее ?
1
24
5 лет назад
1
Castiel, еще раз перечитай мой комментарий выше - там есть и основные отличия и то где хранится информация о кастере. Главное преимущество такого способа - нет жонглирования множеством групп и таймеров, можно даже полностью без групп обойтись, а юнитов для перебора в массиве хранить. Второе ключевое отличие - более гибкая система, позволяющая хранить дополнительную информацию о кровотечении индивидуально для каждой цели и получать эту информацию зная только юнита-цель.
2
8
5 лет назад
Отредактирован Castiel
2
prog:
Castiel, еще раз перечитай мой комментарий выше - там есть и основные отличия и то где хранится информация о кастере. Главное преимущество такого способа - нет жонглирования множеством групп и таймеров, можно даже полностью без групп обойтись, а юнитов для перебора в массиве хранить. Второе ключевое отличие - более гибкая система, позволяющая хранить дополнительную информацию о кровотечении индивидуально для каждой цели и получать эту информацию зная только юнита-цель.
Хорошо я понял! Но вот не могу понять, если записывать GetHandleId(unit), то как обратно найти юнита или можно прям по хендлу и наносить урон ? Дело ведь происходит в именной функции отдельно не вписываемой в сам таймер! а значения в функции таймеров нельзя передать. И как перебрать группу разных id если один 14325432 другой 43223545 ! каким способом ? и узнать размер этого же массива таблицы! или хранить id цели под ключами [1],[2],[3]..... ?Или записывать в ключи самих юнитов ?
1
24
5 лет назад
Отредактирован prog
1
Castiel, но никто ведь не мешает записать самого юнита.
function BleedBitch(caster,target,duration,basedamage)
	-- добавляем новое кровотечение к юниту
	local data = bleeding_data[GetHandleId(target)]
	local num_bleed = data.num
	data.num = num_bleed+1
	data[num_bleed] = {caster=caster, duration=duration, damage=GetHeroStr(caster,true)*basedamage}
	GroupAddUnit(BleedGroup,target)
end
В коде выше большая часть кода пропущена для наглядности.
0
8
5 лет назад
0
BleedBitch
BleedBitch хорошее название функции! Типа адресовано мне я так понял!
2
24
5 лет назад
2
Адресовано юниту который будет истекать кровью, я не кидаюсь необоснованными оскорблениями в собеседников.
2
8
5 лет назад
2
prog:
Адресовано юниту который будет истекать кровью, я не кидаюсь необоснованными оскорблениями в собеседников.
Ну вообще то я воспринял это как шутку! Ладно спасибо что подсказал как лучше!+
1
24
5 лет назад
Отредактирован prog
1
Castiel, если что, пример выше это только очень простой пример того как можно записать данные. Его нужно дополнять и расширять для практического использования.
Есть альтернативный способ - вместо записи последовательно, записывать по хендлу кастера и перебирать потом через pairs.
function BleedBitch(caster,target,duration,basedamage)
	-- добавляем новое кровотечение к юниту по хендлу кастера
	local data = bleeding_data[GetHandleId(target)]
	data[GetHandleId(caster)] = {caster=caster, duration=duration, damage=GetHeroStr(caster,true)*basedamage}
	GroupAddUnit(BleedGroup,target)
end

function BleedTickUnit (target)
	local data = bleeding_data[GetHandleId(target)]
	for cid, bdat in pairs(data)
		Damage(bdat.caster, target, bdat.damage)
	end
end
Перебор через pairs медленней перебора по индексам, но и мороки с ним меньше, плюс проверка на то есть ли на цели кровотечение от кастера проще. Но есть нюанс - тогда в перебираемой таблице не должно быть лишних записей, чтобы не париться проверками нужная ли это запись или что-то левое.
0
8
5 лет назад
Отредактирован Castiel
0
prog:
Castiel, если что, пример выше это только очень простой пример того как можно записать данные. Его нужно дополнять и расширять для практического использования.
Есть альтернативный способ - вместо записи последовательно, записывать по хендлу кастера и перебирать потом через pairs.
function BleedBitch(caster,target,duration,basedamage)
	-- добавляем новое кровотечение к юниту по хендлу кастера
	local data = bleeding_data[GetHandleId(target)]
	data[GetHandleId(caster)] = {caster=caster, duration=duration, damage=GetHeroStr(caster,true)*basedamage}
	GroupAddUnit(BleedGroup,target)
end

function BleedTickUnit (target)
	local data = bleeding_data[GetHandleId(target)]
	for cid, bdat in pairs(data)
		Damage(bdat.caster, target, bdat.damage)
	end
end
Перебор через pairs медленней перебора по индексам, но и мороки с ним меньше, плюс проверка на то есть ли на цели кровотечение от кастера проще. Но есть нюанс - тогда в перебираемой таблице не должно быть лишних записей, чтобы не париться проверками нужная ли это запись или что-то левое.
А если добавлять одного и того же юнита в группу ? Не получится ли, что один и тот же юнит в группе несколько раз состоит ? Может стоит сделать проверку ?
2
28
5 лет назад
Отредактирован PT153
2
А если добавлять одного и того же юнита в группу ? Не получится ли, что один и тот же юнит в группе несколько раз состоит ? Может стоит сделать проверку ?
Проверка уже делается внутри. В 1.31 функции добавления и удаления в\из группу\ы возвращают правду, если юнит был действительно добавлен или удалён. Ложь, если не был.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.