How To Use A Skinned Mesh For A Custom Character (And Animate It)

Hello there, my friends of DevForum.

Today I would like to share something that I don’t think is even close to easy enough to find tutorials on.
By the end of this tutorial, you should know how to:
1: Import skinned meshes for use as custom characters
2: Animate them
3: Use them in-game

Without wasting any more time, let’s start.

STEP 1: IMPORTING THE CHARACTER
To use Avatar Importer, go into the plugins tab and select “Avatar Importer”
tutorial 6
From there, select “Custom” and select the 3d model of your character. NOTE: For this method, your character MUST be a .fbx file.

Now that you have the character model in the workspace, follow these steps:

  1. Rename the “FBXImportGeneric” group to “StarterCharacter”.
  2. You can delete the “InitialPoses” folder.
  3. Replace the AnimationController with a Humanoid.
  4. Add a part called “HumanoidRootPart”. Turn CanCollide off and move it around the character. Also turn the transparency to 1.

Now your explorer should look like this: (I changed the name of the cube later as well)
tutorial 9

STEP 2: CREATING MOTOR6D’S
First, you’ll need to install a plugin that can do this. I personally like to use this plugin, but there are others you can use, like RigEdit.
First, select the HumanoidRootPart.
Then, select your character.
Create a Motor6d between them. To do this with Constraint Editor, click “new Motor6d”
This should create a Motor6d parented to the HumanoidRootPart.
tutorial 10

STEP 3: ANIMATING THE CHARACTER
Now that we have the Motor6d set up, we can animate our character.
In the plugins tab, select Animation Editor.
tutorial 11
The animation editor will open, if you’ve done everything correctly, click on the character, and then create animation.
It should look something like this if you have your bones done correctly:
tutorial 12
This isn’t a tutorial on how to animate, so I’ll fast-forward to after I’ve made the animation.
Publish the animation, and keep the ID somewhere for later.

STEP 4: APPLYING THE ANIMATIONS
In this tutorial, we’ll use a custom animate script because I couldn’t get Roblox’s default one to work.
Create a LocalScript called “Animate” inside of StarterCharacterScripts, and put this script inside of it:

repeat task.wait() until script:FindFirstChildWhichIsA("Animation")

local idleAnim = script.Parent.Humanoid:LoadAnimation(script.Idle)
idleAnim.Looped = true
idleAnim.Priority = Enum.AnimationPriority.Idle
local runAnim = script.Parent.Humanoid:LoadAnimation(script.Run)
runAnim.Looped = true
runAnim.Priority = Enum.AnimationPriority.Movement
local jumpAnim = script.Parent.Humanoid:LoadAnimation(script.Jump)
jumpAnim.Looped = true
jumpAnim.Priority = Enum.AnimationPriority.Movement
local climbAnim = script.Parent.Humanoid:LoadAnimation(script.Climb)
climbAnim.Looped = true
climbAnim.Priority = Enum.AnimationPriority.Movement
local fallAnim = script.Parent.Humanoid:LoadAnimation(script.Fall)
fallAnim.Looped = true
fallAnim.Priority = Enum.AnimationPriority.Movement
local swimAnim = script.Parent.Humanoid:LoadAnimation(script.Swim)
swimAnim.Looped = true
swimAnim.Priority = Enum.AnimationPriority.Movement
local sitAnim = script.Parent.Humanoid:LoadAnimation(script.Sit)
sitAnim.Looped = true
sitAnim.Priority = Enum.AnimationPriority.Movement

game["Run Service"].Heartbeat:Connect(function()
	if script.Parent.HumanoidRootPart.Velocity.Magnitude > 0.1 then
		if script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Dead then
			for _, i in script.Parent.Humanoid:GetPlayingAnimationTracks() do
				i:Stop()
			end
		elseif script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Seated then
			if not sitAnim.IsPlaying then
				sitAnim:Play()
			end
		elseif script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Jumping then
			if not jumpAnim.IsPlaying then
				jumpAnim:Play()
			end
		elseif script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Climbing then
			if not climbAnim.IsPlaying then
				climbAnim:Play()
			end
		elseif script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Freefall then
			if not fallAnim.IsPlaying then
				fallAnim:Play()
			end
		elseif script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Swimming then
			if not swimAnim.IsPlaying then
				swimAnim:Play()
			end
		elseif script.Parent.Humanoid:GetState() == Enum.HumanoidStateType.Running then
			if not runAnim.IsPlaying then
				runAnim:Play()
			end
		end
	else
		for _, i in script.Parent.Humanoid:GetPlayingAnimationTracks() do
			if i.Name ~= "Idle" then
				i:Stop()
			end
		end
		if not idleAnim.IsPlaying then
			idleAnim:Play()
		end
	end
end)

If you don’t have any of those animations, comment out anything that you don’t use.
It may also be better to switch the position of the elseif’s.
Under the LocalScript, add 7 animations and name them like this:
tutorial 18
Put the ID of each animation you have into the animations accordingly.
And lastly, place your grouped character into StarterPlayer and everything should work!

Thank you for taking the time to read this tutorial. If you have any questions or critiques, feel free to leave a comment!
If something doesn’t work for you, also leave a comment. You can DM me about it too!

27 Likes

https://i.gyazo.com/70b249ec047984b9994bb1976cc8c7f5.mp4

I’m not using it for a StarterCharacter, but you did manage to fix my Playing Animation problem.
However, do you have any clue why it just… leaves? I didn’t script it to move or anything.

Nevermind, I fixed it. I had to adjust the HipHeight of the Humanoid.

i have a problem with sizing down my chatacter, it just squashes it and ‘rips’ the mesh when i resize it because it takes up the whole map, how do i fix this?

Hi there, what do you mean by squashes and rips? Were you holding shift while resizing it?

Assuming you’re using blender, when you export as a FBX make sure you turn the scale down to 0.01 and scale your rig in blender according to the roblox size you need.