там нет утечек, действия происходят в основном с реальными, единственное что обнулять в конце юнита не нужно, если цикл уже заканчивается юнит == null, но это явно не причина твоих бед
а стоп, нашел утечку, ты создал группу в начале но не удалил в конце, лол)
если ты выставляешь дамми не разлагается и не оживляется всё - после смерти он сразу же удаляется из игры, а этот триггер юзлесс и лишь портит качество способностей, потому что когда юнит умирает он хотя бы анимацию ещё проигрывает, частицы ещё разлетаются, а при мгновенном удалении юнита это выглядит отвратительно
сорян конечно если чью-то религию подпортил, но меня раздражает когда вижу подобную фигню
сам же триггер по факту лишняя нагрузка, если бы тут была подчистка хэша под родительским ключом юнита или что-то в этом духе - я бы ещё понял, но обычное удаление когда можно выставить время смерти на 0.00...
Nikolay36, программист высшего уровня это если бы всё самостоятельно было написано, а просто подкрутить и что-то переделать это даже гуишник может, да и вообще это прозвучало от тебя как боготворение фрога
в общем я поленился и не добавил все настройки, но оставил комменты по которым ты быстро сориентируешься что к чему и сам доделаешь как надо
то что я бы посоветовал переделать, это выбирать юнитов вокруг точки падения, которая регистрируется после первого пораженного юнита, а не вокруг последней пораженной цели, в видео ты можешь посмотреть пример как глупо полёт смотрелся (0:24)
library mylib
globals
constant hashtable H = InitHashtable()
private group TempG = CreateGroup()
private group TempG1
private unit bj_lastFilterUnit
private unit TempUnit
private unit CUEX
private real TempReal
private real MaxX
private real MinX
private real MaxY
private real MinY
endglobals
// воспомогательные фукнции
native UnitAlive takes unit id returns boolean
private function SetUnitPositionEx takes unit u, real x, real y returns nothing
if x > MaxX then
set x = MaxX
elseif x < MinX then
set x = MinX
endif
if y > MaxY then
set y = MaxY
elseif y < MinY then
set y = MinY
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
endfunction
private function CreateUnitEx takes player id, integer unitid, real x, real y, real face returns unit
set CUEX = CreateUnit(id,unitid,x,y,face)
call UnitAddAbility(CUEX,'Arav')
call SetUnitPathing(CUEX,false)
call SetUnitPositionEx(CUEX,x,y)
return CUEX
endfunction
private function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
private struct Spell
unit caster
unit target
unit dummy
unit dummy1
real speed
real angle
real dmg
real fly
real fly1
real time
real dist
real dist1
real radius
real x
real y
integer dummyid
boolean b = true
integer count
group g
endstruct
private function cond takes nothing returns boolean // выбор ближайших целей для кинжала
set bj_lastFilterUnit = GetFilterUnit()
return UnitAlive(bj_lastFilterUnit) and IsUnitEnemy(bj_lastFilterUnit,GetOwningPlayer(TempUnit)) and not IsUnitInGroup(bj_lastFilterUnit,TempG1)
endfunction
private function DamageCond takes nothing returns boolean // кому наносить урон
set bj_lastFilterUnit = GetFilterUnit()
if UnitAlive(bj_lastFilterUnit) and IsUnitEnemy(bj_lastFilterUnit,GetOwningPlayer(TempUnit)) then
call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl",bj_lastFilterUnit,"chest"))
call UnitDamageTarget(TempUnit,bj_lastFilterUnit,TempReal,false,false,null,null,null)
endif
return false
endfunction
private function casterr takes nothing returns boolean // это для кинжала, выбор кастера когда кинжал упал
return GetFilterUnit() == TempUnit
endfunction
private function move1 takes nothing returns nothing //это для эффекта кругового удара
local timer t = GetExpiredTimer()
local integer i = GetHandleId(t)
local unit u = LoadUnitHandle(H,i,0)
local unit u1 = LoadUnitHandle(H,i,1)
local real tm = LoadReal(H,i,2)-.01
call SetUnitPositionEx(u1,GetUnitX(u),GetUnitY(u))
if tm <= 0. then
call KillUnit(u1)
call PauseTimer(t)
call DestroyTimer(t)
call FlushChildHashtable(H,i)
else
call SaveReal(H,i,2,tm)
endif
set t = null
set u = null
set u1 = null
endfunction
// периодическая проверка кастера у кинжала
private function checkcaster takes nothing returns nothing
local Spell A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
local timer t
set A.time = A.time-.01
set TempUnit = A.caster
call GroupEnumUnitsInRange(TempG,A.x,A.y,100,Condition(function casterr))
if A.time <= 0. or FirstOfGroup(TempG) != null then
if FirstOfGroup(TempG) != null then
set t = CreateTimer()
call SaveUnitHandle(H,GetHandleId(t),0,A.caster)
call SaveUnitHandle(H,GetHandleId(t),1,CreateUnitEx(Player(0x0F),'u002',GetUnitX(A.caster),GetUnitY(A.caster),GetRandomReal(0,360)))
call SaveReal(H,GetHandleId(t),2,.10)
call SetUnitFlyHeight(CUEX,50,0)
call SetUnitScale(CUEX,2,2,2)
call TimerStart(t,.01,true,function move1)
set t = null
call GroupClear(TempG)
set TempReal = A.dmg
call GroupEnumUnitsInRange(TempG,GetUnitX(A.caster),GetUnitY(A.caster),A.radius*0.8,Condition(function DamageCond))
endif
call KillUnit(A.dummy)
call KillUnit(A.dummy1)
call RemoveUnit(A.dummy1)
call DestroyGroup(A.g)
set A.g = null
set A.caster = null
set A.dummy = null
call A.destroy()
call FlushChildHashtable(H,GetHandleId(GetExpiredTimer()))
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endif
endfunction
// перемещение кинжала когда он падает
private function setpos takes nothing returns nothing
local Spell A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
local real x = GetUnitX(A.dummy)+A.speed*Cos(A.angle)
local real y = GetUnitY(A.dummy)+A.speed*Sin(A.angle)
set A.dist = A.dist-A.speed
call SetUnitPositionEx(A.dummy,x,y)
call SetUnitFlyHeight(A.dummy,ParabolaZ(A.fly,A.dist1,A.dist)+A.fly1,0)
if A.dist <= 0. then
set A.x = x
set A.y = y
set A.dummy1 = CreateUnitEx(GetOwningPlayer(A.caster),A.dummyid,x,y,GetRandomReal(0,360))
call SetUnitScale(A.dummy1,.5,.5,.5)
call TimerStart(GetExpiredTimer(),.01,true,function checkcaster)
endif
endfunction
private function move takes nothing returns nothing
local Spell A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
local real x = GetUnitX(A.dummy)+A.speed*Cos(A.angle)
local real y = GetUnitY(A.dummy)+A.speed*Sin(A.angle)
local real x1 = GetUnitX(A.target)
local real y1 = GetUnitY(A.target)
local unit u
local real r
local real r1
set A.angle = Atan2(y1-y,x1-x)
call SetUnitPositionEx(A.dummy,x,y)
if SquareRoot((x-x1)*(x-x1)+(y-y1)*(y-y1)) <= 50. then
call SetUnitX(A.dummy,x1)
call SetUnitY(A.dummy,y1)
call UnitDamageTarget(A.caster,A.target,A.dmg,false,false,null,null,null)
if A.b then // установление дистанции падения кинжала после первой цели
set A.x = x1+A.radius*Cos(A.angle)
set A.y = y1+A.radius*Sin(A.angle)
set A.b = false
endif
set A.count = A.count-1
set TempUnit = A.dummy
set TempG1 = A.g
call GroupEnumUnitsInRange(TempG,x1,y1,A.radius,Condition(function cond))
if A.count <= 0 or FirstOfGroup(TempG) == null then
// настройки для падения кинжала
set A.dist = SquareRoot((x-A.x)*(x-A.x)+(y-A.y)*(y-A.y))
set A.dist1 = A.dist // (для параболы)
set A.angle = Atan2(A.y-y1,A.x-x1)
set A.speed = SquareRoot((x-x1)*(x-x1)+(y-y1)*(y-y1))*.1
call TimerStart(GetExpiredTimer(),.01,true,function setpos)
else
// выбор ближней цели
set r = A.radius*2
loop
set u = FirstOfGroup(TempG)
exitwhen u == null
set r1 = SquareRoot((GetUnitX(u)-x1)*(GetUnitX(u)-x1)+(GetUnitY(u)-y1)*(GetUnitY(u)-y1))
if r1 < r then
set r = r1
set A.target = u
endif
call GroupRemoveUnit(TempG,u)
endloop
call GroupAddUnit(A.g,A.target)
endif
endif
endfunction
private function Trig_Spell_Actions takes nothing returns nothing
local timer t = CreateTimer()
local Spell A = Spell.create()
local integer lvl
set A.caster = GetTriggerUnit()
set A.target = GetSpellTargetUnit()
set A.angle = Atan2(GetUnitY(A.target)-GetUnitY(A.caster),GetUnitX(A.target)-GetUnitX(A.caster))
set A.dummy = CreateUnitEx(GetOwningPlayer(A.caster),'u000',GetUnitX(A.caster)+50*Cos(A.angle),GetUnitY(A.caster)+50*Sin(A.angle),A.angle*bj_RADTODEG)
set A.g = CreateGroup()
set lvl = GetUnitAbilityLevel(A.caster,'A000')
if lvl == 1 then
set A.dmg = 100.00
set A.count = 3
set A.speed = 25.00
set A.radius = 300.00 // радиус поиска целей а так же дистанция падения кинжала от первой пораженной цели
set A.fly = 300.00 // максимальная высота кинжала
set A.fly1 = 50.00 // постоянная высота кинжала
set A.time = 5.00 // время существования кинжала
set A.dummyid = 'u001' // какого юнита спавнить для отображения радиуса подбора кинжала
//elseif lvl == 2 then
endif
call GroupAddUnit(A.g,A.target)
call SetUnitFlyHeight(A.dummy,A.fly1,0)
call SaveInteger(H,GetHandleId(t),0,A)
call TimerStart(t,.03125,true,function move)
set t = null
endfunction
//===========================================================================
private function mycond takes nothing returns boolean
if GetSpellAbilityId() == 'A000' then
call Trig_Spell_Actions()
endif
return false
endfunction
function InitTrig_Spell takes nothing returns nothing
set gg_trg_Spell = CreateTrigger( )
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x00), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x01), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x02), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x03), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x04), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x05), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x06), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x07), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x08), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x09), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0A), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0B), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0C), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0D), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0E), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x0F), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerAddCondition( gg_trg_Spell, Condition(function Trig_Spell_Actions) )
set MaxX = GetRectMaxX(GetWorldBounds())
set MinX = GetRectMinX(GetWorldBounds())
set MaxY = GetRectMaxY(GetWorldBounds())
set MinY = GetRectMinY(GetWorldBounds())
endfunction
endlibrary
а насчёт вращения юнита, если мемхак не помогает, можешь найти дамми модель 360 градусов и прикрепить к ней кинжал как эффект, устанавливая нужную анимацию модели в соответствии с таким-то градусом, костыльно, но работает без проблем
но столкнулся с рядом проблем в анимации: то, одно клинок улетает в неизвестность, невзирая на условия, то летит нормально; то клинок приземляется куда нужно, но оказывается, что только под определённым углом, то сильно мимо, можете помочь с тем, как правильно сделать анимацию?
у тебя проблемы с анимацией или с движением кинжала? не понятно что ты хочешь
если именно технические проблемы, а не визуальные (по которым ты мемхак юзаешь для вращения по yaw/pitch/roll), то я могу сделать эту абилку и скинуть тебе
» WarCraft 3 / Утечки в коде
» WarCraft 3 / Дуэли спэллмейкеров
» WarCraft 3 / Иконки на заказ
» WarCraft 3 / Дуэли спэллмейкеров
» WarCraft 3 / Утечки в коде
» WarCraft 3 / Дуэли спэллмейкеров
» WarCraft 3 / изменения интерфейса РО
» WarCraft 3 / Триггер пополняющий группу юнитов в Word Editor WarCraft 3
» WarCraft 3 / Способности и алгоритмы на заказ
Заказ принят
Способность: Аванпост
Спелл будет завершен к: сегодня ближе к вечеру
» WarCraft 3 / Чем полезен и полезен ли вообще этот чудо тригер?))))
» WarCraft 3 / Обучение jass
» WarCraft 3 / Есть ли модели дота в открытом доступе?
Ред. rsfghd
» WarCraft 3 / Полёт клинка
» WarCraft 3 / Полёт клинка
Ред. rsfghd
» WarCraft 3 / Полёт клинка
» WarCraft 3 / Триггер при взятии предмета в WorldEditor
» WarCraft 3 / Warcraft 3 Reforged Взломан!
» WarCraft 3 / Утекают ли не обнулённые переменные типа handle
» WarCraft 3 / Вопрос по снаряду
Ред. rsfghd
» WarCraft 3 / Вопрос по снаряду
» WarCraft 3 / Неуязвимое здание с отображением хп
Ред. rsfghd
» WarCraft 3 / Полёт клинка
то что я бы посоветовал переделать, это выбирать юнитов вокруг точки падения, которая регистрируется после первого пораженного юнита, а не вокруг последней пораженной цели, в видео ты можешь посмотреть пример как глупо полёт смотрелся (0:24)
» WarCraft 3 / Полёт клинка
» WarCraft 3 / Полёт клинка
он спрашивает почему кинжал себя так странно ведёт)
Ред. rsfghd
» WarCraft 3 / Полёт клинка