Аннотация
Разработан алгоритм появления деревьев. Алгоритм позволяет контролировать количество пеньков и максимальное количество деревьев для предотвращения утечек из-за перенаполнения декорациями.
Введение
Стояла задача построить алгоритм появления деревьев. К сожалению, контролировать напрямую разрушение большого количества разрушаемых объектов - деревьев 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()
Заключение
Если знаете альтернативные алгоритмы, пожалуйста дайте ссылку.
Ссылки
Можно скачать карту-пример
В примере использован импорт альтернативной модели дерева
В примере использован генератор ландшафта
В примере использован импорт альтернативной модели дерева
В примере использован генератор ландшафта