instantiationgodotgdscript

How to change visibility of a sprite in one instance of a scene in Godot


I am relatively new to Godot, and I'm having a bit of trouble making a Tic Tac Toe game as practice. I have two scenes: one is the gameboard, which resembles a #. The other scene is called "playable square". It will represent the Area where the user can click to play either X or 0 depending their turn. This playable square scene consists of an Area2D node, with a Collision2D node and two sprites: one for the X, and one for the 0. Both sprites have their visibility set to false. The idea is that when the user clicks on the Area2D root node, one of the two sprites will become visible. In my main scene, I have placed nine instances of the "playable square" scene. And its script is like this:

extends Area2D

@onready var theX = $TheX
@onready var theO = $The0



# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
   pass

func _input(event):
if event.is_action_pressed("mouseleft"):
    theX.visible=true
    

func play0():
   theO.visible=true

However, upon clicking on one of them, the X becomes visible in all squares. I know that resources are shared between instances, but how can I make them be unique per instance? I tried making each "playable square" instance local to the main scene, but the same thing keeps happening. I also tried using "Access as Unique Name" on the X and 0 sprites, to no avail. I'm obviously missing something very basic here but I can't figure it out. Any info will be appreciated!


Solution

  • Your problem is, that you are using the wrong function for your click check.

    _input is called for every element in your scene, if an input happens. It is actually not important, where you click on the screen it will be transmitted to all elements. If you really want to use this function you need to check the postition of the mouse.

    Because you are already using Area2Ds I recomment another way. The Area2D has an signal called input_event. You find, if you select your root node in the playable_square scene and then switch to the Node tab in the inspector. Alternativly you can connect it via code, like in my example below.

    Connect it with your playable_square script and copy your existing code into that function. This Signal will only fire, if an input event is happening in your collision area.

    your script would look like this:

    extends Area2D
    
    @onready var theX = $TheX
    @onready var theO = $The0
    
    
    func _ready()
        connect("input_event", _on_input_event)
    
    # Called every frame. 'delta' is the elapsed time since the previous frame.
    func _process(delta):
       pass
    
    func _on_input_event(viewport, event, shape_idx):
        if event.is_action_pressed("mouseleft"):
            theX.visible=true
    
    
    func play0():
       theO.visible=true
    

    The connect part might differ, if you are using a diffrent version of Godot. I'm on 4.0