What is best way to define a complex path that sprite is to follow?

Ideally I would create a closed path using curves in a vector program, and then somehow use this path to script a sprite to move. Is this the way to do this, any libraries, etc that can read in a vector file?

May need to give us more info, but a starting point might be the DefTimeLine library (Def Timeline) – it lets you define a path with a simple sequence of t.add(...) calls:

local t = timeline.new()
t.add(".", "position.x", nil, 150, nil, 2, nil,'label_1')
t.add(".", "position.y", nil, 150, nil, 2, nil, 'label_1')
t.add(".", "position.y", nil, 0, nil, nil, 2)	
t.play()

I also hacked together a bezier curve animation (GitHub - jbp4444/bzAnim: A Lua/Defold-based animation library for bezier curve animations) which can accept sequences of animations – but it is not as polished as DefTimeline.

1 Like

I ended up making my own spline library

-- Put functions in this file to use them in several other scripts.
-- To get access to the functions, you need to put:
-- require "my_directory.my_file"
-- in any script using the functions.

local M = {}



function M.get_point(t, control_points)
	local num_control_points = #control_points
	local index = math.floor(t * (num_control_points - 1)) + 1
	local local_t = t * (num_control_points - 1) - index + 1

	local p0 = control_points[(index - 2) % num_control_points + 1]
	local p1 = control_points[(index - 1) % num_control_points + 1]
	local p2 = control_points[index % num_control_points + 1]
	local p3 = control_points[(index + 1) % num_control_points + 1]

	return catmull_rom(p0, p1, p2, p3, local_t)
end

function catmull_rom(p0, p1, p2, p3, t)
	local t2 = t * t
	local t3 = t2 * t

	local m0 = (p2 - p0) / 2
	local m1 = (p3 - p1) / 2

	local a = 2 * t3 - 3 * t2 + 1
	local b = t3 - 2 * t2 + t
	local c = t3 - t2
	local d = -2 * t3 + 3 * t2

	return a * p1 + b * m0 + c * m1 + d * p2
end

function M.draw_spline(control_points, screen_x, screen_y)
	local scale = vmath.vector3(screen_x, screen_y, 1)
	print(scale)
	for t = 0, 1, .01 do
		local point = M.get_point(t, control_points)
		point.x = point.x * scale.x
		point.y = point.y * scale.y
		local next_t = t + .01
		if next_t <= 1 then
			local next_point = M.get_point(next_t, control_points)
			next_point.x = next_point.x * scale.x
			next_point.y = next_point.y * scale.y
			msg.post("@render:", "draw_line",
				{ start_point = point, end_point = next_point, color = vmath.vector4(1, 0, 0, 1) })
		end
	end

	-- Draw straight lines between control points
	for i = 1, #control_points - 1 do
		local start_point = control_points[i]
		local end_point = control_points[i + 1]
		msg.post("@render:", "draw_line",
			{ start_point = start_point, end_point = end_point, color = vmath.vector4(0, 1, 0, 1) })
	end
end

return M
2 Likes