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.

  • On the Multiple Voice ChallengePewskeepskiI achieved it without an additional AudioStreamPlayer. I simply assigned current_item["voice"] to the audio_stream_player.stream, after creating an additional "voice" dictionary and adding it to all of the dialogue. This seems to work just fine. 6 6 May. 28, 2024
  • Text Speed Challenge Solutionintent-mantis```gdscript ... rich_text_label.visible_ratio=0.0 var tween := create_tween() #the dialog will appear at a rate of 30 characters per second var tween_time:float = rich_text_label.get_total_character_count()/30.0 #minimum tween time will be 0.5 seconds if tween_time<0.5:tween_time=0.5 ... tween.tween_property(rich_text_label,"visible_ratio",1,tween_time) ... ``` Here is the solution I had for the text speed challenge. It is very similar to your solution, but I added a minimum for the tween time that I think works better if the dialog is very short. 1 3 May. 20, 2024
  • My solution to the multiple voices challengeAceThis is what I came up with to solve the challenge. I ended up with a dictionary inside of a dictionary inside of an array. ```gdscript extends Control @onready var rich_text_label: RichTextLabel = %RichTextLabel @onready var next_button: Button = %NextButton @onready var back_button: Button = %NextButton2 @onready var audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer @onready var body: TextureRect = %Body @onready var expression: TextureRect = %Expression var bodies : Dictionary = { "sophia" : { "texture": preload("res://assets/sophia.png"), "voice": preload("res://assets/talking_synth.mp3"), }, "pink" : { "texture": preload("res://assets/pink.png"), "voice": preload("res://assets/talking_synth_alternate.ogg"), } } var expressions := { "regular": preload("res://assets/emotion_regular.png"), "happy": preload("res://assets/emotion_happy.png"), "sad": preload("res://assets/emotion_sad.png"), "angry": preload("res://assets/extras/emotion_angry.png") } var dialogue_items : Array[Dictionary] = [ { "expression": expressions["regular"], "text": "I'm learning about Arrays...", "character": bodies["sophia"], }, { "expression": expressions["regular"], "text": "How is that going?", "character": bodies["pink"], }, { "expression": expressions["sad"], "text": "It's a little bit coplicated.", "character": bodies["sophia"], }, { "expression": expressions["regular"], "text": "Tell me what you know so far.", "character": bodies["pink"], }, { "expression": expressions["happy"], "text": "Let's see if I got it right: an array is not a list of values!", "character": bodies["sophia"], }, { "expression": expressions["sad"], "text": "...", "character": bodies["pink"], }, { "expression": expressions["happy"], "text": "Did I get it right? Did I?", "character": bodies["sophia"], }, { "expression": expressions["sad"], "text": "No.", "character": bodies["pink"], }, { "expression": expressions["angry"], "text": "Dang it!", "character": bodies["sophia"], }, ] var current_item_index := 0 func show_text() -> void: var current_item := dialogue_items[current_item_index] rich_text_label.text = current_item["text"] expression.texture = current_item["expression"] rich_text_label.visible_ratio = 0.0 var tween := create_tween() var text_appearing_duration : float = current_item["text"].length() / 30.0 tween.tween_property(rich_text_label, "visible_ratio", 1.0, text_appearing_duration) audio_stream_player.stream = current_item["character"]["voice"] var sound_max_length : float = audio_stream_player.stream.get_length() - text_appearing_duration var sound_start_position := randf() * sound_max_length audio_stream_player.play(sound_start_position) tween.finished.connect(audio_stream_player.stop) body.texture = current_item["character"]["texture"] slide_in() ``` 1 2 Aug. 12, 2024
  • Solution to the voice challenge! (Not a question)Abdul Hannan AhmedHi! Here's how I came up with a solution to the voice challenge! ```gdscript extends Control @onready var rich_text_label: RichTextLabel = %RichTextLabel @onready var next_button: Button = %NextButton @onready var back_button: Button = %BackButton @onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer @onready var body: TextureRect = %Body @onready var expression: TextureRect = %Expression var bodies := { "sophia": preload("res://assets/sophia.png"), "pink": preload("res://assets/pink.png"), } var voices := { "sophia": preload("res://assets/talking_synth.mp3"), "pink": preload("res://assets/talking_synth_alternate.ogg") } var expressions := { "happy": preload("res://assets/emotion_happy.png"), "regular": preload("res://assets/emotion_regular.png"), "sad": preload("res://assets/emotion_sad.png"), "angry": preload("res://assets/extras/emotion_angry.png"), } var dialogue_items: Array[Dictionary] = [ { "expression": expressions["regular"], "character": bodies["sophia"], "text": "Are you a feminist?", "sound": voices["sophia"] }, { "expression": expressions["happy"], "character": bodies["pink"], "text": "Yes!", "sound": voices["pink"] }, { "expression": expressions["regular"], "character": bodies["sophia"], "text": "What's the difference between a feminist and a knife?", "sound": voices["sophia"] }, { "expression": expressions["regular"], "character": bodies["pink"], "text": "What do you mean?", "sound": voices["pink"] }, { "expression": expressions["regular"], "character": bodies["sophia"], "text": "I just said what's the difference between a feminist and a knife?", "sound": voices["sophia"] }, { "expression": expressions["sad"], "character": bodies["pink"], "text": "Is that even a question???", "sound": voices["pink"] }, { "expression": expressions["happy"], "character": bodies["sophia"], "text": "At least the knife has a point", "sound": voices["sophia"] }, { "expression": expressions["angry"], "character": bodies["pink"], "text": "😡😡😡😡😡", "sound": voices["pink"] }, ] ## Holds the index of the currently displayed text. var current_item_index: int = 0 func _ready() -> void: show_text() next_button.pressed.connect(advance) back_button.pressed.connect(go_back) func show_text() -> void: var current_item := dialogue_items[current_item_index] var tween := create_tween() var duration: float = current_item["text"].length() / 30.0 expression.texture = current_item["expression"] body.texture = current_item["character"] rich_text_label.text = current_item["text"] slide_character() rich_text_label.visible_ratio = 0.0 audio_stream_player.stream = current_item["sound"] var maximum_sound_offset: float = audio_stream_player.stream.get_length() - duration var sound_start_position: float = maximum_sound_offset * randf() audio_stream_player.play(sound_start_position) tween.tween_property(rich_text_label, "visible_ratio", 1.0, duration) tween.finished.connect(audio_stream_player.stop) func advance() -> void: current_item_index += 1 if current_item_index == dialogue_items.size(): current_item_index = 0 show_text() func go_back() -> void: current_item_index -= 1 if current_item_index <= 0: get_tree().quit() show_text() func slide_character() -> void: body.modulate.a = 0.0 body.position.x = 200.0 var tween := create_tween() var duration := 0.5 tween.set_trans(Tween.TRANS_QUART) tween.set_ease(Tween.EASE_OUT) tween.tween_property(body, "position:x", 0.0, duration) tween.parallel().tween_property(body, "modulate:a", 1.0, duration) ``` 1 1 Sep. 10, 2024
  • My solution to different voiceVilldarI've used the same AudioStreamPlayer, I've only changed the stream value based on character. The only issue I have is the alternative voice is a little bit to low. Don't know if there's a way to loud it a little bit. Anyway here my code: ```gdscript @onready var audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer var voices := { "sophia_voice" : preload("res://assets/talking_synth.mp3"), "pink_voice" : preload("res://assets/talking_synth_alternate.ogg") } var dialogue_items : Array[Dictionary] = [ { "expression" : expressions["regular"], "text" : "I'm learning about Arrays...", "character" : bodies["sophia"], "voice" : voices["sophia_voice"] }, { "expression" : expressions["sad"], "text" : "...and it is a little bit complicated.", "character" : bodies["pink"], "voice" : voices["pink_voice"] }, ------ ] func show_text() -> void: ------ audio_stream_player.stream = current_item["voice"] var sound_max_length = audio_stream_player.stream.get_length() - tween_appearence_duration var sound_start_position = randf() * sound_max_length audio_stream_player.play(sound_start_position) ----- ``` 2 1 May. 31, 2024
  • Another solution for the voice challengedavidakFirst i added a `voices` dictionary like we did with `bodies` and `expressions`: ```gdscript var voices := { "default": preload("res://assets/talking_synth.ogg"), "alternate": preload("res://assets/talking_synth_alternate.ogg"), } ``` Then, my **first solution** was to add the voices to the `dialogue_items` dictionary, but i did not like to repeat the data which character has which voice so many times, which could lead to errors and less readable code. ```gdscript { "text": "Roses are red", "expression": expressions["regular"], "character": bodies["sophia"], "voice": voices["default"], }, ``` I set the `stream` of the `audio_stream_player` we already had to the voice file from the `dialogue_items` dictionary. ```gdscript audio_stream_player.stream = current_item["voice"] ``` This does work, but is not very elegant. In my **second solution**, i added the voices dict and this code to `show_text`. This is easier to understand. ```gdscript if current_item["character"] == bodies["sophia"]: audio_stream_player.stream = voices["default"] elif current_item["character"] == bodies["pink"]: audio_stream_player.stream = voices["alternate"] ``` I think the most elegant solution would be to add the voice file to a `characters` dictionary, like we did with the texture. So all data about the character is in one place and you separate data from logic. Like @Ace did in their solution. 1 0 Sep. 18, 2024
  • Preloading: predict result types?TJBy reading other posts here I was able to solve the challenge of the two voices as well. I am just wondering if we could somehow know what type of object (class) is returned by the `preload()` keyword. Consider for example the following preloads: ```gdscript preload("res://assets/talking_synth.ogg") preload("res://assets/talking_synth_alternate.ogg") ``` To me it felt as some kind of luck that we could directly assign the result of these preloads to the `audio_stream_player.stream` property. It might perhaps be better, in terms of acquiring problem-solving skills, if we could know or predict the result type of the preloads and match that to the documentation of the `audio_stream_player`. What is your advice? Is there some kind of look-up table to match resource file extensions to the resulting object types (classes) that preloading makes of them? Thanks for your help! 2 0 Aug. 15, 2024
  • Defi HazlarHello, To solve the challenge, I encounter a problem, here is the code: ```gdscript @onready var audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer @onready var body: TextureRect = %Body @onready var expression: TextureRect = %Expression const PINK := 1 const SOPHIA := 0 var speaker_audio :={ SOPHIA : preload("res://assets/talking_synth.ogg"), PINK : preload("res://assets/talking_synth_alternate.ogg") } var current_speaker := SOPHIA var current_item_index := 0 func show_text() -> void: slide_in() var current_item := dialogue_items[current_item_index] rich_text_label.text = current_item["text"] expression.texture = current_item["expression"] body.texture = current_item["character"] rich_text_label.visible_ratio = 0.0 var tween := create_tween() var duration_appearing_txt := 1.2 tween.tween_property(rich_text_label, "visible_ratio", 1, duration_appearing_txt) audio_stream_player.stream = speaker_audio[current_speaker%2] var sound_max_length := audio_stream_player.get_length() - duration_appearing_txt var sound_start_position := randf() * sound_max_length audio_stream_player.play(sound_start_position) tween.finished.connect(audio_stream_player.stop) current_speaker += 1 ``` Edit: I modified the code by keeping it and wanting to directly modify the stream property that connects the audio file. And I get several errors: **In the 'call stack' console:** *Parser Error: Cannot infer the type of "sound_max_length" variable because the value doesn't have a set type.* **And in the editor script:** *Line 108:Cannot infer the type of "sound_max_length" variable because the value doesn't have a set type.* *Line 109:Cannot infer the type of "sound_start_position" variable because the value doesn't have a set type.* 4 0 Aug. 13, 2024
  • Invalid get index 'regular' (on base: 'Nil').TheEffingLawNot sure why I'm getting this error message on line 13 ```gdscript extends Control var expressions: Dictionary = { "happy": preload("res://assets/emotion_happy.png"), "regular": preload("res://assets/emotion_regular.png"), "sad": preload("res://assets/emotion_sad.png"), } var bodies:= { "pink": preload("res://assets/pink.png"), "sophia": preload("res://assets/sophia.png") } var dialogue_text: Array[Dictionary] = [ { "expression": expressions["happy"], "text": "I'm learning about Arrays and Dictionaries...", "character": bodies["sophia"], }, { "expression" : expression["regular"], "text" : "That's amazing! How is it coming along?", "character" : bodies["pink"], }, { "expression" : expressions["sad"], "text" : "it is quite complicated", "character" : bodies["sophia"], }, { "expression" : expressions["regular"], "text" : "But I won't give up. Practice makes perfect!", "character" : bodies["sophia"], }, { "expression" : expressions["happy"], "text" : "That's the spirit! You got this!", "character" : bodies["pink"], } ] var current_item_index := 0 @onready var rich_text_label : RichTextLabel = %RichTextLabel @onready var next_button : Button = %NextButton @onready var previous_button : Button = %PreviousButton @onready var audio_stream_player : AudioStreamPlayer = %AudioStreamPlayer @onready var body: TextureRect = %Body @onready var expression: TextureRect = %Expression func _ready() -> void: next_button.connect("pressed", _advance_text) previous_button.pressed.connect(_previous_text) show_text() func _advance_text() -> void: current_item_index += 1 show_text() func _previous_text() -> void: current_item_index -= 1 show_text() func show_text() -> void: var current_item := dialogue_text[current_item_index % dialogue_text.size()] var text_appearing_duration := 1.0 rich_text_label.text = current_item["text"] expression.texture = current_item["expression"] body.texture = current_item["character"] rich_text_label.visible_ratio = 0.0 var tween = create_tween() tween.tween_property(rich_text_label,"visible_ratio", 1.0, current_item["text"].length()/30.0) var max_sound_length = audio_stream_player.stream.get_length() - text_appearing_duration var sound_start_position = randf() * max_sound_length audio_stream_player.play(sound_start_position) tween.finished.connect(audio_stream_player.stop) slide_in() func slide_in() -> void: var tween = create_tween() tween.set_trans(Tween.TRANS_QUART).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, 2.0) body.scale = Vector2(0.5, 0.5) tween.parallel().tween_property(body, "scale", Vector2(1.0,1.0), 2.0) ``` 2 0 Jul. 02, 2024
  • Function Nikita MyshkinI did not add the function `slide_in()` in `show_text()` I added in the functions `advance()` and `previous()`Everything works for me. I'm wondering why my option works? And how important is it to add `slide_in()` to `show_text()`? Here is my code: ```gdscript extends Control @onready var rich_text_label: RichTextLabel = %RichTextLabel @onready var next_button: Button = %NextButton @onready var previous_button: Button = %PreviousButton @onready var audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer @onready var audio_stream_player_pink: AudioStreamPlayer = $AudioStreamPlayerPink @onready var body: TextureRect = %Body @onready var expression: TextureRect = %Expression var expressions := { "happy": preload("res://assets/emotion_happy.png"), "regular": preload("res://assets/emotion_regular.png"), "sad": preload("res://assets/emotion_sad.png"), "angry": preload("res://assets/extras/emotion_angry.png") } var bodies := { "sophia": preload("res://assets/sophia.png"), "pink": preload("res://assets/pink.png") } var voice := { "voice_sophia": preload("res://assets/talking_synth.ogg"), "voice_pink": preload("res://assets/talking_synth_alternate.ogg") } var dialogue_items : Array[Dictionary] = [ { "expression": expressions["regular"], "text": "I'm learning about Array...", "character": bodies["pink"], "voice": voice["voice_pink"] }, { "expression": expressions["sad"], "text": "... and it is a little bit complicated.", "character": bodies["sophia"], "voice": voice["voice_sophia"] }, { "expression": expressions["happy"], "text": "I'm happy!", "character": bodies["pink"], "voice": voice["voice_pink"] }, { "expression": expressions["angry"], "text": "Шел бы ты нахуй мудила и забери собой свои две сосиски!", "character": bodies["sophia"], "voice": voice["voice_sophia"] }, ] var current_item_index := 0 func _ready() -> void: show_text() next_button.pressed.connect(advance) previous_button.pressed.connect(previous) previous_button.visible = false func show_text() -> void: var current_item := dialogue_items[current_item_index] rich_text_label.visible_ratio = 0.0 rich_text_label.text = current_item["text"] expression.texture = current_item["expression"] body.texture = current_item["character"] audio_stream_player.stream = current_item["voice"] audio_stream_player_pink.stream = current_item["voice"] next_button.visible = current_item_index < dialogue_items.size() - 1 previous_button.visible = current_item_index > 0 var tween := create_tween() var text_appearing_duration: float = current_item["text"].length() / 20.0 tween.tween_property(rich_text_label, "visible_ratio", 1.0, text_appearing_duration) var sound_max_lenght_pink := audio_stream_player_pink.stream.get_length() - text_appearing_duration var sound_start_position_pink := randf() * sound_max_lenght_pink audio_stream_player_pink.play(sound_start_position_pink) tween.finished.connect(audio_stream_player_pink.stop) var sound_max_lenght := audio_stream_player.stream.get_length() - text_appearing_duration var sound_start_position := randf() * sound_max_lenght audio_stream_player.play(sound_start_position) tween.finished.connect(audio_stream_player.stop) func advance() -> void: current_item_index = min(current_item_index + 1, dialogue_items.size() - 1) show_text() slide_in() func previous() -> void: current_item_index = max(current_item_index - 1, 0) show_text() slide_in() 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, 1.0) body.modulate.a = 0.0 tween.parallel().tween_property(body, "modulate:a", 1.0, 1.0) ``` 1 0 Jul. 01, 2024
  • What's a footgun?tesfalconThat sounds like a bad translation of a Japanese anime. 1 0 Jun. 19, 2024
  • Make the body slide in only if it change charactertuktuk22i add new variables and if statement to make the body slide only if it change character (body texture). it works but i curious is there any "better/proper" way to code it ? ```gdscript # ........ var current_item_index := 0 # new var var character_name : Dictionary = bodies["sophia"] var last_character : Dictionary = character_name func _ready() -> void: show_text() slide_in() next_button.pressed.connect(advance) func show_text() -> void: var current_item := dialogue_items[current_item_index] rich_text_label.text = current_item["text"] expression.texture = current_item["expression"] body.texture = current_item["character"] audio_stream_player.stream = current_item["voice"] rich_text_label.visible_ratio = 0.0 #new code here character_name = current_item["character"] var tween := create_tween() #var text_appearing_duration := 1.2 var text_appearing_duration : float = current_item["text"].length() / 30.0 var sound_max_length := audio_stream_player.stream.get_length() - text_appearing_duration var sound_start_position := randf() * sound_max_length audio_stream_player.play(sound_start_position) tween.tween_property(rich_text_label,"visible_ratio", 1.0, text_appearing_duration) tween.finished.connect(audio_stream_player.stop) func advance() -> void: # new code here last_character = character_name current_item_index += 1 if current_item_index == dialogue_items.size(): get_tree().quit() else: show_text() if last_character != character_name : slide_in() func slide_in() -> void: var tween := create_tween() tween.set_trans(Tween.TRANS_QUART) tween.set_ease(Tween.EASE_OUT) body.position.x = 400.0 body.modulate.a = 0.0 body.scale = Vector2(0.8, 1.1) tween.tween_property(body, "position:x", 0.0, 0.8) tween.parallel().tween_property(body, "modulate:a", 1.0, 0.7) tween.parallel().tween_property(body, "scale", Vector2(1.0, 1.0), 0.7) ``` 1 0 Jun. 14, 2024
  • Adding the second voice challenge.AJ StudiosThe second voice is not playing. I'm including here the following lines of code: the `voices dictionary` I created, the lines of code I added to the `var dialogue_items: Array[Dictionary]`, the `@on ready variables` and the lines of code that play the sound under the `func show_text()` ```gdscript # The voices dictionary I created var voices := { "voiceA": preload ("res://assets/talking_synth.mp3"), "voiceB": preload ("res://assets/talking_synth_alternate.ogg"), } # The new additions to the dialogue_items Array var dialogue_items: Array[Dictionary] = [ { "character": bodies["sophia"], "voice": voices["voiceA"], }, { "character": bodies["pink"], "voice": voices["voiceB"], }, # New @on ready vars @onready var audio_stream_player_a: AudioStreamPlayer = $AudioStreamPlayerA @onready var audio_stream_player_b: AudioStreamPlayer = $AudioStreamPlayerB # I was wondering If I can combine var sound_max_length & var sound_max_length_2 # var sound_start_position & var sound_start_position_2 # That way I don't have to write so much code. func show_text() -> void: ... var sound_max_length := audio_stream_player_a.stream.get_length() - text_appearing_duration var sound_start_position := randf() * sound_max_length audio_stream_player_a.play(sound_start_position) # We stop the audio when the text finishes appearing. tween.finished.connect(audio_stream_player_a.stop) var sound_max_length_2 := audio_stream_player_b.stream.get_length() - text_appearing_duration var sound_start_position_2 := randf() * sound_max_length audio_stream_player_b.play(sound_start_position) # We stop the audio when the text finishes appearing. tween.finished.connect(audio_stream_player_b.stop) ``` 10 0 May. 30, 2024
  • Preformance CostStevenWhat is the performance cost of preloading data into a dictionary over and over verses loading when needed? Also, would it be better to have multiple AudioStreamPlayers? I'm thinking that the most hands-off approach in code would be to include it in the dictionary or have a separate dictionary for audio. I ended up adding audio to the dictionary and using one line of code to play the audio. audio_stream_player.set_stream(current_item["voice"]) 1 0 May. 27, 2024
  • Is my way of handling the "different voice" challenge sub-optimal or otherwise bad?SingleMom420My solution to the challenge of using the alternate voice sound for the other character involved making another AudioStreamPlayer node and then adding a check to `show_text()`: ```gdscript if current_item["character"] == preload("res://assets/sophia.png"): audio_stream_player.play(sound_start_position) else: audio_stream_player_2.play(sound_start_position) tween.finished.connect(audio_stream_player.stop) tween.finished.connect(audio_stream_player_2.stop) ``` This seems to be working as intended, but the hint for the challenge mentioned creating another dictionary with the preloaded sound files, which I did not do. My method seems quicker because I don't have to go back and add a new item to all the dictionaries in the `dialogue_items` array. Is there some disadvantage to my way that I'm not seeing, or is it also acceptable? 4 0 May. 17, 2024
Site is in BETA!found a bug?