World:rayCast (日本語)

LÖVE 0.8.0 から使用可能
このメソッドは以前のバージョンでは非対応です。

斜線計算を行い、それと交差する取付具がある関数を呼び出します。コールバックの順序に関しては推定することができません。

関数の呼び出し毎に、六種類の引数が関数へ渡されます。

概要

function callback(fixture, x, y, xn, yn, fraction)
   return 1
end

引数

Fixture fixture
斜線と交差する取付具。
number x
交差地点の x 位置。
number y
交差地点の y 位置。
number xn
形状の端にある表面法線ベクトル x 値。
number yn
形状の端にある表面法線ベクトル y 値。
number fraction
0 から 1 までの数値とした斜線上にある交差の位置です (または斜線の長さが返値で変更されたものと同等の高さ)。

返値

number
斜線は返値により制御できます。標準値は 1 であり正数にて斜線の長さを新規設定します。値 0 は斜線の終端です。コールバック関数で -1 が返される場合は、何も発生せず公差は無視されます。

注釈

LÖVE 0.8.0 ではコールバック関数へ渡される法線ベクトルは love.physics.getMeter により尺度変更されてしまう不具合があります。

関数

概要

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

引数

number x1
斜線の始点として x 位置。
number y1
斜線の始点として y 位置。
number x2
斜線の終点として x 位置。
number y2
斜線の終点として y 位置。
function callback
この関数は六種類の引数を取得して必ず数値を返します。

返値

ありません。

用例

いくつかの無作為な形状に対して斜線計算します。

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 -- 全ての形状に対して斜線計算を継続します。
end

function createStuff()
	-- 以前の要素を消去します。
	for i = #Terrain.Stuff, 1, -1 do
		Terrain.Stuff[i].Fixture:destroy()
		Terrain.Stuff[i] = nil
	end

	-- いくつか形状を無作為に生成します。
	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()
	-- ここで現在の尺度に対する不具合を回避するために 1 を設定します。
	love.physics.setMeter(1)

	-- 開始ごとに同じ要素を無作為に開始します。
	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)

	-- 取付具の当たる一覧の消去。
	Ray.hitList = {}
	
	-- 斜線位置の計算。
	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
	
	-- 射線計算を行い hitList テーブルへ登録します。
	World:rayCast(Ray.x1, Ray.y1, Ray.x2, Ray.y2, worldRayCastCallback)
end

function love.draw()
	-- 地形の描画。
	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

	-- 斜線の描画。
	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)

	-- 存在する場合は交差地点および通常ベクトルを描画します。
	for i, hit in ipairs(Ray.hitList) do
		love.graphics.setColor(255, 0, 0)
		love.graphics.print(i, hit.x, hit.y) -- 地点のほかに当たり順を表示します。
		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
この用例の画面撮影。

関連


そのほかの言語