Godot 3.2 Player Skin Changer Tutorial

insert intro here

Here are the steps we will take to achieve this:

  1. Create a main scene with a character selection menu. This menu will have two buttons to go forwards and backwards, a small preview of the character you are selecting, and a name for the character.
  2. Use an autoload singleton to store the path to the skin texture for use in-game.
  3. Replace the player’s default texture with the one stored in the singleton.

Included below is a zip file containing a starting template for the tutorial. All it contains is a folder with a base Zelda-like player controller and three player sprite sheets. You can still follow along using your own game, but if you get lost, I recommend following along with the template so you see how everything fits.

playerskin-tutorial-start

MainMenu.tscn

First, open up the game. If you are not following the template, you should at least already have a player set up with a sprite sheet and an AnimationPlayer. Create a new scene. This will be our menu scene, so you can select User Interface in the Create Root Node menu. I am going to call it “MainMenu”. Save this into the root directory of the project as “MainMenu.tscn”. You should also go to Project>Project Settings, select Run, and set the Main Scene to this new scene.

Add a Panel node as a child and name it SkinSelect. Size it as so in the center of the screen:This panel is going to hold all of the skin selection UI, along with its script. This tutorial is going to use the default Godot theme, and the template has a low screen resolution making this theme somewhat blurry. If you would like to see how to make your own themes, you can check out this page in the docs.

Next add two Button nodes and name them “Back” and “Next”. Place them on the left and right ends of the panel. Now add a Sprite node and put it in the center. Name it “Preview”. Set its Texture to the sprite sheet of your default skin, and adjust the Vframes and Hframes as necessary. If you are using the template, the Texture would be “res://player/player1.png” and Vframes and Hframes are 7 and 6, respectively.

We can also optionally add a short animation to this preview. Create a new AnimationPlayer node, make a short animation of the preview’s first two frames, and set it to loop and autoplay.

Finally, we’re going to add a Label node to show the character’s name for each skin. Call it “Name” give it some default text, and center it underneath the preview. I also increased the size of the preview sprite in this next screenshot.

SkinSelect.gd

Now let’s move onto the SkinSelect script. Right-click SkinSelect and add a new script. I will be saving mine to “res://SkinSelect.gd”. We will start by making two variables: one that will keep track of the currently selected skin, and one that will store all of the names and paths to skins in a dictionary.

extends Panel

var selected = 0

var skins = {
	"Chain": "res://player/player1.png",
	"Knot": "res://player/player2.png",
	"Tie": "res://player/player3.png"
}

skins is where you will add all of the alternate png files the player can choose from. The keys are the names and their values are the paths. You can add as many skins as you want.

Next we’ll make our update_skin function. We will pass a parameter to go back and forth through the dictionary using the buttons.

func update_skin(new_selection):
	selected = wrapi(selected + new_selection, 0, skins.size())
	$Preview.texture = load(skins.values()[selected])
	$Name.text = skins.keys()[selected]

Let me break this down. The parameter we pass will be the direction we will move through the dictionary; if it receives -1 it will go back, if it receives 1 it will go forwards. The first line in the function will wrap the selection from 0 to the size of the skins dictionary, so if you are at 0 and try to go back it will bring you to the end, and if you’re at the end and go forward it will bring you to 0. The next line updates the preview to the texture of the selected skin. The last line updates the label to the name of the selected skin. Just remember that the keys are the names and their values are the paths.

Now we just need to run this function when the Back and Next buttons are pressed. We will do this with signals. Add this _ready function.

func _ready():
	$Back.connect("pressed", self, "update_skin", [-1])
	$Next.connect("pressed", self, "update_skin", [1])
	update_skin(0)

All this does is connect the pressed signal to this script’s update_skin function. The last parameter there is an array of parameters we will pass to the function. In this case, it’s the -1 and 1 I was talking about that will move through the list backwards or forwards. The Back button being pressed runs update_skin(-1) and chooses the previous skin, and the Next button being pressed runs update_skin(1) and chooses the next skin. We also run update_skin(0) so that the label and preview always starts off with the first skin in that list. The default texture and label text we set earlier was just to make sure everything looks correct.

You can run the game now and have a nice little skin selection. However, we still need two things: a button to start the game, and a way for the player in another scene to know which skin it should be using. We will come back to this script in a minute.

Settings.gd

Still in the script editor, hit File>New Script. Name it “Settings.gd” and save it to the root directory. This is going to be an AutoLoad singleton, which means it will be accessible by any script in any scene and its state will stay the same even if the root scene is changed. This will let us save the current skin to this script, and when we change to the main game scene, the player will know what skin to use. I am calling this Settings, but if you already have some sort of global script in your project you can throw this next part in there and use that.

All this script needs is one variable: skin_path. Set it to the path to the default skin png.

extends Node

var skin_path = "res://player/player1.png"

On the top of the editor, select Project>Project Settings. Go to the AutoLoad tab. Press the folder next to Path and select “Settings.gd”. Add it. You should end up with a screen like this:

Return to “SkinSelect.gd”. Add a line to update_skin that will set Settings.skin_path to the selected skin’s value.

func update_skin(new_selection):
	selected = wrapi(selected + new_selection, 0, skins.size())
	$Preview.texture = load(skins.values()[selected])
	$Name.text = skins.keys()[selected]
	Settings.skin_path = skins.values()[selected]

Now we need the player to actually pull from this file. Head into your player script. If you are following the template, this is “res://player/Player.gd”. Add a _ready function, and set $Sprite‘s Texture to load(Settings.skin_path).

func _ready():
	$Sprite.texture = load(Settings.skin_path)

The last thing we need to do is add a button to our MainMenu that will go into our game scene. When I say game scene, I mean whatever initial scene that contains your player that all of your actual gameplay takes place, like a Level 1 or a first town. For this tutorial, I am not going to make a game scene. Instead, I will just change the scene to the player’s scene, since that is enough to show off the skin changing.

Add a Button node to MainMenu. Name it “Play”, and change its Text to “Play”. Center it above the skin selection panel. I am just going to add the script to the button itself as “res://Play.gd”. All we’re going to do here is change the root scene to “res://player/Player.tscn”.

extends Button

func _ready():
	connect("pressed", self, "play")

func play():
	get_tree().change_scene("res://player/Player.tscn")

Now if you run the game, you can choose a skin, hit play, and it will appear in-game.

insert gif here

insert conclusion here

playerskin-tutorial-finish