randomtoenailmonkey
randomtoenailmonkey

Reputation: 25

Pygame Raycasting for line of sight

I am making a 2d top-down shooter game and ideally I would like the enemies to only shoot at the player when they see him/her (so the player could hide behind a crate etc.)

I have done research and I think the best way to do this would be raycasting. I have not been able to find a good example of raycasting in pygame.

Alternatively, I saw this piece of code on a different stackoverflow question ( Pygame Line of Sight from Fixed Position )

def isInLine(player, person):
    deltaX = person[0] - player[0]
    deltaY = person[1] - player[1]

    if (person[0] == player[0]) or (person[1] == player[1]) or (abs(deltaX) == abs(deltaY)):
       return true

but I am not sure if it would accomplsih the kind of thing I want to and if it is I'm not sure how I would implement it.

What I am asking is firstly, would the code I am using accomplish what I wanted to do and if so how would I implement it and is there a better way to do it.

Upvotes: 0

Views: 2275

Answers (1)

Almonso
Almonso

Reputation: 51

I am assuming the variables 'player' and 'person' are the positions of the player and enemy? If so, the code you have added will check if either the two objects:

  • are in the same x position (person[0] == player[0])
  • are in the same y position (person[1] == player[1])
  • have equal x and y differences, i.e. the objects are at 45 degrees to each other ( abs(deltaX) == abs(deltaY) ).

This doesn't seem like what you want, however.

What might work is if you check if :

  • the angle between the enemy and barrier is equal to the angle between the enemy and the player. One way to do that is to use tan(angle) = opposite / adjacent, or deltaY / deltaX.

  • the enemy is further from the player than from the barricade. This can be done using pythagoras.

Here is a function for this which might help:

import math

def isInLine(enemy_pos, player_pos, barrier_pos):
   # get x and y displacements from enemy to objects
   playerDX = player_pos[0] - enemy_pos[0]
   playerDY = player_pos[1] - enemy_pos[1]
   barrierDX = barrier_pos[0] - enemy_pos[0]
   barrierDY = barrier_pos[1] - enemy_pos[1]

   # have to convert to degrees, as math uses radians
   playerAngle = math.degrees( math.atan(playerDY / playerDX) )
   barrierAngle = math.degrees( math.atan(barrerDY / barrierDX) )

   # use pythagoras to find distances
   playerDist = math.sqrt( (playerDX)**2 + (playerDY)**2 )
   barrierDist = math.sqrt( (barrierDX)**2 + (barrierDY)**2 )

   return (playerAngle == barrierAngle) and (playerDist > barrierDist)

So if the angles of the player and barrier from the enemy are equal, that are along the same line. If the enemy is also further from the player than from the barricade, the player is behind the barricade compared to the enemy.

EDIT: Actually this will only work if the line from the enemy to the barrier is exactly equal to the line from the enemy to the player. This might need editing to take into account the range of the barrier.

Upvotes: 1

Related Questions