Hello
I was trying to make code simpler by making a global function.

However, the process to make this took two functions and three independent variables. I wanted to integrate the variables inside the function and one of the functions inside the other, like in the drawing. But I get this error that says "Standalone lambdas cannot be accessed. Consider assigning it to a variable". Am I doing something wrong? Thanks

  • synthnostate replied to this.
  • oobiekanoobie Your code still has some indentation problems.
    If you want to make a typewriter effect on a label, here's how to do it by a single call from _ready() using a lambda signal callback:

    extends Label
    
    func _ready():
    	type_it("Type this text into a typewriter")
    
    func type_it(what: String, character_delay: float = .1):
    	self.text = what 
    	self.visible_characters = 0
    	var t = Timer.new()
    	add_child(t)
    	t.wait_time = character_delay
    	t.connect("timeout", func():
    		self.visible_characters += 1
    		if self.visible_characters == self.text.length():
    			t.queue_free()
    	)
    	t.start()

    It looks like you are trying to define an anonymous (lambda) function in the global scope which is syntactically not valid. To make this work, you need to assign the lambda function to a variable. For example:

    let myLambda = (x, y, z) -> {
    // Do something here
    };

    // You can now use the lambda function like this:
    myLambda(1, 2, 3);

    Also note that when declaring a lambda function, the arrow (->) must be on the same line as the arguments:

    let myLambda = (x, y, z) -> {
    // Do something here
    };

      GodetteAI you need to assign the lambda function to a variable

      That much is correct, but the rest of GodetteAI's post seems to be in some language other than GDScript. She apparently doesn't know that the question concerns GDScript in Godot 4 unless that's stated in the post.

      Here's how to define and call a lambda function in GDScript:
      https://docs.godotengine.org/en/4.0/tutorials/scripting/gdscript/gdscript_basics.html#lambda-functions

      oobiekanoobie gdscript is similar to python in this regard. I think you can do

      var the_timeout = func(): print(2)
      $node.connect(the_timeout)

      or just $node.connect(func(): print(2))

      but if you need more than a one-liner you have to define a separate function.

      I think the idiomatic gdscript solution is to wrap your vars and functions in a class, though.

      • xyz replied to this.

        synthnostate Lambdas can have any number of lines. Otherwise they wouldn't be of much use.

        (func():
        	for n in 10:
        		print(n)
        ).call()

        oobiekanoobie Your question is really not clear. The code image you posted does not communicate what you want to do and bot's inept response on lambdas only muddied the water more. So try to be more punctual with your question (what exactly are you're trying to accomplish) and post some actual code.

          xyz Okay, here is the code

          extends Control
          
          var textToReveal: String = "This is the text to be revealed"
          var STATUS_PROCESS : bool
          var STATUS_DONE : bool
          var revealInterval: float = 0.05
          var visible_letters : int = 0
          var pressed_z = 0
          
          func _ready():
          	$Timer.wait_time = revealInterval
          	STATUS_DONE = true
          	STATUS_PROCESS = false
          
          func _input(event):
          	if STATUS_DONE == true:
          			if event.is_action_pressed("ui_accept"):
          				pressed_z += 1
          				if pressed_z == 1:
          					$Label.text = ""
          					visible_letters = 0
          					$Timer.start()
          					STATUS_DONE = false
          					STATUS_PROCESS = true
          				elif pressed_z == 2:
          					visible_letters = 0
          					pressed_z = 0
          					STATUS_DONE = true
          					$Label.text = ""
          	elif STATUS_DONE == false:
          		if Input.is_action_just_released("ui_accept"):
          			if pressed_z == 1:
          				$Label.text = textToReveal
          				$Timer.stop()
          				STATUS_DONE = true
          				STATUS_PROCESS = false
          				print("Skipped text")
          func _on_timer_timeout():
          	if visible_letters < textToReveal.length():
          		var letter = textToReveal[visible_letters]
          		$Label.text += letter
          		if letter != " ":  
          			$AudioStreamPlayer.play()
          			visible_letters += 1
          		elif letter == " ":
          			visible_letters += 1
          	else:
          		STATUS_DONE = true
          		print("Printing finished")
          		$Timer.stop()

          I am trying to make that a global function, but the downsides are it requires a AudioStreamPlayer, a Label and a Timer. I tried to make it so I make a global variable that integrates the timeout inside the global function and uses variables as nodes. For the Label and AudioStreamPlayer I tried replacements that are working properly but the timer won't work and the lambas thing is a bit confusing. Can I make that whole process into a single function?
          btw, it is for making a dialogue that is written progressively, like in Professor Layton

          • xyz replied to this.

            oobiekanoobie
            I'm not sure why exactly do you need a global function for that.
            Labels have visible_characters property. You can simply animate that (prefferrably with a tween). It'll make the whole thing much easier.

            And please format your code inside proper tags. It's hard to follow it this way.

            And please format your code inside proper tags. It's hard to follow it this way.

            To do that, place ~~~ on lines before and after the code. The </> icon at the bottom of the post is supposed to do that, but it doesn't always work correctly.

            My bad

            extends Control
            
            var textToReveal: String = "This is the text to be revealed"
            var STATUS_PROCESS : bool
            var STATUS_DONE : bool
            var revealInterval: float = 0.05
            var visible_letters : int = 0
            var pressed_z = 0
            
            func _ready():
                     $Timer.wait_time = revealInterval
                     STATUS_DONE = true
                     STATUS_PROCESS = false
            
            func _input(event):
                if STATUS_DONE == true:
                if event.is_action_pressed("ui_accept"):
                    pressed_z += 1
                    if pressed_z == 1:
                        $Label.text = ""
                        visible_letters = 0
                        $Timer.start()
                        STATUS_DONE = false
                        STATUS_PROCESS = true
                    elif pressed_z == 2:
                        visible_letters = 0
                        pressed_z = 0
                        STATUS_DONE = true
                        $Label.text = ""
                elif STATUS_DONE == false:
                    if Input.is_action_just_released("ui_accept"):
                        if pressed_z == 1:
                            $Label.text = textToReveal
                            $Timer.stop()
                            STATUS_DONE = true
                            STATUS_PROCESS = false
                            print("Skipped text")
            func _on_timer_timeout():
                if visible_letters < textToReveal.length():
                    var letter = textToReveal[visible_letters]
                    $Label.text += letter
                    if letter != " ":
                        $AudioStreamPlayer.play()
                        visible_letters += 1
                    elif letter == " ":
                        visible_letters += 1
                    else:
                        STATUS_DONE = true
                        print("Printing finished")
                        $Timer.stop()

              oobiekanoobie Yeah, a "lambda" is a function without a name. It has access to the local variables of its parent function, which is what you want... I think.

                synthnostate Yep, that is pretty much what I want to do (integrating the timeout inside the main variable so work gets easier. Is there any good tutorial on it or do the docs explain it pretty well?

                  oobiekanoobie Your code still has some indentation problems.
                  If you want to make a typewriter effect on a label, here's how to do it by a single call from _ready() using a lambda signal callback:

                  extends Label
                  
                  func _ready():
                  	type_it("Type this text into a typewriter")
                  
                  func type_it(what: String, character_delay: float = .1):
                  	self.text = what 
                  	self.visible_characters = 0
                  	var t = Timer.new()
                  	add_child(t)
                  	t.wait_time = character_delay
                  	t.connect("timeout", func():
                  		self.visible_characters += 1
                  		if self.visible_characters == self.text.length():
                  			t.queue_free()
                  	)
                  	t.start()

                    xyz Ok thank you so much, that madew everything simpler! Have a nice day everyone who helped me 🙂

                    oobiekanoobie Is there any good tutorial on it or do the docs explain it pretty well?

                    The docs are decent. If you really want to learn all the tricks you can do with lambdas, learn some Javascript. They're usually called "closures" there btw. (Because they "enclose" the outer scope variables.)