GodotWorkshop

Introductory to Godot Workshop!

Learn how to create games with Godot by creating your first basic game!

What is Godot?

image

A game engine is a tool that allows for ease of creation of games. Game engines have features that make it easy to make whatever you can dream up! An example of some features common in game engines are the following:

Some well known game engines are Unity, Unreal Engine, Godot, CryEngine, GameMaker, PyGame, RPGMaker, and Scratch.

You can also create your own game engine using any programming language! It is pretty involved as you have to figure out how to interact with the computer to display and make sounds on your own but these challenges can be really rewarding to solve!

What sets Godot apart from other game engines?

A number of features set Godot apart from the pack.

1) Godot is completely free

This is really critical. A lot of game engines are free for personal use but cost money if you want to actually make professional games with them. Godot is free no matter if you are a huge development team or a solo developer making games for fun!

2) Godot is lightweight

Upon downloading the game enigne, you will notice how easy it is to use on your computer! Game engines are historically large programs that consume a lot of memory and processing power. Godot on the otherhand is very easy to run on any computer and its download size is around 500 MB, smaller than most social media apps! It can also run on any type of computer!

3) Godot is Open-Source

Screenshot 2025-02-03 at 7 06 02 PM An open-source application is an application that’s sourcecode is publicly available online. The developers of Godot are people in the game development community that use Godot and publicly contribute to the project. What this means is that Goodt will always be free and the community is super supportive and open to allow the app to be prosperious!

4) Godot is EASY!!!

Game engines are sterotypically super complicated, packed with tons of features that are poorly explained. Godot is suprisingly insanely easy to get started with. It features a Python-like programming language called GDScript with documentation built into the application. Hovering over any library function allows you to pull up the wiki page for what that function does and how it works. Features mostly behave as you would expect making it super easy to start making games with Godot after getting over the initial learner barrier as you will soon see!

5) Godot is a new technology

The last thing that sets Godot apart is that its constantly changing. The fact that it is constantly changing and evolving is super interesting to developers in the industry looking for future ways to streamline the process of making games. This interest in the technology might be something that helps you secure an interview where you can talk about your experience with this technology (this is something I experienced when interviewing with Riot Games!!).

For these reasons, we will be teaching and recommending Godot to be used for LionJam and future game jams!

Installing Godot

The best way of downloading Godot in my opinion is through the website!

You can find the download link here!

image

You can additionally download it off of Github or Steam but I recommend downloading the latest version from their website since the app is constantly changing and that we you can decide when to update the engine.

Exploring the Engine

Screenshot 2025-02-05 at 3 55 29 PM

Upon opening the engine and creating a new project you should see something like above!

Before we start building lets explore the editor!

Let us first take a look at the panel on the bottom left.

Screenshot 2025-02-05 at 3 58 37 PM

This is the file explorer, all the files in our project including our assets (like art, sfx, music, and code) will all be contained in this area. Its up to you how you organize this, but its just to make it easy to find things when working with a lot of files!

res:// is the base directory for your project. If you open the file explorer on your computer and navigate to the place you opened your project in, you should see icon.svg, like we see in the editor!

Epic!!

Next let’s take a look at the viewport!

Screenshot 2025-02-05 at 4 02 21 PM

The viewport is the area shown above. It allows us to see what our game looks like! Once we start adding some stuff to our game we will see the viewport populate. Within the viewport there are a couple of tools to allow you to edit assets on the fly like a scale tool, move tool, and rotate tool. Once you add a camera to your game, it will also show up here so you can see what your game will look like when being played. Last thing to note is there is two version of the viewport, the 2D and 3D version. You can switch between the versions at the top of your screen!

Screenshot 2025-02-05 at 4 09 10 PM

The next area we can take a look at is the bottom panel. This is home to some important tools we will use while editing. First is the Output tab. This is where all our error messaegs and print messages will show up - stuff thats pretty important for debugging! Next is the debugger which will let you figure out the values of differnet variables at different times during the run of your game. It will also help you find out where errors are coming from! The audio tab lets you control the volume of different sounds from your game. The animation player is super important - its very powerful. It will probably primarily be used for creating animations though! The shader editor is where you will write shaders for your game!

Screenshot 2025-02-05 at 4 16 09 PM

The last two panels are definitley the most important besides the viewport. First the Hierarchy/Scene Panel is on the left side of the screen. This panel showcases all the nodes (we will describe this term soon) that are in the scene. It also shows the hierarchy of nodes (parental relations of objects). Every scene has a root node as a main reference to the scene. It is useful for organizational purposes. Here is what the panel looks like with 1 Node2D in it.

Screenshot 2025-02-05 at 4 23 47 PM

The last main panel is the Inspector panel on the right side of the editor. Here we can find all the properties of an object or node like its position, its size, its texture and more! Under the Node tab of the inspector is also a bunch of events also known as Signals that can be connected to code when the node is interacted with in certain ways.

Screenshot 2025-02-05 at 4 24 29 PM

It would also be a good idea to familiarize yourself with the contents of the drop downs at the top of the screen. These are the places where you will be able to change the resolution of your game, save, export, and change the controls.

Screenshot 2025-02-05 at 4 27 13 PM

With that, you should be familiar with the layout of the editor!

Godot Terms

While using Godot, you will come across Nodes and Scenes before working on games with Godot its important to understand what they are and how they work.

Nodes

In Godot a Node is the base unit object and class. Nodes have base properties and functions. Within Nodes, you can attach scripts that let you program the node and its properties. Additionally, you can attach the signals to functions within the script, allowing them to handle when signals are activated.

Godot offers a bunch of preset nodes that you will use while making games. The one that will be most important to us is the Node2D. This node features properties such as transform (which is a collection of information such as position, rotation, and scale), it also inherits from the Node base class.

Another example of a Node is a CharacterBody2D node. This node features properties that allow for movement and physics handling. Additionally, it inherits from CollisionObject2D which allows for the node to collide with other collision objects, assuming it has a collision shape.

Pretty much everything in Godot is a node, so you will see them everywhere! Heres a video where you can learn about every Node available in Godot!

Scenes

Screenshot 2025-02-05 at 5 06 29 PM

Now that we know about Nodes, we can explore scenes. Scenes are collections of nodes, with a root node to allow for a hierarchal relationship within the collection. While this relationship allows for organizaiton, it also allows for you to combine different nodes together. The properties of children follow the properties of the parent. For example, if one Node2D is the child of another Node2D, and the parents position is being updated, the child will move around relative to the parent.

This allows for us to combine nodes to create all sorts of objects. For example, you might use a scene as a collection of nodes that represent a playable character, that will feature a node that controls the animations and a collision shape node and maybe the item the character is holding in its hand.

With a scene like a character, we can then put that scene within another scene like the level. This is called nesting!

The nesting of scenes allows for you to keep your project super organized with each type of object (including menus and UI) having its own scene!

Scenes are another super important topics. I highly recommend checking out Brackey’s Godot intro where he goes super into the scene system!

Planning out our game!

The game that we will be making for the workshop is a clone of the google dinosaur game!

image

Here’s the assets we are gonna need for our game:

With all of that, we will be able to bring it all into Godot to make our game!

I have provided some assets that I will be using in the Github repository! Feel free to download the assets folder within the dinotime folder!

This section is inspired by the following youtube video by Coding with Russ

Here are where the assets are from that we use! Parallax Background - https://jesse-m.itch.io/jungle-pack Dinosaur - https://arks.itch.io/dino-characters Tree stump - https://free-game-assets.itch.io/free-swamp-2d-tileset-pixel-art

Dino Time!

Make sure to start off with an empty project!

Parallax Background

The first thing we are going to do is create our moving background. You may have seen in some games how backgrounds look like they are 3D despite being 2D. Developers accomplish this by using an effect called Parallax. Parallax moves different layers of background images at different speeds to make it look like theres some dimensionalituy to the background. It’s easier to undersand in practice so lets check it out!

First thing we want to do is setup this structure of a scene. Godot has a parallax background node that we can use as our root node. Then we can add in a Sprite2D, this is just a Node2D with a texture property, for the blank background. Once you have added in the Sprite2D, add in bg1.png to its texture slot in the properties panel! Additionally, we are gonna turn off the property “Centered” under offset.

Next we are going to add in a ParallaxLayer node below our Sprite2D for the blank background (see the attached image for what that looks like). The ordering of the ParallaxLayer nodes determines the order they appear on the screen, the lower the node is the closer it will be to the front. In the parallax node we just added, we are going to add in another Sprite2D where we can add in the first background texture, bg2.png. We are going to want to uncheck the “centered” property again here. You also might notice the texture looks a little small and blurry. To fix this, I opened the Node2D Transform property and scaled the image by 3, and then went to the Texture property and changed the filter to “nearest”. This fixed up our resolution issues! Screenshot 2025-02-06 at 9 13 39 PM

Now that we have that setup, we can now setup how the background can move. Under the motion properties of our ParallaxLayer lets set the x value of mirroring to 1156 - this value comes from multiplying the width of our texture by 3 (remember when we scaled the texture by 3 to make it larger!). Then we set our scale’s x value to 0.6, this is the speed our background will be moving out. Sometimes values in Godot are linked such as the x and y value of the Scale. We can unlink them by clicking the chain icon and then we can just individually change the X value, otherwise we would be moving the background both vertically and horizontally.

Once we have done this, we can copy and paste the Parallax layer 3 more times for our layered background, making sure to replace the images with the corresponding background images. After copying and pasting, change the scale values to increase by 0.1 as our layers get closer to the front. When we play our game, we will see how the layers closer to the screen will move faster.

After all of that, we are finished with our background! It should look something like below. Let’s save it to a scenes folder we can create within our assets folder as background.tscn. Screenshot 2025-02-06 at 10 02 31 PM

Setting up our Dino!

Next we are gonna set up the dinosaur character. First lets create a new scene with a CharacterBody2D as the root node. Then we are going to add in a AnimatedSprite2D, CollisionShape2D, and an AudioStreamPlayer node. It should look like the setup below.

Screenshot 2025-02-06 at 10 12 39 PM

First lets setup the character’s animations. In our AnimatedSprite2D lets look at the Animation property and create a new SpriteFrames object to store our sprite frames for our character. Then upon opening the SpriteFrames, the animation tab on the bottom appears. Here is where we can add the different animations for our character. We are going to create 3 different animations: idle (for when the character isn’t moving), running, and jumping. You can create each new animation by clicking the icon with the green plus in the top left of the animation panel. From there we can add frames to our animations by clicking the icon that looks like the grid. We will import the sprites from our sprite sheet that is in the assets folder. Once you open up the sprite sheet, a popup like below should appear! Make sure to change our Horizontal and Vertical to be 24 and 1 respectively, this is because we have 24 sprites all in 1 row. We will use the first 4 frames for the idle animation.

Screenshot 2025-02-06 at 10 21 24 PM

After chosing those 4 frames, pick out the next 6 frames for a running animation and one of the frames where the dinosaur has 1 leg up for the jump animation. Once you are done, you should be able to see our dinosaur in the viewport. Once again this texture looks a little blurry so lets fix that up by scaling by 6 and changing the filter mode to nearest. You should now see something like this!

Screenshot 2025-02-06 at 10 27 20 PM

Now that we have our animations set up, lets setup our collision shape which we will use for checking if we are touching the floor or obstacles. Click on your CollisionShape2D node and add a Rectangle collision shape to the Shape property. Then adjust the size to fit the dinosaur by dragging the edges of the box or changing the width and height on the CollisionShape object. We should see something like this! With that we are pretty much all set!

Screenshot 2025-02-06 at 10 30 17 PM

Last thing to do is setup our jumping sound effect (by the way I made this using sfxr)! I changed the name of my AudioStreamPlayer to be JumpSFX and dragged in my wav file into the stream property. With that our character is all good to go for now! Let’s save the scene and move on!

Ground Pound

Next lets create the ground our character will be running on. It will be a similar process to what we have been doing! Lets create a new scene with a StaticBody2D as the root. StaticBodys are useful for floors and walls because they don’t move with physics! Let’s add in a Sprite2D and a CollisionShape2D to our scene as well as our grass floor as the texture for the sprite, scale the StaticBody2D by 3 and fix the resolution on our texture like we have done previously. Next, make sure to drag your floor to the bottom of the canvas, as thats where its going to be in the game. Then add in a rectangular collision shape to the ground. You may notice that the ground is wider than the canvas size. This will allow us to make it seem like the ground is moving while we are running and we will use it later when we are coding our gameplay loop. Thats all we need to setup for the ground for now. Lets also change the name of the root node to ground and save the scene!

Screenshot 2025-02-06 at 10 43 52 PM

Creating the Main Scene

Lets now create our main scene where its all gonna come together.

First create a new scene with a unit plain Node as the root node. Next lets add in our dino, ground, and backgrounds scenes that we just made. We can do that by clicking the chain button next to the plus sign in the hierarchy. Make sure while adding that they are correctly orded so the dinosaur is in front of the ground, which is in front of the background. Additionally, to make sure the dinosaur is always at the front, we can go back to the dino scene and by clicking the movie icon next to the node and change the Z-Index property in Ordering to be 1. This will ensure that it is positioned in fron of everything that has a Z-Index less than it and everything is 0 by default.

After that, lets add a Camera2D node - this is what is displayed when we are playing the game. Change its transform position property to be 576 x and 324 y so that the camera is center on the screen. After doing this, we can save the scene and run the game! You should be able to see all the sprites we just setup on the screen.

Screenshot 2025-02-06 at 10 54 42 PM

Epic! Lets now add some code to add some movement to our character. Go back to the dino scene and lets click the add script button in the hierarchy. Click create and you should get a file that looks like the following.

Screenshot 2025-02-06 at 11 01 23 PM

This looks a little scary but for those who know Python its also a little familiar. This is GDScript, Godot’s programming language. Lets go through every line of code and learn some things about this language.

In the first line of code we are extending from the class CharacterBody2D, inhieriting its functionality. For the unfamiliar, this means that we are taking the functionality of whatever the CharacterBody2D has to offer, and adding more on top of it!

Next, we declare 2 consts SPEED and JUMP_VELOCITY. A const is just a value that is unchanging throughout the run of our program, this will be pretty useful for values like SPEED or JUMP_VELOCITY, since we want our SPEED or JUMP_VELOCITY to always be the same for the most part.

Next, we have a function called _physics_process with a parameter delta. The physics_process function is called on every object that has it 60 times a second at least, and delta is the amount of time between the current frame and the last frame. We can use this function to ensure we are consistently performing our physics calculations.

Next it looks like we add gravity if the object is not on the floor after multiplying it by delta. Godot offers some cool functions to make physics a lot easier, like the is_on_floor() function. We multiply gravity by delta to insure that we are updating our velocity consistently every second.

The following lines check if the enter key or “ui_accept” is being pressed and if the player is on the floor, if so updates their velocity. The last couple of lines of code allow for you to move left and right. Since we will be moving the background to simulate motion we can delete these, execept the move_and_slide function. move_and_slide takes our newly updated physics values to change the position of the object.

With all of this in mind lets make a couple changes. Remember that theres indentation like Python! First lets update our jump velocity to be -500 instead of -400. You can think of this as applying a negative y velocity equivalent to 500 pixels/s. Since the Godots coordinate system starts in the top left corner and y increases as you go down, this is applying an upwards velocity and changing it from 400 -> 500 is increasing that velocity!

We can also delete the speed variable because we are not going to be using it anymore - we deleted the code that lets you move with the arrow keys! Lastly, lets create a new @onready variable called jumpsfx and set it = $JumpSFX. @onready means that the variable will be set when the scene is created when the game starts. “$JumpSFX” means that we will go into the heirarchy tree and get the child node named JumpSFX. This line will create a reference to the JumpSFX that we can use to call jumpsfx.play() right after we set our jump_velocity, which will cause the jump sfx to play when we jump!

Screenshot 2025-02-06 at 11 36 08 PM

Now when we start the game, if you press the enter key you will be able to see the player jump and hear the sfx!

Next lets change our animations when we press the enter key. Using the same strategy we used for the audio player, lets include our animation player node and play the different animations when our character is in different states like below.

Screenshot 2025-02-06 at 11 43 32 PM

Now our player will be running when they are on the ground and in the jumping animation after they jump!

We have done a lot here! Lets go setup the stump we are gonna use later as an obstacle!

Stumpin’

Lets repeat what we did before and create a stump with a collision shape that looks like this. Make sure to fix the resolution and to scale it! Screenshot 2025-02-06 at 11 49 12 PM

Easy peasy now!

Loopin’

Time to setup the main gameplay loop! Lets go back to the main game scene and add a script on the root node. In this node we are going to setup a couple things. First we are going to setup a newgame function that gets called every time the game is started. Then we will setup the process function that gets called every frame, this is where we will move the floor and the background. We are lastly going to setup scoring and obstacles and restarting the game. Heres the code for the first half of what we set to accomplish. Lets add some UI so we can display the score on the screen next.

For explainations what the lines do, check out the comments I left noted by #s!

extends Node

@onready var dino = $Dino
@onready var ground = $Ground
@onready var background = $Background
@onready var camera = $Camera2D

# The starting position of the camera and the dinosaur!
const DINO_START_POS = Vector2i(103, 497)
const CAM_START_POS = Vector2i(576, 324)

# Speed variables that we can use to increase the speed of the game over time
var speed : float 
const START_SPEED = 10.0
const MAX_SPEED = 25
var screen_size : Vector2i

var score : int

# This is called when the game starts!
func _ready() -> void:
	screen_size = get_window().size
	newgame()

# our new game functon! here we are gonna set up a bunch of the initial values for all of our objects
func newgame():
	dino.position = DINO_START_POS
	camera.position = CAM_START_POS

	# zeroing out the velocities for the moving objects!
	dino.velocity = Vector2i(0,0)
	ground.position = Vector2i(0,0)
	
	speed = START_SPEED
	score = 0 

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	# constantly moving the dinosaur and the camera to the right!
	dino.position.x += speed
	camera.position.x += speed
	
	score += speed * 3

	# This bit is a little tricky!
	# Once the ground is about to be off the screen,
	# we move it forward the amount of the sreensize to ensure we never run out of ground
	if camera.position.x - ground.position.x > screen_size.x * 1.5:
		ground.position.x += screen_size.x

Sweet! Now you should see the dinosaur moving and the ground moving!

Now we are going to setup the UI for the game to showcase the scoring. Create a new scene with a CanvasLayer node as the root node.

Screenshot 2025-02-07 at 12 23 47 AM

Using the label nodes I created the following UI. Then I linked it to my main scene like we did with all the other scenes!

Combining our new UI with our existing code we can update the scoring and also add speed increasing!

extends Node

@onready var dino = $Dino
@onready var ground = $Ground
@onready var background = $Background
@onready var camera = $Camera2D
@onready var ui = $UI

const DINO_START_POS = Vector2i(103, 497)
const CAM_START_POS = Vector2i(576, 324)

var speed : float 
const START_SPEED = 10.0
const MAX_SPEED = 25
const SPEED_CONST =  100000
var screen_size : Vector2i

var score : int
var playing : bool

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	screen_size = get_window().size
	newgame()

func newgame():
	dino.position = DINO_START_POS
	camera.position = CAM_START_POS
	dino.velocity = Vector2i(0,0)
	ground.position = Vector2i(0,0)
	
	ui.get_node("Start").show()
	dino.animator.play("idle")
		
	speed = START_SPEED
	score = 0 
	update_score()

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if playing:
		# we can increase our speed over time with this line
		# we take the minimum of our max_speed const and the start_speed + some score multiplier!
		speed  = min(START_SPEED + score/SPEED_CONST, MAX_SPEED)
		dino.position.x += speed
		camera.position.x += speed
		
		score += speed * 3
		update_score()
		
		if camera.position.x - ground.position.x > screen_size.x * 1.5:
			ground.position.x += screen_size.x
	else:
		# this allows us to start the game by having to press enter!
		if Input.is_action_just_pressed("ui_accept"):
			playing = true
			ui.get_node("Start").hide()
		
# updating the score text!
func update_score():
	ui.get_node("Score").text = "SCORE: " + str(score)
	

Our last bit of code will be adding the obstacle to our scene. This is the trickiest part!

extends Node

# Preload is going to give us a copy of the stump we can "spawn in"
var stump_asset = preload("res://assets/scenes/stump.tscn")

@onready var dino = $Dino
@onready var ground = $Ground
@onready var background = $Background
@onready var camera = $Camera2D
@onready var ui = $UI

const DINO_START_POS = Vector2i(103, 497)
const CAM_START_POS = Vector2i(576, 324)

var speed : float 
const START_SPEED = 10.0
const MAX_SPEED = 25
const SPEED_CONST =  100000

# these are some new variables we will need to know where to create the stumps on the screen
var screen_size : Vector2i
var ground_height : int

# a variable that tracks if there is currently a stump on the screen and the current stump
var stumped : bool
var current_stump

var score : int
var playing : bool


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	# this gets the information we need for where to spawn the stump
	screen_size = get_window().size
	ground_height = ground.get_node("Sprite2D").texture.get_height()
	stumped = false
	newgame()

func newgame():
	dino.position = DINO_START_POS
	camera.position = CAM_START_POS
	dino.velocity = Vector2i(0,0)
	ground.position = Vector2i(0,0)
	
	ui.get_node("Start").show()
	dino.animator.play("idle")
		
	speed = START_SPEED
	score = 0 
	update_score()

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if playing:
		speed  = min(START_SPEED + score/SPEED_CONST, MAX_SPEED)

		# if we have a stump spawned, check if its off the screen, otherwise create a new one
		if stumped:
			if(current_stump.position.x < dino.position.x):
				stumped = false
		else:
			create_stump()
		
		dino.position.x += speed
		camera.position.x += speed
		
		score += speed
		
		update_score()
		
		if camera.position.x - ground.position.x > screen_size.x * 1.5:
			ground.position.x += screen_size.x
	else:
		if Input.is_action_just_pressed("ui_accept"):
			playing = true
			ui.get_node("Start").hide()

# this is our function for creating a new stump on the screen
func create_stump():
	# first we create the stump node
	var stump = stump_asset.instantiate()

	# Then we get the height of the stump and scale and use that to position it on the screen
	var stump_height = stump.get_node("Sprite2D").texture.get_height()
	var stump_scale = stump.get_node("Sprite2D").scale
	var stump_x = screen_size.x + score + randi_range(100, 300)
	var stump_y = screen_size.y - ground_height - (stump_height * stump_scale.y * 4) + 12
	stump.position = Vector2i(stump_x, stump_y)

	# set our stump boolean to true and add it to the scene by calling add_child
	stumped = true
	add_child(stump)
	current_stump = stump
	
func update_score():
	ui.get_node("Score").text = "SCORE: " + str(score)
	

Try out the game and see how the stumps spawn. Now we just have to make sure we can get hit by them!

With this next code we now have a game over screen that appears when we enter the hitbox of an obstacle!

extends Node

var stump_asset = preload("res://assets/scenes/stump.tscn")

@onready var dino = $Dino
@onready var ground = $Ground
@onready var background = $Background
@onready var camera = $Camera2D
@onready var ui = $UI

const DINO_START_POS = Vector2i(103, 497)
const CAM_START_POS = Vector2i(576, 324)

var speed : float 
const START_SPEED = 10.0
const MAX_SPEED = 25
const SPEED_CONST =  100000
var screen_size : Vector2i
var ground_height : int

var stumped : bool
var score : int
var playing : bool
var game_overed : bool
var current_stump 

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	screen_size = get_window().size
	ground_height = ground.get_node("Sprite2D").texture.get_height()
	stumped = false
	game_overed = false
	newgame()

func newgame():
	dino.position = DINO_START_POS
	camera.position = CAM_START_POS
	dino.velocity = Vector2i(0,0)
	ground.position = Vector2i(0,0)
	
	stumped = false
	# delete any stumps if they exist
	if(current_stump):
		current_stump.queue_free()
		current_stump = null
	
	ui.get_node("Start").text = "Press Enter to Play"
	ui.get_node("Start").show()
	dino.animator.play("idle")
		
	speed = START_SPEED
	score = 0 
	update_score()

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if playing:
		speed  = min(START_SPEED + score/SPEED_CONST, MAX_SPEED)
		
		if stumped:
			if(current_stump.position.x < dino.position.x):
				stumped = false
		else:
			create_stump()
		
		dino.position.x += speed
		camera.position.x += speed
		
		score += speed
		
		update_score()
		
		if camera.position.x - ground.position.x > screen_size.x * 1.5:
			ground.position.x += screen_size.x
	elif(game_overed):
		# new game over state!
		if Input.is_action_just_pressed("ui_accept"):
			newgame()
			game_overed = false
	else:
		if Input.is_action_just_pressed("ui_accept"):
			playing = true
			ui.get_node("Start").hide()
		
func create_stump():
	var stump = stump_asset.instantiate()
	var stump_height = stump.get_node("Sprite2D").texture.get_height()
	var stump_scale = stump.get_node("Sprite2D").scale
	var stump_x = screen_size.x + score + randi_range(400, 600)
	var stump_y = screen_size.y - ground_height - (stump_height * stump_scale.y * 4) + 12
	stump.position = Vector2i(stump_x, stump_y)
	stumped = true
	# when something enters the collision body of the stump -> we call the function hit_stump
	stump.body_entered.connect(hit_stump)
	add_child(stump)
	current_stump = stump

# call the game_over function if the dinosaur is what touches the stump
func hit_stump(body):
	if(body.name == "Dino"):
		game_over()
		
func game_over():
	playing = false
	game_overed = true
	ui.get_node("Start").text = "GAME OVER - press enter to start over"
	ui.get_node("Start").show()
	
func update_score():
	ui.get_node("Score").text = "SCORE: " + str(score)
	

Yay! Congrats on finishing your first Godot game! Try to mess around and add some more functionality to the game and learn more Godot!