I am working on a game where the player can place down motion sensors and if a motion sensor detects movement, it’s corresponding map icon will light up on an in-game map.
I have the item placement, motion sensor script, and even creating icons per motion sensor to place on the map down. However my current script can only place map icons in the right position and amount relative to the motion sensors. After this, though, each icon can’t continue to communicate with the motion sensors.
To put it more simply: there is no “1-to-1” between the motion sensor item, and the map icon. Each map icon is created per motion sensor, and is placed correctly on the map, but once the icon is created nothing else can be done.
Because of this, there is no way to make the correct map icon do ANYTHING in relation to a motion sensor because there is no connection or communication between the two. Preferably I would want a system where a motion sensor can be assigned some sort of value that ties it to a motion sensor, but I can’t figure out how to code that in properly.
The current code for the map icons are as follows:
func _on_viewportmanager_refreshstatusicons():
# refresh map icons
get_tree().call_group("sensoricon", "delete_self")
# create an icon per motion sensor, and place it where the motion sensor's position is
for sensor_position: Vector3 in Global.motionsensorpositions:
motionsensor_icon_create(sensor_position)
func motionsensor_icon_create(at_position: Vector3):
# create icon
var iconinstance := preload("res://motionsensor_icon.tscn").instantiate()
# translate the 3D motion sensor position into the 2D map icon position
iconinstance.position = Vector2((at_position.z * 14) + 172, (-at_position.x * 14) + 495)
add_child(iconinstance)
I don’t really understand by “holds a reference”. I do understand what your saying, coding in some sort of ID that links the icon and motion sensor together, but I don’t know how to do it. Same with a dictionary, not sure how that would help for my use case.
After all, I don’t know a way to tell each map icon WHICH motion sensor it is tied to. Not that I can’t figure out how to make the map icon and motion sensor scripts communicate to each other.
Each node is an object. When you assign an object to a variable, that variable then contains what we call a reference to that object. This reference lets you access that node’s property and call its methods. You can use references when you need nodes to refer to or access each other.
So when you do:
var iconinstance := preload("res://motionsensor_icon.tscn").instantiate()
the variable iconinstance is a reference to the top node in the instantiated scene. You can create more references to the same node and store them in convenient variables, put them into dictionaries etc…
Also note that it’s not scripts that are communicating to each other. Rather, it’s nodes that run those script that are communicating. The same script can be attached to many nodes. Each individual node the script is attached to, defines its own execution context for that specific instance of the script. You’re effectively running the same script multiple times “simultaneously”.
Suppose a scene has a script attached to its top node. When you instantiate that scene several times, each instance will run its own instance of that script. So you don’t really communicate to the script as such. You communicate to a specific instance of it and you do it via a reference to the node the script is attached to.
Sorry for unmarking this as the solution, but I still can’t figure out how to make this work. Since what is being instantiated is the icon script, not the motion sensor script, I don’t see how your advice would help?
I now have coded in a system to give a basic ID to each motion sensor clone, but still no way to make that tie into my map icon code. Because the “iconinstance” is just preloading the map icon script, not anything to do with the in-game intractable motion sensor, if that makes sense? So I still don’t know how to make what I am envisioning work. Because even if I write stuff to a new array or dictionary, again how do I make each map icon correlate with the correct motion sensor? I can make as many IDs for each motion sensor as I want but if I can’t get that to work with the
for sensor_position: Vector3 in Global.motionsensorpositions:
motionsensor_icon_create(sensor_position)
You need to get the sensor node references when creating icons, and then store a reference to a sensor node on the corresponding icon’s side. That way each icon will hold a reference to its sensor node.
I can’t tell you how specifically to do it because you didn’t show enough of your code and scene structure.
Right now Global.motionsensorpositions only holds Vector3s, so by the time that loop runs the sensor itself is out of the picture. If that array holds the sensor nodes instead, you can read the position off the sensor and hand the sensor to the icon in the same step.
Wherever you’re currently appending the position, append the node:
This does seem to work, but I get console errors that imply that I can’t write a node to an array in general.
I have the code you’ve written down running, and I have the “sensor” var applied by:
var sensor = self
I get errors like “Trying to assign value of type ‘Node’ to a variable of type ‘Node3D’.” and replacing “Node3D” in the script with just “Node” makes the “sensor” variable not be able to get it’s position? As in, the “iconinstance.position” part of the script can’t get the global_position from the sensor variable. See the error:
Invalid access to property or key 'global_position' on a base object of type 'Node (sensorsmanager.gd)'.
However the array does appear to be accepting Nodes, as I can print the contents of it and get
Both entries in that print are the same object, the id #138462368165 repeats, and it’s the node running sensorsmanager.gd. So var sensor = self is putting the manager into the array rather than each individual sensor, and since that manager is a plain Node it has no transform, which is where the global_position error comes from.
The append wants to happen where a sensor gets placed, since that’s the one spot that has the new sensor node in hand. Wherever your old code appended the Vector3 to motionsensorpositions, it’d be something like:
var sensorinstance := preload("res://motionsensor.tscn").instantiate()
add_child(sensorinstance)
sensorinstance.global_position = place_position
Global.motionsensors.append(sensorinstance)
I’d keep the Node3D typing rather than loosening it to Node, and check that the root of your motion sensor scene is a 3D node (Node3D, Area3D, StaticBody3D, whichever it is). If that root is a plain Node the position problem follows you no matter what goes in the array.
Can you post the code that actually places a sensor? That’s the piece that hasn’t been shown yet and it’s where this all hinges.
The motion sensor has it’s root node be an Area3D. Tried putting that into the Array but I got the same “Trying to assign value” just this time with an Area3D instead of a Node3D.
Global.motionsensors.append(sensor) is appending sensor rather than sensorinstance. I’m guessing that’s the var sensor = self from your earlier post, which points at the sensorsmanager node, so every placement pushes that same manager into the array. That would explain the print showing the same object twice, and the type error following you around no matter which 3D type you declare, since the manager itself is a plain Node.
Global.motionsensors.append(sensorinstance)
If nothing else is using that var sensor = self line, it can come out too.