The Ultimate Guide to Vector3:Cross() and Vector3:Dot()

Well that is the simplest explanation of cross and dot I have ever seen. Incredible.
Great job, best tutorial on the devforum by far.

1 Like

I appreciate it dude!!
This is enough chrar

1 Like

I really used to think these are complicated and for crazy good scripters who know what they are doing but turns out its simple as heck ty man have a great life!

1 Like

hi i was wondering if you knew how to find if the player is going down a slope, I need it to make the player go faster when they are sliding down a slope. this is what I have but what would go in the NORMAL part of the script

local incline = Vector3.new(1, 0, 0):Cross(Vector3.new(NORMAL)

				if incline.magnitude == 0 then
					incline = Vector3.new(1, 0, 0)
				end

				local angle = math.acos(Vector3.new(0, 1, 0):Dot(incline))
				if angle > math.pi / 1.5 then
					print("Angle")
					Slide.Velocity = angle * Slide.Velocity * 1.15
				else
					print("No Angle")
					Slide.Velocity = Slide.Velocity * 0.99
				end
1 Like

Ok so this is a perfect example of somewhere where you can utilize Dot, and I love the way you did it in your code. Personally, I would just use a raycast from your HumanoidRootPart directly downward and then just use the normal from that.
(
local ray = workspace:Raycast(HRP.Position, Vector3.new(0, -hipheight - 1, 0), params)
local normal = ray and ray.Normal
)

1 Like

thank you so much i will try that

Its not working but im pretty sure this is my fault, as Iā€™m very new to raycasting I think my variables are off.

local HumanoidRootPart = Character.PrimaryPart
local HipHeight = Humanoid.HipHeight
local Params = RaycastParams.new()
local ray = workspace:Raycast(HumanoidRootPart.Position, Vector3.new(0, -HipHeight - 1, 0), Params)
local normal = ray and ray.Normal

				local incline = Vector3.new(1, 0, 0):Cross(Vector3.new(normal))

				if incline.magnitude == 0 then
					incline = Vector3.new(1, 0, 0)
				end

				local angle = math.acos(Vector3.new(0, 1, 0):Dot(incline))
				if angle > math.pi / 1.5 then
					print("Angle")
					Slide.Velocity = angle * Slide.Velocity * 1.15
				else
					print("No Angle")
					Slide.Velocity = Slide.Velocity * 0.95
				end
1 Like

Ok yes do for the raycast, you will want to include an ignorelist. Do it like this:

local params = RaycastParams.new()
params.FilterDescendantsInstances = {player.Character}
params.FilterType = Enum.RaycastFilterType.Blacklist

ok thanks im trying it out now

ok so I dont think its working but my code is all messed up and I was wondering if you could help. basically Iā€™m running a while true do lap but I couldnā€™t get the loop to stop when the player stoped sliding so I added a spawn() function hoping I would be able to stop it but I couldnā€™t and it kept running only difference is now the rest of my code is running with the spawn function still going but I want it to stop when the player stops sliding any tips if I should use a different loop or something to stop it. hereā€™s the code:

local function OnHoldingDown(Action)
print(Variables.Sprinting)
if Module.HoldDownEnabled then
if not Variables.Overheated and Variables.ActuallyEquipped and Variables.Enabled and Variables.Sprinting == true then
Character.Humanoid.WalkSpeed = 0

  	local Slide = Instance.new("BodyVelocity")
  	
  	if Action == "Go"  and not HoldingDownCooldown then
  		ReplicatedStorage.Modules.ViewmodelHandler.Sliding.Value = true
  		HoldingDownCooldown = true
  		Variables.HoldDown = true
  		
  		--if Animations.HoldDownAnim then
  		--	Animations.HoldDownAnim:Play(nil, nil, Module.HoldDownAnimationSpeed)
  		--end
  		--if VMAnimations.VMHoldDownAnim then
  		--	VMAnimations.VMHoldDownAnim:Play(nil, nil, Module.VMHoldDownAnimationSpeed)
  		--end
  		Humanoid.HipHeight = 0.5
  		Slide.MaxForce = Vector3.new(1,0,1) * 45000
  		Slide.Velocity = Character.HumanoidRootPart.CFrame.lookVector * 50
  		Slide.Parent = Character.HumanoidRootPart
  		spawn(function()
  			while true do
  				wait(0.1)
  				if Variables.Sprinting == true then
  					local HumanoidRootPart = Character.PrimaryPart
  					local HipHeight = Humanoid.HipHeight
  					local Params = RaycastParams.new()
  					Params.FilterDescendantsInstances = {Character}
  					Params.FilterType = Enum.RaycastFilterType.Blacklist
  					local ray = workspace:Raycast(HumanoidRootPart.Position, Vector3.new(0, -HipHeight - 1, 0), Params)
  					local normal = ray and ray.Normal

  					local incline = Vector3.new(1, 0, 0):Cross(Vector3.new(normal))

  					if incline.magnitude == 0 then
  						incline = Vector3.new(1, 0, 0)
  					end

  					local angle = math.acos(Vector3.new(0, 1, 0):Dot(incline))
  					if angle > math.pi / 1.5 then
  						print("Angle")
  						Slide.Velocity = angle * Slide.Velocity * 1.5
  					else
  						print("No Angle")
  						Slide.Velocity = Slide.Velocity * 0.8
  					end
  				else
  					repeat wait(0.1) until Variables.Sprinting == true
  				end
  			end
  		end)
  	else
  		Character.Humanoid.WalkSpeed = 16
  		Variables.HoldDown = false
  		
  		--if Animations.IdleAnim then
  		--	Animations.IdleAnim:Play(nil, nil, Module.IdleAnimationSpeed)
  		--end
  		--if VMAnimations.VMIdleAnim then
  		--	VMAnimations.VMIdleAnim:Play(nil, nil, Module.VMIdleAnimationSpeed)
  		--end
  		--if Animations.HoldDownAnim and Animations.HoldDownAnim.IsPlaying then
  		--	Animations.HoldDownAnim:Stop()
  		--end
  		--if VMAnimations.VMHoldDownAnim and VMAnimations.VMHoldDownAnim.IsPlaying then
  		--	VMAnimations.VMHoldDownAnim:Stop()
  		--end
  		Humanoid.HipHeight = 2
  		Slide:Destroy()
  		Character.PrimaryPart.Velocity = Vector3.new(0,0,0)
  		ReplicatedStorage.Modules.ViewmodelHandler.Sliding.Value = false
  		wait(0.5)
  		HoldingDownCooldown = false
  	end
  end

end

1 Like

I actually have a trick I use for something like this. I do something like this:

function executeSlide()
    local localFunctionId = os.clock()
    globalFunctionId = localFunctionId

    while wait(0.1) do
       if localFunctionId ~= globalFunctionId then
            break
        end
        dostuff()
    end
end


-- and in a different part of the script when the player stops sliding, do this:
globalFunctionId = os.clock()

thanks but what is GlobalFunctionId it is underlining it like it doesnā€™t recognise it

TYSM I WORKED but that problem I had at the start still remains its not detecting the Slope or Angle hereā€™s the script one more time:

Script Here

local function OnHoldingDown(Action)
print(Variables.Sprinting)
if Module.HoldDownEnabled then
if not Variables.Overheated and Variables.ActuallyEquipped and Variables.Enabled and Variables.Sprinting == true then

		local Slide = Instance.new("BodyVelocity")
		
		if Action == "Go"  and not HoldingDownCooldown then
			Character.Humanoid.WalkSpeed = 0
			ReplicatedStorage.Modules.ViewmodelHandler.Sliding.Value = true
			HoldingDownCooldown = true
			Variables.HoldDown = true
			
			--if Animations.HoldDownAnim then
			--	Animations.HoldDownAnim:Play(nil, nil, Module.HoldDownAnimationSpeed)
			--end
			--if VMAnimations.VMHoldDownAnim then
			--	VMAnimations.VMHoldDownAnim:Play(nil, nil, Module.VMHoldDownAnimationSpeed)
			--end
			Humanoid.HipHeight = 0.5
			Slide.MaxForce = Vector3.new(1,0,1) * 45000
			Slide.Velocity = Character.HumanoidRootPart.CFrame.lookVector * 50
			Slide.Parent = Character.HumanoidRootPart
			GlobalFunctionId = localFunctionId
			spawn(function()
				while wait(0.1) do
					if localFunctionId ~= GlobalFunctionId then
						Slide.Velocity = Slide.Velocity * 0
						if Slide then
							Slide:Destroy()
						end
						break
					end
					
					if Variables.Sprinting == true then
						local HumanoidRootPart = Character.PrimaryPart
						local HipHeight = Humanoid.HipHeight
						local Params = RaycastParams.new()
						Params.FilterDescendantsInstances = {Character}
						Params.FilterType = Enum.RaycastFilterType.Blacklist
						local ray = workspace:Raycast(HumanoidRootPart.Position, Vector3.new(0, -HipHeight - 1, 0), Params)
						local normal = ray and ray.Normal

						local incline = Vector3.new(1, 0, 0):Cross(Vector3.new(normal))

						if incline.magnitude == 0 then
							incline = Vector3.new(1, 0, 0)
						end

						local angle = math.acos(Vector3.new(0, 1, 0):Dot(incline))
						if angle > math.pi / 1.5 then
							print("Angle")
							Slide.Velocity = angle * Slide.Velocity * 1.1
						else
							print("No Angle")
							Slide.Velocity = Slide.Velocity * 0.9
						end
					else
						repeat wait(0.1) until Variables.Sprinting == true
					end
				end
			end)
		else
			GlobalFunctionId = os.clock()
			Character.Humanoid.WalkSpeed = 16
			Variables.HoldDown = false
			
			--if Animations.IdleAnim then
			--	Animations.IdleAnim:Play(nil, nil, Module.IdleAnimationSpeed)
			--end
			--if VMAnimations.VMIdleAnim then
			--	VMAnimations.VMIdleAnim:Play(nil, nil, Module.VMIdleAnimationSpeed)
			--end
			--if Animations.HoldDownAnim and Animations.HoldDownAnim.IsPlaying then
			--	Animations.HoldDownAnim:Stop()
			--end
			--if VMAnimations.VMHoldDownAnim and VMAnimations.VMHoldDownAnim.IsPlaying then
			--	VMAnimations.VMHoldDownAnim:Stop()
			--end
			Humanoid.HipHeight = 2
			Slide:Destroy()
			Character.PrimaryPart.Velocity = Vector3.new(0,0,0)
			ReplicatedStorage.Modules.ViewmodelHandler.Sliding.Value = false
			wait(0.5)
			HoldingDownCooldown = false
		end
	end
end

end

Bump since this post is very helpful, thanks for making it.

I am going to use dot for my game. The soldiers that you control move and turn via AlignForce/Orientation respectively, meaning its not instant turning so the unit can only shoot once it has lined up the shot. So i will use the dot product of the offset vector (offset vector from object a to b is always B.Position - A.Position) and the units LookVector to see if it is able to shoot

1 Like

Ok so there are just a couple things about this, number one:

if incline.magnitude == 0 then

This will literally never occur, instead it get down to like 0.005. Replace that with this:

if incline.magnitude < 0.01 then

Next, you may have meant to write this instead:

local incline = Vector3.new(0, 1, 0):Cross(Vector3.new(normal))

Vector3.new(1, 0, 0) is a vector pointing directly to the right, so I donā€™t think thats what you meant to put, however Vector3.new(0, 1, 0) faces directly up.

Hope all this helps man!

It seems to print the same thing still (ā€œNo Angleā€) Although I feel Iā€™m getting really close to getting it right
so here is my new script:

local function OnHoldingDown(Action)
	if Module.HoldDownEnabled then
		if not Variables.Overheated and Variables.ActuallyEquipped and Variables.Enabled then
			
			local Slide = Instance.new("BodyVelocity")
			
			if Action == "Go"  and not HoldingDownCooldown then
				Character.Humanoid.WalkSpeed = 0
				ReplicatedStorage.Modules.ViewmodelHandler.Sliding.Value = true
				HoldingDownCooldown = true
				Variables.HoldDown = true
				
				if Animations.HoldDownAnim then
					Animations.HoldDownAnim:Play(nil, nil, Module.HoldDownAnimationSpeed)
				end
				if VMAnimations.VMHoldDownAnim then
					VMAnimations.VMHoldDownAnim:Play(nil, nil, Module.VMHoldDownAnimationSpeed)
				end
				Humanoid.HipHeight = 0.5
				Slide.MaxForce = Vector3.new(1,0,1) * 45000
				Slide.Velocity = Character.HumanoidRootPart.CFrame.lookVector * 50
				Slide.Parent = Character.HumanoidRootPart
				GlobalFunctionId = localFunctionId
				spawn(function()
					while wait(0.1) do
						if localFunctionId ~= GlobalFunctionId then
							Slide.Velocity = Slide.Velocity * 0
							if Slide then
								Slide:Destroy()
							end
							break
						end
						
						--if Variables.Sprinting == true then
							local HumanoidRootPart = Character.PrimaryPart
							local HipHeight = Humanoid.HipHeight
							local Params = RaycastParams.new()
							Params.FilterDescendantsInstances = {Character}
							Params.FilterType = Enum.RaycastFilterType.Blacklist
							local ray = workspace:Raycast(HumanoidRootPart.Position, Vector3.new(0, -HipHeight - 1, 0), Params)
							local normal = ray and ray.Normal

							local incline = Vector3.new(0, 1, 0):Cross(Vector3.new(normal))

							if incline.magnitude < 0.01 then
								incline = Vector3.new(1, 0, 0)
							end

							local angle = math.acos(Vector3.new(0, 1, 0):Dot(incline))
							if angle > math.pi / 1.5 then
								print("Angle")
								Slide.Velocity = angle * Slide.Velocity * 1.1
							else
								print("No Angle")
								Slide.Velocity = Slide.Velocity * 0.9
							end
						--else
						--	repeat wait(0.1) until Variables.Sprinting == true
						--end
					end
				end)
			else
				GlobalFunctionId = os.clock()
				Character.Humanoid.WalkSpeed = 16
				Variables.HoldDown = false
				
				if Animations.IdleAnim then
					Animations.IdleAnim:Play(nil, nil, Module.IdleAnimationSpeed)
				end
				if VMAnimations.VMIdleAnim then
					VMAnimations.VMIdleAnim:Play(nil, nil, Module.VMIdleAnimationSpeed)
				end
				if Animations.HoldDownAnim and Animations.HoldDownAnim.IsPlaying then
					Animations.HoldDownAnim:Stop()
				end
				if VMAnimations.VMHoldDownAnim and VMAnimations.VMHoldDownAnim.IsPlaying then
					VMAnimations.VMHoldDownAnim:Stop()
				end
				Humanoid.HipHeight = 2
				Slide:Destroy()
				Character.PrimaryPart.Velocity = Vector3.new(0,0,0)
				ReplicatedStorage.Modules.ViewmodelHandler.Sliding.Value = false
				wait(0.5)
				HoldingDownCooldown = false
			end
		end
	end
end

Sorry if Iā€™m late, but how exactly would you do this?

So basically, since you can use Dot to calculate how much your camera is looking at something:

First, find the unit vector between the monsterā€™s position and your characterā€™s position,

local unit = (monsterPosition - localCharacterPosition).Unit

This ā€œunitā€ variable above is a Vector3 unit direction that the monster is from you.

You can calculate how much your camera is going in that direction by using:

local dotProduct = unit:Dot(camera.CFrame.LookVector)

The closer to -1 this ā€œdotProductā€ variable is, the farther away from the monster you are looking!

4 Likes

Thank you, this really helped!

1 Like

How can I implement this into my flying system to turn like a airplane?