Torso's LookVector seems to be aligned to the world's Z axis

The primary thing I want to achieve here is, among other things, a quadratic path that I can interpolate the player along—like a weird jump.

Explanation

The Bézier function seems to work fine, however something is wrong with my point positions.
Looking along the world Z axis gives the result I want.



…but the further you deviate from the Z axis, the closer point two (and subsequently three) approach the character’s origin (but not on the Y axis).

Default perspective for clarity; along the Z axis:


and a bit-between the X & Z axis:

My assumption is it’s something wrong with the math for p1 (point one).
I’ve looked all over for help or a solution but it’s an odd one to put a name to.
I apologize if the solution is stupidly simple.

Code

This is the LocalScript for the tool:

--!strict
local QuadraticBezier3 = require('@self/QuadraticBezier3')

local Tool = script.Parent
local Action = Tool.InputContext.Action

local Player = game:GetService('Players').LocalPlayer 
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character.Humanoid

local function Down()
	if Humanoid.FloorMaterial ~= Enum.Material.Air then
		local tcf: CFrame = Character.Torso.CFrame
		local p0 = tcf.Position
		local p1 = (tcf + (tcf.LookVector * Vector3.new(0, 2, 5))).Position
		local p2 = p1 + Vector3.new(0, 8, 0)
		
		local bezier = QuadraticBezier3.new(p0, p1, p2)
		bezier:DrawDebugPath(5)
		bezier:Destroy()
		
	end
end

local function SetInputEnabled(value: boolean)
	return function()
		Tool.InputContext.Enabled = value
	end
end

Action.Pressed:Connect(Down)

Tool.Equipped:Connect(SetInputEnabled(true))
Tool.Unequipped:Connect(SetInputEnabled(false))

And if it’s important, the code for the Bézier module:

--!strict
local Debris = game:GetService('Debris')
local function lerp(a: Vector3, b: Vector3, t: number): Vector3
	return a + (b - a) * t
end

local QuadraticBezier3 = {}
QuadraticBezier3.__index = QuadraticBezier3

export type QuadraticBezier3 = typeof(setmetatable({}::QuadraticBezier3Data, QuadraticBezier3))
--export type QuadraticBezier3 = setmetatable<QuadraticBezier3Data, typeof(QuadraticBezier3)>

type QuadraticBezier3Data = {
	p0: Vector3, p1: Vector3, p2: Vector3
}

local function createDebugPart()
	local part = Instance.new('Part')
	part.Archivable = false
	part.Anchored = true
	part.CanCollide = false
	part.CanQuery = false
	part.CanTouch = false
	part.AudioCanCollide = false
	part.Size = Vector3.new(0.125, 0.125, 0.125)
	part.Transparency = 0.5
	part.Material = Enum.Material.Neon
	part.TopSurface = Enum.SurfaceType.Smooth
	part.BottomSurface = Enum.SurfaceType.Smooth
	return part
end

--[=[
	Create a path of parts to demonstrate the curve.
	Useful for debugging.
	
	@param lifetime: number
	@param color: Color3?
	@param parent: Instance?
	@return void
--]=]
function QuadraticBezier3.DrawDebugPath(self: QuadraticBezier3, lifetime: number, color0: Color3?, color1: Color3?, parent: Instance?)
	local folder = Instance.new('Folder')
	folder.Name = 'DebugCurve'
	folder.Parent = parent or workspace.Terrain
	
	local half = Vector3.new(0.5, 0.5, 0.5)
	local color0 = color0 or Color3.new(0, 1, 1)
	local pp0, pp1, pp2 = createDebugPart(), createDebugPart(), createDebugPart()
	pp0.Size, pp1.Size, pp2.Size = half, half, half
	pp0.Position, pp1.Position, pp2.Position = self.p0, self.p1, self.p2
	pp0.Color, pp1.Color, pp2.Color = color0, color0, color0
	pp0.Parent, pp1.Parent, pp2.Parent = folder, folder, folder
	
	local nParts = 0
	for  i = 0, 1, 0.01 do
		nParts += 1
		local part = createDebugPart()
		part.Name = tostring(nParts)
		part.Color = color1 or Color3.new(1, 0, 0)
		part.CFrame	= CFrame.new(self:GetValueAtTime(i))
		part.Parent = folder
	end
	
	Debris:AddItem(folder, lifetime)
end

--[=[
	Get a Vector3 position from the curve at the given time/alpha.
	
	@param t: number
	@return Vector3
--]=]
function QuadraticBezier3.GetValueAtTime(self: QuadraticBezier3, t: number): Vector3
	local l1, l2 = lerp(self.p0, self.p1, t), lerp(self.p1,self.p2, t)
	return lerp(l1, l2, t)
end

--[=[
	Destroy the QuadraticBezier3 class.

	@return void
--]=]
function QuadraticBezier3.Destroy(self: QuadraticBezier3)
	self = nil
end

--[=[
	Create a new QuadraticBezier3 curve class.
	
	@param p0: Vector3
	@param p1: Vector3
	@param p2: Vector3
	@return Bezier	
--]=]
function QuadraticBezier3.new(p0: Vector3, p1: Vector3, p2: Vector3)
	local self = {}
	
	self.p0, self.p1, self.p2 = p0, p1, p2

	return setmetatable(self, QuadraticBezier3)
end

return QuadraticBezier3

Additionally, example.rbxl (84.7 KB)

Again I apologize if the solution is dead simple. Nothing is coming to mind unfortunately.
Thanks.

I’ll assume the (0, 2, 5) is a translation vector and say that this isn’t combining them like you’d expect, partly because these vectors don’t have the same interpretation. I think CFrame is more common for this kind of work:

local p1 = (tcf * CFrame.new(0, 2, 5)).Position
1 Like

yeah this is multiplying on top of the axis-aligned lookvector instead of the object-aligned cframe

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.