[lua] Всё о визуализации способностей в Warcraft3

Содержание:

Замена области наведения на свою

Сделаем свою способность, которая будет в момент наведения показывать нам квадрат вместо круга, ну и применяться на квадратную область.
К сожаление много вспомогательного кода, который вынужден контролировать отмену наведения и то способ через новое событие TriggerRegisterCommandEvent оказался не очень хорошим, так как не учитывает условия не прожатия, хотя добавляет достаточно редкое событие - событие клика мышкой на стандартную способность в панели приказов, я так долго это искал, а оно уже с января было доступно.
раскрыть
OutPoint=6000
TIMER_PERIOD = 0.03125
function AngleBetweenXY(xa, ya, xb, yb)
	return math.atan(yb - ya, xb - xa)
end
function DistanceBetweenXY(xa, ya, xb, yb)
	local dx = xb - xa
	local dy = yb - ya
	return math.sqrt(dx * dx + dy * dy)
end
function math.clamp (inb, low, high) --
	return math.min( math.max(inb, low ), high )
end

function math.lerp(a, b, t)
	return a + (b - a) * t
end

function repeatN(t, m)
	return math.clamp(t - math.floor(t / m) * m, 0, m)
end

function lerpTheta(a, b, t)
	local dt = repeatN(b - a, 360)
	if dt>180 then	dt=dt-360 end
	return math.lerp(a, a + dt, t)
end

function AngleBetweenXY(xa, ya, xb, yb)
	return math.atan(yb - ya, xb - xa)
end

function MoveXY(x,y, distance, angle)
	return x + distance * math.cos(angle * bj_DEGTORAD),y + distance * math.sin(angle * bj_DEGTORAD)
end

-------------------- СМЕНА КУРСОРА!-------------------------
---
---
MarkerIsON={}
function ChangePointer2Image(hero)
	local p=GetOwningPlayer(hero)
	local range=400
	local image=CreateImage("Square256",range,range,range,OutPoint,OutPoint,0,0,0,0,4)
	--print("создан новый маркер")
	SetImageRenderAlways(image, true)
	ShowImage(image,false)
	if GetLocalPlayer()==p then
		ShowImage(image,true)
	end
	local angleCast = AngleBetweenXY(GetUnitX(hero), GetUnitY(hero), GetPlayerMouseX[0], GetPlayerMouseY[0]) / bj_DEGTORAD
	local curAngle=angleCast
	local distance=DistanceBetweenXY(GetUnitX(hero), GetUnitY(hero), GetPlayerMouseX[0], GetPlayerMouseY[0])
	local cutDistance=distance
	TimerStart(CreateTimer(), TIMER_PERIOD, true, function()
		--local x,y=GetPlayerMouseX[data.pid],GetPlayerMouseY[data.pid]
		distance=DistanceBetweenXY(GetUnitX(hero), GetUnitY(hero), GetPlayerMouseX[0], GetPlayerMouseY[0])
		cutDistance=math.lerp(cutDistance,distance,TIMER_PERIOD * 8)
		--cutDistance=distance
		angleCast = AngleBetweenXY(GetUnitX(hero), GetUnitY(hero), GetPlayerMouseX[0], GetPlayerMouseY[0]) / bj_DEGTORAD
		curAngle = lerpTheta(curAngle, angleCast, TIMER_PERIOD * 8)
		--curAngle=angleCast
		local x,y=MoveXY(GetUnitX(hero),GetUnitY(hero),cutDistance,curAngle)
		x,y=x-range/2,y-range/2
		SetImagePosition(image,x,y,0)

		if not MarkerIsON[GetHandleId(hero)] then
			SetImagePosition(image,OutPoint,OutPoint,0)
			DestroyTimer(GetExpiredTimer())
			--DestroyImage(image)
		end

	end)
end




do --Инициализация
	TimerStart(CreateTimer(), 0.1, false, function()
		InitMouseMoveTrigger()
		RegisterClickAbility()
		RegisterCancel()
		InitSelectionRegister()
	end)
end

GetPlayerMouseX = {}
GetPlayerMouseY = {}
function InitMouseMoveTrigger()
	local MouseMoveTrigger = CreateTrigger()
	for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
		local player = Player(i)
		--if GetPlayerSlotState(player) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(player) == MAP_CONTROL_USER then
		TriggerRegisterPlayerEvent(MouseMoveTrigger, player, EVENT_PLAYER_MOUSE_MOVE)
		GetPlayerMouseX[i] = 0
		GetPlayerMouseY[i] = 0
		--end
	end

	TriggerAddAction(MouseMoveTrigger, function()
		--print("ismove")
		--print("x="..BlzGetTriggerPlayerMouseX().." y="..BlzGetTriggerPlayerMouseY())
		local id = GetPlayerId(GetTriggerPlayer())
		if BlzGetTriggerPlayerMouseX() ~= 0 then
			GetPlayerMouseX[id] = BlzGetTriggerPlayerMouseX()
			GetPlayerMouseY[id] = BlzGetTriggerPlayerMouseY()
		end
	end)
end

function RegisterClickAbility()
	local trigger = CreateTrigger()
	TriggerRegisterCommandEvent(trigger, FourCC("A000"), "channel")
	TriggerAddAction(trigger, function()
		local hero=GetTriggerUnit()
		MarkerIsON[GetHandleId(hero)]=true
		ChangePointer2Image(hero)
	end)
end

function RegisterCancel()
	local gg_trg_AnyCancel = CreateTrigger()
	TriggerRegisterPlayerMouseEventBJ(gg_trg_AnyCancel, Player(0), bj_MOUSEEVENTTYPE_DOWN)
	TriggerRegisterPlayerEventEndCinematic(gg_trg_AnyCancel, Player(0))
	TriggerAddAction(gg_trg_AnyCancel, function()
		local hero=SingleSelection[GetPlayerId(GetTriggerPlayer())]
		if MarkerIsON[GetHandleId(hero)] then
			MarkerIsON[GetHandleId(hero)]=false
		end
	end)

end

SingleSelection={}
function InitSelectionRegister()
	local this = CreateTrigger()
	for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
		TriggerRegisterPlayerUnitEvent(this, Player(i), EVENT_PLAYER_UNIT_SELECTED, nil)
	end
	TriggerAddAction(this, function()
		local hero = GetTriggerUnit()
		SingleSelection[GetPlayerId(GetOwningPlayer(hero))]=hero
	end)
end

function CreateTreeInSquareArea(x,y,range)
	local len=range/2
	local step=64
	local x0,y0=x-len,y+len
	local count=range//step
	--Горизонтальные
	for i=0,count do
		CreateDestructable(FourCC('ZTtw'), x0+step*i, y0, GetRandomReal(0,360), 0.5, 1)
		CreateDestructable(FourCC('ZTtw'), x0+step*i, y0-step*5, GetRandomReal(0,360), 0.5, 1)
	end
	--Вертикальные
	for i=1,count-1 do
		CreateDestructable(FourCC('ZTtw'), x0, y0-step*i, GetRandomReal(0,360), 0.5, 1)
		CreateDestructable(FourCC('ZTtw'), x0+step*5, y0-step*i, GetRandomReal(0,360), 0.5, 1)
	end
end
По поводу кода если кратко:
  1. Отслеживаем событие активации способности
  2. Создаём квадратное изображение на месте курсора
  3. Отслеживаем события успешной активации или отмены способности

Targeting Image

Все помним этот бесящий пункт в способности Канал (ныне Поддержание), который полностью скрывал курсор
Лично мне впервые довелось это применить, мы заменяем курсор активации
Ну и квадратная текстурка
Минусы
  • Если не сглаживать движение области, то оно выглядит рваным, дефолтной скоростью движения курсора не далось добиться
  • Мой способ сглаживания достаточно чудной, ибо учитывает не только угол но и направление, в итоге при большой скоростью квадрат движется по дуге
  • Не добавил условия непрожатия типа (блокировка, стан, молчанка).
С кд и маной, должен сделать по позже

`
ОЖИДАНИЕ РЕКЛАМЫ...
0
1
4 года назад
0
почему не могу посмотреть рисуем маркеры с помощью точек
0
22
4 года назад
0
Soul7:
почему не могу посмотреть рисуем маркеры с помощью точек
Потому что оно ещё не готово
2
18
2 года назад
2
Деревья затемняются слева от героя
0
32
2 года назад
0
Vlod, не вижу ничего, такого. А система так то фигня, я уже лучше сделал гораздо, особенно исправлено сглаживание при следовании за курсором
0
37
2 года назад
0
Насколько лень было windows+G нажать, что гифку аж на gfycat залил?)
1
32
2 года назад
1
ScorpioT1000, так мы его тогда только ввели и я активно только туда всё и заливал, сейчас я такое не делаю, рес то старый кстати
0
27
5 месяцев назад
0
Гифок нет
2
32
5 месяцев назад
2
А вот на это исходника нет, чтобы восстановить гифку, вообще эти наработкии имею гораздо лучшие реализации, надо скорее всего статью с публикации снять
0
27
5 месяцев назад
0
А я помню хотел у тебя здесь скомуниздить наработки, а тут просто ни кода, ни примера-карты. Просто показываем "как я могу".
2
32
5 месяцев назад
2
а тут просто ни кода,
Есть тут код, вверху под катом, может с телефона каты не открываются? А то жаловались недавно
Чтобы оставить комментарий, пожалуйста, войдите на сайт.