Factory production based on list

Ok im having brain fog.

in Godot I created simple list of id names. Then I have hundreds of these lists ea containing the next wave of enemies.

Then when I instanced an object it would check the id name and set the sprite, health, and speed of obj in its _ready or _init function and delete it from the list.

In Defold - So I want to have as few factories as possible- so when a factory produces a GO, then that GO should be able to read the next ID in the list and set its sprite, id, health and speed. In defold / lua what is the best practice /structure for this kind of thing?

so if the main script has the factory function- it would also need to hold the array- then in the game object script it would need to read that array and change itself? And delete the item in the array/list upon self destruction at collision etc.

Main Script:

timer function:
reads array/list
calls factory

instanced GO script
reads array and sets sprite, id, health, and speed based in array id
deletes itself from array on destruction

Am I thinking clearly here?

Hello Jb_skaggs,

I think it’s largely a good path, but I believe you can fill a [properties] table when you create the factory, which you could fill with the next instance of the array, this would mean that you don’t need to read the array in the script.

[properties]

(optional) A Lua table with any script property values to initiate the game object with. See the Script property manual for information on script properties.

To find out what the recommended approach is we would need an update from someone more knowledgeable than myself.

Cheers,
Spen

2 Likes

Yep, you can use script properties. These can be set when calling factory.create() or from the editor when selecting the script component of a game object in the scene (not applicable in your case).

--enemy.script
go.property("sprite_id", hash(""))
go.property("health", 100)
go.property("speed", 50)

function init(self)
   sprite.play_flipbook("#sprite", self.sprite_id)
   print(self.health)
   print(self.speed)
end
-- enemy definition
local BLAZER = {
	sprite_id = hash("blazer"),
	health = 10,
	speed = 100,
}

-- enemy definition
local BRUTE = {
	sprite_id = hash("brute"),
	health = 100,
	speed = 10,
}


function init(self)
	-- enemies to spawn
	self.enemies = {
		BLAZER,
		BLAZER,
		BRUTE,
		BLAZER,
		BRUTE
	}

	-- spawn an enemy every 2 seconds
	timer.delay(2, true, function()
		-- get the next enemy to spawn
		local enemy = table.remove(self.enemies)
		if enemy then
			factory.create("#enemyfactory", pos, nil, enemy)
		end
	end)
end
4 Likes

Thanks!

Alright back from getting chemo pump removed, eating lunch, and modeling some marbles- now Im going to see if I can implement this lesson!

1 Like

Clarification: So would I have each sprite listed in outline of collection then for the enemies?

GO
brute (sprite)
blazer(sprite)

or am I updating the existing sprite from the atlas?

Currently I think the NAVGO library requires the enemies to call their sprite “sprite”

Your generic enemy game object has one sprite component. In the enemy.script you change the animation/image used by your sprite component like I showed in the example.

1 Like

Thanks:)

-- enemy definition
local YELLOW = {
	sprite_id = hash("2dyellowsprite"),
	health = 10,
	speed = 100,
}

-- enemy definition
local RED = {
	sprite_id = hash("2dredsprite"),
	health = 100,
	speed = 10,
}

-- enemy definition
local BLUE = {
	sprite_id = hash("2dbluesprite"),
	health = 100,
	speed = 10,
}

-- enemy definition
local GREEN = {
	sprite_id = hash("2dgreensprite"),
	health = 100,
	speed = 10,
}



function init(self)
	-- enemies to spawn
	self.enemies = {
		YELLOW,
		BLUE,
		YELLOW,
		GREEN,
		RED
	}
	local message = {}
	message.collisions = { hash("wall") }
	message.debug = false
	message.deleteNodeAfterGotten = true
	message.nodeNeighborRange = 400
	message.nodeNeighborRange = 400
	msg.post("/NavGO_HandlerGO#NavGO_HandlerScript", hash("init"), message)
	-- get the next enemy to spawn
	local enemy = table.remove(self.enemies)
	if enemy then		
		timer.delay(1, true, function()
				local url = "#factory"
				local position = vmath.vector3(-200, 200, 0) -- position where character spawns
				local rotation = vmath.quat_rotation_z(0) --quat angle the character spawns at
				local properties = { Start_path_ID = 1, End_path_ID = 100, speed = 400 } -- table of values to send to object
				local scale = vmath.vector3(0.5, 0.5, 0.51) -- scale to spawn at
				
				factory.create(url, position, rotation, properties, scale, enemy)
				
			end
		)
	end
end

The obj spawns but does not receive any of the “enemy” info.

ERROR:GAMESYS: Unable to play animation '' from texture '/_generated_d934a80e.texturec' since it could not be found.
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 400
DEBUG:SCRIPT: hash: []
DEBUG:SCRIPT: enemy
ERROR:GAMESYS: Unable to play animation '' from texture '/_generated_d934a80e.texturec' since it could not be found.
DEBUG:SCRIPT: Directional - PATH FOUND
INFO:DLIB: SSDP: Done on address 192.168.0.2
INFO:DLIB: SSDP: Done on address 192.168.56.1

I dont know how to print the name of the table in enemy to see which table its actually sending.

You’re sending the “properties” table. The “enemy” table is used as the sixth argument in the factory.create function, which is dropped, I assume, as it only takes five arguments.

You’ll need to merge the two tables and only send one of them. Something like:

local url = "#factory"
local position = vmath.vector3(-200, 200, 0) -- position where character spawns
local rotation = vmath.quat_rotation_z(0) --quat angle the character spawns at
local properties = { Start_path_ID = 1, End_path_ID = 100, speed = 400 } -- table of values to send to object
for key, val in pairs(enemy) do
    properties[key] = val
end
local scale = vmath.vector3(0.5, 0.5, 0.51) -- scale to spawn at

factory.create(url, position, rotation, properties, scale)
1 Like

Well that makes sense if factory create can only have 5 options.

This though is a completely new concept to me what is it doing exactly and how does it get passed on?

When I added this the factory quit producing objs and showed this response:

INFO:DLIB: Log server started on port 55277
INFO:ENGINE: Target listening with name: DESKTOP-T9J0991 - fe80::6864:d0a8:85fb:42cf - Windows
INFO:ENGINE: Engine service started on port 55278
INFO:ENGINE: Defold Engine 1.2.178 (af6a29c)
INFO:ENGINE: Loading data from: build/default
INFO:ENGINE: Initialised sound device 'default'
DEBUG:SCRIPT: Listening for debugger on 0.0.0.0
DEBUG:SCRIPT: Debugger connected from 127.0.0.1
DEBUG:SCRIPT: nil
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 400
DEBUG:SCRIPT: hash: []
ERROR:GAMESYS: Unable to play animation '' from texture '/_generated_d934a80e.texturec' since it could not be found.
INFO:DLIB: SSDP: Started on address 192.168.0.2
INFO:DLIB: SSDP: Started on address 192.168.56.1
DEBUG:SCRIPT: WARNING: NODE url: [main:/NavGO_NodeGO#NavGO_NodeScript] does not have any connections within range.
DEBUG:SCRIPT: -- NavGo is ready to be used
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 10
DEBUG:SCRIPT: hash: [2dredsprite]
DEBUG:SCRIPT: Directional - PATH FOUND
INFO:DLIB: SSDP: Done on address 192.168.0.2
INFO:DLIB: SSDP: Done on address 192.168.56.1

I only have five objects in my table yellow, blue, yellow, green, red and notice above it repeatedly says 2dredsprite which should have only been once. And it showed none of the others at all. And none of them appeared on the game map.

My whole project quit working.

So I reloaded my previous save and its not working and Im getting java errors.

I sent a copy of my script of my backup before these changes to the NAVGO library post and just incase there was an error I am overlooking. So I am now trying to discover what exactly is happening with my system. I dont think the code we added above did any of this- since its also affecting a previous working project.

Try restarting Defold.

I did and rebooted my system same problem. I am going to remake this project. And see what happens.

Ok, let us know how it goes

Okay I remade the project all objects spawn and move.

-- enemy definition
local YELLOW = {
	sprite_id = hash("yellowsprite"),
	health = 10,
	speed = 100,
}

-- enemy definition
local RED = {
	sprite_id = hash("redsprite"),
	health = 100,
	speed = 10,
}

-- enemy definition
local BLUE = {
	sprite_id = hash("bluesprite"),
	health = 100,
	speed = 10,
}

-- enemy definition
local GREEN = {
	sprite_id = hash("greensprite"),
	health = 100,
	speed = 10,
}



function init(self)
	
	-- enemies to spawn
	self.enemies = {
		YELLOW,
		BLUE,
		YELLOW,
		GREEN,
		RED
	}
	local message = {}
	message.collisions = { hash("wall") }
	message.debug = false
	message.deleteNodeAfterGotten = true
	message.nodeNeighborRange = 400
	message.nodeNeighborRange = 400
	msg.post("/NavGO_HandlerGO#NavGO_HandlerScript", hash("init"), message)
	-- get the next enemy to spawn
	local enemy = table.remove(self.enemies)
	if enemy then		
		timer.delay(1, true, function()
			local url = "#factory"
			local position = vmath.vector3(-200, 200, 0) -- position where character spawns
			local rotation = vmath.quat_rotation_z(0) --quat angle the character spawns at
			local properties = { Start_path_ID = 1, End_path_ID = 100, speed = 400 } -- table of values to send to object
			local scale = vmath.vector3(0.5, 0.5, 0.51) -- scale to spawn at
			--for key, val in pairs(enemy) do
				--properties[key] = val --this adds the tables from enemy to the properties variable for factory.create
			--end
			factory.create(url, position, rotation, properties, scale)

		end
	)
end
end

But if I add this:

for key, val in pairs(enemy) do
	properties[key] = val --this adds the tables from enemy to the properties variable for factory.create
end

to add the sprite_id etc then no objects render.

obj script:

require("navGo_pathfinding.NavGO_Global")

go.property("Start_path_ID", -1)
go.property("End_path_ID", -1)
go.property("speed", 400)
go.property("sprite_id", hash(""))
go.property("health", 100)




local function distance(vec1, vec2)
	return math.ceil( math.sqrt( math.pow(vec1.x - vec2.x, 2) + math.pow(vec1.y - vec2.y, 2) ) )
end

local function moveCharacter(self)
	local path, found = NAVGO.GET_PATH_FROM_DIRECTIONAL_ID(self.Start_path_ID, self.End_path_ID)
	if not found then
		print("Directional - NO PATH FOUND")
	else
		print("Directional - PATH FOUND")
		local delay = 0
		local lastPos = go.get_position(go.get_id())
		print("Number of nodes in path" .. tostring(#path))
		for i=1, #path do
			local newPosition = vmath.vector3(path[i].x, path[i].y, 0)
			local time = distance(newPosition, lastPos) / self.speed -- move at a consistend speed
			go.animate(go.get_id(), "position", go.PLAYBACK_ONCE_FORWARD, newPosition, go.EASING_LINEAR, time, delay)
			print("is calling go.animate")
			lastPos = newPosition
			delay = delay + time
		end
		--timer.delay(delay, false, moveCharacter)
	end
end


------------------
--Core functions--
------------------

function init(self)
	sprite.play_flipbook("#sprite", self.sprite_id)
	print(self.health)
	print(self.speed)
	print("sprite:")
	print(self.sprite_id)
	timer.delay(1, false, moveCharacter)
	print("start")
	print(self.Start_path_ID)
	print("end")
	print(self.End_path_ID)
end

Adding pprint(enemy) lets me see what is being sent.

The output is so:

DEBUG:SCRIPT: 
{ --[[000001C098F1CC10]]
  health = 100,
  sprite_id = hash: [redsprite],
  speed = 10
}
INFO:DLIB: SSDP: Started on address 192.168.0.2
INFO:DLIB: SSDP: Started on address 192.168.56.1
DEBUG:SCRIPT: WARNING: NODE url: [main:/NavGO_NodeGO#NavGO_NodeScript] does not have any connections within range.
DEBUG:SCRIPT: 100
DEBUG:SCRIPT: 400
DEBUG:SCRIPT: sprite:
DEBUG:SCRIPT: hash: []
DEBUG:SCRIPT: start
DEBUG:SCRIPT: 1
DEBUG:SCRIPT: end
DEBUG:SCRIPT: 100
ERROR:GAMESYS: Unable to play animation '' from texture '/_generated_2eb13aa7.texturec' since it could not be found.
DEBUG:SCRIPT: Directional - PATH FOUND
DEBUG:SCRIPT: Number of nodes in path10
DEBUG:SCRIPT: is calling go.animate
INFO:DLIB: SSDP: Done on address 192.168.0.2
INFO:DLIB: SSDP: Done on address 192.168.56.1

Which is wrong as the object is YELLOW and hash for sprite should be “yellowsprite” instead it reads “redsprite” but in the object it reads “”.

Strange. Could you perhaps share the project with me (bjorn@defold.se) or a small repro case? I’m sure it’s some trivial little thing we both miss!

I’m seeing spawning balls of different colors:

I have no idea what’s going on with the NavGO in this screenshot though!

Things I changed was to set the spawn position to (200, 200, 0) instead of (-200, 200, 0) to immediately see the balls. I also changed to a repeating timer and I grab a new enemy in the timer callback:

function init(self)

	-- enemies to spawn
	self.enemies = {
		YELLOW,
		BLUE,
		YELLOW,
		GREEN,
		RED
	}
	local message = {}
	message.collisions = { hash("wall") }
	message.debug = false
	message.deleteNodeAfterGotten = true
	message.nodeNeighborRange = 400
	message.nodeNeighborRange = 400
	msg.post("/NavGO_HandlerGO#NavGO_HandlerScript", hash("init"), message)
	-- get the next enemy to spawn
	timer.delay(1, true, function()
		local enemy = table.remove(self.enemies)
		if enemy then
			local url = "#factory"
			local position = vmath.vector3(200, 200, 0) -- position where character spawns
			local rotation = vmath.quat_rotation_z(0) --quat angle the character spawns at
			local properties = { Start_path_ID = 1, End_path_ID = 100, speed = 400 } -- table of values to send to object
			local scale = vmath.vector3(0.5, 0.5, 0.51) -- scale to spawn at
			for key, val in pairs(enemy) do
				properties[key] = val --this adds the tables from enemy to the properties variable for factory.create
			end
			factory.create(url, position, rotation, properties, scale)
		end
	end)
end

Well that is an improvement and one that Dr Campbell can help with I think. I am hopeful all this work will also make his library more useful and attractive to others.

I also think I generate an anti-code field that causing all programming to glitch.
:slight_smile:

2 Likes