есть одна 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]) - считывание координат
графики:
скриншот карты:
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
30
а как передать переменные внутрь ForGroup?
Через глобалки. Я что-то не припомню чтоб в жасс состояние гонки завезли. Так что все форгрупы выполнятся строго подряд.

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

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

это если юнит не самолётик.
Булевый флаг по индексу будет всяко быстрее вызова функции и сравнения чисел.
14
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 способа
Загруженные файлы
26
host_pi, насколько я помню Варкрафт просто не умеет в период меньше чем 0.01. На счёт коробок, их вобще по идее не нужно обновлять пер Фрейм. У них должно быть состояние активации и деактивации после применения к ним силы или падения.

У меня была похожая система в проекте. Но там еще была загвоздка с тем, что весь террейн был разрушаемый. По этому при разрушении клетки я искал объект на клетке и активировал ему физику на некоторое время пока он опять не оказывался в состоянии покоя.
14
Jack-of-shadow: Но там еще была загвоздка с тем, что весь террейн был разрушаемый. По этому при разрушении клетки
тут тоже самое, если кодом убрать под собой ландшафт, то все объекты полетят вниз пока не долетят до следующей твёрдой клетки
14
обновлено до версии 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
дальше уже только оптимизация кода для повышения фпс
Загруженные файлы
14
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 и коробки проваливались - наверное неправильно очищал группу через дестрой, покурю ещё это место
Загруженные файлы
30
наверное неправильно очищал группу через дестрой
Глобальная группа очищается через ClearGroup.
14
nazarpunk: Очищать глобальную группу G дешевле, чем дрочить создание/удаление локалки.
Глобальная группа очищается через ClearGroup
исправлено, на фпс не сказалось, но код стал на несколько строк меньше
nazarpunk: На каждого юнита вызывается UnitIndex. Тоесть лишний цикл на количество игроков. Можно просто каждому грибу записать его индекс через SetUnitUserData. Будет дешевле.
после переработки UnitIndex и переноса номера юнита в его хп - количество фпс увеличилось в разы
теперь можно с 30 коробками бегать в 64 фпс
и даже заспавнить 50 коробок двумя лесенками на 30 фпс
подробности на графике
код 1.7 тут controlc.com/4bf12fa3
30
после переработки UnitIndex и переноса номера юнита в его хп - количество фпс увеличилось в разы
Не стал писать в вопросе, но для хранения данных именно на грибах идеально подойдут паралельные массивы по индексу игрока. В каждом отдельном месте выигрыша может быть незначительным, но в совокупности может зарешать.
14
nazarpunk: для хранения данных именно на грибах идеально подойдут паралельные массивы по индексу игрока
ага, там изначально вся инфа (кроме координат) и хранится в таких массивах - направление, нажатые стрелки, ускорение, гравитация, цвет, имя, коды, наблюдение, статус финиша, фон, музыка
30
ага, там изначально вся инфа
А как же проверка на самолётик? Её тоже лучше булевым флагом хранить.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.