How to animate 2 characters and play it in-game like a takedown animation

Hey guys this is my first tutorial expect me to make some mistakes if possible try correcting me i will try my best to describe everything in this tutorial.
anyway i am gonna be showing you how you can animate 2 characters and play it in-game. Like a takedown animation
here is an example of a roblox takedown animation:

game is “Right 2 Fight” by Rolve

but how are you gonna do it? well its simple but hard and takes time
so i will be explaining them step by step
also do note that there may be other methods to do it but for me personally i find the method i am using suitable
also sorry if some of the video isnt working.
The method is using 2 different animation and play them at the same time so it looks like a takedown animation

and also you must atleast know scripting and know how to use moon animator as it is the only animator (i think) that support multiple characters and we will be using it
i think you should also know how to animate
if you dont know one of these you may be confuse in this tutorial

Step 1

open your studio and add 2 Dummy (can be R6 or R15 whatever you prefer i will be using R15)

you can name them like, the first one will be the main and the second one will be the enemy (it is important to name them and it also prevent confusion)

then make both dummy face each other and then put them atleast 5 stud between each other or any stud you want, i recommend 5 stud, you can do it along the Z or X axis and this stud part is very important as you will be position the dummy 5 stud from you later on when we will try to play the animation in game.
here is an image of how it look like:

i hope you know how to do that. i simply position one in a random position lets say 60,0,0 then i position the other one like 65,0,0 and then rotate them so they can face each other

Step 2

open moon animator create an animation folder Then you can add both rigs/characters:
you add the rig by pressing the “+” sign
PlusSign (2)

here is a video how you can add the rigs:

Now you can animate them
i will just make a simple animation and by simple i mean this:

Now you can export it
eeeee

It will be exported as 2 Different animation

animations

if you wouldnt have named them, then you would be confused on which is which
now when you have both animation ID and you also know which animation is for who, like the main animation is for the player and the enemy animation will be for the dummy, you can now start scripting

Step 3

once we add the animationId to the animations lets save the animations in a folder and also parent the folder to a remote function or event i will go with remote function as i want to return stuff to the client

Folder

then go to server script service and add a script and then add these lines:
Do note you can change the script mine look bad to be honest.

local animHandler = ----your remote function or event
local animationFolder = ----your animation folder

animHandler.OnServerInvoke = function(plr,enemy) 
	
	local mainChar = plr.Character
	mainChar.Humanoid.WalkSpeed = 0 ---make the player not able to move, its a bad method tbh
        
        ---remember where i said the stud part is important well here it is, it position the character by making it face the dummy and make the dummy face you then put its position relatively 5 stud away from you so that it can play the animation properly and perfectly
	mainChar.HumanoidRootPart.CFrame = CFrame.new(mainChar.HumanoidRootPart.Position,Vector3.new(enemy.HumanoidRootPart.Position.X,mainChar.HumanoidRootPart.Position.Y,enemy.HumanoidRootPart.Position.Z)) ---make plr face the dummy
	enemy.HumanoidRootPart.CFrame = mainChar.HumanoidRootPart.CFrame * CFrame.new(0,0,-5) -- position the dummy to teleport to 5 stud from you
	enemy.HumanoidRootPart.CFrame = CFrame.new(enemy.HumanoidRootPart.Position,Vector3.new(mainChar.HumanoidRootPart.Position.X,enemy.HumanoidRootPart.Position.Y,mainChar.HumanoidRootPart.Position.Z)) ---make dummy face the plr


	local Animation1 = mainChar.Humanoid:LoadAnimation(animationFolder.main)  ---the player animation
	local Animation2 = enemy.Humanoid:LoadAnimation(animationFolder.enemy) ----the enemy animation
	task.wait(.5)  ----this is optional i am making the script to wait just so both animation can load
	Animation1:Play()---play both of the animation
	Animation2:Play()
	Animation1.Stopped:Wait() ---wait for the player animation to finish then make the player move again(i recommend you to wait for the player animation to finish and not the dummy)

	print("finish")
	mainChar.Humanoid.WalkSpeed = 16
	return true ---returning a true to the client
end

In the script above in the positioning part there is many ways to do it. i just used the easy one

and now for the local script add it in StarterPlayerScripts.
note that this script will invoke the remote event that plays the animation when you press the F key near a dummy.

you can change this script/or use another script if you want

local input = game:GetService("UserInputService")
local remoteEvent = --- your remote event
local char = game.Players.LocalPlayer
local debounce = false
input.InputBegan:Connect(function(key)
	if debounce then return end
	if key.KeyCode == Enum.KeyCode.F then ---if player presses F
		for i,v in pairs(workspace:GetChildren()) do 
                        if not v:FindFirstChild("Humanoid") then return end ---if its not a dummy end the script
			if (char.Character.HumanoidRootPart.Position - v.HumanoidRootPart.Position).Magnitude <= 10 then ----if the player is closed to a dummy
				debounce = true
				remoteEvent:InvokeServer(v) ---using a remote function will yield the script till the server return a value thats why i wanted to use a remote function so the server wait for the animation to finish then it returns a value
				wait(2) ---wait a couple of second to prevent spam
				debounce = false
			else 
				print("you are far from enemy bruh!") ---you are far from the enemy bruh
			end
		end
	end
end)

and done!
now i can bully some dummy just by pressing F near them


yes i made 2 animation and also ik the animations are trash cuz i am scripter not animator

you can also add multiple stuff to your animation like camera, sound effect, damage ,or anything else you want. mine is just a tutorial
I hope it helps. if there is part that is confusing or anything else feel free to tell me ill try my best to answer it
also if you want to try the game here → TakeDown animation Testing - Roblox

164 Likes

Absolutely love this.

I myself haven’t gotten around to diving into Moon animator; I’ve just stuck with the default one. However, a game I’m working on will require animations of two rigs and this tutorial could not of popped up at a better time. For your first tutorial this is amazing and I hope to see more animation tutorials from you in future!

6 Likes

You can use additional Motor6D Connecting first character to second

4 Likes

Really amazing tutorial! But…

You should probably use

mainChar.Humanoid:WaitForChild("Animator"):LoadAnimation(animationFolder.yourAnimName)

Since, Humanoid:LoadAnimation()'s deprecated, don’t think it’ll be a good idea to put deprecated functions in a tutorial. Still an amazing tutorial!

4 Likes

and now you just need to add damage to it and it would be perfect

4 Likes

Animator are made so that it can replicate animation from client to server (from what it says on the api)
which mean that if playing animation on the server there is no need to use animator as it only handle replication between client and server.
playing the animation via humanoid:loadAnimation on the server would definitely replicate it to all client
so thats why i put humanoid:loadAnimation there.

5 Likes

“Never stop learning”

Something I always heard, and was always true. Really good to know this! Thanks!

4 Likes

i want to ask something
all most all the scripters says to play animation(and vfx in general) on local so why did you choose to play it in the server?

1 Like

I thought about if for couple of mins if someone can confirm will be appreciated
its depend on the situation the animations are used if they are used only on players i think you should do it locally.

But that is not always the case lets take for example a game with npcs since npcs dont have animator their animation is serversided (most of the time) and u need to do it serversided so it will work on both sides (players and npcs)

2 Likes

how like connect two humanoidrootparts ?

1 Like

Because you cannot animate health, you would have to script it.

The moment the animation plays, add this to the script:

task.wait( --[[Time until character is hit]] )
mainChar.Humanoid.Health == mainChar.Humanoid.Health - How much damage

you can repeat it again if that character gets hurt or another gets hurt.

1 Like

How would you go about exporting the animation of the camera and playing it too?

I want to use Moon Animator instead of hand scripting it because it takes less time and hand scripting might not always look good

1 Like

I know how that works you don’t need to explain that to me. I never even asked for it.

1 Like

does it work on a real player???

1 Like

When I tried implementing a takedown animation for two players I get a delay on one of them. Does anyone know how to prevent this?

1 Like

Play the animations at the same time, if you aren’t already.

1 Like

After loading the animations I play it at the same time which matches on the server, but not the client initiating it.

1 Like

That’s strange, can you show a video clip so I can see what’s desynced? I might be able to see what’s going on from there.

Server Script:

    local exerAnimator = exerHum:FindFirstChildOfClass("Animator")
	local larryAnimator = larryHum:FindFirstChildOfClass("Animator")
	local exerTrack = exerAnimator:LoadAnimation(infoMod.swingComboFinExec)
	local larryTrack = larryAnimator:LoadAnimation(infoMod.swingComboFinLarry)
	repeat task.wait() until ((exerTrack.Length > 0) and (larryTrack.Length > 0))
	larryTrack:Play()
	exerTrack:Play()

Is it normal to have a slight delay between the client(right) and server(left). That’s why you also see a hitch for the knockback because it relies on a keyframe to do the knockback which is what i’ve been trying to fix

For some reason it seems like the client happens a little too fast, but that’s weird because it’s played on the server.

Try loading it into the humanoid instead of the animator as a quick test and see if there’s still delay because I have no clue what’s going on there…

1 Like