robhol Posted September 6, 2008 Share Posted September 6, 2008 Okay, I want to make a system for admins in my server, that will list all players that are approximately in front of the user's facing direction. I've made you guys a super paint illustration (>.>) to hopefully make it a bit clearer. I will of course have to loop through all the players and check something, I just have no idea about the math in this one. Help please? Link to comment
Ace_Gambit Posted September 6, 2008 Share Posted September 6, 2008 (edited) This is a function I've made some while ago. It is not perfect because it only takes 2 dimensions into account but it may give you an idea how to proceed. What it does is return true if target is within a certain angle of the source' line of sight. The parameters are as follows: source = any element representing the LOS source target = any element to test the angle against traceAngle = maximum angle to take into account (for example 20 degree) minDepth = minimal depth to take into account from source to target maxDepth = maximum depth to take into account from source to target minOffsetZ = minimal height offset to take into account from source to target minOffsetZ = maximum height offset to take into account from source to target function testTargetAngleAgainstLoS(source, target, traceAngle, minDepth, maxDepth, minOffsetZ, maxOffsetZ) local oX, oY, oZ = getElementPosition(source) local rotX, rotY, rotZ = getObjectRotation(source) local tX, tY, tZ = getElementPosition(target) local targetDist2D = getDistanceBetweenPoints2D(oX, oY, tX, tY) local losX, losY, losZ = oX, oY, oZ local btX, btY, btZ = oX, oY, oZ local btDist2D = 0 local pX2D, pY2D = 0, 0 local pDist2D = 0 local ptotDist2D = 0 local angle = 0 if (targetDist2D < minDepth or targetDist2D > maxDepth or tZ < (oZ - minOffsetZ) or tZ > (oZ + maxOffsetZ)) then return end losX = losX - math.sin(math.rad(rotZ)) * targetDist2D losY = losY + math.cos(math.rad(rotZ)) * targetDist2D btX = btX - math.sin(math.rad(rotZ + 180)) * targetDist2D btY = btY + math.cos(math.rad(rotZ + 180)) * targetDist2D btDist2D = getDistanceBetweenPoints2D(btX, btY, tX, tY) if (tX > losX) then pX2D = tX - (math.abs(tX - losX) / 2) else pX2D = losX - (math.abs(losX - tX) / 2) end if (tY > losY) then pY2D = tY - (math.abs(tY - losY) / 2) else pY2D = losY - (math.abs(losY - tY) / 2) end pDist2D = getDistanceBetweenPoints2D(oX, oY, pX2D, pY2D) ptotDist2D = getDistanceBetweenPoints2D(pX2D, pY2D, tX, tY) angle = math.deg(math.tan(ptotDist2D / pDist2D)) * 2 return (angle > 0 and angle < traceAngle and targetDist2D < btDist2D) end Edited September 6, 2008 by Guest Link to comment
robhol Posted September 6, 2008 Author Share Posted September 6, 2008 Thanks, and the Z coord is not a problem, since it should not be evaluated at all, the function should be 2D. Link to comment
Mr.Hankey Posted September 6, 2008 Share Posted September 6, 2008 what about isElementOnScreen ?! Link to comment
Gamesnert Posted September 6, 2008 Share Posted September 6, 2008 what about isElementOnScreen ?! No, he means in the entire map. So if he looks at direction 123 for example, he wants to be able to see if there are any players near his sight. No matter the range. As you can see in the example, he wants to see over an extremely long range. Link to comment
robhol Posted September 6, 2008 Author Share Posted September 6, 2008 Yes.. i'll play with Ace's code and it'll prolly work out. And i need to download some ebooks on trigonometry.. Link to comment
Ace_Gambit Posted September 6, 2008 Share Posted September 6, 2008 This is what I used. http://www.euclideanspace.com/maths/alg ... /index.htm Link to comment
Scarface Posted September 6, 2008 Share Posted September 6, 2008 very nice guys cant wait to test it! Link to comment
DefiniteIntegral Posted September 7, 2008 Share Posted September 7, 2008 A dot product might be a bit easier and faster perhaps, as it only requires a few lines of code. Here is an example for finding the angle between two players relative to source rotation. This is 2d only as requested by opening poster. function findAngle(sourcePlayer, targetPlayer) local sourceX, sourceY, sourceZ = getElementPosition(sourcePlayer) local sourceRotX, sourceRotY, sourceRotZ = getPedRotation(sourcePlayer) local targetX, targetY, targetZ = getElementPosition(targetPlayer) -- get relative position local relativePosX = targetX - sourceX local relativePosY = targetY - sourceY -- get distance local distance = math.sqrt(relativePosX*relativePosX + relativePosY*relativePosY) -- normalize relativePosX = relativePosX / distance relativePosY = relativePosY / distance -- get source angle vector. should already be normalized. I might have sin and cos the wrong way around.. local sourceVecX = math.sin(math.rad(360-sourceRotZ)) local sourceVecY = math.cos(math.rad(360-sourceRotZ)) -- use dot product to find cos of angle between vectors local dotProduct = (sourceVecX * relativePosX) + (sourceVecY * relativePosY) -- return acos of dot product. convert angle to degrees before returning. return math.deg(math.acos(dotProduct)) end This function will return a value between 0 and 180 representing angle away from the direction the admins player model is facing. Of course it might be more convenient for the admin to use camera angle instead of ped angle. Link to comment
Gamesnert Posted September 7, 2008 Share Posted September 7, 2008 A dot product might be a bit easier and faster perhaps, as it only requires a few lines of code.Here is an example for finding the angle between two players relative to source rotation. This is 2d only as requested by opening poster. function findAngle(sourcePlayer, targetPlayer) local sourceX, sourceY, sourceZ = getElementPosition(sourcePlayer) local sourceRotX, sourceRotY, sourceRotZ = getPedRotation(sourcePlayer) local targetX, targetY, targetZ = getElementPosition(targetPlayer) -- get relative position local relativePosX = targetX - sourceX local relativePosY = targetY - sourceY -- get distance local distance = math.sqrt(relativePosX*relativePosX + relativePosY*relativePosY) -- normalize relativePosX = relativePosX / distance relativePosY = relativePosY / distance -- get source angle vector. should already be normalized. I might have sin and cos the wrong way around.. local sourceVecX = math.sin(math.rad(360-sourceRotZ)) local sourceVecY = math.cos(math.rad(360-sourceRotZ)) -- use dot product to find cos of angle between vectors local dotProduct = (sourceVecX * relativePosX) + (sourceVecY * relativePosY) -- return acos of dot product. convert angle to degrees before returning. return math.deg(math.acos(dotProduct)) end This function will return a value between 0 and 180 representing angle away from the direction the admins player model is facing. Of course it might be more convenient for the admin to use camera angle instead of ped angle. Good piece of code. However, I fear it's not what he's looking for... He's looking for something that shows ALL players in an angle just a bit bigger than his sight. And the looking depth as far away as you want. Link to comment
DefiniteIntegral Posted September 7, 2008 Share Posted September 7, 2008 However, I fear it's not what he's looking for... He's looking for something that shows ALL players in an angle just a bit bigger than his sight. And the looking depth as far away as you want. Well yes, obviously. I just assumed he was competent enough to apply that function to all players on the server, and compare the returned angle with some predetermined limiting factor, say a 45 degree angle. function getAllPlayersWithinAngleRangeOfSource(sourcePlayer, angleLimit) local returnPlayerList = {} for i,player in pairs(g_Players) do if findAngle(sourcePlayer, player) <= angleLimit then table.insert(returnPlayerList, player) end end return returnPlayerList end Can you return tables in this manner? I forget. This should cover all users regardless of distance. Anyway something like this is kind of basic, if a scripter can't even figure that out what chance does he really stand making something good anyway? Oh well everything learned is progress on the way I suppose Link to comment
Gamesnert Posted September 7, 2008 Share Posted September 7, 2008 However, I fear it's not what he's looking for... He's looking for something that shows ALL players in an angle just a bit bigger than his sight. And the looking depth as far away as you want. Well yes, obviously. I just assumed he was competent enough to apply that function to all players on the server, and compare the returned angle with some predetermined limiting factor, say a 45 degree angle. function getAllPlayersWithinAngleRangeOfSource(sourcePlayer, angleLimit) local returnPlayerList = {} for i,player in pairs(g_Players) do if findAngle(sourcePlayer, player) <= angleLimit then table.insert(returnPlayerList, player) end end return returnPlayerList end Can you return tables in this manner? I forget. This should cover all users regardless of distance. Anyway something like this is kind of basic, if a scripter can't even figure that out what chance does he really stand making something good anyway? Oh well everything learned is progress on the way I suppose You can return them this way, but you can't output them this way. If you want to output them to the chatbox, you need table.concat. Which is simply something like: foodTable={"apples","bananas","kiwis"} --Example table... LOL outputChatBox("Foods: " .. table.concat(foodTable,", ") .. ".") That SHOULD return: Foods: apples, bananas, kiwis Might be that you already knew that, but just to be sure. Link to comment
DefiniteIntegral Posted September 7, 2008 Share Posted September 7, 2008 You can return them this way, but you can't output them this way.If you want to output them to the chatbox, you need table.concat. Which is simply something like: foodTable={"apples","bananas","kiwis"} --Example table... LOL outputChatBox("Foods: " .. table.concat(foodTable,", ") .. ".") That SHOULD return: Foods: apples, bananas, kiwis Might be that you already knew that, but just to be sure. Yeah, I decided to use a return type that is more generic. As in, it is easy to use a list of player pointers to do various tasks, like fetch and display names or perform other operations, but a list of names is pretty limiting in what you can do without additional work. I sure am not silly enough to try outputting an element pointer directly to a display function requiring string input Anyway, by now robhol should have enough information to set up his player scan just about any way he wants.. Sorry if my lingo is a bit off, I am accustomed to C/C++. I still think in terms of pointers / references.. I don't know how to 'talk lua' Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now