So, in a turn based game I am trying to have weapons have an arch of viable attack ranges, like the main gun can fire in a 90 degree arch from the front of the unit. I am trying to figure out what method to pursue for detecting if the enemy is within this arch or not, I have been looking at RayCast but it seems to be more in a line, I could I suppose use a bunch spread out over the 90 degrees, but that seems a little excessive if I am going to be having multiple weapons with different firing ranges, and angles.

Not sure what direction to pursue for research purposes, to discover making an arch shaped firing angle for detection purposes only, since hitting will all be calculated by code.

  • xRegnarokx angle_to_point() will give you an absolute angle of a line drawn between two points, this is not what you want.

    Instead you need to determine the angle between two direction vectors, one is unit's front axis (global_transform.x in your case) the other is the vector that goes from unit position to target position. So if this angle is less than half of your total spread angle - the target is inside. Since you already calculate the direction vector you can also check if its length is less than max distance. This gives you the full check:

    func is_target_in_range(source, target, spread_angle, distance_max):
    	var look_at_target = target.global_position - source.global_position
    	var look_at_front = source.global_transform.x
    	
    	# distance check
    	var distance = look_at_target.length()
    	if distance > distance_max:
    		return false
    		
    	# angle check
    	var angle = look_at_target.angle_to(look_at_front)
    	angle = rad_to_deg(abs(angle))
    	if angle > spread_angle/2:
    		return false
    		
    	# both checks passed, we're in range
    	return true

I would write my own math to figure it out. Since it's a turn-based game, using a physics collision doesn't seem necessary even though it would work just fine.

I assume you are only caring about two dimensions, which makes it easy. If this is 3D then you'd have to work with a cone instead.

Use your angle, i.e. 90°, with the weapon's position and facing to calculate two lines representing the firing arc. Then for each enemy you'd want to shoot, determine if they are both between those lines and in front of the gun. If both are true, then you know they're within the firing arc.

This method is rudimentary and would be very slow for a real-time game, but for a turn-based game with a discrete number of targets you're checking, it will do just what you want.

    award A way that I have been thinking of going about this would be to get the angle_to_point() and use that with the transformed position of the attacker to determine the angle of the ship relative to its rotation with the target.

    Something like this, haven't gone down the rabbit hole yet though.

    Var arch = range(-45, 46)
    If rad_to_deg(a.transform.x.angle_to_point(b)) == arch:

    Because it doesn't need to check all targets, just the one you right click. It will then check each weapon to see if it is within the firing range. Probably storing var arch on each weapon, putting the weapons in a group and using a for loop to check if the weapon is usable, if it is, activating it for use.

    • xyz replied to this.

      xRegnarokx angle_to_point() will give you an absolute angle of a line drawn between two points, this is not what you want.

      Instead you need to determine the angle between two direction vectors, one is unit's front axis (global_transform.x in your case) the other is the vector that goes from unit position to target position. So if this angle is less than half of your total spread angle - the target is inside. Since you already calculate the direction vector you can also check if its length is less than max distance. This gives you the full check:

      func is_target_in_range(source, target, spread_angle, distance_max):
      	var look_at_target = target.global_position - source.global_position
      	var look_at_front = source.global_transform.x
      	
      	# distance check
      	var distance = look_at_target.length()
      	if distance > distance_max:
      		return false
      		
      	# angle check
      	var angle = look_at_target.angle_to(look_at_front)
      	angle = rad_to_deg(abs(angle))
      	if angle > spread_angle/2:
      		return false
      		
      	# both checks passed, we're in range
      	return true

        There's also something call ShapeCast2D ;
        You could create a ShapeCast2D named ShotgunAttackingRange and enabled it when the player tries to shoot.

        xyz ahhh awesome. Thanks mate, that makes a lot of sense!