Difference between revisions of "Blind Spots From First Principles"

From UFOpaedia
Jump to navigation Jump to search
Line 1: Line 1:
 
(Strictly speaking for XCOM1, but should generalize to XCOM2 and Apocalypse.)
 
(Strictly speaking for XCOM1, but should generalize to XCOM2 and Apocalypse.)
  
<i>[[User:Zaimoni|Zaimoni]]</i>: It's a parallelogram problem: the two lines of fire are not coincident, and the displacement between the firing point and the center is "just enough" to create the blind spot.
+
''[[User:Zaimoni|Zaimoni]]'': It's a parallelogram problem: the two lines of fire are not coincident, and the displacement between the firing point and the center is "just enough" to create the blind spot.
  
 
Facing table [firer is at relative coordinates (0,0)]
 
Facing table [firer is at relative coordinates (0,0)]
{|
+
{| class="wikitable"
 
! borderline facing || target || real facing
 
! borderline facing || target || real facing
 
|-
 
|-
| N-NE || (-2,1) || N/0 ||
+
| N-NE || (-2,1) || N/0  
 
|-
 
|-
| E-NE || (-1,2) || NE/1 ||
+
| E-NE || (-1,2) || NE/1
 
|-
 
|-
| E-SE || (1,2) || E/2 ||
+
| E-SE || (1,2) || E/2  
 
|-
 
|-
| S-SE || (2,1) || SE/3 ||
+
| S-SE || (2,1) || SE/3
 
|-
 
|-
| S-SW || (2,-1) || S/4 ||
+
| S-SW || (2,-1) || S/4
 
|-
 
|-
| W-SW || (1,-2) || SW/5 ||
+
| W-SW || (1,-2) || SW/5  
 
|-
 
|-
| W-NW || (-1,-2) || W/6 ||
+
| W-NW || (-1,-2) || W/6  
 
|-
 
|-
| N-NW || (-2,-1) || NW/7 ||
+
| N-NW || (-2,-1) || NW/7
 
|}
 
|}
  
 
Partial firing voxel table (from Seb76's work):
 
Partial firing voxel table (from Seb76's work):
{|
+
{| class="wikitable"
! facing || internal x-y coordinates of voxel ||
+
! facing || internal x-y coordinates of voxel
 
|-
 
|-
| N/0 || (8,1) ||
+
| N/0 || (8,1)
 
|-
 
|-
| NE/1 || (14,1) ||
+
| NE/1 || (14,1)
 
|-
 
|-
| E/2 || (15,8) ||
+
| E/2 || (15,8)  
 
|-
 
|-
| SE/3 || (15,15) ||
+
| SE/3 || (15,15)
 
|-
 
|-
| S/4 || (8,15) ||
+
| S/4 || (8,15)
 
|-
 
|-
| SW/5 || (1,15) ||
+
| SW/5 || (1,15)
 
|-
 
|-
| W/6 || (1,8) ||
+
| W/6 || (1,8)
 
|-
 
|-
| NW/7 || (1,1) ||
+
| NW/7 || (1,1)
 
|}
 
|}
  
Line 54: Line 54:
 
Without loss of generality, consider the ambusher to be at (0,0); we wish to identify squares with range 19 or less in (1..18,1..18) that should be ambushable.
 
Without loss of generality, consider the ambusher to be at (0,0); we wish to identify squares with range 19 or less in (1..18,1..18) that should be ambushable.
  
{|
+
{| class="wikitable"
 
! target || ambush line of fire || SE slope || targetable? || ambush?
 
! target || ambush line of fire || SE slope || targetable? || ambush?
 
|-
 
|-
Line 214: Line 214:
  
 
==See Also==
 
==See Also==
 
+
* [[Line of sight]]
[[Line of sight]]
+
* [[User talk:Bomb Bloke:Firing Accuracy]]
 
 
[[User talk:Bomb Bloke:Firing Accuracy]]
 

Revision as of 09:30, 25 May 2013

(Strictly speaking for XCOM1, but should generalize to XCOM2 and Apocalypse.)

Zaimoni: It's a parallelogram problem: the two lines of fire are not coincident, and the displacement between the firing point and the center is "just enough" to create the blind spot.

Facing table [firer is at relative coordinates (0,0)]

borderline facing target real facing
N-NE (-2,1) N/0
E-NE (-1,2) NE/1
E-SE (1,2) E/2
S-SE (2,1) SE/3
S-SW (2,-1) S/4
W-SW (1,-2) SW/5
W-NW (-1,-2) W/6
N-NW (-2,-1) NW/7

Partial firing voxel table (from Seb76's work):

facing internal x-y coordinates of voxel
N/0 (8,1)
NE/1 (14,1)
E/2 (15,8)
SE/3 (15,15)
S/4 (8,15)
SW/5 (1,15)
W/6 (1,8)
NW/7 (1,1)

(Following to be revised) Example: north wall in square 1 south of unit, ambusher unit facing SE (facing 3). Defender facing when returning fire is 7. Assuming a "sane" pixel-line drawing algorithm:

  • If the resulting firing line has classical SE slope strictly exceeding 2, the ambusher's firing line should hit the north wall and not be an issue.
  • If the classical SE slope is exactly 2, we have an edge case and the actual line-tracing algorithm determines whether the ambusher has a line of fire.
  • Due SE isn't a blind spot.
  • In both cases, we have a 8-pixel diagonal line (containing the endpoints) between the unit's centroid at (8,8) and the firing origin. The defender can return fire if his line of fire goes through the ambusher's firing origin, otherwise he is blind. [This only makes sense because we're analyzing in voxelspace.) The critical classical SE slope is 15/14; for this slope, the actual line-tracing algorithm determines whether the ambusher has a line of fire.

Without loss of generality, consider the ambusher to be at (0,0); we wish to identify squares with range 19 or less in (1..18,1..18) that should be ambushable.

target ambush line of fire SE slope targetable? ambush?
(2,1) ((-15, 15), (-40, 24)) 25/9 no
(3,2) ((-15, 15), (-56, 40)) 41/25 yes yes
(4,2) ((-15, 15), (-72, 40)) 57/25 no
(4,3) ((-15, 15), (-72, 56)) 57/41 yes yes
(5,3) ((-15, 15), (-88, 56)) 73/41 no
(5,4) ((-15, 15), (-88, 72)) 73/57 yes yes
(6,4) ((-15, 15), (-104, 72)) 89/57 yes yes
(7,4) ((-15, 15), (-120, 72)) 105/57 yes yes
(8,4) ((-15, 15), (-136, 72)) 121/57 yes yes
(6,5) ((-15, 15), (-104, 88)) 89/73 yes yes
(7,5) ((-15, 15), (-120, 88)) 105/73 yes yes
(8,5) ((-15, 15), (-136, 88)) 121/73 yes yes
(9,5) ((-15, 15), (-152, 88)) 137/73 yes yes
(10,5) ((-15, 15), (-168, 88)) 153/73 no
(7,6) ((-15, 15), (-120, 104)) 105/87 yes yes
(8,6) ((-15, 15), (-136, 104)) 121/87 yes yes
(9,6) ((-15, 15), (-152, 104)) 137/87 yes yes
(10,6) ((-15, 15), (-168, 104)) 153/87 yes yes
(11,6) ((-15, 15), (-184, 104)) 169/87 yes yes
(12,6) ((-15, 15), (-200, 104)) 185/87 no
(8,7) ((-15, 15), (-136, 120)) 121/103 yes yes
(9,7) ((-15, 15), (-152, 120)) 137/103 yes yes
(10,7) ((-15, 15), (-168, 120)) 153/103 yes yes
(11,7) ((-15, 15), (-184, 120)) 169/103 yes yes
(12,7) ((-15, 15), (-200, 120)) 185/103 yes yes
(13,7) ((-15, 15), (-216, 120)) 201/103 yes yes
(14,7) ((-15, 15), (-232, 120)) 217/103 no
(9,8) ((-15, 15), (-152, 136)) 137/119 yes yes
(10,8) ((-15, 15), (-168, 136)) 153/119 yes yes
(11,8) ((-15, 15), (-184, 136)) 169/119 yes yes
(12,8) ((-15, 15), (-200, 136)) 185/119 yes yes
(13,8) ((-15, 15), (-216, 136)) 201/119 yes yes
(14,8) ((-15, 15), (-232, 136)) 217/119 yes yes
(15,8) ((-15, 15), (-248, 136)) 233/119 yes yes
(10,9) ((-15, 15), (-168, 152)) 153/135 yes yes
(11,9) ((-15, 15), (-184, 152)) 169/135 yes yes
(12,9) ((-15, 15), (-200, 152)) 185/135 yes yes
(13,9) ((-15, 15), (-216, 152)) 201/135 yes yes
(14,9) ((-15, 15), (-232, 152)) 217/135 yes yes
(15,9) ((-15, 15), (-248, 152)) 233/135 yes yes
(11,10) ((-15, 15), (-184, 168)) 169/151 yes yes
(12,10) ((-15, 15), (-200, 168)) 185/151 yes yes
(13,10) ((-15, 15), (-216, 168)) 201/151 yes yes
(14,10) ((-15, 15), (-232, 168)) 217/151 yes yes
(12,11) ((-15, 15), (-200, 184)) 185/167 yes yes
(13,11) ((-15, 15), (-216, 184)) 201/167 yes yes
(14,11) ((-15, 15), (-232, 184)) 217/167 yes yes
(13,12) ((-15, 15), (-216, 200)) 201/183 yes yes

[Yes, strictly speaking all of those classical slopes are negative, but that's implied (for this choice of coordinates) by specifying a southeast bearing.]

We have a dual analysis and table for ambusher with west wall one square east.

Python 2.6 source code for constructing the ambush line of fire for the above table follows (should also be in the next update to my XCOM editor suite as XCOM1.py):

# Voxelspace: 0..15,0..15,0,23..0 internal coordinates
fire_voxel_x_y_from_facing = ((1,8),(1,14),(8,15),(15,15),(15,8),(15,1),(8,1),(1,1))

# coords are internal-square: row,col format with 0,0 at upper-left
# we need to self-test this
def facing_from_coords(src,dest):
	delta = (dest[0]-src[0],dest[1]-src[1])
	if 0==delta[0]:
		if 0<delta[1]:
			return 2
		else:
			return 6
	elif 0==delta[1]:
		if 0<delta[0]:
			return 4
		else:
			return 0
	elif 0<delta[0]:
		if 0<delta[1]:
			if 2*delta[0]<=delta[1]:
				return 2
			elif 2*delta[1]<delta[0]:
				return 4
			else:
				return 3
		else: #if 0>delta[1]
			if 2*delta[0]<-delta[1]:
				return 6
			elif -2*delta[1]<=delta[0]:
				return 4
			else:
				return 5
	else: #if 0>delta[0]
		if 0<delta[1]:
			if -2*delta[0]<delta[1]:
				return 2
			elif 2*delta[1]<=-delta[0]:
				return 0
			else:
				return 1
		else: #if 0>delta[1]
			if -2*delta[0]<=-delta[1]:
				return 6
			elif -2*delta[1]<-delta[0]:
				return 0
			else:
				return 7

# yes, Voxelspace rows are reverse-order to coordinate rows
def convert_firearm_attack_unit_coords_from_map_to_voxels(src,dest):
	fire_offset = fire_voxel_x_y_from_facing[facing_from_coords(src,dest)]
	return ((-16*src[0]-fire_offset[0],16*src[1]+fire_offset[1]),(-16*dest[0]-8,16*dest[1]+8))

See Also