Looks like you're not logged in

Login or Register to continue

Lesson Q&A

Use this space for questions related to what you're learning. For any other type of support (website, learning platform, payments, etc...) please get in touch using the contact form.

  • Bravobardcore-pandaI want to give kudos after every lesson but I worry that it would flood the Q&A section. Since there are no comments yet, I'll do it on this one! You guys have accomplished an amazing pedagogical feat with this course. I teach coding to kids, so I can tell how much thought you've put into everything. All the exercises, the order in which you introduce ideas, the practices, the challenges you give us, the extra resources you point us to, teaching the programmer's mindset, little bits of humor... Keep up the great work Nathan and team! 1 42 May. 20, 2024
  • Challengemarinaton```gdscript extends Control #Control as the root node, with the script attached #There is also ColorRect node in the Scene Dock #BBcode is enabled @onready var texture_rect = %TextureRect @onready var texture_rect_2 = %TextureRect2 @onready var texture_rect_3 = %TextureRect3 @onready var rich_text_label = %RichTextLabel @onready var timer = %Timer var dialogue_items: Array[String] = [ "[center]Long ago, there existed a kingdom where a golden power lay hidden.[/center]", "[center]It was a prosperous land blessed with forests, tall mountains, and peace.[/center]", "[center]But one day a man of great evil found the golden power and took it for himself...[/center]", "[center] ....................................................................[/center]", "[center]This boy, who traveled through time to save the land, was known as the Hero of Time[/center]", "[center]The boy's tale was down through generations until it became legend...[/center]", ] func _ready() -> void: timer.autostart = false timer.wait_time = 10.0 timer.start() fading_1() image_slide_1() show_text() timer.timeout.connect(func() -> void: current_item_index += 1.0 if current_item_index == dialogue_items.size(): get_tree().quit() else: fading_2() ) func show_text() -> void: rich_text_label.text = dialogue_items[current_item_index] var text_wait: float = rich_text_label.get_parsed_text().length() / 10.0 timer.wait_time = text_wait func fading_1() -> void: var tween := create_tween() tween.set_trans(Tween.TRANS_SINE) tween.set_ease(Tween.EASE_OUT) rich_text_label.modulate.a = 0.0 tween.tween_property(rich_text_label, "modulate:a", 1.0, 0.4).set_delay(2) func fading_2() -> void: var tween := create_tween() tween.set_trans(Tween.TRANS_EXPO) tween.set_ease(Tween.EASE_OUT) rich_text_label.modulate.a = 1.0 tween.tween_property(rich_text_label, "modulate:a", 0.0, 0.4).set_delay(2) tween.finished.connect(func() -> void: timer.start() fading_1() show_text() if dialogue_items[2] == dialogue_items[current_item_index]: image_fade_1() if dialogue_items[4] == dialogue_items[current_item_index]: image_fade_2() image_slide_2() ) func image_slide_1() -> void: var tween := create_tween() tween.tween_property(texture_rect, "position", Vector2(0, 0), 25) func image_slide_2() -> void: var tween := create_tween() tween.tween_property(texture_rect_3, "position", Vector2(-700, 0), 25) func image_fade_1() -> void: var tween_fade := create_tween() tween_fade.tween_property(texture_rect, "modulate:a", 0, 0.8) func image_fade_2() -> void: var tween_fade := create_tween() tween_fade.tween_property(texture_rect_2, "modulate:a", 0, 0.8) ``` I tried to replicate the intro slideshow from the Zelda Wind Waker video and keep the code size as small as I could. [https://imgur.com/a/Mey5n04](https://imgur.com/a/Mey5n04) Initially, I thought I could use Timer's **time_left** property, so that **fading_2** could start before timer reaches 0, but it didn't work as intended, so I used another way to complete the challenge. 1 3 May. 31, 2024
  • ChallengeKetanThis last challenge took waaaay longer than I thought, so the least I can do is share with you what I created! I decide to play around with a Camera2D node to experiment a bit, here's the code! ```gdscript extends Control @onready var camera_2d: Camera2D = $Camera2D @onready var background: TextureRect = %Background @onready var rich_text_label: RichTextLabel = %RichTextLabel @onready var blackscreen: ColorRect = $Camera2D/Blackscreen @onready var timer: Timer = $Timer @onready var color_rect_2: ColorRect = $Camera2D/ColorRect2 @onready var initial_pos: Marker2D = $InitialPos @onready var secondary_pos: Marker2D = $SecondaryPos @onready var third_pos: Marker2D = $ThirdPos var count := 0 var backgrounds := [ preload("res://challenge/Sprite-0001.png"), preload("res://challenge/Sprite-0002.png"), preload("res://challenge/Sprite-0003.png"), preload("res://challenge/Sprite-0004.png"), preload("res://challenge/Sprite-0005.png"), ] var story_text: Array[String] = [ "[center]A long, long time ago, before any human was ever born...[/center] [center]The only thing on earth was Nature.[/center]", "[center]Flowers, trees and an endless amount of animals were living in armony with the planet.[/center]", "[center]But then, from deep within the ground...[/center]", "[center]And high above the clouds, higher than anything else...[/center]", "[center]A looming danger was about to disrupt this peaceful life.[/center]", ] func _ready() -> void: timer.timeout.connect(fade_to_background) show_text() func show_text() -> void: print(count) if count > 0: rich_text_label.position.y = 275 elif count == story_text.size(): get_tree().quit() var tween := create_tween() match count: 1: tween.tween_property(camera_2d,"position:x", 1000, 8.0) 2: tween.tween_property(camera_2d,"position:y", 400, 10.0) _: tween.tween_property(camera_2d,"position:y", 400, 10.0) rich_text_label.visible_ratio = 0.0 rich_text_label.text = story_text[count] var display_text_velocity: float = rich_text_label.get_parsed_text().length() / 15.0 tween.parallel().tween_property(rich_text_label, "visible_ratio", 1.0, display_text_velocity) tween.tween_property(blackscreen, "modulate:a", 1.0, 2.0) count += 1 await get_tree().create_timer(12.0).timeout new_background() func new_background() -> void: match count: 1: camera_2d.position = secondary_pos.position 2: camera_2d.position = third_pos.position _: camera_2d.position =initial_pos.position rich_text_label.visible_ratio = 0.0 if count == story_text.size(): get_tree().quit() else: background.texture = backgrounds[count] fade_to_background() show_text() func fade_to_background() -> void: var tween := create_tween() tween.tween_property(blackscreen, "modulate:a", 0.0, 4.0) ``` 3 2 Oct. 13, 2024
  • Challenge SolutionPaulJust wanted to say thankyou very much, the course has been fantastic so far, and thankyou for your help on some of my previous questions. Contrary to a few of the other comments, I really enjoyed the invitation to go and make something from a blank canvas and play with all of the things we've learned! A little daunting at first but once I got started, I was hooked! I made a little story, I've called it: "There was a blob". [https://www.youtube.com/watch?v=r-mYhDRMK_k](https://www.youtube.com/watch?v=r-mYhDRMK_k) I wanted to try programmatically drawing and manipulating some nodes, and creating a story that naturally looped but with randomised elements. I think it turned out well, but I'm sure there's a host of dodgy code where I was just trying to work something new out. (not after feedback per se, but here's my project to poke around at if desired!) [https://drive.google.com/file/d/1YGkPG_f7wIWlWNKn6Q8GTuNY2EB9_Pth/view?usp=sharing)](https://drive.google.com/file/d/1YGkPG_f7wIWlWNKn6Q8GTuNY2EB9_Pth/view?usp=sharing)) 2 1 Sep. 27, 2024
  • Scale/Slideshow ChallengeAJ StudiosI took on both challenges and wanted to show you guys the results I got. It's not ideal or the best but at least I was able to do it. Here's a link to the video: [https://youtu.be/UMWJ57LwDZo](https://youtu.be/UMWJ57LwDZo) 6 1 May. 29, 2024
  • Challenge & Questions!!required-cheetahWhat a challenge...! ```gdscript extends Control @onready var texture_rect: TextureRect = %TextureRect @onready var rich_text_label: RichTextLabel = %RichTextLabel @onready var timer: Timer = %Timer @onready var blackscreen: ColorRect = %Blackscreen @onready var text_blackscreen: ColorRect = %TextBlackscreen var images = { "beach"= preload("res://assets/challenge_intro/beach.jpg"), "dark_landscape" = preload("res://assets/challenge_intro/dark_landscape.jpg"), "happy_land" = preload("res://assets/challenge_intro/happy_land.jpg"), "landscape" = preload("res://assets/challenge_intro/landscape.jpg"), "mermaid" = preload("res://assets/challenge_intro/mermaid.jpg"), "skull" = preload("res://assets/challenge_intro/skull.jpg"), "ritual" = preload("res://assets/challenge_intro/ritual.jpg"), "soldier" = preload("res://assets/challenge_intro/soldier.jpg"), "swamp" = preload("res://assets/challenge_intro/swamp.jpg") } var intro_items:Array[Dictionary] = [ { "image": images["mermaid"], "text": "[center]I have seen a rumor born, swathed in snug mystery...[/center]" }, { "image": images["landscape"], "text": "[center]left lying under the sun, in the hills of the Gadrobi[/center]" }, { "image": images["ritual"], "text": "[center]where the sheep have scattered on wolf-laden winds...[/center]" }, { "image": images["beach"], "text": "[center]and the shepherds have fled, a whispering of sands[/center]" }, { "image": images["skull"], "text": "[center]and it blinked in the glare, a heart hardened into stone...[/center]" }, { "image": images["soldier"], "text": "[center]while the shadow of the Gates of Nowhere crept 'cross the drifting dust of home[/center]" }, { "image": images["swamp"], "text": "[center]I have seen this rumor born, a hundred thousand hunters of the heart...[/center]" }, { "image": images["dark_landscape"], "text": "[center]in a city bathed in blue light...[/center]" }, ] var current_item_index = 0 # Called when the node enters the scene tree for the first time. func _ready() -> void: fade_in() show_text() await get_tree().create_timer(12.0).timeout advance() if current_item_index >= 1: timer.start() #fade_in() func _process(delta: float) -> void: pass func show_text() -> void: if current_item_index <= intro_items.size(): var current_item = intro_items[current_item_index] rich_text_label.text = current_item["text"] texture_rect.texture = current_item["image"] func advance() -> void: current_item_index += 1 if current_item_index == intro_items.size(): timer.stop() fade_out() await get_tree().create_timer(5.0).timeout get_tree().quit() else: show_text() fade_in() func fade_in() -> void: var tween = create_tween() tween.tween_property(text_blackscreen, "modulate:a", 0.0, 4.0) tween.tween_property(blackscreen, "modulate:a", 0.0, 4.0) # func fade_out() -> void: var tween = create_tween() tween.tween_property(text_blackscreen, "modulate:a", 1.0, 3.0) tween.tween_property(blackscreen, "modulate:a", 1.0, 3.0) func _on_timer_timeout() -> void: advance() ``` [https://youtu.be/whwn3GyTFAs](https://youtu.be/whwn3GyTFAs) **Questions:** 1. I wanted to do some simple camera movements. I saw someone posted their methods, but I have trouble understanding them. Might need some tips and guidance :p 2. How can I make a cross fade between pictures? Also, any suggestions for improvement? **Thanks a lot guys! I've learned so much <3** 1 0 Nov. 17, 2024
  • My slideshowPurpleSunriseHello! I made a slideshow! I would never have thought I could achieve this! Thank you so much for the wonderful job you are doing with this course! I feel I am REALLY learning finally! The pictures are screenshots from the game concepts arts I made with blender. I want to port this concept into a 2D game I want to make after I finish this course. Do you think is achievable? Here's the slideshow: [https://drive.google.com/file/d/1bhYeSYVhBZY_ZKuDpH3ZKpqEJiqCy2F7/view?usp=sharing](https://drive.google.com/file/d/1bhYeSYVhBZY_ZKuDpH3ZKpqEJiqCy2F7/view?usp=sharing) And here's the code. I know it could be improved a lot. Actually I would be REALLY happy if I could get tips and improvements from the teachers! I decided that arrays would be the fastest and easiest way to achieve this but I am curious to know if I could do it nesting dictionaries in arrays. ```gdscript extends Control @onready var scene: TextureRect = %Scene @onready var audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer @onready var transition: ColorRect = %Transition @onready var label: Label = %Label @onready var timer: Timer = %Timer var scenes : Array=[ preload("res://Slideshow/1.png"), preload("res://Slideshow/2.png"), preload("res://Slideshow/3.png"), preload("res://Slideshow/4.png"), preload("res://Slideshow/5.png"), preload("res://Slideshow/6.png"), preload("res://Slideshow/7.png"), preload("res://Slideshow/8.png"), preload("res://Slideshow/9.png"), preload("res://Slideshow/10.png"), preload("res://Slideshow/11.png"), preload("res://Slideshow/12.png"), preload("res://Slideshow/13.png"), preload("res://Slideshow/14.png"), preload("res://Slideshow/16.png"), preload("res://Slideshow/18.png"), preload("res://Slideshow/19.png"), preload("res://Slideshow/20.png"), ] var scene_text : Array[String] =[ "Every young boy in the country dreams to become a cosmonaut one day.", "Your father is one of them.", "Misha, you will find what you're looking for. But you have to go through a lot of trials.", "See new worlds...", "", "Overcome obstacles...", "Solve puzzles...", "", "", "You will travel so far...", "Very far... To infinite horizons...", "I know I promised you I would return...", "I know it's hard to keep going...", "", "Thorugh this cold and lonely space...", "But you know... The darkest hour...", "Always...", "Comes before the dawn...", ] var scene_index := 0 var text_index := 0 func _ready() -> void: label.text = "" fade_in() timer.timeout.connect(advance) func play_text() -> void: timer.stop() label.modulate.a = 0.0 label.text = scene_text[text_index] var tween = create_tween() tween.tween_property(label, "modulate:a", 1.0, 1.0) tween.finished.connect(timer.start) func advance() -> void: scene_index += 1 text_index += 1 if scene_index == scenes.size() or text_index == scene_text.size(): fade_out() else: var next_scene := scene.duplicate() var node_index_counter := 0 add_child(next_scene) move_child(next_scene, -7 ) next_scene.modulate.a = 0.0 next_scene.texture = scenes[scene_index] var transition_speed := 2.0 var tween = create_tween() tween.tween_property(next_scene, "modulate:a", 1.0, transition_speed) tween.parallel().tween_property(label, "modulate:a", 0.0, transition_speed) node_index_counter = next_scene.get_index() print(node_index_counter) tween.finished.connect(play_text) func fade_in() -> void: audio_stream_player.play() var tween = create_tween() tween.set_trans(Tween.TRANS_CIRC) tween.tween_property(transition, "modulate:a", 0.0, 4.0) tween.parallel().tween_property(audio_stream_player, "volume_db", -10.0, 4.0) tween.finished.connect(play_text) func fade_out() -> void: var tween = create_tween() tween.set_trans(Tween.TRANS_CIRC) tween.tween_property(transition, "modulate:a", 1.0, 4.0) tween.parallel().tween_property(audio_stream_player, "volume_db", -80.0, 4.0) tween.finished.connect(get_tree().quit) ``` 2 0 Nov. 03, 2024
  • Slideshow Challenge: Stop tween animation?MrBright01Righto. First... thanks to GDQuest for being my rubber ducky. I spent a half hour typing out a question and in the process answered it (in the tween, "modulate.a" uses : and not .) But in doing so, I cam across a problem I had throughout the entirety of M7. When I click the button for next item or back item, the tween seems to pick up where the previous version left off. For example, below is a from-scratch slideshow challenge. The only problem so far is that if I click next before the animation ends, the next tween picks up where it left off position wise, but takes the full three seconds to finish whatever distance is left. Is there a way to get it to not do that? Like, it there a way to add "stop running tween when button is pressed"? ```gdscript func load_scene() -> void: text_rect.modulate.a = 0.0 text_rect.texture = combined_scene[scene_count]["image"] text_rect.position.y = 50 var s_tween = create_tween() print("Tween Start") #s_tween.set_trans(Tween.TRANS_QUART) #s_tween.set_ease(Tween.EASE_OUT) s_tween.parallel().tween_property(text_rect, "modulate:a", 1.0, 1.0) s_tween.parallel().tween_property(text_rect, "position:y", 0.0, 3.0) s_tween.finished.connect(_on_tween_finish) ``` 2 0 Oct. 30, 2024
  • For the second challange, what's the best approach for timing the transitions?substantial-tarsierI imagine a possible solution (or at least the one I would try first) is to have the block of text transition in, have a timer node wait a few seconds, then transition back out and just tweak the length of the timer node until it feels about right. But this also seems like clumsy non-elegant way of going about this. lol. 1 0 Oct. 15, 2024
  • Challenge 2: too big?davidakThis feels like too much work for a challenge. While i finished the other challenges in a few minutes by adding like 3 lines of code, this one feels like it will take half an hour, maybe even more than the average lesson! If i understand correctly, i would have to create a new scene and start from scratch. Adding many nodes and code. Then look for images and decide which one to use. One could be creative here and invent a story, but i don't think it's worth the effort for a challenge. So i would only create a demo. Do i understand the scope correctly? I feel overwhelmed by this challenge, because i don't know where to begin and feel discouraged, because the hints are not really helpful for solving the challenge. I want to do every challenge, to get the most out of the course, but this one seem to be too much for me. I left this challenge out and continued with the next 3 lessons. Could you add more hints about the high-level steps to solve the challenge? 1 0 Sep. 18, 2024
  • Challenge 1: instructions uncleardavidak> What can you do to make the animation even more attractive? That's kind of a big task. I haven't done a lot of animations and haven't seen a lot of cartoons to know how it's usually done. > Can you use scale to give Sophia a bit of squash and stretch? Sure i can, but how exactly should the animation look like? Can you maybe show an example video, as hint? I made her squash at the end when coming in. Hope that's good enough. ```gdscript tween.tween_property(body, "position:x", 0.0, 0.3) tween.parallel().tween_property(body, "modulate:a", 1.0, 0.2) tween.parallel().tween_property(body, "scale", Vector2(0.9, 1.0), 0.2) tween.tween_property(body, "scale", Vector2(1.0, 1.0), 0.1) ``` 1 0 Sep. 17, 2024
  • Intro slideshow that tells a story (Zelda-like) (Solution)HarbingerShThis is a rather complicated solution... So I tried to copy the Zelda intro slideshow and that's what I came up with! First, we set up a new scene [https://prnt.sc/jtlMUy1HSHwl](https://prnt.sc/jtlMUy1HSHwl) your scene should look like this The `Background` should be a Full Rect black color, whereas the `ImageRect` should look something like this [https://prnt.sc/H9a-NmMIo2bg](https://prnt.sc/H9a-NmMIo2bg) And most important is to make sure that the `ImageRect` Clip Children property under the visibility section is set to Clip Only [https://prnt.sc/ZUHhEtnpf25T](https://prnt.sc/ZUHhEtnpf25T) and the `Image` node is set to Full Rect and Expand Mode is set to `Fit height Proportional` and the Stretch Mode to `Keep Aspect Centered` [https://prnt.sc/vi3-ocRtZxtM](https://prnt.sc/vi3-ocRtZxtM) the `IntroText` label should also be a Full Rect and aligned to the center also make sure to set the modulate to be transparent as the default [https://prnt.sc/D5kmjvZrpJma](https://prnt.sc/D5kmjvZrpJma) same with the `Caption` label keep it centered and anchor it to the bottom of the screen but don't change the modulate property keep it as it is [https://prnt.sc/6kcYAadY5wK2](https://prnt.sc/6kcYAadY5wK2) now we can start coding first create a new Resource by right clicking on the `lessons` file in the Filesystem dock then Create new -> Script [https://prnt.sc/Q2hHBh3nM-VS](https://prnt.sc/Q2hHBh3nM-VS) make sure to set the inheritance to `Resource` and give it a name like `Caption` [https://prnt.sc/Hvg4aVCLtjSH](https://prnt.sc/Hvg4aVCLtjSH) this is the code for the new `Resource` ```gdscript class_name Caption extends Resource enum DIRECTIONS { Down, Up, Right, Left } @export var image: Texture2D = null @export var scroll_direction: DIRECTIONS = DIRECTIONS.Down @export_multiline var text: Array[String] = [] #Change that to whatever suits you! const image_base_divion: float = 50.0 func _on_get_duration_for_image() -> float: var image_size: float = 0.0 match scroll_direction: DIRECTIONS.Down, DIRECTIONS.Up: image_size = image.get_height() DIRECTIONS.Right, DIRECTIONS.Left: image_size = image.get_width() return image_size / image_base_divion func _on_get_duration_for_one_caption() -> float: return _on_get_duration_for_image() / text.size() ``` then, go back to the `IntroSlideshow` node (the root node) and make new script and add this code also ```gdscript class_name Slideshow extends Control @onready var intro_label: Label = %IntroText @onready var image: TextureRect = %Image @onready var caption: Label = %Caption @export_multiline var intro_text: String = "" @export_range(1.0, 10.0) var intro_text_duartion: float = 5.0 @export var slides: Array[Caption] = [] func _ready() -> void: await _on_display_intro_text() _on_display_slides() func _on_display_intro_text() -> void: intro_label.set_text(intro_text) var tween: Tween = create_tween() tween.tween_property(intro_label, "modulate", Color(1.0, 1.0, 1.0, 1.0), 1.2) await get_tree().create_timer(intro_text_duartion).timeout tween = create_tween() tween.tween_property(intro_label, "modulate", Color(1.0, 1.0, 1.0, 0.0), 1.2) await tween.finished func _on_display_slides() -> void: for slide: Caption in slides: image.set_texture(slide.image) image.scale = Vector2.ONE image.pivot_offset = image.texture.get_size() / 2 var direction: String = "" var end_position: float = 0.0 match slide.scroll_direction: slide.DIRECTIONS.Down: direction = "position:y" image.position.y = -image.texture.get_height() slide.DIRECTIONS.Up: direction = "position:y" image.position.y = 0 end_position = -image.texture.get_height() slide.DIRECTIONS.Right: image.scale = Vector2(1.2, 1.2) direction = "position:x" image.position.x = image.get_size().x * 0.1 end_position = -(image.get_size().x * 0.1) slide.DIRECTIONS.Left: image.scale = Vector2(1.2, 1.2) direction = "position:x" image.position.x = -(image.get_size().x * 0.1) end_position = image.get_size().x * 0.1 var tween: Tween = create_tween() tween.tween_property(image, direction, end_position, slide._on_get_duration_for_image()) var caption_duration: float = slide._on_get_duration_for_one_caption() var half_caption_duration: float = caption_duration / 2.0 for text: String in slide.text: caption.modulate = Color(1.0, 1.0, 1.0, 1.0) caption.visible_ratio = 0.0 caption.set_text(text) var new_tween: Tween = create_tween() new_tween.tween_property(caption, "visible_ratio", 1.0, half_caption_duration) await get_tree().create_timer(caption_duration).timeout new_tween = create_tween() new_tween.tween_property(caption, "modulate", Color(1.0, 1.0, 1.0, 0.0), 0.2) await new_tween.finished ``` in the inspector you will see all things to make your intro, like the Intro text and it's duration and most importent the Slides property which now you can click on it and add a new `Caption Resource` which contain a Image to display and the Scroll Direction and a Array of Strings to add as many Captions as you need! [https://prnt.sc/eB-pweat_hWm](https://prnt.sc/eB-pweat_hWm) now add a new image and select the direction and add captions [https://prnt.sc/j-CIHC4SnTL0](https://prnt.sc/j-CIHC4SnTL0) now run the scene and done! 👍 you could imporve it and add sounds effects that would be a good practice for you! 1 0 Sep. 08, 2024
  • (improved) My fix to tween animation problems when advancing dialogue quickly.MatejOne thing that bothered me was, that upon advancing the dialogue quickly, *the animations wouldn't restart from the baseline* (or in other words, *the initial position we want to tween from*). I looked into **Tween** and **PropertyTweener** documentation, and thought that maybe '**.from_current()**' (a method available to PropertyTweener) could help? And it does work. At least for this project so far. No matter how quickly I advance the dialogue, the tweens will always start from the values that are located under '**# INITIAL VALUES**' (see comment in the code below). This also works for the tween that is animating the text appearing on the screen. ```gdscript ## Animate the body sliding in upon advancing/rewinding dialogue. func slide_in() -> void: # Setting up the tween. var tween := create_tween() tween.set_trans(Tween.TRANS_QUAD) tween.set_ease(Tween.EASE_OUT) tween.set_parallel() # INITIAL VALUES body.position.x = 120.0 body.modulate.a = 0.0 body.scale.x = 0.98 body.scale.y = 1.04 # Animating the object properties to desired values. tween.tween_property(body, "position:x", 0.0, 0.8).from_current() tween.tween_property(body, "modulate:a", 1.0, 0.4).from_current() tween.tween_property(body, "scale:x", 1.0, 0.2).from_current().set_trans(Tween.TRANS_BOUNCE) tween.tween_property(body, "scale:y", 1.0, 0.5).from_current().set_trans(Tween.TRANS_BOUNCE) #... func show_text() -> void: #... tween.tween_property(rich_text_label, "visible_ratio", 1.0, text_appearing_duration).from_current() #... slide_in() ``` Of course another solution is to somehow disable the buttons until the longest tween is finished (including the text we're animating in this project). **HOWEVER!** - Another problem arose! The audio playback would still sometimes stop prematurely and/or not start from the beginning and then stop. Again, this time when we advance through the dialogue before '**tween.tween_property(rich_text_label, "visible_ratio", 1.0, text_appearing_duration)**' finishes animating. I've managed to find a solution for that: instead of stopping the audio playback with '**tween.finished.connect()**' - stop it with a **'timer.timeout()'** signal and use another **custom signal** to stop the old timer when we advance dialogue faster than '**text_appearing_duration**' (because I use this variable for the '**timer.wait_time()**'). I know that on its own, the explanation isn't descriptive enough, so here are the relevant pieces of code with the implemented solution from my workbook project: ```gdscript extends Control #... # The signal below will be emitted whenever # fucntions 'advance()' or 'go_back()' are called. signal current_item_index_changed # **DEFINING THE CUSTOM SIGNAL** # This signal is then connected to 'timer.stop()' # in the 'show_text()' function. More on that below. func _ready() -> void: show_text() next_button.pressed.connect(advance) back_button.pressed.connect(go_back) # This function is called when 'next_button' is pressed. func advance() -> void: current_item_index += 1 current_item_index_changed.emit() # **EMITTING THE CUSTOM SIGNAL** if current_item_index == dialogue_items.size(): current_item_index = 0 show_text() else: show_text() # This function is called when 'back_button' is pressed. func go_back() -> void: if current_item_index != 0: current_item_index_changed.emit() # **EMITTING THE CUSTOM SIGNAL** current_item_index -= 1 show_text() func show_text() -> void: # ... # Animating text. rich_text_label.visible_ratio = 0.0 var text_appearing_duration: float = log(rich_text_label.get_total_character_count()) / 2.0 var tween := create_tween() tween.tween_property(rich_text_label, "visible_ratio", 1.0, text_appearing_duration).from_current() # Play audio while text animates. var sound_max_length: float = audio_stream_player.stream.get_length() - text_appearing_duration var sound_start_position: float = randf() * sound_max_length audio_stream_player.play(sound_start_position) # ** THIS IS WHERE THE TIMER IS CREATED AND UTILIZED (to stop aduio playback) ** var timer := Timer.new() current_item_index_changed.connect(timer.stop) # <- This will stop the old timer before starting... add_child(timer) # ...a new one when player advances too quickly. timer.wait_time = text_appearing_duration timer.one_shot = true timer.start() timer.timeout.connect(audio_stream_player.stop) # The timer will still stop the audio playback if the player waits for the text animation to finish. # Body slide animation. slide_in() ## Animate the body sliding in upon advancing/rewinding dialogue. func slide_in() -> void: # ... ``` I also more than welcome any criticism or possible problems this could create. Or perhaps a better solution. 2 0 Aug. 25, 2024
  • Resizing the window during an animation?big-hearted-emu```gdscript extends Control @onready var black_bar_top: ColorRect = %BlackBarTop @onready var black_bar_bottom: ColorRect = %BlackBarBottom @onready var button: Button = %Button func _ready() -> void: button.pressed.connect(_on_button_pressed) func _on_button_pressed() -> void: animate_black_bars() # Position of bottom bar breaks if window resized during animation. func animate_black_bars() -> void: var black_bar_top_size := 50.0 var black_bar_bottom_position := black_bar_bottom.position.y - 100.0 var black_bar_animation_time := 2.8 var tween := create_tween().set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT) tween.set_parallel() tween.tween_property(black_bar_top, "size:y", black_bar_top_size, black_bar_animation_time) tween.tween_property(black_bar_bottom, "position:y", black_bar_bottom_position, black_bar_animation_time) tween.tween_property(button, "modulate:a", 0.0, black_bar_animation_time) tween.finished.connect(func() -> void: button.queue_free() ) ``` [https://i.imgur.com/PX5Inng.gif](https://i.imgur.com/PX5Inng.gif) The unwanted effect can be seen in the gif. The problem is how I animate the bottom bar. The black bars are anchored **top wide** and **bottom wide** respectively. Default **size.x** based on *screen size* and default **size.y** set to **zero**. I initially tried to animate them by changing both of their size.y properties, except I cannot make the bottom bar's size.y negative. Second attempt was rotating the bottom bar 180° and positioning it manually back to its place. The problem then is that when resizing the screen, it extends in the opposite direction. Third attempt was simply having the bar already visible off screen and animating its **position.y** to the correct place. This is the code above. The problem I'm stuck on now is that I have added `var black_bar_bottom_position := black_bar_bottom.position.y - 100.0` in order to prevent the bar from doing weird stuff based on your window size at the time of pressing the button. Once you do press the button, however, if you resize the window during the animation, the bar's position gets out of whack. If you resize it after the animation finished, everything is fine. Now, I get how and why everything happens, I just have no idea how to fix it. The only thing I can think of is checking every frame for the current screen size and adjusting the position of the bar based on that, which... there has to be a better way of doing this. Preventing the resizing of the window from the project settings is another one, but it does mention it's not reliable. 8 0 Aug. 12, 2024
  • tween.TRANS_QUART vs. tween.set_trans(Tween.TRANS_QUART)RussellApologies if I just missed this in the lesson, but what is the difference between tween.TRANS_QUART and tween.set_trans(Tween.TRANS_QUART)? In this example, at least, the result seemed to be the same. BTW, you guys have done a great job with this entire course so far. I'm really enjoying this (and learning) a lot! 1 0 Jul. 27, 2024
  • Auto-continuing the dialoguesdyldoHi, Regarding the slideshow challenge (and using your current code), is there a way to auto-continue the dialogue by calling func advance() after a certain delay? For example: after x amount of seconds, the dialogue will "click next" automatically and advance to the next dialogue. I tried using set_method(advance, from_value, to_value, duration) and adding an idx parameter to func advance() so the current_item_idx = idx; however, that just seems to break the code. ```gdscript func show_text() -> void: var current_item := dialogue_items[current_item_idx] rich_text_label.text = current_item["text"] expression.texture = current_item["expression"] rich_text_label.visible_ratio = 0.0 var text_speed: float = rich_text_label.text.length() / 30.0 var tween := create_tween().set_parallel() tween.tween_method(advance, 0, 3, 30.0).set_delay(5.0) tween.tween_property(rich_text_label, "visible_ratio", 1.0, text_speed) var sound_length := audio_stream_player.stream.get_length() - text_speed audio_stream_player.play(randf() * sound_length) tween.finished.connect(audio_stream_player.stop) slide_in() func advance(idx: int) -> void: current_item_idx = idx if current_item_idx == dialogue_items.size(): current_item_idx = 0 show_text() ``` Can you explain why this doesn't work? Can you also explain more behind how the set_method works? 1 0 Jul. 25, 2024
  • Expression remains a bit transparentandrea-putortiHey there! I did everything as mentioned in the lesson and my code does look like the same as yours, but when I start the scene, the Expression remains a bit transparent, at the end of the animation, although I changed the modulate of the whole Body (Expression is indeed its child). This is my project: [https://we.tl/t-YJUxliAZy4](https://we.tl/t-YJUxliAZy4) Thanks! Here's the code too: ```gdscript func slide_in() -> void: var tween := create_tween() tween.set_trans(Tween.TRANS_QUART) tween.set_ease(Tween.EASE_OUT) body.position.x = 200.0 tween.tween_property(body, "position:x", 0.0, 0.3) body.modulate.a = 0.0 tween.parallel().tween_property(body, "modulate:a", 1.0, 0.2) ``` 2 0 Jul. 01, 2024
  • Null value error using TimerStonemonkeyI get the error " cannot call method 'set delay' on a null value" on the second `await` method call. I'm just trying to use a timer to wait for the previous tweens to finish and also hope that the new `texture` value get's applied before animating the second set of tweens. ```gdscript func play_slides()->void: var tween = create_tween() slide.texture = slides[0] tween.tween_property(slide, "modulate:a", 1.0, 2.0) tween.tween_property(slide, "modulate:a", 0.0, 2.0).set_delay(2.0) timer.wait_time = 2.0 timer.start() await timer.timeout slide.texture = slides[1] tween.tween_property(slide, "modulate:a", 1.0, 2.0) tween.tween_property(slide, "modulate:a", 0.0, 2.0).set_delay(2.0) #cannot call method `set delay` on a null value ``` 5 0 Jun. 14, 2024
  • Quiz sctructureArtemaleIn case I am creating a quiz-type game where I should choose the right answer button. What is an optimal way for 30 questions quiz? To create 30 scenes with 1 question per scene or should I try to use arrays, dictionaries etc. to stay with one main scene? 9 0 Jun. 10, 2024
  • Question about set_parallel() vs tween.parallel()fledgerI tried to tackle the first scale challenge before going forward with the slideshow challenge. When I messed with the scale it seemed to mess with the animations all playing. I removed the tween.parallel from the tweens and placed set_parallel()higher up in the code. However, this seems to ignore the position animation entirely. I will share the code as comments because I am having issues making it all in one post. My apologies in advance! 4 0 Jun. 02, 2024
  • Scale/Slideshow challenge results!pikminfan71Hope you like how it turned out! [https://youtu.be/s_6bjRCZHZg](https://youtu.be/s_6bjRCZHZg) 4 0 May. 31, 2024
Site is in BETA!found a bug?