Can I send a message to THE SCRIPT of a factory spawned object and change the state of already generated objects?

Hi guys, if you look at this it might be easier to explain what I’m trying to do…

MY MINI-GOAL:
(0) Let’s call the green blocks floaties and the red blocks bumps
(1) When Icarus hits a floaty with a feather it turns into a bump.
(2) I want to limit Icarus to picking up only one bump at a time, i.e. after he has one I want any others that happen to be on screen to stay there even if he touches them, until (5) happens
(3) When he picks up a bump it shows on the HUD
(4) When he has a bump his projectile changes from a feather to fries(just a placeholder for now).
(5) When he fires the fries, his projectile changes back to a feather, and he can pick up bumps again.

MY PROBLEM:
I’m struggling with (2). Is it possible to send a msg.post(…), from the icarus.script to the bump.script? At the moment the bumps are generated using a factory which is triggered when a feather hits a floaty. I want to send a message that can hopefully temporarily disable collision detection only between Icarus and the bumps, when Icarus has already got a bump. I’ve got a boolean flag, “pick_me_up” in the bump.script to hopefully help with this:

if message_id == hash("contact_point_response") then
		if message.group == hash("icarus") and pick_me_up then
			pick_me_up = false
			go.delete()
		end	

Now my hope is that after I fire off fries that I’ll send a message to the bump script that will then change the pick_me_up variable back to true. In this case a go.property() wont work because I want to affect all instances of the bumps when I flick the pick_me_up switch not just individual instances. I’m hoping that I can change the state of all bump instances dynamically. Is this even possible?

  • I’ve tried: msg.post("/bump#script", “set_pickupable”), which I knew wouldn’t work but I still had to give it a go.

  • I’ve tried: msg.post(“bump#script”, “set_pickupable”), which I thought might work, but it didn’t. I get this error message: Instance ‘(null)’ could not be found when dispatching message ‘contact’ sent from default:/icarus#script

  • I’ve tried sending a message from a bump that’s been collected just so I can get its url so I can send a message back to it, but because I delete bumps straight away the instances no longer exist. So this didn’t work either.

Any suggestions? Can this even be done? Cheers

PS. I’m not entirely convinced that the collision group with a boolean thing will even work properly. It doesn’t seem to be working very well on some experiments I’ve done. I think I’m misunderstanding something about life-cycles or the frame rates are throwing something off, but that’s a story for another day.

When you spawn a game object using factory.create() you get an id back. You can use this id to post messages to the game object:

local id = factory.create(...)
msg.post(id, "my_message")

This would send the message to all components of the created game object, but in the case of a custom message such as “my_message” only script components would actually care about it. If you want to send the message to a specific component on the spawned game object you can create a url that includes the component id:

local id = factory.create(...)
msg.post(msg.url(nil, id, "script"), "my_message")

The msg.url() function expects three arguments: socket, path, fragment. In this case there’s no need to specify the socket since the game object posting the message and the spawned game object exist in the same collection. The path part of the url can be set to the id of the spawned object. The fragment part of the url is set to the id of the script, which I assume is “script”.

When it comes to your specific problem about sometimes ignoring collisions with collision group bump I’d say that it’s probably better to try and keep as much of the logic and game state as possible in the icarus/hero script. Something like:

function init(self)
	-- keep track of if the hero has picked up a bump or not
	self.has_picked_up_bump = false
end

function on_input(self, action_id, action)
	if action_id == hash("fire") and action.released then
		-- hero is firing fries if bump has been picked up, otherwise a feather
		if self.has_picked_up_bump then
			shoot_fries()
			-- reset the bump flag
			-- the player should be able to pick up a bump again
			self.has_picked_up_bump = false
		else
			shoot_feather()
		end
	end
end

function on_message(self, message_id, message)
	if message_id == hash("collision_response") then
		-- hero is colliding with a bump
		-- if the hero hasn't already picked up a bump we pick it up
		-- and set the flag
		if message.group == hash("bump") and not self.has_picked_up_bump then
			go.delete(message.other_id)
			self.has_picked_up_bump = true
		end
	end
end
6 Likes

Thanks britzyl! Once again I owe you a beer

2 Likes

Actually one other thing. I see that you declared self.has_picked_up_bump in init() in the example code. I don’t understand the real difference between declaring a local variable at the top of your script that has scope across the whole script and a"self.x" variable in init(). Is there advantages/disadvantages to using one over the other? I’ve tried swapping between both just to experiment, but it doesn’t seem to affect output either way. Things just seem to run the same. I read the lua in defold part of the manual and it says that the order of statements may be an issue when using “local” to define a function, but I don’t know if there’s any other major difference? Cheers :relaxed:

1 Like

they have different context, in your case if there is another lcarus in game then they will share same variable pick_me_up value, following is the detail, .

https://www.defold.com/manuals/lua/#_lua_contexts_in_defold

2 Likes

Thanks for that

You can check out this discussion here:

2 Likes