# 249. WoT putting tank detection in place

Having figured out how I want tanks to see each other, it’s time to see if I can build the system. I didn’t look forward to this, because there’s a lot of testing, and usually some difficult bugs, in something this complicated.

### List of tiles

In my last post, I found a way of getting a list of tiles that are in the line of sight between two tanks. Now I need to create some “trees”, enter their positions in the tile table, and modify my code so it doesn’t just get a list of tiles, but looks at which trees are included in each tile.

So in the video below, I have my two tanks, and all the trees are drawn in light green. I run my code to get a list of the tiles I need to inspect, get a list of the trees in those tiles, and shade them in darker green. So as I move one of the tanks around the screen, the line between the tanks will move too. Any tree that is even partly in a square that is crossed by the line, should be shaded darker. And that is what you see. So that seems to work.

### List of trees for checking

Now I’ve put the “list of tiles” code into my tank project, and used it to get a list of trees that need to be tested for blocking the view.

At first, it seemed to give me a random list of trees all over the map, and I spent a couple of hours puzzling before I realised that I sort the trees by distance from the player at each frame, and that messed up the order of the trees. I stored an ID number for each tree, which never changed, to fix this. I did it wrong, and spent some more unhappy hours wondering why my tank wasn’t hidden when it should be.

Anyway. Here is a video of another tank looking at my tank, and all the trees that need to be checked are shaded orange. For this test, I spaced all the trees evenly over the map, and made them small so I could always see the other tank. You can see the tree colours changing as the other tank moves around.

### Figuring out the width of the target tank

This is tricky because the other tank could be at any angle, and it is not square, so if it is looking straight at us, it will be narrower than if we are looking at it from the side.

I didn’t try to solve this in the last post, but had an idea for doing it. And I think it works, like this. Suppose tank A is looking at tank B, and we want to know how wide B looks.

- When building our tank model, create 4 “corner” positions, which are the outer edges of the body.
- When we want to figure out the width of B, first rotate all four positions by the current angle of the (body of the) tank, so we know where they are, for B
- Subtract the position of A from each of them (which gives us the direction from A to each corner of B)
- Calculate the angle (in radians) of each direction (x,0,z)
- Calculate the smallest and largest angle, which gives us the width as an angle, in radians

So if tank T is looking at the two sides of tank A in this drawing, the angle made by the line between T and each side can be converted into an angle. We can then calculate the angles from tank A to each side of all the trees we need to look at, to see if the angles overlap.

But there was a problem with this method, because the atan function I am using to calculate angles, flips from positive to negative at 180 degrees, and this makes a mess of my comparison of angles. So in the end I found a better alternative, and a nice trick.

### The angleBetween function

The built in angleBetween function will calculate the angle between two 2D direction vectors, which don’t have to be normalised first. We are effectively working in 2D, because our tanks can only look around (and move) on a flat surface, so I can use this function.

First, I calculate the direction from tank A to tank T. This will be our baseline direction against which everything else will be measured. Then I calculate the directions from tank A to the two sides of tank B, and use angleBetween to calculate the difference in angle from the baseline.

T = position of tank that is looking A = position of other tank A1 = position of left side of tank A A2 = position of right side of tank A baseline = A - T angle1 = baseline:angleBetween(A1 - T,baseline) --eg -0.05 angle2 = baseline:angleBetween(A2 - T,baseline) --eg 0.10

So tank A is at an angle between -0.05 and +0.10 radians of the line from T to A.

Now suppose I have a tree, and I calculate the positions of its left and right edges, then use angleBetween again to get the angles in the same way as I did for tank A. I can now test whether the range of angles overlaps, eg if the tree angles are -0.14 to -0.02, then the tree blocks the view of tank A between -0.05 and -0.02.

As discussed in the last post, I need an easy way of deleting the overlapping part, and the best I could think of was to split the range for tank A into (say) 20 pieces, so for the range above, it might be -2.15, -2.1475,-2.145,…-2.10. Then I test each of these points against the range of the tree, and if any of them fall inside the tree range, I delete that point from the table.

And finally – below is the result. The trees that are being tested are shaded orange, and the visibility percentage is shown at upper left. Note this shows how much of our tank can be seen by the other tank.

The trick

Oh, and I did say I found a nice trick. Or rather, yojimbo2000 did. Here is a version of angleBetween that is 2-3 times faster, as long as you don’t mind passing through the x,y position values separately instead of in a vector. It’s very neat when you think it is calculating the difference between two angles with just one trig function.

--angle between (x1,y1) and (x2,y2) in radians function AngleBetween(x1,y1,x2,y2) return atan2( x1*y2 - y1*x2, x1*x2 + y1*y2 ) end

ss