SimpleRPG

In this tutorial series, we will cover the basics of developing a simple 2D top-down RPG with Godot 3.2. After the first introductory tutorials, we will get to the heart of game development, learning to use sprites, physics, animations, GUIs, sounds and to program the logic of the game with the Godot script language, GDScript.

  1. Installation and introduction to the editor
  2. Nodes and Scenes
  3. First project
  4. Developing a pixel art RPG
  5. Player movement
  6. Physics and collisions
  7. Using tile maps to create the game map
  8. 2D Sprite animation
  9. Designing the game GUI
  10. Monsters and Artificial Intelligence
  11. Attacks, Damage & Death
  12. Picking and Using Items
  13. Experience Points and Level Advancement
  14. NPCs, Quests and Dialogues
  15. Adding sounds and music using AudioStream nodes
  16. Pause menu. Restart and quit game
  17. Exporting the project
  18. Adding a house with interior
  19. Start Menu – Changing Scene – Saving and Loading the game

Bonus tutorial: Dragging the player with the mouse

You can download the game project on GitHub.

Other Godot posts

51 Comments

mohammad bayazid jalali arasa · January 13, 2020 at 1:47 am

love ur simple tut. continue making man

    Davide Pesce · January 13, 2020 at 7:27 am

    Thank you Mohammad!

      rich engle · October 20, 2020 at 7:41 pm

      any good 3 d physics tutorials?

        Davide Pesce · October 22, 2020 at 7:08 pm

        I don’t have a specific one to suggest, but by searching on Google or YouTube you will surely find something.

Dan · February 20, 2020 at 2:31 pm

Hello David Epesce , would the last tutorial include game save and load data? Thanks for your awesome tutorial.

    Davide Pesce · February 20, 2020 at 2:36 pm

    Hi Dan, I’ll probably write a tutorial dedicated to saving and loading games in the coming weeks.

Danthn · February 21, 2020 at 4:30 am

That would be amazing! I look forward to that Keep up the good work, Davide Pesce.

Laurence · February 24, 2020 at 11:59 pm

Wow, these tutorials are really good, smart and concise and im finding them super helpful.

Still trying to figure out if i want to pursue godot or unity and this will give me some good insight in how godot works (though still unsure if i like a game engine dependant language over c#)

Subcriber · March 15, 2020 at 2:31 pm

Your tutorials are really nice and helpful.
I have followed you step by step but for some reasons when i run the game the dialogues don’t show up and i still don’t understand why. Could you help me?
Thanks a lot.

    Davide Pesce · March 15, 2020 at 3:17 pm

    Hi! To help you I need to see your project. If you can upload it to Dropbox or Google Drive and send me the link (here or privately via the Contact page) as soon as possible I take a look at it and let you know!

      Subcriber · March 15, 2020 at 5:08 pm

      Here is the link to Google Drive:
      https://drive.google.com/open?id=1mSDfHpdsaDMzChBUilwWCzVoZmqlnT3s
      Please take a look!
      Hope to get your reply soon.
      Thanks

        Davide Pesce · March 16, 2020 at 11:11 am

        You have a problem in the Font.tres file. My advice is to delete it, recreate it from scratch (the instructions are in this tutorial) and reassign it to all Label and RichTextLabel nodes.

          Subcriber · March 16, 2020 at 7:21 pm

          Wow it finally works!!! Thank you so much!!!!

Anastasia · March 28, 2020 at 2:35 pm

I’m almost done with this series (for now hehehe) and I want to say im so thankfull i found it And i thank you so much for all the times you helped me because there’s been plenty! What you are doing here is very wholesome

    Davide Pesce · March 29, 2020 at 1:29 pm

    Thanks Anastasia, I am glad to have been of some help! 🙂

Zag · April 26, 2020 at 2:30 pm

Hi Davide. These GODOT tutorials are AWESOME!!! Absolutely helped me who had ZERO programming background to understand how actually the game coding related to each other & works! I was searching Youtube for tutorial but mostly shown specific solution for specific problems & was about to give up. And I found you while having last try!!! Hope to see more simple tutorials are coming. RTS or farming will be Great!!! Thank you Davide!!!

    Davide Pesce · April 26, 2020 at 7:30 pm

    Thanks Zag, I’m happy that my tutorials have helped you!
    I still have a tutorial scheduled to finish the RPG series and a standalone one, I hope to finish them soon.
    I have yet to decide what to do next, an RTS would be interesting. Maybe a bit ambitious as an idea, but I’ll think about it!

Nozgoth · May 5, 2020 at 6:31 pm

Will you teach level transition?

    Davide Pesce · May 6, 2020 at 3:48 pm

    In the next tutorial we will go from the main menu to the game so yes, we will learn to load a level (actually I have already mentioned the change_scene function, but in that tutorial it was used to reset the game)

Phigiro · May 12, 2020 at 7:32 pm

Hi Davide!
These tutorials are great!

There are people who can explain well, there are those who can explain very well and than there are you. 🙂

Can you foresee when part 19 is finished?
I Can´t wait! :-))

    Davide Pesce · May 12, 2020 at 10:07 pm

    Thanks for the support Phigiro! Unfortunately the job is taking most of my time, I hope to publish part 19 by the end of May!

daniel · May 23, 2020 at 10:30 pm

the player movemenr is saying error at the entitles it wont move or play

    Davide Pesce · May 24, 2020 at 11:55 am

    Hi Daniel, I can’t help you unless you give me more information about your problem.
    Since these tutorials have now been tested by hundreds of people successfully, the only suggestion I can give you is to follow them step by step and compare the code of your scripts with the one on GitHub.

Cary · June 13, 2020 at 11:53 am

Hi David,

Just wanted to say a massive thank you for this tutorial. I’ve been wanting to try my hand at game programming for over 20 years and just never found the resources. I have very little experience and with your expert guidance I have nearly created and game in 1 week. You are an absolute legend.
Keep up the amazing work.

    Davide Pesce · June 14, 2020 at 9:51 am

    Glad to have been of help, Cary!

Phigiro · July 7, 2020 at 3:26 pm

Hi Davide!

Can you now foresee when part 19 is finished?
I really Can´t wait! :-))

Or have you stoped the Godot-Tutorials?

Greetings from germany

    Davide Pesce · July 7, 2020 at 5:36 pm

    Hi Phigiro!
    Part 19 is in progress and I have many others tutorials planned for the future, but unfortunately my job is taking all my time. So I don’t know when I will be able to finish it. I’m sorry for the delay!

Ransum-TNI · July 10, 2020 at 10:36 pm

I try to make a Platformer Game, i’m new in Godot..
Actually i’m on problems now..
I want to make some Hidden Traps, you know something like Invisible Object and when Player touch it’s Area it’ll show up and boom.. Player dead.

And there’s a problem on it, the Animation of this Hiddens Trap is perfectly work.. also the Area2D Script (Command to Reload Scene) but both are Triggered at the Same times.. so The Animations won’t show and yes it’s Directly brought us to Reload Scene Command..
How can I fix it?
Can you help me please..
I try to ask this question on Facebook but they give me nothing but Judging on me..

Thanks Before
This is my E-MAIL if reply this lemme know it..
prakasgarda2017 [at] gmail.com

Also, sorry for broken English..
I’m 17 y.o student that want to learn Coding especially in Game Development things 🙂

    Davide Pesce · July 11, 2020 at 1:16 pm

    You need to introduce a delay between the animation and the reloading of the scene. You could use a Timer: when the player enters the Area2D you start the timer, and when the timeout occurs you reload the scene.

oddEvan · July 11, 2020 at 5:39 pm

Just wanted to leave a note here that I’ve started working my way through these and I’m really excited about it. Thanks for putting these out here!

NewbieInCoding · July 28, 2020 at 3:58 pm

Can you please make tutorial on making 3d games in godot? I am finding it difficult. I tried searching tutorials in yt and internet but couldn’t find a good one. Your tutorials are step by step easy to understand and i really found them helpful.

Phigiro · August 20, 2020 at 7:22 pm

Hi Davide,

i have a little Problem:
I want to make an Intro and an Outro.
In the intro/outro the palyer should go somewhere and do something.

Is it state of the art to copy the main scene (rpg tutorial) twice for that.
The problem i see is, when i have, for example, changes in the playernode, then i have to do it in each copy of main scene.

Sorry i´m very new at Godot.

Thanks! 🙂

    Davide Pesce · August 21, 2020 at 11:56 am

    Hi Phigiro, the best solution is to make Player a separate scene, so that if you edit it, changes are automatically applied to all scenes in which it’s instantiated.

      Phigiro · August 21, 2020 at 1:39 pm

      Hey! 😃
      Thanks for your answer!
      Do i have to make a separate scene for the Tilemap to?

        Davide Pesce · August 21, 2020 at 7:34 pm

        What to make as a separate scene and what not is often a personal choice, Godot’s node/scene system is very flexible and allows you to organize a projects in many different ways.

        As a general rule, I recommend that you create a scene when you intend to use an element multiple times. If you have a game divided in levels, and each level has its own map, the tilemap usually doesn’t need to be in its own separate scene.

Phigiro · August 21, 2020 at 8:21 pm

ok, now i understand!

And yes, in my case i use the tilemap three times, in the intro, for the game and the outro.
And perhaps somewhere else. But it is always on the same map.
So it make sence, to separate the tilemap.

Thanks for that! 🙂

.. · October 1, 2020 at 9:08 am

Hi Davide,
I am trying to make a door at the end of a level in my game, and when the player comes in contact with the door it changes levels. Unfortunately the code doesn’t seem to work so if you could have a look and try and see what the problem is that would help.

(the code is in the character)

func _on_Door_body_entered(body):
if body.get_name() == “Player”:
get_tree().change_scene(“res://Inbetween Scene/Inbetween scene.tscn”)

    Davide Pesce · October 3, 2020 at 9:46 am

    If you send me a link to your project, I’ll try to check it out as soon as I have some free time

Anurag · October 3, 2020 at 3:01 pm

Thanks for your tutorials! I was wondering whether you could make a state machine tutorial..that would be helpfull.I’m a beginner so I find it difficult to understand.

    Davide Pesce · October 6, 2020 at 3:21 pm

    Hi Anurag, it’s an interesting topic so I gladly do it. But you will have to wait a bit, unfortunately I don’t have much free time at the moment.

      Anurag · October 13, 2020 at 1:50 pm

      Yep ,will look forward to it

Dzandaa · October 5, 2020 at 8:13 am

Hi,
This is part of my code to load a new level:
Hope this help!

###################################
# Level Names: Level1, Level2, etc...
# Active Level is in CurrentLevel
###################################

func ChangeLevel():        
  Level = Level + 1
  var NewLevel = "res://Levels/Level"+str(Level)+".tscn"
  if(ResourceLoader.exists(NewLevel)):
    LoaderLoadLevel(NewLevel)

func LoaderShowError(Error):
  print("Error : "+ Error)
          
func LoaderLoadLevel(Path): 
  ProgressBar.visible = true
  Loader = ResourceLoader.load_interactive(Path)
  if Loader == null: # check for errors
    LoaderShowError("No Level")
    return
  set_process(true)
  set_physics_process(false)
  
  CurrentLevel.queue_free() # get rid of the old scene
  
  get_node("../Progress").SetProgress(0.0)      
  
func LoaderSetNewLevel(scene_resource):
  CurrentLevel = scene_resource.instance()
  get_node("/root/World").add_child(CurrentLevel)

func LoaderUpdateProgress():
  var progress = float(Loader.get_stage()) / Loader.get_stage_count()
  # Update Progress Bar?
  get_node("../Progress").SetProgress(progress)     
  
###############
# Process
###############
func _process(_time):
  if Loader == null:
  # no need to process anymore
    set_process(false)
    return
               
  # use "LoadTime" to control for how long we block this thread
  var t = OS.get_ticks_msec()        
  while OS.get_ticks_msec() < t + LoadTime: 

  # poll your loader
  var err = Loader.poll()

  if err == ERR_FILE_EOF: # Finished loading.
    var resource = Loader.get_resource()
    Loader = null
    ProgressBar.visible = false
    LoaderSetNewLevel(resource)
    set_physics_process(true)
    break
  elif err == OK:
    LoaderUpdateProgress()
  else: # error during loading
    LoaderShowError("Loading")
    Loader = null
    break


###############
# Progress bar
###############
Progress -> Canvas Layer
Background -> ColorRect (1024 x 600 Pos: 0,0)
  ProgressFrame -> ColorRect (1024 x 44 Pos: 0, 278)
    ProgressBar -> ColorRect (1020 x 40 Pos: 2,2)
Label -> Label (“Loading…” 576 x 112 Pos: 208, 119)

###############
# Code in Progress:
###############

func SetProgress(Progress):
  $Background/ProgressFrame/ProgressBar.rect_size.x = 1020.0 * Progress

    Davide Pesce · October 6, 2020 at 3:13 pm

    Thanks for sharing your code!

Jason · October 22, 2020 at 6:35 pm

Bro why don’t you teach how to do an inventory

    Davide Pesce · October 22, 2020 at 7:05 pm

    I’ll think about it.

VerteronParticle · March 1, 2021 at 3:49 pm

Bruh – thank you.

I’ve been bouncing between multiple Godot tutorials, and so far, yours is the best. All the others had missing pieces / incomplete steps, and yours does not, for which I am very grateful.

I’ve burned through everything except saving the game, and the house – plan on doing all that tonight.

I did have a general question, though –

I diverged from the tutorial shortly after creating the fireball, and decided to build ‘burning’ and ‘burned’ states for a Tree entity. I learned after the fact that you can animate tilemaps, which may still be something I can leverage to accomplish what I’m trying to do, but so far I’ve been hitting a fairly huge confuse point. Maybe you can help.

I’ve been able to modify your code to create a burning animation when the tree enters ‘burning’, and then delete it / replace with a burned-out stump sprite. My problem is, I’m trying to get the fire to spread.

I thought about using raycasting, but that seems like a really messy solution, as I’d need to either sweep the ray around in a full 360-degree arc to detect neighboring trees, or create a ton of them each pointing in a direction that will equal a separate, neighboring tile.

Some suggestions centered around using body_entered / body_exited signals, but I don’t think this will work because those are for detecting collisions, and the entities I’m interested in detecting are not ‘entering’ or ‘exiting’ the detection radius – they were there all along.

Do you have any thoughts that might at least point me in the right direction? I’m willing to bash my head against this problem as long as I have to, but it’d suck to spend weeks doing that, only to learn that the functionality I’m trying to leverage will not accomplish the task I have in mind.

I appreciate your input, and all the awesome work you put into this. I’m very much hoping you do more for Godot.

Hope you have a great day.

    Dzandaa · April 17, 2021 at 2:24 pm

    Another idea is to use a recursive function like:

    extends TileMap

    var tree = 3
    var trunk = 4

    func BurnTree(var Pos):
    var Type = self.get_cellv(Pos)
    if(Type != tree):
    return
    self.set_cellv(Pos, trunk)
    OS.delay_msec(10)
    BurnTree(Pos + Vector2(0,-1))
    BurnTree(Pos + Vector2(-1,0))
    BurnTree(Pos + Vector2(1,0))
    BurnTree(Pos + Vector2(0,1))
    pass

    # Called when the node enters the scene tree for the first time.
    func _ready():
    pass # Replace with function body.

    func _unhandled_input(event):
    if (event is InputEventMouse):
    if (event.get_button_mask() == 1):
    var Mouse_Pos = get_viewport().get_mouse_position()
    var Map_Pos = world_to_map(Mouse_Pos)
    BurnTree(Map_Pos)

dzandaa · April 17, 2021 at 10:35 am

Hi VerteronParticle,

It’s been a while I didn’t used Godot

Perhaps you can try using a signal like:
signal Tree_Is_Burning
After the tree is replaced with a burned-out
emit_signal(“Tree_Is_Burning”, self)

And in the tree receiving the signal:
Check if it is not already burned,
Compute the distance of the emitting tree and self
position.distance_to(emitting )
and if the distance is lower than a value, repeat the Tree_Is_Burning signal process

Just an idea 🙂

Good luck

Leave a Reply

Your email address will not be published. Required fields are marked *

By continuing to browse this Website, you consent to the use of cookies. More information

This Website uses:

By continuing to browse this Website without changing the cookies settings of your browser or by clicking "Accept" below, you consent to the use of cookies.

Close