Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Алгоритм
Версия Warcraft:
1.31+

Аннотация

Разработан алгоритм появления деревьев. Алгоритм позволяет контролировать количество пеньков и максимальное количество деревьев для предотвращения утечек из-за перенаполнения декорациями.

Введение

Стояла задача построить алгоритм появления деревьев. К сожалению, контролировать напрямую разрушение большого количества разрушаемых объектов - деревьев TreesMax >= 30000 не представляется возможным. Для прямого контроля пришлось бы создавать триггер отлавливающий разрушение каждого дерева
native TriggerRegisterDeathEvent takes trigger whichTrigger, widget whichWidget returns event
При том, что триггер отлавливающий события смерти "любого" разрушаемого объекта
function TriggerRegisterDestDeathInRegionEvent takes trigger trig, rect r returns nothing
Создает для каждого дерева, который был на карте изначально, триггер прямого отлова его разрушения. Автор не пробывал создавать отдельный триггер, отлавливающий разрушение, для каждого дерева, потому, что почему-то решил что это глупая затея. Поэтому была создана настоящая система.

Описание

Существует два массива деревьев: udg_Trees , udg_Trees1 , в которые записываются деревья в зависимости от того, который текущий. Пусть udg_Trees1 - текущий массив, udg_Trees - проверяемый массив. Функция-супервизии
Функция супервизии
private function TreeSupervise takes nothing returns nothing
	local integer j = udg_TreesPointer
	local destructable loc_currTree
	//call BJDebugMsg("SW: " + I2S(j) + " L: " + I2S(udg_Delta_supervise))
    loop
    exitwhen( (j == GetOldArrCount()) or (j - udg_TreesPointer == udg_Delta_supervise) )
	set loc_currTree = GetOldTree(j)
		if (GetDestructableLife(loc_currTree) <= 0) then
			call addStump(loc_currTree)
			set udg_newStumpCount = udg_newStumpCount + 1
		else
			call addTreeCurrArr(loc_currTree)
		endif
		set j = j + 1
    endloop
	if(j == GetOldArrCount())then
		call SuperviseRefresh()
	else
		set udg_TreesPointer = j
	endif
endfunction
проверяет массив udg_Trees и добавляет живые деревья в текущий массив udg_Trees1 и пеньки в массив udg_Stumps . По достижению конца проверяемого массива проверяемый и текущий меняются местами. Таким образом есть массив наполненный "только" пеньками.
В случае если udg_Stumps переполнен, создается новый круг записи пеньков в этот массив. В новом цикле записи старые пеньки удаляются, а место в массиве udg_Stumps перезаписываются новыми. Однако, если старый пенек вдруг "ожил" ,обычно в следствии заклинания, то он записывается вновь в текущий на данный момент массив деревьев.
Весь код
library WoodLibSupervise initializer onInit

/*
============== Добавление стороннего дерева в систему ================
function AddOtherTreeSystem takes destructable NewTree returns nothing

============== Установка времени между итрециями роста ===============
function SetPeriodicGrowTime takes real NewTime returns nothing

============== Получение времени между итерациями ====================
function GetGrowTime takes nothing returns real
*/
globals
	//
	private trigger udg_trg_TreeGrowINI
	private trigger udg_trg_ElapsedStartGrow
	// Размеры Парамтры Карты
	private real udg_MapMinX 
	private real udg_MapMinY
	private real udg_MapMaxX
	private real udg_MapMaxY
	//
	private integer udg_StumpsPointer         //
	private integer array udg_tree_skin       // Переменная для записи вариантов скинов деревьев
	private real array udg_tree_scale         // Переменная для записи вариантов масштабов для скинов деревьев
	
	// Переменные настройки таймера
	private timer udg_timer_PeriodicGrow
    private real udg_time_PeriodicGrow        //Время между итерациями роста
    private integer udg_GrowTreeNum           //Число деревьев за итеррацию
	//
	private destructable array udg_Trees      // Массив деревьев 0
	private integer udg_TreesCount            // Счетчик числа массива деревьев
	//
	private destructable array udg_Trees1     // Массив деревьев 1
	private integer udg_Trees1Count           // Счетчик числа массива 2 деревьев
	//
	private integer udg_currArray			  // Указатель на текущий массив
	private integer udg_TreesPointer          // Указатель на текущее положение курсора супервизии
	private integer udg_newStumpCount	      // Число новых пеньков найденных при супервизии	
	private integer udg_TreesMax              // Максимальное кол-во деревьев в массиве
	//
	private destructable array udg_Stumps     // Массив пеньков
	private integer udg_StumpsCount           // Размер массива пеньков
	private integer udg_StumpsMax         	  // Максимальный размер массива пеньков
	//
	private timer udg_timer_Supervise         // Таймер супервизии
    private real udg_time_Supervise           // Время между супервизиями
	private integer udg_Delta_supervise       // Длинна супервизии
	private integer udg_newTreesCount         // Счетчик новых деревьев в цикле между переворотом массивов
endglobals

// Функция возращающая дерево текущего массива
private function GetCurrTree takes integer j returns destructable
	if(udg_currArray == 0) then
		return udg_Trees[j]
	else
		return udg_Trees1[j]
	endif
endfunction

//Функция возращающая счетчик текущего массива
private function GetCurrArrCount takes nothing returns integer
	if(udg_currArray == 0) then
		return udg_TreesCount
	elseif (udg_currArray == 1) then
		return udg_Trees1Count
	endif
	call BJDebugMsg("Ошибка теущего массива -1")
	return -1
endfunction

//Функция возращающая счетчик старого массива
private function GetOldArrCount takes nothing returns integer
	if(udg_currArray == 1) then
		return udg_TreesCount
	elseif (udg_currArray == 0) then
		return udg_Trees1Count
	endif
	call BJDebugMsg("Ошибка теущего массива -1")
	return -1
endfunction

//Функция добавления элемента в текущий массив без проверки на превышение максимума
private function addTreeCurrArr takes destructable NewTree returns nothing
	if(udg_currArray == 0) then
		set udg_Trees[udg_TreesCount] = NewTree
		set udg_TreesCount = udg_TreesCount + 1
	elseif (udg_currArray == 1) then
		set udg_Trees1[udg_Trees1Count] = NewTree
		set udg_Trees1Count = udg_Trees1Count + 1
	endif
endfunction

// Функция возвращающая дерево старого массива
private function GetOldTree takes integer j returns destructable
	if(udg_currArray == 1) then
		return udg_Trees[j]
	else
		return udg_Trees1[j]
	endif
endfunction

//Фунция смены текущего и старого массива на противоположные
private function ArraysStatusChange takes nothing returns nothing
	if(udg_currArray == 0) then
		set udg_currArray = 1
		//call BJDebugMsg("Смена статусов. Число деревьев: " + I2S(udg_TreesCount))
		set udg_Trees1Count = 0
	else
		set udg_currArray = 0
		//call BJDebugMsg("Смена статусов. Число деревьев: " + I2S(udg_Trees1Count))
		set udg_TreesCount = 0
	endif
endfunction 

/*Функция, которая создает дерево случайного типа
 в случайном месте и возвращает на него указатель 
*/
private function CreateRandomTree takes nothing returns destructable
	local integer loc_type = GetRandomInt(0, 1)
	local integer loc_tree_skin = udg_tree_skin[loc_type]
	local real loc_X = GetRandomReal( udg_MapMinX, udg_MapMaxX)
	local real loc_Y = GetRandomReal( udg_MapMinY, udg_MapMaxY)
	local real loc_scale = GetRandomReal(0.8,1.2)*udg_tree_scale[loc_type]
	local integer loc_skin_var = GetRandomInt(0, 9)
	// Создание дерева
        local destructable distr = CreateDestructable(loc_tree_skin,loc_X,loc_Y,GetRandomReal(0, 360),loc_scale, loc_skin_var)
        //Анимация роста дерева
	//call SetDestructableAnimation(distr, "Birth")
        return distr
endfunction

// ====== Добавление стороннего дерева в систему ====== 
function AddOtherTreeSystem takes destructable NewTree returns nothing
    if(udg_TreesMax - GetOldArrCount() - udg_newTreesCount + udg_newStumpCount > 0) then
        call addTreeCurrArr(CreateRandomTree())
        set udg_newTreesCount = udg_newTreesCount + 1
    else
        //Если мест нет - то удалить
        call RemoveDestructable(udg_Stumps[udg_StumpsPointer])
    endif
endfunction

// ====== Зобавление пенька в массив ====== 
/*Зная индекс пенька в массиве деревьев
добавление его в круговой массив пеньков*/
private function addStump takes destructable NewStump returns nothing
	if( udg_StumpsCount == udg_StumpsMax ) then
		/* Если массив пеньков заполнен,
		то удаление старого пенька по указателю нуля кругового массива и 
		змена его на новый пенек
		*/
        //Поверка стал ли пенек по указателю нуля массива пеньков деревом
        if(GetDestructableLife(udg_Stumps[udg_StumpsPointer]) > 0) then
            //Если пенек стал деревом проверка на свободу места в основном наборе
            call AddOtherTreeSystem(udg_Stumps[udg_StumpsPointer])
        else
            //Если все как обычно то удаление пенька
            call RemoveDestructable(udg_Stumps[udg_StumpsPointer])
        endif
		set udg_Stumps[udg_StumpsPointer] = NewStump
		set udg_StumpsPointer = udg_StumpsPointer + 1
        //call BJDebugMsg("Успешная перезапись пня")
		if(udg_StumpsPointer > udg_StumpsMax) then
			set udg_StumpsPointer = 0
		endif
	else
		/*Есть место в массиве пеньков, то простое заполнение массива пеньков*/
		set udg_Stumps[udg_StumpsCount] = NewStump
		set udg_StumpsCount = udg_StumpsCount + 1
        //call BJDebugMsg("Успешная запись пня")
	endif
endfunction



// ====== Обновленние супервизии ====== 
private function SuperviseRefresh takes nothing returns nothing
	//call BJDebugMsg("При супервизии найденно пеньков: " + I2S(udg_newStumpCount))
    //
    call ArraysStatusChange()
	set udg_TreesPointer = 0
	set udg_newStumpCount = 0
	set udg_newTreesCount = 0
endfunction

/* ======  Функция супервизии =========================
Функция проверки масива деревьев на появившиеся пеньки
и набора массива пеньков и его перетасовки
*/
private function TreeSupervise takes nothing returns nothing
	local integer j = udg_TreesPointer
	local destructable loc_currTree
	//call BJDebugMsg("SW: " + I2S(j) + " L: " + I2S(udg_Delta_supervise))
    loop
    exitwhen( (j == GetOldArrCount()) or (j - udg_TreesPointer == udg_Delta_supervise) )
	set loc_currTree = GetOldTree(j)
		if (GetDestructableLife(loc_currTree) <= 0) then
			call addStump(loc_currTree)
			set udg_newStumpCount = udg_newStumpCount + 1
		else
			call addTreeCurrArr(loc_currTree)
		endif
		set j = j + 1
    endloop
	if(j == GetOldArrCount())then
		call SuperviseRefresh()
	else
		set udg_TreesPointer = j
	endif
endfunction

// ====== Инициализация супервизии =====================
private function SuperviseStart takes nothing returns nothing
	local timer loc_timer = CreateTimer()
	//call BJDebugMsg("Инициализация супервизии")
	set udg_TreesPointer = 0
	set udg_newStumpCount = 0
	set udg_newTreesCount = 0
	call TimerStart(loc_timer, udg_time_Supervise ,true,function TreeSupervise)
	set udg_timer_Supervise = loc_timer
endfunction

// ====== Функция внедряющая дерево в систему ===========
private function SystemTreeCreate takes nothing returns nothing
	local destructable distr
	if ( udg_TreesMax - GetOldArrCount() - udg_newTreesCount + udg_newStumpCount > 0 ) then
        	//Создание нового дерева и запись его в текущий массив
        	call addTreeCurrArr(CreateRandomTree())
        	set udg_newTreesCount = udg_newTreesCount + 1
	endif
endfunction

// ====== Переодическая функция создания ========================
private function PereodicTreeCreate takes nothing returns nothing
	local integer i = 0
	loop
	exitwhen(i == udg_GrowTreeNum)
		call SystemTreeCreate()
	set i = i + 1
	endloop
endfunction

// ====== Функция, которая начинает рост деревьев ====== 
private function StartGrow takes nothing returns nothing
        local timer loc_timer = CreateTimer()
        call TimerStart(loc_timer, udg_time_PeriodicGrow ,true,function PereodicTreeCreate)
        set udg_timer_PeriodicGrow = loc_timer
        call SuperviseStart()
endfunction


// ====== Функция инициализации переменных ======================
private function Var_Init takes nothing returns nothing
	set udg_MapMinX = GetRectMinX(GetEntireMapRect())
	set udg_MapMaxX = GetRectMaxX(GetEntireMapRect())
	set udg_MapMinY = GetRectMinY(GetEntireMapRect())
	set udg_MapMaxY = GetRectMaxY(GetEntireMapRect())
	//
	set udg_TreesCount  = 0
	set udg_Trees1Count = 0
	set udg_TreesMax = 30000        // Установка максимального числа деревьев
	set udg_Delta_supervise = 100   // Установка длительности супервизии
	set udg_currArray = 0
	set udg_StumpsCount = 0
    set udg_StumpsMax = 5000        //Установка максимального кол-ва пеньков  
	set udg_TreesPointer = 0
	set udg_StumpsPointer = 0
	set udg_newStumpCount = 0
	set udg_newTreesCount = 0
	// Параметры визуализации деревьев
	set udg_tree_skin[0] = 'LTlt'
	set udg_tree_skin[1] = 'B001'
	set udg_tree_scale[0] = 1
	set udg_tree_scale[1] = 0.8
	// Параметры супервизии
	set udg_time_PeriodicGrow = 0.05       // Время между итерациями роста
    set udg_GrowTreeNum = 1                // Число деревьев за итеррацию
    set udg_time_Supervise = 0.1
endfunction

// ====== Получение времени между итерациями ==================
function GetGrowTime takes nothing returns real
    return udg_time_PeriodicGrow
endfunction

// ====== Установка времени между итрециями роста =============
function SetPeriodicGrowTime takes real NewTime returns nothing
    set udg_time_PeriodicGrow = NewTime
    call DestroyTimer(udg_timer_PeriodicGrow) 
    set udg_timer_PeriodicGrow = CreateTimer()
    call TimerStart(udg_timer_PeriodicGrow, udg_time_PeriodicGrow ,true,function PereodicTreeCreate)
endfunction


//===========================================================================
function onInit takes nothing returns nothing
    call Var_Init()
    call StartGrow()
endfunction

endlibrary
В функции Var_Init настраиваются технические переменные , такие как время периодичности роста udg_time_PeriodicGrow , число деревьев за такт udg_GrowTreeNum . В данной реализации рост деревьев начинается сразу, но его можно переназначить, при помощи изменения положения функции StartGrow()

Заключение

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

Ссылки

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