есть одна 2D карта (по зеленой кнопке)
но код для просчёта коллизий может обработать только 11 юнитов
(если играть всемером - то получится, что можно добавить только 4 доп.юнита на карту)
если сделать 12 или 50 юнитов - то варик просто захлёбывается
(в карте есть счетчик обработки коллизий - максимально 80000 операций в секунду)
есть желающие поковыряться в коде и улучшить его, чтобы он смог обрабатывать 50 юнитов?
коллизии - это столкновение. по X это толкание соседних юнитов вправо влево, по Y это носить на голове или стоять сверху на юните
код карты тут:
EN controlc.com/b12ac4e8
RU controlc.com/dcfc0814
цепочка функций по просчёту коллизий:
main - начало карты
Frame__init - инициализация кадра
Frame__Main - просчет одного кадра (частота 0.02)
Frame__PlayersGroup - просчет группы юнитов
Frame__SquaresMoving - движение юнитов
Frame__MovingY [b==false] - движение по Y
if MushroomMoving_RectCondition "UpWidthOM" + "DownWidthOM"  - сравнение ректов
MushroomMoving_CollisionCheck - проверка на коллизии
set otherx=GetUnitX(OrangeMushroom[j]) + set othery=GetUnitY(OrangeMushroom[j]) - считывание координат
графики:
скриншот карты:
`
ОЖИДАНИЕ РЕКЛАМЫ...
1
29
6 месяцев назад
1
Глянул на код. Это просто шикарно. На каждого юнита вызывается UnitIndex. Тоесть лишний цикл на количество игроков. Можно просто каждому грибу записать его индекс через SetUnitUserData. Будет дешевле.
Очищать глобальную группу G дешевле, чем дрочить создание/удаление локалки.
Удаление из группы происходит за O(n), поэтому лучше перебирать группы не через удаление юнита, а через ForGroup. Она к тому же создаёт псевдопоток, что позволяет обойти оплимит.
Этой проверки я так и не понял.
GetUnitTypeId(OrangeMushroom[i])!='orai'
1
25
6 месяцев назад
Отредактирован Jack-of-shadow
1
Еще кучу ифов в SetUnitMoveAnimation (к которому Frame__Main каждые 0.02 сек по тыще раз обращается), можно через хеш урезать до одной строки.
cjass
define SaveAnimation (tp,aniName,index) = {SaveInteger(hash,AnimationKey,StringHash(I2S(tp)+aniName),index)}
define LoadAnimation (tp,aniName) = {LoadInteger(hash,AnimationKey,StringHash(I2S(tp)+aniName))}
void AnimationIni(){
SaveAnimation ('uobs',"Walk First",0)
SaveAnimation ('uobs',"Walk Second",1)
SaveAnimation ('ufro',"Walk First",6)
SaveAnimation ('uobs',"Walk Second",7)
//..и все остальные
}
define SetUnitMoveAnimation (u,aniName)={SetUnitAnimationByIndex(u,LoadAnimation(GetUnitTypeId(u)))}

goodlyhero, тут не частоту надо понижать (от этого фриз не исчезнет), а именно разбивать обработку юнитов на разное время. Таймер 0.01 с начало обрабатывает 1-ую часть всех юнитов, потом 2-ую, 3 итд, потом снова первую. Таким образом, если мы разделим всех юнитов например на 5 групп, то то все юниты будут обрабатываться с частотой 0.05 сек.

В Frame__Main/BossMoving тоже что то жеское..
0
14
6 месяцев назад
Отредактирован host_pi
0
goodlyhero: Впринципе, период тут можно сильно повысить с 0.02. Даже если вы будете проверять коллизии с частотой 0.1, производительность поднимется в пять раз.
я уже пробовал менять это значение - ничего не меняется по нагрузке и по фпс
(да и любой из вас его может изменить за пол минуты и чекнуть результат - www.epicwar.com/maps/332635 вот новая версия карты 1.4 с добавленным радиусным ускорением )
это чисто лимит варкрафта на колво вложенных циклов и операций в одном стеке
единственное что из похожего помогает уменьшить тормоза и поднять фпс - это ириновский !actioninterval
nazarpunk: На каждого юнита вызывается UnitIndex. Тоесть лишний цикл на количество игроков. Можно просто каждому грибу записать его индекс через SetUnitUserData. Будет дешевле.
Очищать глобальную группу G дешевле, чем дрочить создание/удаление локалки.
замечания хорошие, нужно тестировать всякие наносекунды - сколько на практике это добавляет тормозов
nazarpunk: Удаление из группы происходит за O(n), поэтому лучше перебирать группы не через удаление юнита, а через ForGroup. Она к тому же создаёт псевдопоток, что позволяет обойти оплимит.
о, ради такого уже стоит вернуться к коду и протестировать, возможно это и будет тем решением о котором я и писал с самого начала - не изменяя логики кода пустить отдельным потоком просчет коллизий
nazarpunk: Этой проверки я так и не понял.
GetUnitTypeId(OrangeMushroom[i])!='orai'
это если юнит не самолётик. там есть самолетики которые сами по себе летают и имеют особые условия по физике, например отсутствие гравитации или способность возить других на своем борту
Jack-of-shadow: можно через хеш урезать до одной строки. cjass
это всё хорошо, только war3 не понимает cjass, можно хоть на си шарпе, питоне или джаве писать в пол строки и козырять этим - только компилятор все равно переведёт в обычный многострочный jass, это разве не очевидно?
Jack-of-shadow: В Frame__Main/BossMoving тоже что то жеское
ничего там нету жесткого, там сразу выход из функции по первому условию - if FinalStage==true and BlackBoss !=null
это всё мелочи, обычный код не нагружает варик в щщщи
то есть какой смысл оптимизировать чужой код (который в новых версиях карты вообще обфусцирован) ради наносекунд или уменьшения в каком-то месте с 5 строк до 3, когда уже выявлена реальная причина тормозов - это количество коробок и их обсчёт коллизий
нагружают именно коллизии и как уже выше было сказано - вложенный квадратичный (а теперь уже радиусный) цикл по ним
1
25
6 месяцев назад
Отредактирован Jack-of-shadow
1
я уже пробовал менять это значение - ничего не меняется по нагрузке и по фпс
попробуй что то типо того:
globals
 integer playersMax                = 10//кол-во игроков
 integer playersPerFrameProcessed  = 2 //сколько игроков будет обработано за 0.01 сек
 integer playersCurrectFrameOffset = 1 //следующий игрок для обработки коллизий
englobals 

function Frame__PlayersGroup takes nothing returns nothing
	local integer i
		 
		if playersCurrectFrameOffset > PlayersGroupMax {playersCurrectFrameOffset = 0} 
		set i = playersCurrectFrameOffset
		
		loop
	     set playersCurrectFrameOffset = playersCurrectFrameOffset + 1
		 exitwhen i > playersCurrectFrameOffset+playersPerFrameProcessed
	      //тут обрабатываешь игрока

		 set i = i + 1
	    endloop	
        set playersCurrectFrameOffset = i	
endfunction 		


function Frame__PlayersGroupIni takes nothing returns nothing
	local trigger t=CreateTrigger()
	call TriggerRegisterTimerEvent(t,0.01,true)
	TriggerAddAction(t,function Frame__PlayersGroup)
endfunction 

я может гденить накосячил но смысл думаю понятен

это всё хорошо, только war3 не понимает cjass
Вобщето с JNGP понимает), но не суть, на обычном джасс +- тоже самое можно сделать.
0
14
6 месяцев назад
Отредактирован host_pi
0
nazarpunk: лучше перебирать группы не через удаление юнита, а через ForGroup. Она к тому же создаёт псевдопоток, что позволяет обойти оплимит.
а как передать переменные внутрь ForGroup? а потом еще и вернуть результат? она же вызывается с takes nothing returns nothing
для этого создавать новый вопрос с тестовым мини кодом?
делать на глобалках? или на той же ht? а они разве не перезапишутся, если несколько ForGroup будут выполняться в разных тредах и перезаписывать результат в одну свою глобалку на true/false условно хаотично
или если ты в 3 глобалки (или в 3 значения в ht) записываешь входящие i , x , y - то они тоже будут прыгать при вызове MushroomMoving_CollisionCheck\ForGroup несколько раз т.к. идёт перезапись входящих общих переменных i x y при каждом их вызове
Открыть код
function UnitIndex takes unit u returns integer
	local integer i=1
	loop
		exitwhen i>PLAYER_MAXINUM+Stage_BoxsCount
		if u==OrangeMushroom[i] then
			set u=null
			return i
		endif
		set i=i+1
	endloop
	set u=null
	return 0
endfunction

function MushroomMoving_CollisionCheck_ForGroup takes nothing returns nothing
	local unit u=null
	local integer j=0
	local real otherx
	local real othery
	set u = GetEnumUnit()
	if u!=OrangeMushroom[i] then
		set j=UnitIndex(u)
		if (GetPlayerSlotState(GetOwningPlayer(OrangeMushroom[j]))==PLAYER_SLOT_STATE_PLAYING or j>PLAYER_MAXINUM) and LevelClearState[j]==false then
			if MB_Frame_On==1 then
				set MB_CollisionY = MB_CollisionY+1
			endif
			set otherx=GetUnitX(OrangeMushroom[j])
			set othery=GetUnitY(OrangeMushroom[j])
			if ContainsCoords(otherx-64,othery-64,otherx+64,othery+64,x,y)==true then
				if PropellyCondition==true then
					if GetUnitTypeId(OrangeMushroom[j])!='orai' then
						set u=null
						set Frame_MainPlayerY=j
						return false
					endif
				else
					set u=null
					set Frame_MainPlayerY=j
					return false
				endif
			endif
		endif
	endif
	set u=null
	return true
endfunction

function MushroomMoving_CollisionCheck takes integer i,real x,real y returns boolean
	local group G = CreateGroup()
	call GroupEnumUnitsInRange(G, x,y, 128, null)
	call ForGroup(G,function MushroomMoving_CollisionCheck_ForGroup)
	call DestroyGroup(G)
	set G=null
endfunction
Jack-of-shadow: попробуй что то типо того:
попробую и это решение, думаю колупаться долго буду со всем этим чтобы завести и протестировать оба решения
1
29
6 месяцев назад
Отредактирован nazarpunk
1
а как передать переменные внутрь ForGroup?
Через глобалки. Я что-то не припомню чтоб в жасс состояние гонки завезли. Так что все форгрупы выполнятся строго подряд.

Кстати, почему такты не бережёшь и сразу не делаешь:
local unit u = GetEnumUnit()

а они разве не перезапишутся, если несколько ForGroup будут выполняться в разных тредах и перезаписывать результат в одну свою глобалку на true/false условно хаотично
Условно хаотично бывает в асинхронных языках, где ты в жассе нашёл асинхронность? Вэйты не в счёт.

это если юнит не самолётик.
Булевый флаг по индексу будет всяко быстрее вызова функции и сравнения чисел.
0
14
6 месяцев назад
Отредактирован host_pi
0
nazarpunk: лучше перебирать группы не через удаление юнита, а через ForGroup. Она к тому же создаёт псевдопоток, что позволяет обойти оплимит
попробовал накалякать через ForGroup
Открыть код и видео
globals
	integer MushroomMoving_CollisionCheck_i
	real MushroomMoving_CollisionCheck_x
	real MushroomMoving_CollisionCheck_y
	boolean array MushroomMoving_CollisionCheck_boo
endglobals

function MushroomMoving_CollisionCheck_ForGroup takes nothing returns nothing
	local unit u=GetEnumUnit()
	local integer j=0
	local real otherx
	local real othery
	local integer i = MushroomMoving_CollisionCheck_i
	local real x = MushroomMoving_CollisionCheck_x
	local real y = MushroomMoving_CollisionCheck_y
	if u!=OrangeMushroom[i] then
		set j=UnitIndex(u)
		if (GetPlayerSlotState(GetOwningPlayer(OrangeMushroom[j]))==PLAYER_SLOT_STATE_PLAYING or j>PLAYER_MAXINUM) and LevelClearState[j]==false then
			if MB_Frame_On==1 then
				set MB_CollisionY = MB_CollisionY+1
			endif
			set otherx=GetUnitX(OrangeMushroom[j])
			set othery=GetUnitY(OrangeMushroom[j])
			if ContainsCoords(otherx-64,othery-64,otherx+64,othery+64,x,y)==true then
				if PropellyCondition==true then
					if GetUnitTypeId(OrangeMushroom[j])!='orai' then
						set u=null
						set Frame_MainPlayerY=j
						set MushroomMoving_CollisionCheck_boo[i]=false
						return
					endif
				else
					set u=null
					set Frame_MainPlayerY=j
					set MushroomMoving_CollisionCheck_boo[i]=false
					return
				endif
			endif
		endif
	endif
	set u=null
	set MushroomMoving_CollisionCheck_boo[i]=true
	return
endfunction

function MushroomMoving_CollisionCheck takes integer i,real x,real y returns boolean
	local group G = CreateGroup()
	set MushroomMoving_CollisionCheck_i=i
	set MushroomMoving_CollisionCheck_x=x
	set MushroomMoving_CollisionCheck_y=y
	call GroupEnumUnitsInRange(G, x,y, 128, null)
	call ForGroup(G,function MushroomMoving_CollisionCheck_ForGroup)
	return MushroomMoving_CollisionCheck_boo[i]
	call DestroyGroup(G)
	set G=null
endfunction
коллизии начали кашлять
особенно в конце видео где 3 коробки - там видна рандомность - то стоит на коробке то проваливается


Jack-of-shadow: попробуй что то типо того:
сначала попробовал по аналогии с твоим кодом , только таймер в 100 раз меньше чем 0.02 = чтобы просчитать 100 коробок за 1 фрейм
call TriggerRegisterTimerEvent(t,0.0002,true)
и даже если коробок 10 а не 100, то просчитает всё за 10 тиков, а остальные 90 будет скипать
а call Frame__SquaresMoving(i) отключил, то есть Frame__SquaresMoving просчитывается отдельным кодом вообще
что должно сказаться на физике
Открыть код и скриншот
globals
	integer playersCurrectFrameOffset = 1
endglobals

function Frame__SquaresMoving2 takes nothing returns nothing
local integer i
	local real saveMaxG=-30
	local integer j=1
if playersCurrectFrameOffset <= PLAYER_MAXINUM+Stage_BoxsCount then
	set i = playersCurrectFrameOffset
	set Frame__SpeedX=8
	set Frame_MainPlayer=i
	if LevelClearState[i]==false then
		call Frame__MovingX(i,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))
		call Frame__MovingY(i,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))
		if s__StatusBorad_World[Status]>=6 then
			if IsUnitInRegion(Water_Rects,OrangeMushroom[i])==true then
				set saveMaxG=-10
			endif
		endif
		if GetUnitTypeId(OrangeMushroom[i])!='orai' then
			if Water_State[i]==true and DownArrow[i]==true then
				set gravity[i]=-15
			else
				if gravity[i]>saveMaxG then
					set gravity[i]=gravity[i]-2.0
				elseif gravity[i]<saveMaxG then
					set gravity[i]=saveMaxG
				endif
			endif
		endif
		if GetUnitTypeId(OrangeMushroom[i])!='orai' then
			if Frame__AccelerationCheck[i]==false then
				if Acceleration[i]!=0 then
					if Acceleration[i]>60 then
						set Acceleration[i]=60
					elseif Acceleration[i]>1 then
						set Acceleration[i]=Acceleration[i]-1
					elseif Acceleration[i]<-60 then
						set Acceleration[i]=-60
					elseif Acceleration[i]<-1 then
						set Acceleration[i]=Acceleration[i]+1
					else
						set Acceleration[i]=0
					endif
				endif
			else
				set Frame__AccelerationCheck[i]=false
			endif
		endif
	endif
        set playersCurrectFrameOffset = playersCurrectFrameOffset+1
endif	
endfunction

function Frame__SquaresMoving2Init takes nothing returns nothing
	local trigger t=CreateTrigger()
	call TriggerRegisterTimerEvent(t,0.0002,true)
	call TriggerAddAction(t,function Frame__SquaresMoving2)
endfunction 

function Frame__PlayersGroup takes nothing returns nothing
	local integer i=1
	if GravityChanger_Loading==false then
		set Frame__BoxState=false
		loop
			exitwhen i>PLAYER_MAXINUM
			if GetPlayerSlotState(Player(i-1))==PLAYER_SLOT_STATE_PLAYING then
				set Frame__OldX[i]=GetUnitX(OrangeMushroom[i])
				set Frame__OldY[i]=GetUnitY(OrangeMushroom[i])
			endif
			set i=i+1
		endloop
		set i=1
		loop
			exitwhen i>PLAYER_MAXINUM+Stage_BoxsCount
			if i<=PLAYER_MAXINUM then
				if GetPlayerSlotState(Player(i-1))==PLAYER_SLOT_STATE_PLAYING then
					if CinematicMode==false then
						if Observer_ViewNumber[i]==0 then
							if GravityChanger_State==false then
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[i],0,128,false)
							else
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[i],0,-128,false)
							endif
						else
							if GravityChanger_State==false then
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[Observer_ViewNumber[i]],0,128,false)
							else
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[Observer_ViewNumber[i]],0,-128,false)
							endif
						endif
					endif
					//call Frame__SquaresMoving(i)
				endif
			else
				set Frame__BoxState=true
				//call Frame__SquaresMoving(i)
			endif
			set i=i+1
		endloop
		set Frame__BoxState=false
		set i=1
		loop
			exitwhen i>PLAYER_MAXINUM+Stage_BoxsCount
			if i<=PLAYER_MAXINUM then
				if GetPlayerSlotState(Player(i-1))==PLAYER_SLOT_STATE_PLAYING then
					if CinematicMode==false then
						call BackGroundMove(i,Frame__OldX[i],Frame__OldY[i])
					endif
					set Frame__PropellyState[i]=false
					set Frame__GravityState[i]=false
					if NameTextTag[i]!=null then
						if GravityChanger_State==false then
							call SetTextTagPos(NameTextTag[i],GetUnitX(OrangeMushroom[i])-50,GetUnitY(OrangeMushroom[i])-120,0)
						else
							call SetTextTagPos(NameTextTag[i],GetUnitX(OrangeMushroom[i])+50,GetUnitY(OrangeMushroom[i])+120,0)
						endif
					endif
					call Jumper_Main(i)
					if s__StatusBorad_World[Status]==6 and IsPointInRegion(Arrow_AllRects,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))then
						call Arrow_SecretAction(i)
					endif
				endif
			else
				if Stage_BoxsCount !=0 then
					set Frame__PropellyState[i]=false
					set Frame__GravityState[i]=false
					call Jumper_Main(i)
					if s__StatusBorad_World[Status]==6 and IsPointInRegion(Arrow_AllRects,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))then
						call Arrow_SecretAction(i)
					endif
				endif
			endif
			set i=i+1
		endloop
	endif
endfunction

function main takes nothing returns nothing
call Frame__SquaresMoving2Init()
endfunction
но чё то не завелось, гриб на старте висит в воздухе и не ходит


зато твоя идея
+ этот пост:
nazarpunk: Условно хаотично бывает в асинхронных языках, где ты в жассе нашёл асинхронность?
натолкнули меня на ещё более простое и легко встраиваемое решение через TriggerEvaluate
Открыть код
globals
	trigger Frame__SquaresMoving3Trg = CreateTrigger()
	integer playersCurrectFrameOffset = 1
endglobals

function Frame__SquaresMoving3Act takes nothing returns boolean
local integer i=playersCurrectFrameOffset
	local real saveMaxG=-30
	local integer j=1
	set Frame__SpeedX=8
	set Frame_MainPlayer=i
	if LevelClearState[i]==false then
		call Frame__MovingX(i,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))
		call Frame__MovingY(i,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))
		if s__StatusBorad_World[Status]>=6 then
			if IsUnitInRegion(Water_Rects,OrangeMushroom[i])==true then
				set saveMaxG=-10
			endif
		endif
		if GetUnitTypeId(OrangeMushroom[i])!='orai' then
			if Water_State[i]==true and DownArrow[i]==true then
				set gravity[i]=-15
			else
				if gravity[i]>saveMaxG then
					set gravity[i]=gravity[i]-2.0
				elseif gravity[i]<saveMaxG then
					set gravity[i]=saveMaxG
				endif
			endif
		endif
		if GetUnitTypeId(OrangeMushroom[i])!='orai' then
			if Frame__AccelerationCheck[i]==false then
				if Acceleration[i]!=0 then
					if Acceleration[i]>60 then
						set Acceleration[i]=60
					elseif Acceleration[i]>1 then
						set Acceleration[i]=Acceleration[i]-1
					elseif Acceleration[i]<-60 then
						set Acceleration[i]=-60
					elseif Acceleration[i]<-1 then
						set Acceleration[i]=Acceleration[i]+1
					else
						set Acceleration[i]=0
					endif
				endif
			else
				set Frame__AccelerationCheck[i]=false
			endif
		endif
	endif
return false
endfunction 

function Frame__SquaresMoving3Init takes nothing returns nothing
	call TriggerAddCondition(Frame__SquaresMoving3Trg, Condition(function Frame__SquaresMoving3Act))
endfunction

function Frame__PlayersGroup takes nothing returns nothing
	local integer i=1
	if GravityChanger_Loading==false then
		set Frame__BoxState=false
		loop
			exitwhen i>PLAYER_MAXINUM
			if GetPlayerSlotState(Player(i-1))==PLAYER_SLOT_STATE_PLAYING then
				set Frame__OldX[i]=GetUnitX(OrangeMushroom[i])
				set Frame__OldY[i]=GetUnitY(OrangeMushroom[i])
			endif
			set i=i+1
		endloop
		set i=1
		loop
			exitwhen i>PLAYER_MAXINUM+Stage_BoxsCount
			set playersCurrectFrameOffset=i
			if i<=PLAYER_MAXINUM then
				if GetPlayerSlotState(Player(i-1))==PLAYER_SLOT_STATE_PLAYING then
					if CinematicMode==false then
						if Observer_ViewNumber[i]==0 then
							if GravityChanger_State==false then
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[i],0,128,false)
							else
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[i],0,-128,false)
							endif
						else
							if GravityChanger_State==false then
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[Observer_ViewNumber[i]],0,128,false)
							else
								call SetCameraTargetControllerNoZForPlayer(Player(i-1),OrangeMushroom[Observer_ViewNumber[i]],0,-128,false)
							endif
						endif
					endif
					call TriggerEvaluate(Frame__SquaresMoving3Trg)
				endif
			else
				set Frame__BoxState=true
				call TriggerEvaluate(Frame__SquaresMoving3Trg)
			endif
			set i=i+1
		endloop
		set Frame__BoxState=false
		set i=1
		loop
			exitwhen i>PLAYER_MAXINUM+Stage_BoxsCount
			if i<=PLAYER_MAXINUM then
				if GetPlayerSlotState(Player(i-1))==PLAYER_SLOT_STATE_PLAYING then
					if CinematicMode==false then
						call BackGroundMove(i,Frame__OldX[i],Frame__OldY[i])
					endif
					set Frame__PropellyState[i]=false
					set Frame__GravityState[i]=false
					if NameTextTag[i]!=null then
						if GravityChanger_State==false then
							call SetTextTagPos(NameTextTag[i],GetUnitX(OrangeMushroom[i])-50,GetUnitY(OrangeMushroom[i])-120,0)
						else
							call SetTextTagPos(NameTextTag[i],GetUnitX(OrangeMushroom[i])+50,GetUnitY(OrangeMushroom[i])+120,0)
						endif
					endif
					call Jumper_Main(i)
					if s__StatusBorad_World[Status]==6 and IsPointInRegion(Arrow_AllRects,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))then
						call Arrow_SecretAction(i)
					endif
				endif
			else
				if Stage_BoxsCount !=0 then
					set Frame__PropellyState[i]=false
					set Frame__GravityState[i]=false
					call Jumper_Main(i)
					if s__StatusBorad_World[Status]==6 and IsPointInRegion(Arrow_AllRects,GetUnitX(OrangeMushroom[i]),GetUnitY(OrangeMushroom[i]))then
						call Arrow_SecretAction(i)
					endif
				endif
			endif
			set i=i+1
		endloop
	endif
endfunction

function main takes nothing returns nothing
	call Frame__SquaresMoving3Init()
endfunction
теперь варик не захлёбывается, ник не отклеивается, и каждый гриб(ящик) просчитывается отдельным потоком с сохранением физики
макс количество коробок поднялось до 50+ и уже упирается всё в fps
-box1 поднялось с 11(v1.0) 14(v1.4) до 22 (выше тоже можно но фпс ниже 20)
-box3 поднялось с 11(v1.0) 25(v1.4) до 35 (20 фпс)
при отключении -pro режима фпс вырастет с 20 до 40
теперь осталось причесать код (указанные выше UnitIndex и global G) и опять обновлять версию
а если найти ошибки в 1 и 2 варианте выше в этом посте то и сравнить на скорость и фпс все 3 способа
Загруженные файлы
1
25
6 месяцев назад
Отредактирован Jack-of-shadow
1
host_pi, насколько я помню Варкрафт просто не умеет в период меньше чем 0.01. На счёт коробок, их вобще по идее не нужно обновлять пер Фрейм. У них должно быть состояние активации и деактивации после применения к ним силы или падения.

У меня была похожая система в проекте. Но там еще была загвоздка с тем, что весь террейн был разрушаемый. По этому при разрушении клетки я искал объект на клетке и активировал ему физику на некоторое время пока он опять не оказывался в состоянии покоя.
0
14
6 месяцев назад
0
Jack-of-shadow: Но там еще была загвоздка с тем, что весь террейн был разрушаемый. По этому при разрушении клетки
тут тоже самое, если кодом убрать под собой ландшафт, то все объекты полетят вниз пока не долетят до следующей твёрдой клетки
0
14
6 месяцев назад
Отредактирован host_pi
0
обновлено до версии 1.5
теперь полноценно можно заспавнить 50 коробок и мерять свои фепосы
EN xgm.guru/files/100/315886/comments/520926/OMS_BoxLab_1.5_EN.w3x
RU xgm.guru/files/100/315886/comments/520926/OMS_BoxLab_1.5_RU.w3x
код 1.5 controlc.com/fce08fe1
дальше уже только оптимизация кода для повышения фпс
Загруженные файлы
0
14
6 месяцев назад
Отредактирован host_pi
0
nazarpunk: На каждого юнита вызывается UnitIndex. Тоесть лишний цикл на количество игроков. Можно просто каждому грибу записать его индекс через SetUnitUserData. Будет дешевле
в версии 1.5 не вылечил это место, т.к. через SetUnitUserData и GetUnitUserData можно хранить только 1 значение на каждого юнита
и это значение уже занято в функции Propelly__Main
Propelly__Main
function Propelly__Main takes nothing returns nothing
	local integer i=1
	local integer j=1
	if GetUnitTypeId(GetTriggerUnit())=='orai' then
		loop
			exitwhen Propelly__CompareRect[i]==null
			if GetTriggeringRegion()==Propelly__Rects[i]then
				loop
					exitwhen j>Stage_BoxsCount
					if GetUnitTypeId(OrangeMushroom[PLAYER_MAXINUM+j])=='orai' and GetTriggerUnit()==OrangeMushroom[PLAYER_MAXINUM+j]and GetUnitUserData(GetTriggerUnit())!=i then
						call SetUnitUserData(GetTriggerUnit(),i)
						if Propelly__Angle[i]=="Left" then
							if GravityChanger_State==false then
								call SetUnitAnimation(GetTriggerUnit(),"Stand First")
							else
								call SetUnitAnimation(GetTriggerUnit(),"Stand Second")
							endif
							set LeftArrow[PLAYER_MAXINUM+j]=true
							set RightArrow[PLAYER_MAXINUM+j]=false
						elseif Propelly__Angle[i]=="Right" then
							if GravityChanger_State==false then
								call SetUnitAnimation(GetTriggerUnit(),"Stand Second")
							else
								call SetUnitAnimation(GetTriggerUnit(),"Stand First")
							endif
							set LeftArrow[PLAYER_MAXINUM+j]=false
							set RightArrow[PLAYER_MAXINUM+j]=true
						else
							set LeftArrow[PLAYER_MAXINUM+j]=false
							set RightArrow[PLAYER_MAXINUM+j]=false
						endif
						set gravity[PLAYER_MAXINUM+j]=Propelly__FlyGravity[i]
					endif
					set j=j+1
				endloop
				return
			endif
			set i=i+1
		endloop
	endif
endfunction

function Propelly__SetRect takes trigger t,integer i,rect r,real g,string a returns nothing
	set Propelly__Rects[i]=CreateRegion()
	call RegionAddRect(Propelly__Rects[i],r)
	set Propelly__FlyGravity[i]=g
	set Propelly__CompareRect[i]=r
	set Propelly__Angle[i]=a
	call TriggerRegisterEnterRegion(t,Propelly__Rects[i],null)
endfunction

function Propelly__init takes nothing returns nothing
	local trigger t=CreateTrigger()
	call Propelly__SetRect(t,1,gg_rct_PropellyMove001,10,"none")
	call TriggerAddAction(t,function Propelly__Main)
	set t=null
endfunction
буду искать какими способами можно хранить в юнитах числовую информацию
т.к. на тестах после замены UnitIndex(u) на GetUnitUserData(u) фпс поднялся в разы
например 40 фпс наступает не при -box1 20 , а уже при -box1 37
а если сделать две лесенки: -ladder2 20 + 30 раз -box - итого 50 коробок двумя лесенками - то будет 30 фпс
а в текущей версии на 50 коробках фпс упадёт до 0 из-за UnitIndex
nazarpunk: Очищать глобальную группу G дешевле, чем дрочить создание/удаление локалки.
потестировать это пока не удалось, т.к. коллизии всегда выдавали true и коробки проваливались - наверное неправильно очищал группу через дестрой, покурю ещё это место
Загруженные файлы
1
29
6 месяцев назад
1
наверное неправильно очищал группу через дестрой
Глобальная группа очищается через ClearGroup.
0
14
6 месяцев назад
Отредактирован host_pi
0
nazarpunk: Очищать глобальную группу G дешевле, чем дрочить создание/удаление локалки.
Глобальная группа очищается через ClearGroup
исправлено, на фпс не сказалось, но код стал на несколько строк меньше
nazarpunk: На каждого юнита вызывается UnitIndex. Тоесть лишний цикл на количество игроков. Можно просто каждому грибу записать его индекс через SetUnitUserData. Будет дешевле.
после переработки UnitIndex и переноса номера юнита в его хп - количество фпс увеличилось в разы
теперь можно с 30 коробками бегать в 64 фпс
и даже заспавнить 50 коробок двумя лесенками на 30 фпс
подробности на графике
код 1.7 тут controlc.com/4bf12fa3
1
29
6 месяцев назад
Отредактирован nazarpunk
1
после переработки UnitIndex и переноса номера юнита в его хп - количество фпс увеличилось в разы
Не стал писать в вопросе, но для хранения данных именно на грибах идеально подойдут паралельные массивы по индексу игрока. В каждом отдельном месте выигрыша может быть незначительным, но в совокупности может зарешать.
0
14
6 месяцев назад
Отредактирован host_pi
0
nazarpunk: для хранения данных именно на грибах идеально подойдут паралельные массивы по индексу игрока
ага, там изначально вся инфа (кроме координат) и хранится в таких массивах - направление, нажатые стрелки, ускорение, гравитация, цвет, имя, коды, наблюдение, статус финиша, фон, музыка
1
29
6 месяцев назад
1
ага, там изначально вся инфа
А как же проверка на самолётик? Её тоже лучше булевым флагом хранить.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.