Best way to script a horse?

I’ve been trying to script a horse that you can call, mount, and ride around, but I’ve been experiencing multiple problems while doing this.

aaaaa
(This horse model is just a dummy to give me some visual help for when I add the scripts to the proper one. I do not usually build like this xD)

Ideally I would like the horse to be a humanoid you can ride, so what I did was attach a function to a key to spawn in a horse, another one for mounting/dismounting the horse and one for despawning it after too much time has passed. This is the server side script code that does all of the above:

local players = game:GetService('Players')

local replicatedStorage = game:GetService('ReplicatedStorage')
local callFunction = Instance.new('RemoteFunction',replicatedStorage)
callFunction.Name = 'CallFunction'
local mountEvent = Instance.new('RemoteEvent',replicatedStorage)
mountEvent.Name = 'MountEvent'
local despawnEvent = Instance.new('RemoteEvent',replicatedStorage)
despawnEvent.Name = 'DespawnEvent'

local function call(player, horse)
	if horse == nil then
	local horse = replicatedStorage:WaitForChild('Horse'):Clone()
	horse.Parent = workspace
	horse:SetPrimaryPartCFrame(player.Character:WaitForChild('HumanoidRootPart').CFrame*CFrame.new(20,0,0))
	horse:WaitForChild('Humanoid'):MoveTo(player.Character:WaitForChild('HumanoidRootPart').Position + Vector3.new(6,0,0))

	players.PlayerRemoving:Connect(function(plr)
		if plr.Name == player.Name then
			horse:Destroy()
		end
	end)
	
	player.Character:WaitForChild('Humanoid').Died:Connect(function()
		horse:Destroy()
	end)
		
	return horse
	else
	horse:SetPrimaryPartCFrame(player.Character:WaitForChild('HumanoidRootPart').CFrame*CFrame.new(20,0,0))
	horse:WaitForChild('Humanoid'):MoveTo(player.Character:WaitForChild('HumanoidRootPart').Position + Vector3.new(6,0,0))
	return horse
	end
end

callFunction.OnServerInvoke = call

despawnEvent.OnServerEvent:Connect(function(player, horse)
	horse:Destroy()
end)

mountEvent.OnServerEvent:Connect(function(player, horse, isOn)
	if horse ~= nil then
		local playerHRP = player.Character:WaitForChild('HumanoidRootPart')
		local horseHRP = horse.HumanoidRootPart
		if isOn == false then
			playerHRP.Anchored = true
			horseHRP.Anchored = true
			playerHRP.CFrame = horseHRP.CFrame * CFrame.new(0,2.5,0)
			local weld = Instance.new('WeldConstraint',playerHRP)
			weld.Name = 'HorseWeld'
			weld.Part0 = horseHRP
			weld.Part1 = playerHRP
			playerHRP.Anchored = false
			horseHRP.Anchored = false
		else
			local weld = playerHRP:WaitForChild('HorseWeld'):Destroy()
			playerHRP.CFrame = horseHRP.CFrame * CFrame.new(7,0,0)
		end
	end
end)

However, all the horse movement and features I want to implement such as walking on uneven terrain, jumping, etc. I can’t really figure out, and I’m not sure whether all that should be within the player’s local script or not. I’m currently disabling the player controller script when mounted and assigning new functions to WASD, Shift (to gallop) and Space (to jump).

For the W and S keys I’m using the Humanoid:Move(Vector3.new(0,0,-1, true) command to have the horse move forward and backwards when the respective keys are pressed, and this works fine. However, I’d like to make it so if you only hold down either the A or D keys, the horse rotates indefinitely, without going forward until you let go (constant rotation), but after using both BodyVelocity and BodyGyro, I’ve experienced no success, unless I rotate my camera and press W again. Humanoid.Jump does not work either, while shift to gallop does.

Lastly, I want to make the horse be able to adjust itself on uneven terrain, so it doesn’t just walk on flat ground. I have no idea how to do this and would really appreciate some suggestions.

Thank you very much for reading, and I hope you can help me in this endeavour! :grinning:

9 Likes

For the rotating while standing still you probably can use BodyAngularVelocity.
For the adjusting to terrain part you probably want the same as this guy: Getting the SurfaceNormal for a horse. Doesn’t have an answer, but you might figure it out.

7 Likes

I did actully end up figuring it out, the best way to do this is to use a BodyGyro and a BodyPosition. Cast a ray in the direction of the horse until you hit any part of terrain, then adjust the height of the y-axis to be that off the offset between the horse and the ground. It is super smooth.

Dont mind the missing animations!

https://dl.dropboxusercontent.com/s/bd5hopqu4c06769/16YZP2sSS9.mp4

7 Likes

I think using BodyAngularVelocity will still help make your horse stand on the ground correctly, similar to this: https://swashbucklingsailor.files.wordpress.com/2015/09/skyrim-physics-horse.jpg?w=700

Did you figure out a way to not make it crash into the terrain when the height difference is too high?

3 Likes

I made it like that specifically, horses cant just like climb extremely high slopes, or climb tall strucuters easily.

4 Likes

I messed a bit with this a while ago, but never finished it. Basically what i did was creating a bodyposition inside the horse and then set the position to the horse’s position + horse.CFrame.LookVector. As i said, i didnt finish it, this is just something so you can start scripting.

1 Like

Thanks for the suggestion! I finished the horse a while ago and used BodyVelocity to make it, but I feel that BodyPosition is definitely the better option, since it smoothes out movement. If I ever decide to remake it, I’ll take into account what you’ve said! Cheers!

3 Likes