Waiting for Factory Created Game Object to initialize

Hello,

I am using two factories to spawn two different types of objects.

I spawn over a hundred of object1 and object2 which both have collision boxes and add them to a table.

Then I immediately raycast from the position of object1 to detect if it is right next to any of object2.

The raycasts will always return no result and I’m guessing that its because the collision boxes or the gameobjects aren’t really there yet by the time I run the raycast.

So to test this, I run the raycasts function with a timer delay to wait a frame like this
timer.delay(0, false, function() RaycastAll() end)
This only works for a couple of objects to initialize and the raycasts to produce a result.

So then I upped the timer delay to 0.1 second and it works for all of the raycasts to produce correct results.

I think this must not be a good way to handle this problem because:

#1 I’m running from a nice gaming computer and if somebody runs my game from a old phone it might take them a lot longer to initialize and they would fail again.

#2 I’m guessing if I up the objects to 1000s instead of 100s then I would need to keep increasing the delay.

So my question is how am I supposed to properly wait for the gameobjects to full initialize on any device without putting in some arbitrary delay number? Or it could be possible that I am misinterpreting what the problem really is.

#firstpost, Loving Defold, I’ve been here a week trying to port my game in progress to this engine

1 Like

Not sure what is the cause here, but I can suggest instead of timer using the update() or the fixed_update() function. After you spawn your objects do the raycasts there, if it doesn’t work add a one or two frame delay (a simple boolean flag or a counter variable). See if it produces a consistent result.

Using timer.delay(0, ) should delay the callback until the init() function of all scripts have ran. I’m a bit surprised it doesn’t.

An alternative is to post a message. Messages are processed after the init of all components…

What does your code look like? I assume something like this?

function init(self)
	local objects1 = {}
	local objects2 = {}

	for i=1,100 do
		local id = factory.create("#factory1")
		objects1[#objects1 + 1] = id
	end
	for i=1,100 do
		local id = factory.create("#factory2")
		objects2[#objects2 + 1] = id
	end

	timer.delay(0, false, function()
		for _,id1 in ipairs(objects1) do
			for _,id2 in ipairs(objects2) do
				physics.raycast ...
			end
		end
	end)
end
1 Like

Its a random dungeon creator that runs at the start.
A random dungeon is created as a global string and a message is sent to the script to that it is ready build the dungeon.
The two objects in question are walls and floors. When the script loops through the string and finds a floor this is run
local pos = vmath.vector3(col * 3, row * 3,-3)
local component = "#FloorFactory"
local plane = factory.create(component, pos, nil, nil, 3.0)
table.insert(planeTable, plane)

and when it finds a wall this is run
local pos = vmath.vector3(col * 3, row * 3, 0)
local component = "#WallFactory"
local wall = factory.create(component, pos, nil, nil, 1.5)
table.insert(Map, wall)

then i have added the delay timer to start the raycast function
timer.delay(0.1, false, function() InitWallsAndFloors() end)

function IntiWallsAndFloors()
	local my_groups = { hash("floor") }
	local numIsland = 0
	for i = 1, #Map do

		if Map[i] ~= nil then 


			local numHit = 0
			local my_start = go.get_position(Map[i]) 
			local my_north = my_start + vmath.vector3(0, 3, -3)
			local my_south = my_start + vmath.vector3(0, -3, -3)
			local my_east = my_start + vmath.vector3(3, 0, -3)
			local my_west = my_start + vmath.vector3(-3, 0, -3)
			local result = physics.raycast(my_start, my_north, my_groups)
			local result2 = physics.raycast(my_start, my_south, my_groups)
			local result3 = physics.raycast(my_start, my_east, my_groups)
			local result4 = physics.raycast(my_start, my_west, my_groups)
			
			if result then		
				numHit = numHit + 1
			else				
				msg.post(msg.url(nil, Map[i], "sprite_north"), "disable") 
			end

			local result2 = physics.raycast(my_start, my_south, my_groups)	
			if result2 then	
				numHit = numHit + 1
			else
				msg.post(msg.url(nil, Map[i], "sprite_south"), "disable") 
			end

			local result3 = physics.raycast(my_start, my_east, my_groups)
			if result3 then	
				numHit = numHit + 1
			else
				msg.post(msg.url(nil, Map[i], "sprite_east"), "disable") 
			end

			local result4 = physics.raycast(my_start, my_west, my_groups)
			if result4 then	
				numHit = numHit + 1
			else
				msg.post(msg.url(nil, Map[i], "sprite_west"), "disable")
			end
			
			--print("numhit:"..numHit)
			if numHit == 4  then 
				numIsland = numIsland + 1	
			end
		end
	end	
end

The script then goes on to analyze the dungeon and finds doorways, deadends, room sizes, secret areas etc. All of the analysis will fail if the raycasts from the walls do not hit the floors.

The walls and floors are simple collision boxes and sprites, no scripts, so no separate init functions need to run, but the collision boxes need to be there to be hit.

Unfortunately, the msg.post instead of the timer delay didn’t work. The raycasts didn’t hit the floors.

As for putting the timer in a update function, I’m not sure that will help because we still have a timer, and even if the timer works fine on my gaming computer, it might fail on a old phone that takes longer.

edit: so I did more testing and it seems that waiting 2 frames always works. I did a 1 frame timer that started a empty function that only had another 1 frame timer that called the real function and that worked every time with a total of 2 frames. I haven’t tested this on any devices but hopefully that works.

1 Like