[SOLVED] Problem with my Factory Collection. Spawning delayed

Hi, I’m currently using a Factory collection to generate the endless map of my game as it goes. Each segment is 512px wide and the Factory which spawns these collections is at the 960px position as the intention is that the tiles spawn outside the player’s screen when the end of each segment reaches that point so it’s seemles.

Spawning the tiles works mostly fine but they generate a gap between each segment as seen in the video bellow.

I tried debugging the code and found out that the trigger that checks the position has some kind of delay.

image

Maybe is actually getting the position value of the collection each frame but when it receives the notice that the position is lesser or equal to 960px it’s already bellow that point and that’s why it spawns with those gaps.

Here’s my most recent code of this functional version. I’ve tried looking for possible delay timers for the factory to spawn and other workarounds this issue but I’m against another roadblock. Thanks again in advance for the help and tips

Position Marker/Parent Object that moves the tiles

function init(self)
	self.speed = go.get("/controller#controller", "speed")
	self.spawn_free = true
	
	--self.moving = true
end

function update(self, dt)	
	local pos = go.get_position()
	if self.spawn_free and pos.x <= 960 then
		print(go.get_position())
		msg.post("/level_gen_factory", "spawn_free")
		self.spawn_free = false
	end
	pos.x = pos.x - self.speed * dt 
	go.set_position(pos)

	if pos.x < -10 then
		go.delete(true)
	end
end

Factory code

local probability = {
	[1] = 100,
	[2] = 0,
	[3] = 0,
	[4] = 0
}

local function level_random(max)
	local lvl 
	local random = math.random(1, max)
	if random <= probability[1] then
		lvl = 1
	elseif random <= probability[1] + probability[2] then
		lvl = 2
	elseif random <= probability[1] + probability[2] + probability[3] then
		lvl = 3
	elseif random <= probability[1] + probability[2] + probability[3] + probability[4] then
		lvl = 4
	end

	return lvl 
end

function init(self)
	self.probability_max = 0
	for i = 1, #probability do
		self.probability_max = self.probability_max + probability[i]
	end
	math.randomseed(tonumber(hash_to_hex(hash(tostring({}))):sub(4, 8), 16))

	self.spawn_free= true
end

function on_message(self, message_id, message, sender)
	if message_id == hash("spawn_free") then 
		self.spawn_free = true
		print("Spawn Tile")
	end
end

function update(self, dt)
	if  self.spawn_free then
		self.spawn_free = false
		local pos = go.get_position()
		pos.y = 0
		local component = "/level_gen_factory#level_gen_factory_" ..level_random(self.probability_max)

		local level = collectionfactory.create(component, pos)

		for key, value in pairs(level) do
			msg.post(value, "start_animation", { delay = 0.3 * math.random()})
			msg.post(value, "disable_spawncheck")
		end
	end
end

First off, you’re spawning segments on the next frame after the “spawn_free” message gets sent. If you look at the lifecycle of the update loop, all objects get their update() call and then messages are handled. So your factory script is waiting for a frame.

Instead of setting self.spawn_free = true and waiting until the next update, you should just spawn the segment immediately in on_message.


Secondly, you need to account for the time “in between” frames. Even if your game runs at 500 FPS, it’s still not continuous, it still happens in snapshots, frame-by-frame. That’s the “delay” you’re dealing with.

You’ll never get an event exactly when the segment’s position hits 960. One frame it will be at 982.1023409851, and the next frame it’ll be at 957.3485074219. All of your segments are always at these weird decimal positions, but you’re always spawning them at exactly 960, so there will always be a gap. If you increase the speed or reduce the frame rate, the gap will get larger.

Instead of spawning new segments at a fixed position, you want to spawn them so they match up with the previous segment. What you can do is include the X pos of the segment in your “spawn_free” message and use that plus 512 (or 512*2 if you’re keeping 2 segments visible) as the spawn position instead of exactly 960.


Personally, I would switch things around a bit and make deleting and spawning segments separate. Really, you want to spawn a new segment when the right edge of the right-most segment gets too close to the right edge of the screen. But…that’s probably just me being a perfectionist. :smiley: It shouldn’t matter unless you want to add segments of different widths.

4 Likes

Didn’t have in account the lifecycle, so will definitely try to change that

Also, your solution with the spawning position might be the answer I was looking for, will try that ASAP, thanks for the tips!

2 Likes

When I do this type of scrolling (and I do it a lot) I get the position of the previous GO, and the length of that GO, and add them together to calculate the position of the new GO. Also, rather than spawning a new collection each time, I just have two or three GO and use go.set_position() (as well as go.animate() to get the effect you are looking for. I also make sure objects are spawned (or moved) to a position which is at least 1.5 times the screen width.

However, please bear in mind that we are always looking for “best practices” and efficiency. Whilst you are working on your first games, you shouldn’t feel like you have to get everything perfect according to what people say on the internet.

4 Likes

I think I’m going to try doing it this way as when I tried it gave me the result I wanted.

But I must ask, doing it this way can I randomize the position of the GOs? In the setting of a city I would like that from time to time it has a crossroad or if it were to be a forest to have a river with a bridge to go through, but I don’t want it to be too repetitive. If it’s not it’s alright too, I’ll manage to find a workaround.

And thanks for the help! : D

You should use something like:

Local yposition = math.random(0, 640)
go.set_position(“object”, vmath.vector3(1000, yposition, 0)

That will set the position of “object” to X= 1000, y = random number between 0 and 640.

2 Likes

Marvelous, will be trying these and see how it works.

Again, thank you so much!