Code Doodles!

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

How to crop infinity area with infinity lines

Code: Select all

-- License CC0 (Creative Commons license) (c) darkfrei, 2023

-- infinity area cutting


love.window.setTitle ('crop infinity area by the line')



area = {lines={}}
tempLine = {}

local function pseudoScalarProduct(x1, y1, x2, y2, x3, y3, x4, y4)
	local dx1, dy1 = x2-x1, y2-y1
	local dx2, dy2 = x4-x3, y4-y3
	-- positive - goes inside, clockwise
	return dx1 * dy2 - dx2 * dy1
end

local function findIntersection(x1, y1, x2, y2, x3, y3, x4, y4, unlimStart1, unlimEnd1, unlimStart2, unlimEnd2)

	local dx1, dy1 = x2-x1, y2-y1
	local dx2, dy2 = x4-x3, y4-y3
	local denominator = dx1*dy2-dy1*dx2
	if denominator == 0 then
		return nil -- Линии параллельны или совпадают
	end

	local dx13, dy13 = (x1 - x3), (y1 - y3)

	local t = (dx13 * (y3 - y4) - dy13 * (x3 - x4)) / denominator
	local u = (dx13 * (y1 - y2) - dy13 * (x1 - x2)) / denominator

	if 	(unlimStart1 	or t >= 0) and 
	(unlimEnd1 		or t <= 1) and
	(unlimStart2 	or u >= 0) and 
	(unlimEnd2 		or u <= 1) then
		local intersectionX = x1 + t * (x2 - x1)
		local intersectionY = y1 + t * (y2 - y1)
		return intersectionX, intersectionY
	end

--	return nil
end

local function checkCollisions(area, segment)
	local startUnlimited = true
	local endUnlimited = true
	local segmentValid = false

	local x1, y1, x2, y2 = segment[1], segment[2], segment[3], segment[4]
	for i, aLine in ipairs (area.lines) do
		local x3, y3 = aLine.startPoint[1], aLine.startPoint[2]
		local x4, y4 = aLine.endPoint[1], aLine.endPoint[2]

		-- negative for clockwise direction:
		local psp = pseudoScalarProduct(x1, y1, x2, y2, x3, y3, x4, y4)

		local us1, ue1 = startUnlimited, endUnlimited
		local us2, ue2 = aLine.startUnlimited, aLine.endUnlimited

		if psp < 0 then
			local cx, cy = findIntersection(x1, y1, x2, y2, x3, y3, x4, y4, us1, ue1, us2, ue2)
			if cx then
				startUnlimited = false
				segment[1], segment[2] = cx, cy
				aLine.endPoint[1] = cx
				aLine.endPoint[2] = cy
				aLine.endUnlimited = false

				segmentValid = true
			else
				-- no intersection
			end
		elseif psp > 0 then
			local cx, cy = findIntersection(x1, y1, x2, y2, x3, y3, x4, y4, us1, ue1, us2, ue2)
			if cx then
				endUnlimited = false
				segment[3], segment[4] = cx, cy
				aLine.startPoint[1] = cx
				aLine.startPoint[2] = cy
				aLine.startUnlimited = false

				segmentValid = true
			else
				-- no intersection
			end
		else
			-- parallel
			-- no intersection
		end
	end

-- here some cleaning for old not used area lines

	return startUnlimited, endUnlimited
end

local function cutArea (area, segment)
--	local startUnlimited = true
	local startUnlimited = true
	local endUnlimited = true
--	local endUnlimited = false

	if #segment < 4 then return end

	startUnlimited, endUnlimited = checkCollisions(area, segment)

	local x1, y1, x2, y2 = segment[1], segment[2], segment[3], segment[4]
	local dx, dy = x2 - x1, y2 - y1
	local w, h = love.graphics.getDimensions()

	if (startUnlimited or endUnlimited) and dy ~= 0 then
		local xMin, yMin, xMax, yMax = 10, 10, w - 10, h - 10
		local slope = dx / dy

		-- Calculate extended points for the starting point
		local xStart, yStart
		local xEnd, yEnd


		if dy > 0 then
			--min max
			xStart = x1 + (yMin - y1) * slope
			yStart = yMin

			xEnd = x1 + (yMax - y1) * slope
			yEnd = yMax
		else
			-- max min
			xStart = x1 + (yMax - y1) * slope
			yStart = yMax

			xEnd = x1 + (yMin - y1) * slope
			yEnd = yMin
		end

		--		if xStart < xMin or xStart > xMax or xEnd < xMin or xEnd > xMax then
		if xStart < xMin or xStart > xMax then
			if dx > 0 then
				-- min max

				yStart = y1 + (xMin - x1) / slope
				xStart = xMin

			else
				yStart = y1 + (xMax - x1) / slope
				xStart = xMax
			end
		end

		if xEnd < xMin or xEnd > xMax then
			if dx > 0 then
				yEnd = y1 + (xMax - x1) / slope
				xEnd = xMax
			else
				yEnd = y1 + (xMin - x1) / slope
				xEnd = xMin
			end
		end

		if startUnlimited then
			x1, y1 = xStart, yStart
		end
		if endUnlimited then
			x2, y2 = xEnd, yEnd
		end

	elseif (startUnlimited or endUnlimited) and dy == 0 then
		-- Handling the case when the line segment is horizontal (dy == 0)
		local xMin, xMax = 10, w - 10

		-- Calculate extended points for the starting point
		local xStart = dx > 0 and xMin or xMax
		local yStart = y1

		-- Calculate extended points for the ending point
		local xEnd = dx > 0 and xMax or xMin
		local yEnd = y2

		if startUnlimited then
			x1, y1 = xStart, yStart
		end
		if endUnlimited then
			x2, y2 = xEnd, yEnd
		end
	end

	local line = {
		startPoint = {x1, y1},
		endPoint = {x2, y2},
		startUnlimited = startUnlimited,
		endUnlimited = endUnlimited,
	}

	table.insert(area.lines, line)
end

function love.load()

end


function love.update(dt)

end

local function drawCutLine (line)

	if #line > 3 then
		love.graphics.line (line)
	end
end


local function drawInfinityArea(area)
	for _, line in ipairs(area.lines) do
		local startPoint = line.startPoint
		local endPoint = line.endPoint

		love.graphics.line(startPoint[1], startPoint[2], endPoint[1], endPoint[2])
	end
end


function love.draw()
	love.graphics.setLineWidth (3)
	love.graphics.setColor (0.6,0.6,0.6)
	drawInfinityArea (area)
	love.graphics.setColor (1,1,1)
	drawCutLine (tempLine)
end


function love.mousepressed(x, y)
	tempLine = {x, y}
end

function love.mousemoved (x, y)
	tempLine[3] = x
	tempLine[4] = y
	--	tempLine[4] = tempLine[2]
end



function love.mousereleased ( x, y)
	cutArea (area, tempLine)
	tempLine = {}
end


function love.keypressed(key, scancode, isrepeat)
	if false then
	elseif key == "escape" then
		love.event.quit()
	end
end
2023-07-22T19_29_05-NVIDIA GeForce Overlay DT.png
2023-07-22T19_29_05-NVIDIA GeForce Overlay DT.png (10.27 KiB) Viewed 36360 times
Attachments
main.lua
fixed line filter, works perfect!
(6.3 KiB) Downloaded 378 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Small example how cross unlimited lines, rays and segments:
(press LBM and RBM to change state)

Code: Select all

local function getCutPoint (tDataA, tDataB)
	local x1, y1, x2, y2 = tDataA.pointA.x, tDataA.pointA.y, tDataA.pointB.x, tDataA.pointB.y 
	local x3, y3, x4, y4 = tDataB.pointA.x, tDataB.pointA.y, tDataB.pointB.x, tDataB.pointB.y

	local limidedAStart, limidedAEnd = tDataA.limitedA, tDataA.limitedB
	local limidedBStart, limidedBEnd = tDataB.limitedA, tDataB.limitedB

	local dx1, dy1 = x2-x1, y2-y1
	local dx2, dy2 = x4-x3, y4-y3
	local denominator = dx1*dy2-dy1*dx2
	if denominator == 0 then -- parallel
		return nil
	elseif dx1*dx1 + dy1*dy1 == 0 then 
		return 
	elseif dx2*dx2 + dy2*dy2 == 0 then 
		return
	end

	local dx13, dy13 = (x1 - x3), (y1 - y3)
	local t = (dx13 * (y3 - y4) - dy13 * (x3 - x4)) / denominator
	local u = (dx13 * (y1 - y2) - dy13 * (x1 - x2)) / denominator

	local validPoint = true

	if 
	((not limidedAStart) or (t > 0)) 
	and ((not limidedAEnd)   or (t < 1)) 
	and ((not limidedBStart) or (u > 0))
	and ((not limidedBEnd)   or (u < 1)) 
	then
		local intersectionX = x1 + t * (x2 - x1)
		local intersectionY = y1 + t * (y2 - y1)
		return {x=intersectionX, y=intersectionY}
	end

	return nil
end

tDataA =
{
	pointA = {x=200, y=200},
	pointB = {x=600, y=210},
	limitedA = false,
	limitedB = true,
}

tDataB =
{
	pointA = {x=200, y=400},
	pointB = {x=600, y=300},
	limitedA = true,
	limitedB = true,
}
point = getCutPoint (tDataA, tDataB)

function love.draw ()
	love.graphics.line (tDataA.pointA.x,tDataA.pointA.y, tDataA.pointB.x,tDataA.pointB.y)
	love.graphics.line (tDataB.pointA.x,tDataB.pointA.y, tDataB.pointB.x,tDataB.pointB.y)

	if tDataA.limitedA then
		love.graphics.circle ('line', tDataA.pointA.x, tDataA.pointA.y, 3)
	end

	if tDataA.limitedB then
		love.graphics.circle ('line', tDataA.pointB.x, tDataA.pointB.y, 3)
	end	

	if tDataB.limitedA then
		love.graphics.circle ('line', tDataB.pointA.x, tDataB.pointA.y, 3)
	end

	if tDataB.limitedB then
		love.graphics.circle ('line', tDataB.pointB.x, tDataB.pointB.y, 3)
	end	

	if point then
		love.graphics.circle ('line', point.x, point.y, 5)
	end
end

function love.mousepressed (x, y, index)
	if index == 1 then
		tDataB.limitedB = not tDataB.limitedB
		
	elseif index == 2 then
		tDataA.limitedA = not tDataA.limitedA
	end
	point = getCutPoint (tDataA, tDataB)
end

function love.mousemoved (x, y)
	tDataB.pointB.x,tDataB.pointB.y = x, y
	point = getCutPoint (tDataA, tDataB)
end

function love.keypressed(key, scancode, isrepeat)
	if key == "escape" then
		love.event.quit()
	end
end
Screenshot 2023-08-20 114244.png
Screenshot 2023-08-20 114244.png (6.36 KiB) Viewed 36026 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Raycast, raycasting between point with angle of view and lines in love2d format ({x1, y1, x2, y2}):

Code: Select all

local image = love.graphics.newImage ('img_40x40.png')
local imageW, imageH = image:getDimensions ()

local quads = {}
for x = 1, imageW do
	local quad = love.graphics.newQuad (x,0, x,imageH, image)
end

local lines = {
	{100,200, 550, 200},
	{600,150, 600, 550},
}

player = {x=50, y=400, angle = 0, viewAngle = math.rad(60), samples = 30, rays = {}}

local function raycast (rayX, rayY, angle, segment)
	local dx1 = math.cos (angle)
	local dy1 = math.sin (angle)
	local x1, y1, x2, y2 = rayX, rayY, rayX+dx1, rayY+dy1 
	local x3, y3, x4, y4 = segment[1], segment[2], segment[3], segment[4]

	local dx2, dy2 = x4-x3, y4-y3

	local denominator = dx1*dy2-dy1*dx2
	if denominator == 0 then -- parallel
		return nil
	elseif dx1*dx1 + dy1*dy1 == 0 then 
		return 
	elseif dx2*dx2 + dy2*dy2 == 0 then 
		return
	end

	local dx13, dy13 = (x1 - x3), (y1 - y3)
	local t = (dx13 * (y3 - y4) - dy13 * (x3 - x4)) / denominator
	local u = (dx13 * (y1 - y2) - dy13 * (x1 - x2)) / denominator

	local validPoint = true

	if  (t > 0) and (u > 0) and (u < 1) then
		local intersectionX = x1 + t * (x2 - x1)
		local intersectionY = y1 + t * (y2 - y1)
		local distance = math.sqrt((intersectionX - rayX) ^ 2 + (intersectionY - rayY) ^ 2)
		return intersectionX, intersectionY, distance
	end

	return nil
end

local function update ()
	local dAngle = player.viewAngle / player.samples
	player.rays = {}
	for i = 1, player.samples do
		local angle = player.angle + (i-player.samples/2) * dAngle
		local x = player.x + 600 * math.cos (angle)
		local y = player.y + 600 * math.sin (angle)
		table.insert (player.rays, {player.x, player.y, x, y, angle = angle})
	end

	for iRay, ray in ipairs (player.rays) do
		local minDist = nil
		for iLine, segment in ipairs (lines) do
			local x, y, dist = raycast (player.x, player.y, ray.angle, segment)
			if dist and (not minDist or  (minDist > dist)) then
				ray[3] = x
				ray[4] = y
				minDist = dist
			end
		end
	end
end

function love.load ()
	update ()
end

function love.update (dt)
	local left = love.keyboard.isScancodeDown ('a')
	local right = love.keyboard.isScancodeDown ('d')
	local forward = love.keyboard.isScancodeDown ('w')
	local backward = love.keyboard.isScancodeDown ('s')
	local omega = 1
	local speed = 200
	if left or right or forward or backward then
		if forward or backward then 
			local dx = speed * dt * math.cos (player.angle)
			local dy = speed * dt * math.sin (player.angle)
			if forward and not backward then
				player.x = player.x + dx
				player.y = player.y + dy
			elseif backward and not forward then
				player.x = player.x - dx
				player.y = player.y - dy
			end
		end
		if left and not right then
			player.angle = player.angle - omega * dt
		elseif right and not left then
			player.angle = player.angle + omega * dt
		end

		update ()
	end
end

function love.draw ()
	love.graphics.setColor (1,1,1)
	for i, line in ipairs (lines) do
		love.graphics.line (line)
	end

	love.graphics.setColor (1,1,0)
	for i, line in ipairs (player.rays) do
		love.graphics.line (line)
	end

	love.graphics.setColor (1,1,1)
	love.graphics.print ('press WASD to move')
end


function love.keypressed (k, s)
	if k == 'escape' then	love.event.quit () end
end
Screenshot 2023-09-05 165532.png
Screenshot 2023-09-05 165532.png (56.36 KiB) Viewed 35725 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
Gunroar:Cannon()
Party member
Posts: 1142
Joined: Thu Dec 10, 2020 1:57 am

Re: Code Doodles!

Post by Gunroar:Cannon() »

pgimeno wrote: Wed May 31, 2023 9:03 am
darkfrei wrote: Wed May 31, 2023 7:32 am...
Hi darkfrei, Please read the first post, then look at the doodles that others have posted. Thanks.
Lol, darkfrei took this personally.
The risk I took was calculated,
but man, am I bad at math.

-How to be saved and born again :huh:
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Small doodle to move the parabola with changing of a, b and c coefficients:

Code: Select all

mouseX = 0
mouseY = 0

function drawParabola(a, b, c, xMin, yMin, xMax, yMax, step)
	local points = {}
	for x = xMin, xMax, step do
		local y = a * x * x + b * x + c
		if y >= yMin and y <= yMax then
			table.insert(points, x)
			table.insert(points, y)
		end
	end

	if #points > 2 then
		love.graphics.line(points)
	end
end

function love.draw ()
	local a, b, c = 0.01, 0, 0
	local b2 = b - 2 * a * mouseX
	local c2 = c - b * mouseX + a * mouseX^2 + mouseY
	local xMin, yMin, xMax, yMax = 0, 0, love.graphics.getDimensions ()
	drawParabola(a, b2, c2, xMin, yMin, xMax, yMax, 1)
end

function love.mousemoved (x, y)
	mouseX = x
	mouseY = y
end
2023-09-13T13_21_44-Untitled.png
2023-09-13T13_21_44-Untitled.png (5.88 KiB) Viewed 35577 times

-------------- Update :awesome:

There is a way to draw the parabola with Bezier in Lua!
We are need left and right points (here given with y1, y2, but x1 and x2 are also ok) and with derivatives in that points get the crossing as control point of Bezier:

Code: Select all

function drawBezierParabola (a, b, c, y1, y2)
	-- crop points:
	local x1 = (-b + math.sqrt(b^2 - 4*a*(c-y1))) / (2*a)
	local x2 = (-b - math.sqrt(b^2 - 4*a*(c-y2))) / (2*a)
	
	--[[ backward:
	local y1 = a * x1^2 + b * x1 + c
	local y2 = a * x2^2 + b * x2 + c
	]]

	-- derivatives:
	local k1 = 2 * a * x1 + b
	local k2 = 2 * a * x2 + b

	-- bezier control point:
	local xi = -b/(2*a) - (y2 - y1) / (k1 - k2)
	local yi = k1 * (xi - x1) + y1

	love.graphics.line (love.math.newBezierCurve (x1, y1, xi, yi, x2, y2):render())
	return x1, y1, xi, yi, x2, y2
end

function love.draw ()
-- skipped
	love.graphics.setColor (1,1,1)
	local yLeft, yRight = 100, 50
	local x1, y1, xi, yi, x2, y2 = drawBezierParabola (a, b2, c2, yLeft, yRight)
	
	love.graphics.setColor (1,1,0)
	love.graphics.line (x1, y1, xi, yi, x2, y2)
end
2023-09-13T14_44_54-Untitled.png
2023-09-13T14_44_54-Untitled.png (11.26 KiB) Viewed 35568 times


-------------- Update :awesome:

Drawing parabola with focus and directrix:
https://www.desmos.com/calculator/1shgwazc3e

Code: Select all

function love.draw ()
-- skipped	
	local fx = mouseX -- focus point
	local fy = mouseY
	love.graphics.circle ('line', fx, fy, 5)
	
	local dirY = 500 -- directrix
	love.graphics.line (0,dirY,love.graphics.getWidth(), dirY)
	
	local f = math.abs(dirY-fy)/2 -- focus lenght
	love.graphics.circle ('line', fx, fy+f, 5)
	
	local a = -1/(4*f)
	local b = -2*fx*a 
	local c = fx*fx*a + fy + f
	
	drawBezierParabola (a, b, c, 0, 0)
	
	-- draw line to any point, for example {x = 2*fx, y=ax^2+bx+c}
	local x1 = fx*2
	local y1 = a*x1*x1 + b*x1 + c
	love.graphics.line (fx, fy, x1, y1)
	love.graphics.line (x1, y1, x1, dirY)
	
	local length1 = math.floor(((fx-x1)^2 + (fy-y1)^2)^0.5)
	local length2 = math.floor(dirY-y1)
	
	love.window.setTitle (length1..' '..length2)
end
2023-09-14T09_09_38-280 280.png
2023-09-14T09_09_38-280 280.png (7.08 KiB) Viewed 35518 times


-------------- Update :awesome:

Draw crossings parabolas:

Code: Select all

mouseX = 0
mouseY = 0

function drawArch (x, y, dirY, x1, x2) -- focus x, y; directrix y; limitingX
	local f = math.abs(dirY-y)/2 -- focus lenght

	local a = -1/(4*f)
	local b = -2*x*a 
	local c = x*x*a + y + f

	if not x1 or not x2 then
		if not x1 then
			x1 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
		end
		if not x2 then
			x2 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
		end
	end

	x1, x2 = math.min (x1, x2), math.max (x1, x2)
	local	y1 = a*x1*x1 + b*x1 + c
	local	y2 = a*x2*x2 + b*x2 + c
	local k1 = 2 * a * x1 + b
	local k2 = 2 * a * x2 + b

	-- bezier control point:
	local xi = -b/(2*a) - (y2 - y1) / (k1 - k2)
	local yi = k1 * (xi - x1) + y1
	local bezier = love.math.newBezierCurve (x1, y1, xi, yi, x2, y2)
	love.graphics.line (bezier:render())
end

local function getParabolaIntersection (fx1, fy1, fx2, fy2, dirY)
	local f1 = math.abs(dirY-fy1)/2 -- focus lenght
	local f2 = math.abs(dirY-fy2)/2 -- focus lenght

	local a1 = -1/(4*f1)
	local a2 = -1/(4*f2)
	local b1 = -2*fx1*a1
	local b2 = -2*fx2*a2
	local c1 = a1*fx1*fx1 + fy1 + f1
	local c2 = a2*fx2*fx2 + fy2 + f2

	local A = a1-a2
	local B = b1-b2
	local C = c1-c2
	local discriminant = B^2 - 4 * A * C
	local x1 = (-B - math.sqrt(discriminant)) / (2 * A)
	local x2 = (-B + math.sqrt(discriminant)) / (2 * A)
	x1, x2 = math.min (x1, x2), math.max (x1, x2)
	local y1 = a1 * (x1)^2 + b1*x1 + c1
	local y2 = a1 * (x2)^2 + b1*x2 + c1
	return x1, y1, x2, y2 
end

function love.draw ()
	local fx1 = 150
	local fy1 = 150
	
	local fx2 = mouseX
	local fy2 = mouseY
	local dirY = 500 -- directrix
	
	love.graphics.setColor (0.8,0.8,0.8,0.8)
	love.graphics.setLineWidth (1)
	drawArch (fx1, fy1, dirY)
	drawArch (fx2, fy2, dirY)
	love.graphics.line (0, dirY, love.graphics.getWidth(), dirY)
	
	local x1, y1, x2, y2 = getParabolaIntersection (fx1, fy1, fx2, fy2, dirY)
	love.graphics.setColor (1,1,1)
	love.graphics.circle ('line', x1, y1, 3)
	love.graphics.circle ('line', x2, y2, 5)
	
	love.graphics.setLineWidth (3)
	drawArch (fx1, fy1, dirY, 0, x1)
	drawArch (fx1, fy1, dirY, x2, love.graphics.getWidth())
	drawArch (fx2, fy2, dirY, x1, x2)
end

function love.mousemoved (x, y)
	mouseX = x
	mouseY = y
end
Attachments
2023-09-14T18_36_21-Untitled.png
2023-09-14T18_36_21-Untitled.png (13.46 KiB) Viewed 35503 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

The Voronoi Fortune animation with small error, that I cannot fix:

(press space to pause, press S to step)

Code: Select all

--[[Copyright 2023 darkfrei
The MIT License https://opensource.org/license/mit/ 
<...>--]]
local vfa = {}

local function sortXYBackward (list)
	table.sort(list, function(a, b) return a.y > b.y or a.y == b.y and a.x > b.x or false end)
end

local function sortX (list)
	table.sort(list, function(a, b) return a.x < b.x end)
end

local function reload ()
	vfa.dirY = 0
	vfa.segments = {}
	vfa.parabolaLines = {}
	vfa.sweepLine = {}
	vfa.queue = {}
	for i = 1, #vfa.points-1, 2 do
		local x, y = vfa.points[i], vfa.points[i+1]
		table.insert (vfa.queue, {x=x, y=y, point=true})
	end
	sortXYBackward (vfa.queue)
	for i = #vfa.queue, 1, -1 do
		local event = vfa.queue[i]
--		print (i, event.x, event.y)
	end
end

local function getCircumcircle (x1, y1, x2, y2, x3, y3)
	local d = 2*(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2))
--	print (d)
	local t1, t2, t3 = x1*x1+y1*y1, x2*x2+y2*y2, x3*x3+y3*y3
	local x = (t1*(y2-y3)+t2*(y3-y1)+t3*(y1-y2)) / d
	local y = (t1*(x3-x2)+t2*(x1-x3)+t3*(x2-x1)) / d
	local radius = math.sqrt((x1-x)^2+(y1-y)^2)
	return x, y, radius
end


local function getParabolaCrossPoint (focus1, focus2, dirY) -- focus 1, focus 2, directrix
-- Function to find the intersection point of two parabolas
	local p1x, p1y = focus1.x, focus1.y
	local p2x, p2y = focus2.x, focus2.y
	local f1 = math.abs(dirY-p1y)/2
	local f2 = math.abs(dirY-p2y)/2

	local a1 = -1/(4*f1)
	local a2 = -1/(4*f2)
	local b1 = -2*p1x*a1
	local b2 = -2*p2x*a2
	local c1 = p1x*p1x*a1 + p1y + f1
	local c2 = p2x*p2x*a2 + p2y + f2
	local a = a1-a2
	local b = b1-b2
	local c = c1-c2

	local d = b*b-4*a*c
	local x, y
	if d >=0 then
		x = (-b-math.sqrt (d))/(2*a)
		y = a1*x*x + b1*x + c1
	end
	return x, y
end

function vfa.load ()

	vfa.points = {}
--	vfa.points = {101,100, 201, 200, 301, 300, 401, 400, 501, 500, 601, 600}

	for i = 1, 8 do
		local x = math.random (Width*0.5) + Width*0.25
		local y = math.random (Height*0.5) + Height*0.25
		table.insert (vfa.points, x)
		table.insert (vfa.points, y)
--		table.insert (vfa.points, x+200)
--		table.insert (vfa.points, y)
	end
	reload ()
end

local function pointEvent (focus)
--	local dirY = vfa.dirY
	local dirY = focus.y + 0.0001
	if #vfa.sweepLine == 0 then
		local sep1 = {x=0, y=0}
		local sep2 = {x=Width, y=0}
		table.insert (vfa.sweepLine, sep1)
		table.insert (vfa.sweepLine, focus)
		table.insert (vfa.sweepLine, sep2)
		return
	end

	local index
	for i = 3, #vfa.sweepLine, 2 do
		local sep = vfa.sweepLine[i]
		if not sep.x then
			return
		end
		if focus.x < sep.x then
			index = i-1
			break
		end
	end

	local focusOld = vfa.sweepLine[index]
	local sep2x, sep2y = getParabolaCrossPoint (focusOld, focus, dirY)
	local sep3x, sep3y = getParabolaCrossPoint (focus, focusOld, dirY)
	print (sep2x, sep3x)
	if sep2x and sep3x then
		local sep2 = {x=sep2x, y=sep2y}
		local sep3 = {x=sep3x, y=sep3y}

		table.insert (vfa.sweepLine, index, focusOld)
		table.insert (vfa.sweepLine, index+1, sep2)
		table.insert (vfa.sweepLine, index+2, focus)
		table.insert (vfa.sweepLine, index+3, sep3)

		table.insert (vfa.segments, {sep2, sep3})
	end


	--
	local circleEvent = {}
	local focus1 = vfa.sweepLine[index-2]
	local focus2 = vfa.sweepLine[index]
	local focus3 = vfa.sweepLine[index+2]
	local focus4 = vfa.sweepLine[index+4]
	local focus5 = vfa.sweepLine[index+6]

	local str = ''
	local circle1, circle2
	if focus1 and focus2 then
		str = str .. ' '.. (index-2)..' '.. (index)..' '.. (index+2) .. '; '
		local x, y, r = getCircumcircle (focus1.x, focus1.y, focus2.x, focus2.y, focus3.x, focus3.y)
		circle1 = {cx=x, cy=y, x=x, y=y+r, r=r, sep = vfa.sweepLine[index+1]}

	end
	if focus4 and focus5 then
		str = str .. ' '.. (index+2)..' '.. (index+4)..' '.. (index+6) .. '.'
		local x, y, r = getCircumcircle (focus3.x, focus3.y, focus4.x, focus4.y, focus5.x, focus5.y)
		circle2 = {cx=x, cy=y, x=x, y=y+r, r=r, sep = vfa.sweepLine[index+5]}
	end

	if circle1 then
		table.insert (vfa.queue, circle1)
	end
	if circle2 then
		table.insert (vfa.queue, circle2)
	end
	love.window.setTitle (str)
end



local function circleEvent (circle)
	local separator = circle.sep

	local index
	for i = 3, #vfa.sweepLine, 2 do
		local sep = vfa.sweepLine[i]
		if separator == sep then
			index = i-1
			break
		end
	end

	if index then
		local p1 = vfa.sweepLine[index-3]
		local p5 = vfa.sweepLine[index+3]
		local s2 = table.remove (vfa.sweepLine, index-1)
		local p3 = table.remove (vfa.sweepLine, index-1)
		local s4 = table.remove (vfa.sweepLine, index-1)
		print (tostring(circle.cx))
		s2.x, s2.y = circle.cx, circle.cy
		s4.x, s4.y = circle.cx, circle.cy

		local pNew = {x=circle.cx, y=circle.cy}
		table.insert (vfa.sweepLine, index-1, pNew)

		table.insert (vfa.segments, {s2, pNew})
--		table.insert (vfa.segments, {p5, pNew})
	end
end


local function getParabolaLine (x, y, dirY, xMin, xMax) -- focus, directrix, horizontal limits
-- Function to generate points along a parabola curve
	local line = {}
	local f = math.abs(dirY-y)/2
	local a = -1/(4*f) 
	local b = -2*x*a
	local c = x*x*a + y + f
	local nSteps = math.floor((xMax-xMin)/5)
	local step = (xMax-xMin)/nSteps
	for i = 0, nSteps do
		local x0 = xMin + i * step
		local y0 = a*x0*x0 + b*x0 + c
		table.insert (line, x0)
		table.insert (line, y0)
	end
	return line
end

function vfa.update ()

	if vfa.dirY > Height then
		reload ()
	end

	
	for i = #vfa.queue, 1, -1 do
		sortXYBackward (vfa.queue)
		local event = vfa.queue[i]
		if vfa.dirY > event.y then
			table.remove (vfa.queue, i)
			if event.point then
				pointEvent (event)
			else
				circleEvent (event)
			end
			sortXYBackward (vfa.queue)
		else
			break
		end
	end

	-- update separators
	for i = 3, #vfa.sweepLine-2, 2 do
		local sep = vfa.sweepLine[i]
		local focus1 = vfa.sweepLine[i-1]
		local focus2 = vfa.sweepLine[i+1]
		local x, y = getParabolaCrossPoint (focus1, focus2, vfa.dirY)
		sep.x, sep.y = x, y
	end

	-- update parabolas
	vfa.parabolaLines = {}
	for i = 2, #vfa.sweepLine-1, 2 do
		local sep1 = vfa.sweepLine[i-1]
		local focus = vfa.sweepLine[i]
		local sep2 = vfa.sweepLine[i+1]

		local xMin = sep1.x or 0
		local xMax = sep2.x or 0

		local line = getParabolaLine (focus.x, focus.y, vfa.dirY, xMin, xMax)
		if #line > 3 then
			table.insert (vfa.parabolaLines, line)
		end
	end
end

function vfa.draw ()

	love.graphics.setColor (1,1,1)
	love.graphics.points (vfa.points)
	for i = 1, #vfa.points, 2 do
		love.graphics.circle ('line', vfa.points[i], vfa.points[i+1], 3)
	end
	
	love.graphics.line (0, vfa.dirY, Width, vfa.dirY)

	love.graphics.setColor (1,1,0)
	for i = 1, #vfa.sweepLine, 2 do
		local sep = vfa.sweepLine[i]
		love.graphics.circle ('line', sep.x, sep.y, 5)
		love.graphics.print (i, sep.x, sep.y-20)
	end

	love.graphics.setColor (1,0,0)
	for i, event in ipairs (vfa.queue) do
		if event.point then
			love.graphics.circle ('line', event.x, event.y, 3)
		else
			love.graphics.circle ('line', event.cx, event.cy, event.r)
		end
	end

	love.graphics.setColor (1,1,1)
	for i, line in ipairs (vfa.parabolaLines) do
		love.graphics.line (line)
	end

	love.graphics.setColor (0,1,0)
	for i = 2, #vfa.sweepLine-1, 2 do
		local focus = vfa.sweepLine[i]
		love.graphics.circle ('line', focus.x, focus.y, 5)
		love.graphics.print (i, focus.x+i, focus.y-20)
	end
	
	love.graphics.setColor (0,1,1)
	for i, segment in ipairs (vfa.segments) do
		love.graphics.line (segment[1].x, segment[1].y, segment[2].x, segment[2].y)
	end
end

-------------------------------------
-- love
-------------------------------------

love.window.setMode(800, 800)
Width, Height = love.graphics.getDimensions( )


function love.load()
	-- preheat
	for i = 1, 6 do math.random () end

	vfa.load ()
	pause = false
end


function love.update(dt)
	if not pause then
		vfa.dirY = vfa.dirY+4*60*dt
		vfa.update ()
	end
end


function love.draw()
	love.graphics.setLineWidth (2)
	love.graphics.setLineStyle ('rough')
	vfa.draw ()
end

function love.keypressed(key, scancode, isrepeat)
	if false then
	elseif key == "s" then
		vfa.dirY = vfa.dirY+1
		vfa.update ()
	elseif key == "space" then
		pause = not pause
	elseif key == "escape" then
		love.event.quit()
	end
end

function love.mousepressed( x, y, button, istouch, presses )
	reload ()
	vfa.dirY = y
	vfa.update ()
end

function love.mousemoved( x, y, dx, dy, istouch )

end

function love.mousereleased( x, y, button, istouch, presses )
	if button == 1 then -- left mouse button
	elseif button == 2 then -- right mouse button
	end
end
2023-10-17T16_29_07-6 8 10;  10 12 14..png
2023-10-17T16_29_07-6 8 10; 10 12 14..png (22.26 KiB) Viewed 34353 times
2023-10-17T16_29_28-4 6 8;  8 10 12..png
2023-10-17T16_29_28-4 6 8; 8 10 12..png (23.57 KiB) Viewed 34352 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
marclurr
Party member
Posts: 158
Joined: Fri Apr 22, 2022 9:25 am

Re: Code Doodles!

Post by marclurr »

While I was on holiday last week I had a few ideas for games that would need circle vs arbitrarily rotated rectangle collision resolution. I came up with a solution that I was itching to have a go at implementing. It works nicely, and I thought it was a clever and novel idea until I looked around online and the first result I found was the exact same implementation. Oh well :)

Code: Select all

function rotatePoint(x, y, cosR, sinR)
    local rx = x * cosR - y * sinR
    local ry = y * cosR + x * sinR
    return rx, ry
end


love.graphics.setDefaultFilter("nearest","nearest")
love.graphics.setLineStyle("rough")
local rad = math.pi / 180
local rects = {}


love.math.setRandomSeed(34545)
local rnd = love.math.random
for i = 1, 16 do 
    local r = {x = rnd(16, 640), y = rnd(16, 480), w = rnd(8, 128), h = rnd(8, 128), r = rnd() * 2 * math.pi}
    table.insert(rects, r)
    r.cos = math.cos(r.r)
    r.sin = math.sin(r.r)
    r.invCos = math.cos(-r.r)
    r.invSin = math.sin(-r.r)

    local w, h = r.w /2, r.h/2
    r.cx = r.x + w
    r.cy = r.y + h
      
    local p1x, p1y = rotatePoint(-w, -h, r.cos, r.sin)
    local p2x, p2y = rotatePoint(w, -h, r.cos, r.sin)
    local p3x, p3y = rotatePoint(w, h, r.cos, r.sin)
    local p4x, p4y = rotatePoint(-w, h, r.cos, r.sin)
    r.verts = { 
        p1x + r.cx, p1y + r.cy, 
        p2x + r.cx, p2y + r.cy, 
        p3x + r.cx, p3y + r.cy, 
        p4x + r.cx, p4y + r.cy
    }
 
end

local p = {x = 0, y = 0, r = 16, dx = 0, dy = 0}


function getCollisionInfo(px, py, pr, r)
    px, py = rotatePoint(px - r.cx, py - r.cy, r.invCos, r.invSin)
    px = px + r.cx
    py = py + r.cy

    local testX, testY = px, py
    local dir
    local dirX, dirY = 0, 0
    if px < r.x then
        testX = r.x 
        dirX = -1
    elseif px > r.x + r.w then
        testX = r.x + r.w
        dirX = 1
    end

    if py < r.y then
        testY = r.y
        dirY = -1
    elseif py > r.y + r.h then
        testY = r.y + r.h
        dirY = 1
    end

    local dx = testX -px
    local dy = testY -py
    local d = math.sqrt(dx*dx + dy*dy)
    dirX, dirY = norm(rotatePoint(dirX, dirY, r.cos, r.sin))
    dx, dy = rotatePoint(dx, dy, r.invCos, r.invSin)
    return d <= pr, dirX, dirY, pr - d
end

function norm(x, y)
    local len = math.sqrt(x*x + y*y)
    if len == 0 then 
        return 0, 0
    end
    return x / len, y / len
end


function love.update(dt)
    local ix, iy = 0, 0
    if love.keyboard.isScancodeDown("a") then
        ix = ix - 1
    end
    if love.keyboard.isScancodeDown("d") then
        ix = ix + 1
    end
    if love.keyboard.isScancodeDown("w") then
        iy = iy - 1
    end
    if love.keyboard.isScancodeDown("s") then
        iy = iy + 1
    end

    p.dx = ix
    p.dy = iy

    p.x = p.x + p.dx * 160 * dt 
    p.y = p.y + p.dy * 160 * dt

    for i = 1, #rects do
        local r = rects[i]

        local col, dirX, dirY, d = getCollisionInfo(p.x, p.y, p.r, r)
        r.col = col
        if col then
            p.x = p.x + dirX * d
            p.y = p.y + dirY * d
        end
    end
end


function love.draw()
    love.graphics.clear()
    for i = 1, #rects do
        local r = rects[i]
               
        if r.col then
            love.graphics.setColor(1,0,0,1)
        else
            love.graphics.setColor(1, 1, 1, 1)
        end

        love.graphics.polygon("line", r.verts)
    end

    love.graphics.setColor(1, 1, 1, 1)
    love.graphics.circle("line", p.x, p.y, p.r)
end
User avatar
pgimeno
Party member
Posts: 3672
Joined: Sun Oct 18, 2015 2:58 pm

Re: Code Doodles!

Post by pgimeno »

To get back on topic, I was watching a video about an Arkanoid-type game which abuses physics, and found it very interesting, so I tried to reproduce the setup of one of the levels (level 3, minute 4:35 in the video) with Löve using love.physics. The result, while not as polished, was mesmerizing enough and short enough to be worth of this thread, so here it is.
Attachments
BreakquestLevel3.love
(1.56 KiB) Downloaded 299 times
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Code doodle game about rolling of 5 dice: Press space to reroll

Code: Select all

table.unpack = table.unpack or unpack

love.graphics.setFont(love.graphics.newFont (20))
dx = 20

local function random ()
	return math.random (6)
end

local function getSumm ()
	local value = 0
	for i = 1, 5 do
		local dice = diceSet[i]
		value = value + dice
	end
	return value
end

local function getSame (n)
	local maxSame = math.max (table.unpack (stat))
	if maxSame == 5 then
		return 50
	elseif maxSame >= n then
		return getSumm ()
	else
		return 0
	end
end

local function getFullHouse ()
	local pair = false
	local three = false
	for dice, amount in ipairs (stat) do
		if amount == 2 then
			pair = true
		elseif amount == 3 then
			three = true
		end
	end
	if pair and three then 
		return 35
	else
		return 0
	end
end

local function getStreet (n)
	local longest = 1
	local s = 0
	for i = 1, 6 do
		local amount = stat[i]
		if (i == 6) and (amount > 0) then
			s = s + 1
			if s > longest then
				longest = s
			end
		elseif (amount > 0) then
			s = s + 1
		else
			if s > longest then
				longest = s
			end
			s = 0
		end
	end
	if longest >= n then
		if n == 3 then
			return 30
		elseif n == 4 then
			return 40
		elseif n == 5 then
			return 50
		end
	end
	return 0
end

local function getScores ()
	stat = {0,0,0,0,0,0}
	for i = 1, 5 do
		local dice = diceSet[i]
		stat[dice] = stat[dice] + 1
	end
	
	res = {}
	res[1] = {name = "ones", value = stat[1]*1}
	res[2] = {name = "twoes", value = stat[2]*2}
	res[3] = {name = "trees", value = stat[3]*3}
	res[4] = {name = "fours", value = stat[4]*4}
	res[5] = {name = "fives", value = stat[5]*5}
	res[6] = {name = "sixes", value = stat[6]*6}
	
	res[7] = {name = "3 same", value = getSame (3)}
	res[8] = {name = "4 same", value = getSame (4)}
	res[9] = {name = "5 same", value = getSame (5)}
	
	res[10] = {name = "fullhouse", value = getFullHouse ()}
	
	res[11] = {name = "street 3", value = getStreet (3)}
	res[12] = {name = "street 4", value = getStreet (4)}
	res[13] = {name = "street 5", value = getStreet (5)}
	
	res[14] = {name = "chance", value = getSumm ()}
end

local function reroll ()
	for i = 1, 5 do
		diceSet[i] = random ()
	end
	getScores ()
end

local function updateChances ()
	chances.n = chances.n + 1
	for i, r in ipairs (res) do
		if not chances.res[i] then
			chances.res[i] = {name=r.name, value = r.value}
		else
			chances.res[i].value = chances.res[i].value + res[i].value
		end
	end
end

function love.load()
	pause = true
	diceSet = {}
	reroll ()
	chances = {n=0, res = {}}
	updateChances ()
end


function love.update(dt)
	if not pause then 
		reroll ()
		updateChances ()
	end
end

function love.draw()
	love.graphics.print (table.concat(diceSet, ', '))
	love.graphics.print (table.concat(stat, ', '), 0, 4*dx)
	love.graphics.print ("press SPACE to reroll", 0, 2*dx)
	for i, r in ipairs (res) do
		love.graphics.print (r.name, 0, 4*dx+dx*i)
		love.graphics.print (r.value, 100, 4*dx+dx*i)
	end
	for i, r in ipairs (chances.res) do
		love.graphics.print (r.name, 300, 4*dx+dx*i)
		love.graphics.print (r.value, 400, 4*dx+dx*i)
		love.graphics.print ((r.value/chances.n), 500, 4*dx+dx*i)
	end
end

function love.keypressed(key, scancode, isrepeat)
	if key == "space" then
		reroll ()
		updateChances ()
	elseif key == "p" then
		pause = not pause
	elseif key == "escape" then
		love.event.quit()
	end
end
Attachments
2023-11-06T12_25_11-Untitled.png
2023-11-06T12_25_11-Untitled.png (29.77 KiB) Viewed 16958 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Boids - flocking simulation in toroidal world

Code: Select all

Width,Height = love.graphics.getDimensions()
love.window.setTitle ('Boids - Flocking Simulation')
love.graphics.setLineWidth (3)


-- Define boids class
Boids = {}

Toroidal = {}

function Toroidal.position (x,y , width,height)
	x = (x + width) % width
	y = (y + height) % height
	return x, y
end

function Toroidal.positionDifference(x1, y1, x2, y2, width, height)
	local dx = x2 - x1
	local dy = y2 - y1
	dx = (dx + width / 2) % width - width / 2
	dy = (dy + height / 2) % height - height / 2

	return dx, dy
end


function Toroidal.sqdistance (x1,y1, x2,y2, width,height)
	local dx = math.abs(x1 - x2)
	local dy = math.abs(y1 - y2)

	dx = math.min(dx, width - dx)
	dy = math.min(dy, height - dy)
	return dx*dx + dy*dy
end

function Toroidal.distance (x1,y1, x2,y2, w,h)
	return math.sqrt(Toroidal.sqdistance (x1,y1, x2,y2, w,h))
end


function Boids.newBoid(x, y)
	local boid = {}
	boid.x = x
	boid.y = y
	boid.speed = 200
	local angle = math.random() * 2 * math.pi
	boid.vx = boid.speed * math.cos (angle)
	boid.vy = boid.speed * math.sin (angle)
	boid.angle = angle

	boid.radius = 6
	return boid
end


function Boids:updateAcceleration(boid)
	local separationRadius = 80
	local separation = 20
	local alignmentRadius = 50
	local alignment = 1
	local cohesionRadius = 50
	local cohesion = 1
	local friction = 1/8

	local sepX = 0
	local sepY = 0
	local alignX = 0
	local alignY = 0
	local cohesionX = 0
	local cohesionY = 0
	local total = 0

	for _, other in ipairs(self.boids) do
		if not (boid == other) then
			local diffX, diffY = Toroidal.positionDifference (other.x,other.y, boid.x,boid.y, Width,Height)

			local distance = math.sqrt(diffX*diffX + diffY*diffY)
			local reaction = false
			if distance > 0 then
				if distance < separationRadius then
					sepX = sepX + diffX / distance
					sepY = sepY + diffY / distance
					reaction = true
				end
				if distance < alignmentRadius then
					alignX = alignX + other.vx
					alignY = alignY + other.vy
					reaction = true
				end
				if distance < cohesionRadius then
					cohesionX = cohesionX + diffX
					cohesionY = cohesionY + diffY
					reaction = true
				end
				if reaction then
					total = total + 1
				end
			end

			
		end
	end

	if total > 0 then
		sepX = sepX / total
		sepY = sepY / total

		alignX = alignX / total
		alignY = alignY / total

		cohesionX = boid.x + cohesionX / total
		cohesionY = boid.y + cohesionY / total


		-- Apply the rules
		sepX = sepX * separation
		sepY = sepY * separation

		alignX = alignX * alignment
		alignY = alignY * alignment

		cohesionX = (cohesionX - boid.x) * cohesion
		cohesionY = (cohesionY - boid.y) * cohesion

		local frictionX = boid.vx * friction
		local frictionY = boid.vy * friction

		boid.ax = sepX + alignX + cohesionX - frictionX
		boid.ay = sepY + alignY + cohesionY - frictionY

	else
		local frictionX = boid.vx * friction
		local frictionY = boid.vy * friction
		
		boid.ax = -frictionX 
		boid.ay = -frictionY 
	end


end

function Boids:updateVelocity()
	local vx, vy = 0, 0
	for _, boid in ipairs(Boids.boids) do
		vx = vx + boid.vx
		vy = vy + boid.vy
	end
	vx = vx / #Boids.boids
	vy = vy / #Boids.boids
	for _, boid in ipairs(Boids.boids) do
		boid.vx = boid.vx - vx
		boid.vy = boid.vy - vy
	end
end

function Boids:updatePosition(boid, dt)
	-- Update velocity
	boid.vx = boid.vx + dt * boid.ax
	boid.vy = boid.vy + dt * boid.ay

	-- limit speed
	local speed = math.sqrt(boid.vx^2 + boid.vy^2)
	if speed > boid.speed then
		local factor = boid.speed / speed
		boid.vx = boid.vx * factor
		boid.vy = boid.vy * factor
	end
	if speed > 0 then
		boid.angle = math.atan2 (boid.vy, boid.vx)
	end
	

	-- Update position
	boid.x, boid.y = Toroidal.position(boid.x + boid.vx*dt, boid.y + boid.vy*dt, Width, Height)
	
end

function love.load()
	-- Create a set of boids
	Boids.boids = {}
	for i = 1, 50 do
		local boid = Boids.newBoid(
			math.random(0, love.graphics.getWidth()), 
			math.random(0, love.graphics.getHeight())
		)
		table.insert(Boids.boids, boid)
	end
end

function love.update(dt)
	for _, boid in ipairs(Boids.boids) do
		Boids:updateAcceleration(boid)
	end

--	Boids:updateVelocity()

	for _, boid in ipairs(Boids.boids) do
		Boids:updatePosition(boid, dt)
	end
	
	local boid = Boids.boids[1]
	boid.vx = 0
	boid.vy = 0
	boid.x = Width/2
	boid.y = Height/2
	
	boid.x = love.mouse.getX ()
	boid.y = love.mouse.getY ()
	
end

local function drawBoid (mode, x, y, length, width , angle) -- position, length, width and angle
	love.graphics.push()
	love.graphics.translate(x, y)
	love.graphics.rotate( angle )
	love.graphics.polygon(mode, -length/2, -width /2, -length/2, width /2, length/2, 0)
	love.graphics.pop() 
end

function love.draw()
	love.graphics.clear()

	-- Draw boids
	for _, boid in ipairs(Boids.boids) do
--		love.graphics.circle("fill", boid.x, boid.y, boid.radius)
--		love.graphics.line (boid.x, boid.y, boid.x-boid.vx/10, boid.y-boid.vy/10)
		drawBoid  ('line', boid.x, boid.y, boid.radius*4, boid.radius*2 , boid.angle)
		
	end
end
Attachments
boids-flocking-simulation-01.png
boids-flocking-simulation-01.png (24.93 KiB) Viewed 16779 times
boids-flocking-simulation-01.love
(2.4 KiB) Downloaded 297 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 8 guests