Check if player is looking

Post Reply
User avatar
Extex
Member
Posts: 244
Joined: Wed Mar 14, 2018 23:14
GitHub: Extex101
In-game: Extex

Check if player is looking

by Extex » Post

How can I check if an entity is within the players view?
And have it work for multiple players
Creator of jelys_pizzaria and motorbike, and player of persistent kingdoms. RIP

User avatar
Krock
Developer
Posts: 4650
Joined: Thu Oct 03, 2013 07:48
GitHub: SmallJoker
Location: Switzerland
Contact:

Re: Check if player is looking

by Krock » Post

The FOV value is not exposed to the Lua API, although you could calculate the "top down" X/Z angle between the player's line of sight and the object position.

Demo:
Image

You could also use the dot product of the two vectors to check whether it's within 90°.
Attachments
geometry.png
geometry.png (8 KiB) Viewed 388 times
Last edited by Krock on Mon Jul 08, 2019 17:51, edited 1 time in total.
Look, I programmed a bug for you. >> Mod Search Engine << - Mods by Krock - DuckDuckGo mod search bang: !mtmod <keyword here>

User avatar
Extex
Member
Posts: 244
Joined: Wed Mar 14, 2018 23:14
GitHub: Extex101
In-game: Extex

Re: Check if player is looking

by Extex » Post

XD I don't what that means
Isn't there something called raycast or something like that that makes it so you can check.
EDIT: My comment said caked instead of called (stupid auto correct)
Last edited by Extex on Mon Jul 08, 2019 23:47, edited 1 time in total.
Creator of jelys_pizzaria and motorbike, and player of persistent kingdoms. RIP

neoh4x0r
Member
Posts: 82
Joined: Wed Aug 29, 2018 20:16
GitHub: neoh4x0r

Re: Check if player is looking

by neoh4x0r » Post

Extex wrote:XD I don't what that means
Isn't there something caked raycast or something like that that makes it so you can check.
See: https://mathinsight.org/dot_product
and: https://www.mathsisfun.com/algebra/vect ... oduct.html
The dot product of a with unit vector u, denoted a⋅u, is defined to be the projection of a in the direction of u,
or the amount that a is pointing in the same direction as unit vector u.

Code: Select all

(a dot b) = ||a|| ||b|| cos θ
-----------------
(a dot b) = vector dot product:

Code: Select all

(x1,y1) dot (x2,y2) = (x1 * x2) + (y1 * y2)
(x1,y1,z1) dot (x2,y2,z2) = (x1 * x2) + (y1 * y2) + (z1 * z2)
-----------------
||a|| = The length of a:

Code: Select all

||(x,y)|| = SQRT(x^2 + y^2)
||(x,y,z)|| = SQRT(x^2 + y^2 + z^2)
-----------------

You want to determine the angle between vectors a and b such that
it lies within the wanted range of [0 to 90 degs] or [0 to 1.57 rads, 0 to π/2 rads].

1) calcuate (a dot b)
2) calcuate ||a|| and ||b|| -- multiply the two values together
3) plug in vaules from step 1 and 2 into: (a dot b) = ||a|| ||b|| cos θ

EG:

STEP1 = STEP2 * cos θ
STEP1/STEP2 = cos θ
arccos(STEP1/STEP2) = θ ; θ must be between 0 and 90 degrees
-----------------

If a visual representation is needed the first link: https://mathinsight.org/dot_product
has an interactive representation of this (where you can move the vectors around, etc and get a
good idea of what is actually happening)

User avatar
Extex
Member
Posts: 244
Joined: Wed Mar 14, 2018 23:14
GitHub: Extex101
In-game: Extex

Re: Check if player is looking

by Extex » Post

O_O XD could someone just give me a snippet?
I don't understand these super complicated math things
Or even how I'd put it to code
Isn't there just like a

Code: Select all

if minetest.in_player_view() then
    --Code
end
Creator of jelys_pizzaria and motorbike, and player of persistent kingdoms. RIP

User avatar
Extex
Member
Posts: 244
Joined: Wed Mar 14, 2018 23:14
GitHub: Extex101
In-game: Extex

Re: Check if player is looking

by Extex » Post

Or maybe like:

Code: Select all

local pitch = player:get_look_vertical()
local yaw = player:get_yaw()
local angle = 180
local view = minetest.get_in_range(pos, pitch, yaw, angle)
local entities_in_view = view.objects
--code that makes it run one thing at a time
if entities_in_view[0] then
   --do something
end
Creator of jelys_pizzaria and motorbike, and player of persistent kingdoms. RIP

User avatar
AiTechEye
Member
Posts: 1000
Joined: Fri May 29, 2015 21:14
GitHub: AiTechEye
Location: Sweden

Re: Check if player is looking

by AiTechEye » Post

if you don't know physics this works fine, it compare if the object is front of the player (if the object is farther then a position front of the player)

Code: Select all

viewfield=function(player,ob)
	local pos1=player:get_pos()
	local pos2 = ob:get_pos()
	local d = player:get_look_dir()
	return vector.distance(pos1,pos2)>vector.distance({x=pos1.x+d.x,y=pos1.y+d.y,z=pos1.z+d.z},pos2)
end
Image
Attachments
s.png
s.png (1.08 KiB) Viewed 388 times

User avatar
AiTechEye
Member
Posts: 1000
Joined: Fri May 29, 2015 21:14
GitHub: AiTechEye
Location: Sweden

Re: Check if player is looking

by AiTechEye » Post

i was trying the angle stuff, and it looks like this

Code: Select all

local A = math.sqrt(pos1.x^2+pos1.y^2)
local B = math.sqrt(pos2.x^2+pos2.y^2)
local dot = (pos1.x*pos2.x)+(pos1.y*pos2.y)

local A1=dot
local A2=A*B

print(math.acos(A1/A2),user:get_look_horizontal())
but now?

neoh4x0r
Member
Posts: 82
Joined: Wed Aug 29, 2018 20:16
GitHub: neoh4x0r

Re: Check if player is looking

by neoh4x0r » Post

AiTechEye wrote:i was trying the angle stuff, and it looks like this

Code: Select all

local A = math.sqrt(pos1.x^2+pos1.y^2)
local B = math.sqrt(pos2.x^2+pos2.y^2)
local dot = (pos1.x*pos2.x)+(pos1.y*pos2.y)

local A1=dot
local A2=A*B

print(math.acos(A1/A2),user:get_look_horizontal())
but now?
Yes, that math is correct based on the formulas I posted.
The dot product is positive for acute angles and negative for obtuse angles.
You can see this in action using the interactive applet from mainsight.org:

Code: Select all

https://mathinsight.org/dot_product#applet:dot_product_projection

Code: Select all

local result = math.acos(A1/A2) -- this just another way of saying (a dot b)/||b||
-- local result = A1 / B
local limit = 10 -- limit length of a to some value
if (result < 0 or A > limit) then
 -- object/entity not in view (negative value, obtuse angle, > 90 degs) (or too far away)
else
 -- object/entity  in view (zero or a positive value, acute angles, 0 to 90 degs)
end
------------------------
NOTE: the project of a onto b results in essentially quantifying how much of a intersects b (if a were in the same direction as a b).

When the result is zero, a and b do not intersect, because they are perpendicular (ie a in the direction of b result in a zero-length vector).

If a is longer than b it might be prudent to limit the result to a specific distance.

Also:
a⋅b = ∥a∥∥b∥cos θ -- the projection of a in the direction of b
(a⋅b)/∥b∥ = ∥a∥cos θ -- the projection of a onto b

Another issue is that the above code does not take into account the z coordinate and will only check
if a and b are in a 2-d space ... (ie the result is the same regardless of whether the entity is above or below the player).

----
This will take into account the z-coordinate:

Code: Select all

local A = math.sqrt(pos1.x^2+pos1.y^2+pos1.z^2)
local B = math.sqrt(pos2.x^2+pos2.y^2+pos2.z^2)
local dot = (pos1.x*pos2.x)+(pos1.y*pos2.y)+(pos1.z*pos2.z) 
get_look_horizontal --returns yaw in radians (this is not a vector)
I'll make another post describing how to get a look_vector once I run through the math.

neoh4x0r
Member
Posts: 82
Joined: Wed Aug 29, 2018 20:16
GitHub: neoh4x0r

Re: Check if player is looking

by neoh4x0r » Post

neoh4x0r wrote:get_look_horizontal --returns yaw in radians (this is not a vector)
I'll make another post describing how to get a look_vector once I run through the math.
I have worked out the math by creating a test mod and have confirmed that the below code works.

Code: Select all

local function get_entity_in_view(player,entity)
 local Vp = player:get_pos()           -- get the player's position
 local Ve = entity:get_pos()             -- get the position position of the entity
 local Dc = player:get_look_dir()    -- the camera direction as a normalized vector (unit vector, length=1)

 local Vpe = vector.subtract(Ve, Vp)    -- point to entity from player's position
 local Dpe = vector.normalize(Vpe)     -- create a unit vector from this new vector

 local a = Dpe                                          -- set vector a to entities direction
 local b = Dc                                           -- set vector b to camera direction

 local dot = (a.x * b.x) + (a.y * b.y) + (a.z * b.z)    -- calculate (a dot b)

 -- The equation to derive the angle is: (a dot b) / |a||b| = cos θ
 -- However, the length of a and b are 1 when using normalized (unit) vectors 
 -- so the equation becomes: (a dot b) = cos θ  ... and  θ = arccos(a dot b)

 local angle_rads = math.acos(dot)
 local angle_degs = angle_rads * (180 / math.pi)


 -- note1: that as the distance between the player and entity decreases the viewing angle becomes larger
 -- probably due to how minetest distorts the worlds around the edges (perspective transform)
 -- so if the player is very cose the entity the max angle might need to be increase to 70 degrees
 
 -- note2: 45 degrees is the max here, because the angle is measured for half of the field-of-view
-- the total FOV is 90 degrees
 if angle_degs < 0 or angle_degs > 45 then
  print("entity not in view")
 else
  print("entity in view")
 end
end

User avatar
AiTechEye
Member
Posts: 1000
Joined: Fri May 29, 2015 21:14
GitHub: AiTechEye
Location: Sweden

Re: Check if player is looking

by AiTechEye » Post

I have worked out the math by creating a test mod and have confirmed that the below code works.
your posted code looks pretty easy, but for us that don't know advanced math this math was just impossible to even guess how it works, thanks a lot :)

i was changing the code, so now entityes can see too

player or entity (ob1) see ob2

Code: Select all

local function in_view(ob1,ob2)
	local p1 = ob1:get_pos()
	local a = vector.normalize(vector.subtract(ob2:get_pos(), p1))
	local b
	if ob1:get_luaentity() then
		local yaw = math.floor(ob1:get_yaw()*100)/100
		b = {x=math.sin(yaw)*-1,y=0,z=math.cos(yaw)*1}
	elseif ob1:is_player() then
		b=ob1:get_look_dir()
	else
		return false
	end
	local deg = math.acos((a.x*b.x)+(a.y*b.y)+(a.z*b.z)) * (180 / math.pi)
	return not (deg < 0 or deg > 50) --45 ... cuz minetest is using a somewhat wide screen size
end

neoh4x0r
Member
Posts: 82
Joined: Wed Aug 29, 2018 20:16
GitHub: neoh4x0r

Re: Check if player is looking

by neoh4x0r » Post

@AiTechEye
I was just looking at the latest logs on github for minetest and I came across this commit:
https://github.com/minetest/minetest/co ... 2ae25d719a
Add vector.dot and vector.cross
Mostly copied from MarkuBu's code
So your this part of your code can be changed from (also using math.deg)

Code: Select all

   local deg = math.acos((a.x*b.x)+(a.y*b.y)+(a.z*b.z)) * (180 / math.pi)
to this:

Code: Select all

   local deg = math.deg(math.acos(vector.dot(a,b))
Also you can use vector.direction(a,b) instead of calling vector.subtract and then normalize.

Code: Select all

local a = vector.direction(p1, ob2:get_pos())
The various methods can be found here:
https://github.com/minetest/minetest/bl ... vector.lua

Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests