Coding your own line of sight check is NOT easy, if you have a height map then I would suggest creating the terrain or mesh that goes with it and then using the built in raycast functions to check for each ‘grid space’ which other grid spaces it can see.
you can do that quite simply by having a few embedded for loops:
Vector3[,] gridSpace;
//For each grid space
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
Vector3 parentSpace = gridSpace[x, z];
//Check all grid spaces
for(int zi = 0; zi < depth; zi++){
for(int xi = 0; xi < width; xi++){
Vector3 childSpace = gridSpace[xi, zi];
// shoot a ray from your gridSpace[x, z] to gridSpace[xi, zi] and see if it hits anything on the way, if not, then this 'childSpace' grid space if visible from the 'parentSpace'
// save that information somewhere!
}
}
}
}
Because I had lots of work to do I decided to procrastinate and see if I could write my own line of sightcode so here is a basic (and bad) implementation of how you could do it from scratch using some heightmap data:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class heightmap : MonoBehaviour {
float[,] heights;
HeightMap hMap;
public int xSize = 12;
public int zSize = 3;
void Start(){
heights = new float[xSize,zSize];
for(int z = 0; z < zSize; z++){
for(int x = 0; x < xSize; x++){
heights[x, z] = UnityEngine.Random.Range(0f, 1f);
}
}
hMap = new HeightMap(heights, Vector3.zero, 1, 0.5f);
}
}
public class HeightMap {
HeightPoint[,] hPoints;
float pointSpacing;
Vector3 origin;
int width;
int depth;
float viewUpHeight;
public HeightMap(float[,] h, Vector3 o, float space, float viewUH){
pointSpacing = space;
origin = o;
width = h.GetLength(0);
depth = h.GetLength(1);
viewUpHeight = viewUH;
hPoints = new HeightPoint[width, depth];
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
hPoints[x, z] = new HeightPoint(x, z, new Vector3(origin.x+x*pointSpacing, origin.y+h[x, z], origin.z+z*pointSpacing), this);
}
}
CalcLineOfSight();
CreateMap();
}
public void CreateMap(){
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
GameObject o = GameObject.CreatePrimitive(PrimitiveType.Plane);
o.transform.position = hPoints[x, z].pos;
o.transform.localScale = Vector3.one*pointSpacing/10;
o.name = x + ", " + z;
}
}
}
public void CalcLineOfSight(){
HeightPoint p;
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
List<Point> haveChecked = new List<Point>();
p = hPoints[x, z];
p.Add(p);
for(int zi = 0; zi < depth; zi++){
for(int xi = 0; xi < width; xi++){
if(zi == z && xi == x){
continue;
}
//check indexes on line to target
List<Point> points = FindIntersectedIndexes(x, z, xi, zi);
//check visibility through each index on line
float maxViewGrad = viewUpHeight;
float minViewGrad = Mathf.NegativeInfinity;
float grad = 0;
for(int i = 0; i < points.Count; i++){
if(points_.x == x && points*.y == z){*_
* continue;*
* }*
grad = (hPoints[points.x, points.y].height - p.height)/(new Vector2(x-points_.x, z-points*.y).magnitude);
minViewGrad = Mathf.Max(minViewGrad, grad);
if(minViewGrad > maxViewGrad){
break;
}
if(grad > maxViewGrad){
break;
}
if(grad < minViewGrad){
continue;
}
if(p.visiblePoints.Contains(hPoints[points.x, points.y])){
continue;
}
p.Add(hPoints[points.x, points.y]);
}
}
}
}
}
}*_
* List FindIntersectedIndexes(int y1, int x1, int y2, int x2){*
* //Implements a variation on Bresenham’s line algorithm*
* List points = new List();*
* int i;*
* int ystep;*
* int xstep;*
* int error;*
* int errorprev;*
* int y = y1;*
* int x = x1;*
* int ddy, ddx;*
* int dx = x2 - x1;*
* int dy = y2 - y1;*
* points.Add(new Point(y1, x1));*
* if (dy < 0){*
* ystep = -1;*
* dy = -dy;*
* }else{*
* ystep = 1;*
* }*
* if (dx < 0){*
* xstep = -1;*
* dx = -dx;*
* }else{*
* xstep = 1;*
* }*
_ ddy = 2 * dy;
ddx = 2 * dx;
* if(ddx >= ddy){
errorprev = error = dx;
for (i=0 ; i < dx ; i++){
x += xstep;
error += ddy;
if (error > ddx){
y += ystep;
error -= ddx;
if (error + errorprev < ddx){
points.Add(new Point(y-ystep, x));
}else if (error + errorprev > ddx){
points.Add(new Point(y, x-xstep));
}else{
points.Add(new Point(y-ystep, x));
points.Add(new Point(y, x-xstep));
}
}
points.Add(new Point(y, x));
errorprev = error;
}
}else{
errorprev = error = dy;
for (i=0 ; i < dy ; i++){
y += ystep;
error += ddx;
if (error > ddy){
x += xstep;
error -= ddy;
if (error + errorprev < ddy){
points.Add(new Point(y, x-xstep));
}else if (error + errorprev > ddy){
points.Add(new Point(y-ystep, x));
}else{
points.Add(new Point(y, x-xstep));
points.Add(new Point(y-ystep, x));
}
}
points.Add(new Point(y, x));
errorprev = error;
}
}
return points;
}
}*_
public class HeightPoint{
* int x;*
* int y;*
* float h;*
* public Vector3 pos;*
* public List visiblePoints = new List();*
* HeightMap hMap;*
* public HeightPoint(int xi, int yi, Vector3 p, HeightMap container){*
* pos = p;*
* h = p.y;*
* hMap = container;*
* x = xi;*
* y = yi;*
* }*
* public HeightPoint(int xi, int yi, Vector2 p, float he, HeightMap container){*
* pos = new Vector3(p.x, h, p.y);*
* h = he;*
* hMap = container;*
* x = xi;*
* y = yi;*
* }*
* public void Add(HeightPoint hP){*
* visiblePoints.Add(hP);*
* }*
* public void DebugVisible(){*
* foreach(HeightPoint a in visiblePoints){*
* Debug.Log(a.x + ", " + a.y);*
* }*
* }*
* public float height{*
* get { return h; }*
* set { h = value; }*
* }*
}
public class Point{
* public int x;*
* public int y;*
* public Point(int xi, int yi){*
* x = xi;*
* y = yi;*
* }*
}
The each ‘HeightPoint’ instance should contain a list of the HeightPoint’s that it can ‘see’
I would not advise anyone to use that code over the former alternative I suggested, but it was an interesting challenge to get working, so enjoy that headache!
Scribe