Solarus-Games English Forum

Solarus => Bugs & Feature requests => Topic started by: Manuel345 on August 23, 2016, 10:45:00 AM

Title: Line of sight
Post by: Manuel345 on August 23, 2016, 10:45:00 AM
I am trying to get a line-of-sight working for enemies to detect the hero.

I tried using an invisible custom entity going in a strait line towards the hero and stopping at any wall or impassable surface.
This unfortunately didn't go as planned.

I'm wondering if it would be possible to add a line-of-sight function, probably in sol.main alongside get_distance or maybe directly as a map entity method.


Here's a mockup of how I would use it:


function enemy:on_update()
  if self:get_line_of_sight(hero) then
    self.hasLOS = true
  else
    self.hasLOS = false
  end
end
Title: Re: Line of sight
Post by: Christopho on August 23, 2016, 11:21:54 AM
Using an invisible custom entity like you suggest should work. There is no such function in the API because every game would need different sights.
Title: Re: Line of sight
Post by: Manuel345 on August 23, 2016, 11:29:18 AM
Okay, thank you.

I'll try the invisible entity again, can't hurt to try a different approach.

One problem I had the first time is that the entity would sometimes pass through walls...
But the biggest problem is that I can't test for it on each update because the movement needs to move the entity...
Title: Re: Line of sight
Post by: Christopho on August 23, 2016, 11:39:10 AM
Use custom_entity:set_can_traverse_ground() and custom_entity:set_can_traverse_ground() to define what it can traverse or not.

Instead of a movement, you can make a loop that tries different positions of your entity, with entity:test_obstacles(dx, dy).
For example, to test if the entity can move 200 pixels to the right, try dx = 0 to 200.
Or use a movement with a high speed.
Title: Re: Line of sight
Post by: Manuel345 on August 23, 2016, 11:52:14 AM
Awesome, thanks a lot, I'll do a loop iterating through all positions from the enemy to the hero using test_obstacle!

Here's a mockup:


function line_of_sight(entity)
  local hasLOS = true
  local heroDistance = entity:get_distance(hero)
  local heroAngle = entity:get_angle(hero)

  for i=0, heroDistance do
    local dx, dy = math.cos(heroAngle)*i, -math.sin(heroAngle)*i
    if entity:test_obstacles(dx, dy) then
      hasLOS = false
      break
    end
  end

  return hasLOS
end


Edit It works, thank you so much!!! Also had to invert the Y for some reason, I guess Lua does its math in Cartesian coordinates (negative y towards the bottom)...

Included is the final script for anyone interested.
Title: Re: Line of sight
Post by: Christopho on August 23, 2016, 02:03:35 PM
Nice!
Y increases towards the bottom, yes, not because of Lua but because this is the usual standard to represent screen coordinates. So it is normal that you need to invert the Y coordinate (math.cos() and math.sin() use the math standard).