{"id":21495685,"url":"https://github.com/deepgram/speechspells","last_synced_at":"2026-01-03T07:00:23.267Z","repository":{"id":105856500,"uuid":"465837718","full_name":"deepgram/SpeechSpells","owner":"deepgram","description":null,"archived":false,"fork":false,"pushed_at":"2023-05-03T18:52:07.000Z","size":3514,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-23T21:51:19.355Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"GDScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/deepgram.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-03T18:23:05.000Z","updated_at":"2022-03-09T16:51:50.000Z","dependencies_parsed_at":"2023-06-14T13:30:30.396Z","dependency_job_id":null,"html_url":"https://github.com/deepgram/SpeechSpells","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepgram%2FSpeechSpells","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepgram%2FSpeechSpells/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepgram%2FSpeechSpells/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepgram%2FSpeechSpells/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deepgram","download_url":"https://codeload.github.com/deepgram/SpeechSpells/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244031150,"owners_count":20386534,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-23T16:12:53.753Z","updated_at":"2026-01-03T07:00:18.194Z","avatar_url":"https://github.com/deepgram.png","language":"GDScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\r\ndate: 2022-03-09\r\ntitle: How to Build a Speech-Enhanced Game with Godot and Deepgram\r\nauthor: nikolawhallon\r\ncover: ./README_Assets/Building-a-Game-w-Godot-Deepgram@2x.jpg\r\ncategory: tutorial\r\ncover_alt:\r\ndescription: Learn how to build a speech-enhanced game with Deepgram's ASR engine and the open-source Godot game engine.\r\ntags: [tutorial, game-dev, godot]\r\nseo:\r\n  keywords: video game development, build video game, create game with godot, game development\r\n--\u003e\r\n\r\nIn this post, we will be making a simplified version of the 2D game \"Spooky Speech Spells\" (which you can play [here](https://spookyspeechspells.deepgram.com))\r\nin the Godot game engine using an integration with the Deepgram automatic speech recognition (ASR) engine. Why Godot? Because it is an\r\neasy-to-learn, open-source alternative to the popular industry-standard Unity and can export directly to Mac, Windows, Linux, iOS,\r\nAndroid, and HTML5. Why Deepgram? Because it is the fastest, most accurate, cheapest, and easiest to use ASR engine out there! And why\r\nmake a speech-enhanced game? Well, because it's cool, and games are fun! Beyond that, adding nontraditional input devices can help make your games more accessible.\r\n\r\nThis tutorial is focusing on adding voice input to your game, but if you want to see more tutorials, you can find plenty on the\r\n[Godot website](https://docs.godotengine.org/en/stable/community/tutorials.html).\r\n\r\n## Pre-requisites\r\n\r\nYou will need:\r\n\r\n- Godot installed on your machine - [download Godot here](https://godotengine.org/download). This tutorial was written with version `3.4.3`.\r\n- A Deepgram API Key - [get an API Key here](https://console.deepgram.com/signup?jump=keys).\r\n\r\n## Try the Game\r\n\r\nTo run the game we are going to build and browse its files:\r\n\r\n- Download [this repository](https://github.com/deepgram/SpeechSpells), open Godot, click \"Import\", and browse to and select the `project.godot` file from the repo.\r\n- In the Godot editor, go to the \"FileSystem\" tab in the lower left, and navigate to and open `Scenes/Game.gd`.\r\n- Edit `line 7` of `Scenes/Game.gd` and enter your Deepgram API Key.\r\n- In the top right of the Godot editor, hit the \"Play\" (►) button.\r\n- Move your character with `WASD` and say \"fire\" to cast fire spells!\r\n\r\n## Building the Game\r\n\r\nIn the following sub-sections, we will walk through step-by-step how to make a game where you can move\r\na character around the screen and have the character cast fireball spells by chanting \"fire!\" into your\r\nmicrophone.\r\n\r\n## Setting Up the Project\r\n\r\nOpen Godot and create a \"New Project\" in the project manager.\r\n\r\n\u003cimg src=\"./README_Assets/new_project.png\" alt=\"Create a new project.\" style=\"max-width: 1037px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nNow click \"Browse\" and choose a directory on your filesystem to store the project, and in the \"Project Name\"\r\nfield, write \"SpeechSpells\" and hit \"Create Folder.\" Finally, hit \"Create and Edit,\" and we'll get to the Godot\r\nEditor, where we can build our game.\r\n\r\n\u003cimg src=\"./README_Assets/set_project_name.png\" alt=\"Set the name of the new project.\" style=\"max-width: 1038px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nThe Godot Editor consists of several panels and tabs, and we will be going over the ones we need to interact\r\nwith to build \"Speech Spells\".\r\n\r\nLet's start with the \"Scene\" tab in the upper left panel. In this tab, we can put together \"Scenes,\" which,\r\ntogether with \"Nodes,\" form the basic building blocks of Godot games. Scenes and nodes are classes\r\nin object-oriented programming terminology, but the Godot Editor offers an intuitive way to create, edit,\r\nand manage our various game objects as scenes and nodes. Scenes can be almost anything - a collection\r\nof sprite nodes, a character with animations, attacks, and hit-boxes, or just a collection of scripts\r\nthat execute algorithms and can emit signals to other nodes (we will see this pattern further on). For now,\r\nwhere it says \"Create Root Node\" click \"2D Scene\" and double click the name of the resulting node and rename\r\nit to \"Game\". We will create a few other scenes for this game and add instances of those scenes to our Game\r\nscene.\r\n\r\nBefore saving the scene, let's head over to the lower right \"Filesystem\" tab. Right-click in the filesystem\r\nbrowser there and click \"New Folder...\" to create a folder called \"Scenes\" and then a folder called \"Assets\".\r\nYou may, of course, organize your projects however you like, but this is at least one way of doing it.\r\n\r\nClick on `Scene -\u003e Save Scene` in the upper left corner of the editor to save this scene as `Game.tscn` in the \"Scenes\" directory that you just created.\r\n\r\n\u003cimg src=\"./README_Assets/create_folders.png\" alt=\"Set up the game directory structure.\" style=\"max-width: 249px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nNow, go to `Project -\u003e Project Settings` from the upper left bar, and we will set a couple of properties of our game.\r\nStart by navigating to `Rendering -\u003e Environment` and change the \"Default Clear Color\" to black.\r\n\r\n\u003cimg src=\"./README_Assets/default_clear_color.png\" alt=\"Change the default clear color.\" style=\"max-width: 913px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nNext, navigate to `Display -\u003e Window`, uncheck \"Resizable\", set the \"Width\" to 320, the \"Height\" to 240,\r\nthe \"Test Width\" to 960, the \"Test Height\" to 720, the \"Stretch\" \"Mode\" to \"2d\" and the\r\nStretch \"Aspect\" to \"Keep\". This is setting us up to build a game\r\nwith a very low resolution close to 240p (common for 8-bit pixel games), but when we run the game it will\r\ndisplay in a nice big 960x720 window, effectively tripling the size of the pixels. Godot has many options\r\nunder `Display -\u003e Window`, and understanding these can enable you to effortlessly build games that look\r\nfantastic at multiple resolutions and multiple aspect ratios targeting different devices without ever\r\nhaving to think about anything other than your base resolution (320x240 in our case)!\r\n\r\n\u003cimg src=\"./README_Assets/change_window_settings.png\" alt=\"Set the window settings.\" style=\"max-width: 986px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nWe have one more setting to change - navigate to `Application -\u003e Audio` and check \"Enable Audio Input\".\r\nA warning will appear saying you will need to restart the editor for this to take effect, click the button\r\nthat appears in the lower right (\"Save \u0026 Restart\") to do so.\r\n\r\n\u003cimg src=\"./README_Assets/enable_audio.png\" alt=\"Enable audio.\" style=\"max-width: 911px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nFinally, click the \"Play\" button in the upper right (or press \"F5\") to start up the game - since this is the\r\nfirst time we are playing the game, you will be asked to tell Godot which scene you want to start when the\r\ngame is first opened - we only have `Game.tscn` so select that one. We now have a blank canvas ready to be filled!\r\n\r\n\u003cimg src=\"./README_Assets/press_play.png\" alt=\"Start the game.\" style=\"max-width: 310px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\n## Creating a Player\r\n\r\nNow that we have a running game in a window let's create a player to move around. In the top left of\r\nthe Godot editor, click `Scene -\u003e New Scene`. Like when you first opened this project, the \"Scene\" tab\r\nwill give you some options for the root node. Click \"Other Node\" and navigate to, or use the search\r\nfield to find \"KinematicBody2D\" and click \"Create.\"\r\n\r\n\u003cimg src=\"./README_Assets/create_kinematic_body_2d.png\" alt=\"Create a KinematicBody2D.\" style=\"max-width: 913px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\n\"KinematicBody2D\" is one of the most reasonable types of objects to use for controllable characters.\r\nThis class/node offers convenient methods to make moving and handling collisions with various objects\r\neasy - we will discuss one of these methods shortly.\r\n\r\nNow, right-click the root node and click \"Add Child Node\" and create a \"Sprite\" node. Do this again\r\nand add a \"CollisionShape2D\" node. Your node structure should now look like the following:\r\n\r\n\u003cimg src=\"./README_Assets/player_node_structure.png\" alt=\"The node structure of the Player - the `KinematicBody2D` root node here contains a `Sprite` node and `CollisionShape2D` node as children.\" style=\"max-width: 250px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nThe \"Sprite\" node will contain the image to use for our player. We will use a pixel art\r\nimage of a skull for our player; you can download it [here](./README_Assets/skull.png). Drag the\r\nfile into the \"Assets\" directory in the \"Filesystem\" tab in the lower left, then click on the \"Import\"\r\ntab next to the \"Scene\" tab, uncheck \"Filter\" and click \"Reimport\":\r\n\r\n\u003cimg src=\"./README_Assets/import_skull.png\" alt=\"Import the skull image.\" style=\"max-width: 245px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nThis is importing the image into our project and telling our project not to apply interpolation\r\nwhen scaling the image should the window size change from the base window size (which is a tiny\r\n320x240 for us). Most art assets ought to have some interpolation applied when scaling to smaller\r\n(or larger) resolutions, but this looks notoriously bad for pixel art, where one would expect\r\nthe sharp and blocky sprite to remain sharp and blocky at any resolution.\r\n\r\nNow, navigate back to the \"Scene\" tab, click on the \"Sprite\" node, and drag and drop `skull.png`\r\nfrom the \"Asset\" directory to the \"Texture\" field:\r\n\r\n\u003cimg src=\"./README_Assets/set_skull_texture.png\" alt=\"Set the Player's sprite texture.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nAfter doing this, you should see an image in the scene's 2D view. Finally, some graphics!\r\nYou may want to play around with zooming in or out to get a better view.\r\n\r\nNow, click on the \"CollisionShape2D\" node, then click on the \"Shape\" field on the upper right\r\nand select \"RectangleShape2D\", and change the \"Extents\" \"x\" and \"y\" fields to both be 8:\r\n\r\n\u003cimg src=\"./README_Assets/add_rectangle_shape_2d.png\" alt=\"Setup the Player's CollisionShape2D.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nThis is essentially defining the hit-box of the player. We won't utilize hit-boxes\r\nor collision detection in this tutorial, but it is good practice to learn how to\r\nset up a player as one typically would in a more involved game.\r\n\r\nRename the root node \"Player\" and then save the scene as `Player.tscn` in the \"Scenes\" directory.\r\nNow, with the root node (\"Player\") selected, hit the button which looks like a script with a green\r\nplus sign on it to create a script for this node:\r\n\r\n\u003cimg src=\"./README_Assets/attach_script.png\" alt=\"Attach a script to a node.\" style=\"max-width: 610px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nThis will create a `Player.gd` script, that will help define how this node functions in the game.\r\n`.gd` is the file extension for GDScript source code. GDScript is one of two languages which Godot uses\r\nnatively (the other being a visual programming language which is quite fun!). GDScript is a lot\r\nlike Python, and has a comparatively easy learning curve, helped by the fact that the Godot engine does most of\r\nthe complicated stuff under the hood, leaving the scripting of game objects to be short and quick.\r\nMake the contents of `Player.gd` the following, and you may start to note how few lines of code it takes to perform some actions:\r\n\r\n```\r\nextends KinematicBody2D\r\n\r\nexport var speed = 100\r\nvar velocity = Vector2(0, 0)\r\n\r\nfunc _physics_process(_delta):\r\n\tif Input.is_key_pressed(KEY_W):\r\n\t\tvelocity.y = -speed\r\n\telif Input.is_key_pressed(KEY_S):\r\n\t\tvelocity.y = speed\r\n\telse:\r\n\t\tvelocity.y = 0\r\n\r\n\tif Input.is_key_pressed(KEY_A):\r\n\t\tvelocity.x = - speed\r\n\telif Input.is_key_pressed(KEY_D):\r\n\t\tvelocity.x = speed\r\n\telse:\r\n\t\tvelocity.x = 0\r\n\r\n\tvar _returned_velocity = move_and_slide(velocity, Vector2(0, 0), false, 4, 0, false)\r\n\r\n\tif position.x \u003c 0 - 16:\r\n\t\tposition.x = 320 + 16\r\n\tif position.x \u003e 320 + 16:\r\n\t\tposition.x = 0 - 16\r\n\r\n\tif position.y \u003c 0 - 16:\r\n\t\tposition.y = 240 + 16\r\n\tif position.y \u003e 240 + 16:\r\n\t\tposition.y = 0 - 16\r\n```\r\n\r\nThe first line, `extends KinematicBody2D`, is telling us that our script is an extension of the \"KinematicBody2D\" class,\r\nmeaning we will be able to access any methods and variables that the \"KinematicBody2D\" class offers, plus any variables\r\nand methods that we introduce here in this file. We then define the variables `speed` and `velocity`. We will use `velocity`\r\nto mean the velocity of the player at any given time, and `speed` to mean the maximum horizontal or vertical speed of the\r\nplayer when we move the player.\r\n\r\nNext comes the method `_physics_process(_delta)`. This is a method accessible to many Godot nodes, and is executed\r\nroughly 60 times per second, allowing us to alter objects in a way that the physics engine can understand.\r\nThe \"delta\" argument is the amount of time that has passed since the last call to `_physics_process`, but here we\r\nare not using it, so we place an underscore in front of the argument name to avoid a warning.\r\n\r\nIn this method, we check if the `WASD` keys are pressed, and modify the player's velocity accordingly (\"W\" to move up,\r\n\"A\" to move left, \"S\" to move down, and \"D\" to move right). Note that to move up, we set the \"y\" velocity to `-speed` - this\r\nis because Godot, like many game engines, considers _down_ to be the positive y-direction.\r\n\r\nAfter adjusting the player's velocity, we call the `move_and_slide` method, specifying the velocity as one of its arguments\r\n(the others don't matter for now). This method does a lot of logic internally and can handle collisions with static bodies\r\nand rigid bodies, of any shape or size, and correctly move the player along the surface of bodies instead of bouncing\r\noff of them (hence the \"slide\"). The method returns the resulting velocity of the player after any collisions/slides,\r\nbut since we won't be using this, we place an underscore to avoid a warning.\r\n\r\nLastly, we check and modify the position of the player to wrap around the window - i.e. if the player moves too far to the left,\r\nhave them wrap to the right side of the window.\r\n\r\nSave, and finally go back to the \"Game\" scene, and click the button at the top of the \"Scene\" tab to \"Instance Child Scene\":\r\n\r\n\u003cimg src=\"./README_Assets/instance_child_scene.png\" alt=\"Instance a child scene.\" style=\"max-width: 626px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nSelect the `Player.tscn` we just created. Now our main \"Game\" scene has a \"Player\" scene as a child node! Click the \"Play\" button\r\nand now the game boots up with a skull in the corner - you can move the skull around with `WASD`! Feel free to reposition the skull\r\nin the \"Game\" scene - you can either click and drag the player in the 2D view, or you can directly enter the x and y position\r\nin `Node2D -\u003e Transform -\u003e Position` in the \"Inspector\" tab when the \"Player\" node is selected in the \"Game\" scene:\r\n\r\n\u003cimg src=\"./README_Assets/player_position_in_editor.png\" alt=\"Setting the Player's position.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\n## Creating a Fireball\r\n\r\nLet's make a fireball scene which we will use to have the player shooting fireballs across the screen.\r\nCreate a new scene, for the root node click \"Other Node\" and pick \"Area2D\". Rename this root node \"Fireball\".\r\nAdd two child nodes: an \"AnimatedSprite\" and a \"CollisionShape2D\".\r\n\r\nNext, import into your \"Assets\" directory [fireball_1.png](./README_Assets/fireball_1.png)\r\nand [fireball_2.png](./README_Assets/fireball_2.png).\r\nThe two sprites will make up our fireball animation. For each of the imported fireball sprites, go to the \"Import\" tab,\r\nuncheck \"Filter\" and click \"Reimport\" - just like for our pixel art player sprite, this will ensure that these sprites\r\nmaintain their blocky pixel form even on high-resolution displays.\r\n\r\nNow, click the \"AnimatedSprite\" node, and on the right in the \"Frames\" field, click where it says \"[empty]\" and select\r\n\"New SpriteFrames\". Then click the field again and you should be brought to an editor view where we can add our animation.\r\nClick and drag the `fireball_1.png` and `fireball_2.png` files from the \"Assets\" directory into the \"Animation Frames\" box:\r\n\r\n\u003cimg src=\"./README_Assets/fireball_animation.png\" alt=\"Create the fireball animation.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nNext, click the \"AnimatedSprite\" node again to bring up the \"Inspector\" tab for this node again, check the box titled \"Playing\".\r\nIn the lower-left of the \"Animations\" tab, change the \"Speed\" field to \"12 FPS\". The fireball should now be animated in the editor:\r\n\r\n\u003cimg src=\"./README_Assets/fireball_editor_cropped_animated.gif\" alt=\"The fireball animation in the editor.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nThere are certainly several tabs and fields to navigate through in this process, but I hope you find some of these operations intuitive!\r\nTo create animations, you drag the individual frames into the \"Animation Frames\"\r\nbox, you can then change the speed of the animation just left of this box, and you can set which animation plays by default\r\nin the \"Animation\" field of the \"Inspector\" tab for the \"AnimatedSprite\" node - here you can also set whether the animation\r\nis turned on or off with the \"Playing\" check box.\r\n\r\nNow, click the \"CollisionShape2D\" node, and in the \"Inspector\" tab for the \"Shape\" field select \"New CircleShape2D\". Then\r\nclick the \"CicleShape2D\" to edit it's properties and change its radius to 4:\r\n\r\n\u003cimg src=\"./README_Assets/fireball_hitbox.png\" alt=\"Setting the fireball's hit-box.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\nNow, save the scene as `Fireball.tscn` in the \"Scenes\" directory, and then attach a script to the root node. Make the contents\r\nof the script as follows:\r\n\r\n```\r\nextends Area2D\r\n\r\nexport var speed = 220\r\nvar direction = Vector2(0, 0)\r\n\r\nfunc _physics_process(delta):\r\n\tvar velocity = direction.normalized() * speed\r\n\r\n\trotation = velocity.angle()\r\n\tposition += velocity * delta\r\n\r\n\tif position.x \u003e 320 + 16:\r\n\t\tget_tree().queue_delete(self)\r\n\tif position.x \u003c 0 - 16:\r\n\t\tget_tree().queue_delete(self)\r\n\tif position.y \u003e 240 + 16:\r\n\t\tget_tree().queue_delete(self)\r\n\tif position.y \u003c 0 - 16:\r\n\t\tget_tree().queue_delete(self)\r\n```\r\n\r\nLike with the \"Player\" scene, we are extending the root node's class, in this case an \"Area2D.\" We will give each fireball object\r\na speed and a direction. When `_physics_process` is called, we will update the fireball's position and angle according to\r\nthe fireball's direction and speed. If the fireball goes off-screen, we will destroy it using `get_tree().queue_delete(self)`.\r\n\r\nThat's all there is to the \"Fireball\" scene, but we haven't actually added any fireballs to our game. We could do this by instancing\r\na \"Fireball\" scene in our \"Game\" scene, but for these kinds of objects, there's a better way - we should spawn them via code!\r\n\r\n## Triggering the Fireball With Keystrokes\r\n\r\nGo to the \"Game\" scene and add a script to the root node, just like we did for the \"Player\" scene.\r\nThen edit `Game.gd` to have the following contents:\r\n\r\n```\r\nextends Node2D\r\n\r\nvar rng = RandomNumberGenerator.new()\r\n\r\nfunc _ready():\r\n\trng.randomize()\r\n\r\nfunc _input(event):\r\n\tif event is InputEventKey and event.pressed:\r\n\t\tif event.scancode == KEY_F:\r\n\t\t\tfor i in rng.randi_range(2, 5):\r\n\t\t\t\tspawn_fireball()\r\n\r\nfunc spawn_fireball():\r\n\tvar fireball = load(\"res://Scenes/Fireball.tscn\").instance()\r\n\tadd_child(fireball)\r\n\r\n\tvar random_angle = rng.randf_range(0.0, 2 * PI)\r\n\tfireball.direction = Vector2(cos(random_angle), sin(random_angle))\r\n\tfireball.rotation = fireball.direction.angle()\r\n\tfireball.position = $Player.position\r\n```\r\n\r\nThe first line, `extends Node2D`, is essentially saying that this object is extending the \"Node2D\" class.\r\nThen, we create a global variable for this object called `rng` which will be used for random number generation.\r\nNext, we define the `_ready()` method which is called when an instance of this scene gets created - in this\r\nmethod we are initializing our random number generator.\r\n\r\nThe `_input(event)` method gets called every time there was an input event such as a keystroke, a mouse click,\r\na touch, a game-pad button press, etc. In our case, we are looking to see if the \"F\" key was pressed, and if\r\nso, we want to spawn 2-5 fireballs!\r\n\r\nThe logic handling the spawning of fireballs occurs in the method `spawn_fireball()`. Here we create an instance\r\nof our \"Fireball\" scene, add it as a child of the current scene, and then initialize the fireball's direction,\r\nrotation, and position. We are setting the fireball to spawn exactly where the player object is located,\r\nand we are setting the fireball's direction to be totally random.\r\n\r\nThe syntax `$Player` is syntax sugar\r\nfor `get_node(\"Player\")` and requires that our \"Game\" scene has a child node named \"Player\" (which it does!).\r\nHowever, since GDScript is very much like Python, the game will build and run just fine if one makes\r\na reference to a non-existent object - this will be caught only when the program reaches that line of code,\r\nand it will cause a crash. As Python developers are likely aware, this is sometimes one of the trade-offs of\r\nhaving a \"quick and easy\" language.\r\n\r\nYou should now be able to play the game, move the player around, and press \"F\" to fire off fireballs! Now\r\nthat the basic game is complete, let's add the juicy part by triggering the fireballs not with key presses,\r\nbut with your voice!\r\n\r\n## Triggering the Fireball With Your Voice\r\n\r\nFinally, let's do our Deepgram integration so that we can spawn fireballs by saying \"fire\" into the microphone instead\r\nof pressing a key. To do this, grab the `DeepgramIntegration` directory from `Scenes/DeepgramIntegration`\r\nfrom the [the SpeechSpells repository](https://github.com/deepgram/SpeechSpells) and place it in the `Scenes/` directory in the Godot editor.\r\n\r\nThis integration contains two Godot scenes with accompanying scripts: `MicrophoneInstance` and `DeepgramInstance`.\r\nWe won't go over the inner-workings of these scripts in detail, but feel free to have a look as they have\r\na fair amount of descriptive comments to help explain what is going on. In a nutshell, the `MicrophoneInstance`\r\ninterfaces with your device's microphone and streams the raw audio from the microphone via Godot signals\r\nto the `DeepgramInstance` which handles connecting to Deepgram via Websockets.\r\nThe `DeepgramInstance` then forwards the raw microphone audio to Deepgram, receives ASR results from Deepgram,\r\nand then forwards those results via Godot signals to some other node. In our case, this other node will be\r\nour \"Game\" scene's root node.\r\n\r\n---\r\n\r\n**_Note_**: A common issue which causes the microphone capture to fail on Mac is if Godot's audio sample rate is set to\r\nsomething different then the OS's audio sample rate. If you experience issues with microphone capture on Mac, you\r\ncan check your OS's audio sample rate under `Utilities -\u003e Audio Midi Setup`.\r\n\r\n\u003cimg src=\"./README_Assets/mac_sample_rate_settings.png\" alt=\"Mac audio sample rate settings.\" style=\"max-width: 1850px;display: block;margin-left: auto;margin-right: auto;\"\u003e\r\n\r\n---\r\n\r\nIn your \"Game\" scene, add as a child an instance of the \"DeepgramInstance\" scene, then modify `Game.gd` as follows:\r\n\r\n```\r\nextends Node2D\r\n\r\nvar rng = RandomNumberGenerator.new()\r\n\r\nfunc _ready():\r\n\trng.randomize()\r\n\t$DeepgramInstance.initialize(\"INSERT_YOUR_API_KEY_HERE\")\r\n\r\nfunc _on_DeepgramInstance_message_received(message):\r\n\tvar message_json = JSON.parse(message)\r\n\tif message_json.error == OK:\r\n\t\tif typeof(message_json.result) == TYPE_DICTIONARY:\r\n\t\t\tif message_json.result.has(\"is_final\"):\r\n\t\t\t\tif message_json.result[\"is_final\"] == true:\r\n\t\t\t\t\tvar message_transcript = message_json.result[\"channel\"][\"alternatives\"][0][\"transcript\"]\r\n\t\t\t\t\tprint(\"Transcript received: \" + message_transcript)\r\n\t\t\t\t\tfor _i in message.count(\"fire\"):\r\n\t\t\t\t\t\tspawn_fireball()\r\n\r\n\telse:\r\n\t\tprint(\"Failed to parse Deepgram message!\")\r\n\r\nfunc spawn_fireball():\r\n\tvar fireball = load(\"res://Scenes/Fireball.tscn\").instance()\r\n\tadd_child(fireball)\r\n\r\n\tvar random_angle = rng.randf_range(0.0, 2 * PI)\r\n\tfireball.direction = Vector2(cos(random_angle), sin(random_angle))\r\n\tfireball.rotation = fireball.direction.angle()\r\n\tfireball.position = $Player.position\r\n```\r\n\r\nRemember to replace `INSERT_YOUR_API_KEY_HERE` with your Deepgram API Key.\r\n\r\nNow, to finish up, click your \"Game\" scene's \"DeepgramInstance\" node and in the right panel click the \"Node\" tab (it should be right next\r\nto the \"Inspector\" tab). You should see a `message_received()` signal listed under `DeepgramInstance.gd` - double click this,\r\nmake sure that the \"Game\" node is highlighted, and click \"connect\".\r\n\r\nWhat is this signal doing? Signals are a useful way to organize the transmission of events in game engines.\r\nIn this particular case, the \"DeepgramInstance\" node is signaling to its parent \"Game\" node that it has received a message from Deepgram.\r\nIt passes this message with the signal, the parent \"Game\" node can then react to the signal to trigger further logic.\r\n\r\nIn our case, the \"Game\" node handles this signal in the `_on_DeepgramInstance_message_received` method where tries to parse\r\nthe JSON message from Deepgram into a data structure similar to a Dictionary using `JSON.parse(message)`.\r\n\r\nAfter verifying that the message successfully parsed as a Dictionary, it checks to see whether this is a final result or an interim result.\r\nTo understand the difference between final and interim results in the Deepgram realtime streaming API, check out [this page](https://developers.deepgram.com/documentation/features/interim-results/).\r\nFor our purposes, we are only considering final results. We then grab the transcript from the first alternative in the\r\nASR result, and count how many times the word \"fire\" appears in the transcript, spawning one fireball for each occurrence.\r\n\r\n## Build New Features\r\n\r\nSo now you can walk around and cast fireball spells with your voice! Here are some ideas for next steps\r\nyou may want to try out to make a more fully-featured game:\r\n\r\n- Implement more spells! Try a thunder spell, or an ice beam spell.\r\n- Add enemies and implement collision detection to destroy enemies when your spells hit them.\r\n- Try using [interim results](https://developers.deepgram.com/documentation/features/interim-results/) instead of just final results - this should decrease the latency of the spells substantially, but you will need to watch out for\r\n  double-counting as multiple interim results will give transcripts for the same section of audio!\r\n- Play around with Deepgram's `keyword`, `search`, and/or `phoneme` features to implement spells for out-of-vocab words.\r\n- If you are feeling ambitious, work through some Godot networking tutorials to create a multiplayer game where you and your friends cast spells at each other!\r\n\r\n## Final Thoughts\r\n\r\nSpeech-enhanced games have actually been around for quite some time, with popular titles such as \"Hey You, Pikachu!\" and \"Seaman\",\r\nbut it hasn't been until more recently that ASR engines have really taken off and can start to offer gameplay experiences which are deeper\r\nthan the simple command-based games of the past which only understood a few phrases. With modern ASR engines like Deepgram's, understanding\r\nthousands of commands has become trivial, and much more interesting and complex uses for speech in games is now possible. I encourage anyone\r\ninterested to try things out and explore with us what the future of speech in games might look like! Off the top of my head, I want to lastly\r\nshare some game ideas to get the creative juices flowing in the community:\r\n\r\n- An RPG where warriors fight with swords, archers fight with bows, and mages fight with... speech! Take the \"casting spells\" approach of this\r\n  tutorial and expand it to a game about incantations! (See \"In Verbis Virtus\" for even more inspiration here!)\r\n- Speech-enhanced mini-games: imagine playing a Zelda-esque game where you walk into a town and go to the nearest mini-game building and have\r\n  to play word games ala \"Wheel of Fortune\" to win your next upgrade!\r\n- Games fully controllable via speech: traditional turn-based games are a great candidate to integrate speech controls, and this could greatly\r\n  increase the accessibility of such games! This type of technology does exist, but it can likely be greatly improved with new powerful ASR engines\r\n  like Deepgram.\r\n- Casual social games: imagine playing word and speech-based games in an environment like VR chat!\r\n- AI-based visual novels: imagine playing a visual novel where instead of picking from a list of phrases to progress, you simply say what's on your mind!\r\n- AAA AI-enhanced experiences: take the visual novel idea to the next level and enhance AI components of AAA titles by allowing your character to\r\n  talk to NPCs with a microphone! (Check out games like \"Phasmophobia\" for even more inspiration here!)\r\n\r\nIf you have any questions, please feel free to reach out on Twitter - we're @DeepgramDevs.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepgram%2Fspeechspells","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeepgram%2Fspeechspells","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepgram%2Fspeechspells/lists"}