ID:269390
 
I'm looking to obtain the math for a directional light. The known things about the light are the FOV(Field of view) in degrees, direction, and the range it will light up, which is determined by some other factors of the light. Here's what a light might look like with a FOV of 45 degrees, a direction of 0 degrees, and a range of 5:

X = lighted turf
- = basic turf
P = light source

--XXX--
XXXXXXX
-XXXXX-
--XXX--
---X---
---P---

I've looked at Bresenham's circle drawing algorithm, and even some raycasting stuff for some insight, but I'm still lost.

Prodigal Squirrel
Essentially, you're looking for every turf within a certain distance, between two angles. So we have the field of view as fov (in degrees), the direction as a, and the range as r, from m. You'd do something like this (psuedocode)

var/list/l = turfs in view(r)
var/list/r=list()
for(var/turf/t in l) if(arctan((t.y-m.y)/(t.x-m.x))>(a-(fov/2)) and <(a+(fov/2))) r+=t


Note that that entire thing is pseudocode, and you still need an arctan() function. LummoxJr wrote up one a while ago, a forum search will find it.
In response to Jp
Thanks for effort... But it didn't work. =/

This is what I ended up coming out with:

            var/halffov=fov/2
var/list/affected=list()
for(var/turf/t as turf in range(amount-1,))
var/_x=t.x-x
if(_x==0) continue //So we don't divide by zero, as it produces runtime errors
var/at=arctan((t.y-y)/_x)
if(at>(direction-halffov) && at<(direction+halffov))
affected+=t
for(var/turf/T as turf in affected)
if(T) T.SetIntensity(30)


Did I mess something up here?

P_S

[EDIT]I changed arctan to the arctan2 proc, and the it gives results pretty close to what I want. But not quite what I need. I don't know how to get around the division by 0 errors so it will use turfs on the same x axis. Also, attempting to give a direction of 180, srews up the light. It only seems to work with direction values between 0-135.

In response to Prodigal Squirrel
Hmmm... Forgot about divide by zero errors. I'll tell you what I'm trying to do so that you have an idea of what it was about:

You want to find some turfs that are within a certain range. Therefore, all these turfs will be in the list view(r) (or range, whichever is better). You're looking for turfs that make an angle with the player between playerdirection-(fov/2) and playerdirection+(fov/2). Isn't there a proc that gives you the approximate angle between two atoms?
The math you've described is actually a 90° FOV, which is fairly easy to handle with the code I posted in [link]. The only difference is, you don't start off one square ahead of the source, but at it. I.e., your diagram would look more like this:

--XXX--
XXXXXXX
-XXXXX-
--XXX--
---P---


Here P is at the tip of a triangle. Likewise if P faces a diagonal, it'll be on one corner of a square.

For calculations using arbitrary angles, you'd definitely need to use trig functions to accomplish that.

Lummox JR
In response to Jp
Well, that I understood from the get go. I didn't know which trig function to use, however. Now I do. It's just that, when the direction is between a certain range, the proc doesn't work. Also, I'm not sure how to get around the divide by zero errors. I thunk up a way that wasn't mathematical, but would work, and I thought there might be a mathematical way to avoid those errors instead.

Anyhow, thanks for the help!

P_S
In response to Prodigal Squirrel
You could check whether your looking for the arctan() of an undefined number and automatically stick the thing in. so:

if(t.x-m.x==0) r+=t
if(arctan(... blah blah blah)


That should get around divide-by-zero, and I think it should work. You'll have to test it.