Line Of Sight Function
I`ve created a Line-Of-Sight function that should work for most projects. It checks for map-collisions(using flag0 as the collision layer). Please use it and let me know what you do with it!
I was inspired by this post: https://www.lexaloffle.com/bbs/?tid=48889
But i wanted a simpler starting point for my own approach. A Line Of Sight check is a good starting point for you own approach but also involves some math. So to bypass that step use my function:

UPDATE 16/9/22
added a optional length-variable. Use it to define a max "range" of the that line. Keep in mind that the function already neglects far away points.
Also added a new break point for perfomance.
function can_see(x1,y1,x2,y2,length) --x1 and y1 are the point of view,length is the max distance of the two points local max_length=length or 1000 local xvec=0 local yvec=0 local len=0 local ret=true local tx=x1 local ty=y1 xvec=x2-x1 yvec=y2-y1 len=sqrt(xvec^2+yvec^2) if len==0 or len>max_length then ret=false end xvec=(xvec/len) yvec=(yvec/len) if ret then for i=1,len do tx+=xvec ty+=yvec if fget(mget(flr(tx/8),flr(ty/8)),0) then ret=false break end end end return ret end |
Features (if you're intrested)
- handling LOOONG Distances with a big "Nay" from the function
- always checking from x1/y1 point of view
- stopping when no more calculations are necessary
How it works
- set standard return to a yes (true)
- create a directional vector from 1 to 2
- calculate the distance of that vector
- check wether that distance is too big
- normalize it(max it out at 1) with that distance(so your steps don't get bigger than 8(which would skip a whole sprite, thus negating the whole point of this function))
- loop through incremental steps with that normalized vector
- check for collisions on each point
- if a collision occurs change the output to no and exit the loop to save power
How you might use it(and how i use it)
- Use it for a stealth game and combine it with the general direction the enemys are facing
- Use it for shooting stuff to see how far things will go
- Use it as a starting point for a raycast by returning the distance the ray traveled (I'd like to do that too)
- I'm making my first roguelike to learn about Mazecreations and get better at making fights fun (Which i'm terrible at)
- in this game the enemys, similar to that post linked above, remember the last point where they saw you and approach that point(the white dot). They also have a timer, so they only try to spot you every now and then.
You can find a minimal setup for the function right here:


Wow this is amazing! I'm saving this one to use on future games. Makes me glad to know you were inspired by my bullet trail approach :D yours is way more elegant! 10/10


Thank you! But yours had all the bells and whistles, mine is really just one part of your great system!


This should be possible to do without using SQRT() or exponent, @taxicomics.
Also does it register bricks not just below but above ?
Hmm ... This stands to write code.


Here now, your routine works perfectly !
Use arrow keys to control both sprites. Swap between which with ❎.


What do you mean by below or above?
If you`re talking about the width of the line-yes, i have been thinking about that. Maybe ill add another line so the FOV gets a little less tight, but that'll cost more power. But in some situations it might be able to see through a wall if the two tiles have just one joined corner.
And yes, i do remember that there was a neat way to avoid sqrt, but as i figured that my application only deals with numbers smaller than 128 i did not utilize it.


Actually no problems, @taxicomics. It works perfectly. Try the demo above to really see it works in all situations.
Well done, gold star work !


Thought I would try to recode that without the exponent or SQRT. Here is what I have:


function can_see2(a,b,c,d) local e,f=abs(a-c),abs(b-d) if (e<f) e=f e=max(1,e) repeat if (fget(mget(c\8,d\8),0)) return c+=(a-c)/e d+=(b-d)/e until a==(c+.5)\1 and b==(d+.5)\1 return true end |




Here is a further variation. This one checks only grid boxes assuming that all sprites to move in an 8x8 format.
Use arrow keys to navigate. Press ❎ to swap between control of sprite. If one can see the other, the background will tint dark blue, otherwise black.
The dots you see are the line of sight and optionally drawn in the function.


Hey, thanks for the rewrite! Intresting approches too, now this is the perfect compilation for everybody to choose a version depending on their needs. Good collab!


Yup ! Quite a few choices, @taxicomics. Now if I could just write AStar or MyStar in code as small or smaller than I've done above we'd be all set. :)
And yes, that would be a great internal function to add to future Pico-8.
_can_see(x1,y1,x2,y2,v,{sx,sy,ex,ey,{a[]})
x1 + y1 = coordinates of player. x2 + y2 = coordinates of target. v = value looked for. sx + sy = start of area to look (default 0,0) ex + ey = end of area to look (default 63,63) a = array, if not nil use array[sizex][sizey], otherwise if nil then use map() as normal. wallid=1 if _can_see(playerx,playery,enemyx,enemyy,wallid) then ... scrn={} for i=0,15 do scrn[i]={} for j=0,15 do scrn[i][j]=0 end end b=_can_see(playerx,playery,enemyx,enemyy,wallid,0,0,15,15,scrn) |


Those two bundled would be great! I haven't done any A-star-stuff yet, i used the native pathfinding in Godot but i never wrote my own.
But for A-Star you need a little more code around the function, so i think it is not as straightforward to implement as can_see(). But maybe if it is bundled with the movement and maybe a speed or time() variable, then it might be easier to use for beginners.
Like a Move_To(x1,y1,x2,y2,Speed_in_pixels,collision_flag) that returns the progress or proximity.


I added a new optional variable to the function that i needed in a new project. length, the optional fifth variable, now specifies the max length of that line of sight.
function can_see(x1,y1,x2,y2,length) --x1 and y1 are the point of view local max_length=length or 1000 local xvec=0 local yvec=0 local len=0 local ret=true local tx=x1 local ty=y1 xvec=x2-x1 yvec=y2-y1 len=sqrt(xvec^2+yvec^2) if len==0 or len>max_length then ret=false end xvec=(xvec/len) yvec=(yvec/len) if ret then for i=1,len do tx+=xvec ty+=yvec if fget(mget(flr(tx/8),flr(ty/8)),0) then ret=false break end end end return ret end |
[Please log in to post a comment]