World:rayCast (Français)

Disponible depuis LÖVE 0.8.0
Ce-tte method n'est pas supporté-e par des versions plus anciennes.

Émet un rayon et appelle une fonction pour chaque fixtures dans son intersection.

Fonction

Synopsis

World:rayCast( x1, y1, x2, y2, callback )

Arguments

number (Français) x1
Position en x du point de départ du rayon.
number (Français) y1
Position en y du point de départ du rayon.
number (Français) x2
Position en x du point d'arrivée du rayon.
number (Français) y2
Position en x du point d'arrivée du rayon.
function (Français) callback
Fonction appelée pour chaque fixture ayant une intersection avec le rayon. La fonction prend six arguments et doit retourner un nombre comme valeur de contrôle. Les points d'intersection donné à la fonction le seront dans un ordre arbitraire. Si vous désirez trouvez le point d'intersection le plus proche, vous devez faire le test vous même au sein de la fonction. La façon la plus simple de le faire est en utilisation la valeur de la fraction.

Retourne

Rien.

Fonction de rappel

Synopsis

control = callback( fixture, x, y, xn, yn, fraction )

Arguments

Fixture (Français) fixture
La fixture en intersection avec le rayon.
number (Français) x
La position en x du point d'intersection.
number (Français) y
La position en y du point d'intersection.
number (Français) xn
La valeur x du vecteur normal de la surface du bord de la forme.
number (Français) yn
La valeur y du vecteur normal de la surface du bord de la forme.
number (Français) fraction
La position de l'intersection sur le rayon sous forme de nombre compris entre 0 et 1 (ou bein plus élevé si la longueur du rayon a été changée par la valeur de retourn).

Retourne

number (Français) control
Le rayon peut être contrôlé par la valeur de retour. Une valeur positive défini une nouvelle longueur de rayon, où 1 est la valeur par défaut. Une valeur de 0 termine le rayon. Si la fonction de rappel retourne -1, l'intersection est ignorée comme si elle n'avait pas eu lieu.

Notes

Il y a un bug dans LÖVE 0.8.0 où le vecteur normal passé à la fonction de rappel est agrandit par love.physics.getMeter.

Exemples

Émettre un rayon vers différents formes aléatoires.

function worldRayCastCallback(fixture, x, y, xn, yn, fraction)
	local hit = {}
	hit.fixture = fixture
	hit.x, hit.y = x, y
	hit.xn, hit.yn = xn, yn
	hit.fraction = fraction

	table.insert(Ray.hitList, hit)

	return 1 -- Continue avec l'émission de rayon à travers toutes les formes.
end

function createStuff()
	-- Nettoie les choses précédentes.
	for i = #Terrain.Stuff, 1, -1 do
		Terrain.Stuff[i].Fixture:destroy()
		Terrain.Stuff[i] = nil
	end

	-- Génère quelques formes aléatoires.
	for i = 1, 30 do
		local p = {}

		p.x, p.y = math.random(100, 700), math.random(100, 500)
		local shapetype = math.random(3)
		if shapetype == 1 then
			local w, h, r = math.random() * 10 + 40, math.random() * 10 + 40, math.random() * math.pi * 2
			p.Shape = love.physics.newRectangleShape(p.x, p.y, w, h, r)
		elseif shapetype == 2 then
			local a = math.random() * math.pi * 2
			local x2, y2 = p.x + math.cos(a) * (math.random() * 30 + 20), p.y + math.sin(a) * (math.random() * 30 + 20)
			p.Shape = love.physics.newEdgeShape(p.x, p.y, x2, y2)
		else
			local r = math.random() * 40 + 10
			p.Shape = love.physics.newCircleShape(p.x, p.y, r)
		end

		p.Fixture = love.physics.newFixture(Terrain.Body, p.Shape)

		Terrain.Stuff[i] = p
	end
end

function love.keypressed()
	createStuff()
end

function love.load()
	-- Définit cela à 1 afin d'éviter tous les bugs de changement d'échelle actuels.
	love.physics.setMeter(1)

	-- Utilise les mêmes résultats aléatoires à chaque départ.
	math.randomseed(0xfacef00d)

	World = love.physics.newWorld()

	Terrain = {}
	Terrain.Body = love.physics.newBody(World, 0, 0, "static")
	Terrain.Stuff = {}
	createStuff()

	Ray = {
		x1 = 0,
		y1 = 0,
		x2 = 0,
		y2 = 0,
		hitList = {}
	}
end

function love.update(dt)
	local now = love.timer.getTime()

	World:update(dt)

	-- Nettoie la liste de collision de fixture.
	Ray.hitList = {}
	
	-- Calcule la position du rayon.
	local pos = (math.sin(now/4) + 1.2) * 0.4
	Ray.x2, Ray.y2 = math.cos(pos * (math.pi/2)) * 1000, math.sin(pos * (math.pi/2)) * 1000
	
	-- Émet le rayon et peuple la table de collisions.
	World:rayCast(Ray.x1, Ray.y1, Ray.x2, Ray.y2, worldRayCastCallback)
end

function love.draw()
	-- Trace le terrain.
	love.graphics.setColor(255, 255, 255)
	for i, v in ipairs(Terrain.Stuff) do
		if v.Shape:getType() == "polygon" then
			love.graphics.polygon("line", Terrain.Body:getWorldPoints( v.Shape:getPoints() ))
		elseif v.Shape:getType() == "edge" then
			love.graphics.line(Terrain.Body:getWorldPoints( v.Shape:getPoints() ))
		else
			local x, y = Terrain.Body:getWorldPoints(v.x, v.y)
			love.graphics.circle("line", x, y, v.Shape:getRadius())
		end
	end

	-- Trace le rayon.
	love.graphics.setLineWidth(3)
	love.graphics.setColor(255, 255, 255, 100)
	love.graphics.line(Ray.x1, Ray.y1, Ray.x2, Ray.y2)
	love.graphics.setLineWidth(1)

	-- Trace les points d'intersection et les vecteurs normaux, si il y en a eu.
	for i, hit in ipairs(Ray.hitList) do
		love.graphics.setColor(255, 0, 0)
		love.graphics.print(i, hit.x, hit.y) -- Prints the hit order besides the point.
		love.graphics.circle("line", hit.x, hit.y, 3)
		love.graphics.setColor(0, 255, 0)
		love.graphics.line(hit.x, hit.y, hit.x + hit.xn * 25, hit.y + hit.yn * 25)
	end
end
Capture d'écran de l'example.

Voir également


Autres langues