RTS style fog of war woes
- by Fricken Hamster
So I'm trying to make a rts style line of sight fog of war style engine for my grid based game. Currently I am getting a set of vertices by raycasting in 360 degree. Then I use that list of vertices to do a graphics style polygon scanline fill to get a list of all points within the polygon. The I compare the new list of seen tiles and compare that with the old one and increment or decrement the world vision array as needed.
The polygon scanline function is giving me trouble. I'm mostly following this
http://www.cs.uic.edu/~jbell/CourseNotes/ComputerGraphics/PolygonFilling.html
So far this is my code without cleaning anything up
var edgeMinX:Vector.<int> = new Vector.<int>;
var edgeMinY:Vector.<int> = new Vector.<int>;
var edgeMaxY:Vector.<int> = new Vector.<int>;
var edgeInvSlope:Vector.<Number> = new Vector.<Number>;
var ilen:int = outvert.length;
var miny:int = -1;
var maxy:int = -1;
for (i = 0; i < ilen; i++)
{
var curpoint:Point = outvert[i];
if (i == ilen -1)
{
var nextpoint:Point = outvert[0];
}
else
{
nextpoint = outvert[i + 1];
}
if (nextpoint.y == curpoint.y)
{
continue;
}
if (curpoint.y < nextpoint.y)
{
var curslope:Number = ((nextpoint.y - curpoint.y) / (nextpoint.x - curpoint.x));
edgeMinY.push(curpoint.y);
edgeMinX.push(curpoint.x);
edgeMaxY.push(nextpoint.y);
edgeInvSlope.push(1 / curslope);
if (curpoint.y < miny || miny == -1)
{
miny = curpoint.y;
}
if (nextpoint.y > maxy)
{
maxy = nextpoint.y;
}
}
else
{
curslope = ((curpoint.y - nextpoint.y) / (curpoint.x - nextpoint.x));
edgeMinY.push(nextpoint.y);
edgeMinX.push(nextpoint.x);
edgeMaxY.push(curpoint.y);
edgeInvSlope.push(1 / curslope);
if (nextpoint.y < miny || miny == -1)
{
miny = curpoint.y;
}
if (curpoint.y > maxy)
{
maxy = nextpoint.y;
}
}
}
var activeMaxY:Vector.<int> = new Vector.<int>;
var activeCurX:Vector.<Number> = new Vector.<Number>;
var activeInvSlope:Vector.<Number> = new Vector.<Number>;
for (var scanline:int = miny; scanline < maxy + 1; scanline++)
{
ilen = edgeMinY.length;
for (i = 0; i < ilen; i++)
{
if (edgeMinY[i] == scanline)
{
activeMaxY.push(edgeMaxY[i]);
activeCurX.push(edgeMinX[i]);
activeInvSlope.push(edgeInvSlope[i]);
//trace("added(" + edgeMinX[i]);
edgeMaxY.splice(i, 1);
edgeMinX.splice(i, 1);
edgeMinY.splice(i, 1);
edgeInvSlope.splice(i, 1);
i--;
ilen--;
}
}
ilen = activeCurX.length;
for (i = 0; i < ilen - 1; i++)
{
for (var j:int = i; j < ilen - 1; j++)
{
if (activeCurX[j] > activeCurX[j + 1])
{
var tempint:int = activeMaxY[j];
activeMaxY[j] = activeMaxY[j + 1];
activeMaxY[j + 1] = tempint;
var tempnum:Number = activeCurX[j];
activeCurX[j] = activeCurX[j + 1];
activeCurX[j + 1] = tempnum;
tempnum = activeInvSlope[j];
activeInvSlope[j] = activeInvSlope[j + 1];
activeInvSlope[j + 1] = tempnum;
}
}
}
var prevx:int = -1;
var jlen:int = activeCurX.length;
for (j = 0; j < jlen; j++)
{
if (prevx == -1)
{
prevx = activeCurX[j];
}
else
{
for (var k:int = prevx; k < activeCurX[j]; k++)
{
graphics.lineStyle(2, 0x124132);
graphics.drawCircle(k * 20 + 10, scanline * 20 + 10, 5);
if (k == prevx || k > activeCurX[j] - 1)
{
graphics.lineStyle(3, 0x004132);
graphics.drawCircle(k * 20 + 10, scanline * 20 + 10, 2);
}
prevx = -1;
//tileLightList.push(k, scanline);
}
}
}
ilen = activeCurX.length;
for (i = 0; i < ilen; i++)
{
if (activeMaxY[i] == scanline + 1)
{
activeCurX.splice(i, 1);
activeMaxY.splice(i, 1);
activeInvSlope.splice(i, 1);
i--;
ilen--;
}
else
{
activeCurX[i] += activeInvSlope[i];
}
}
}
It works in some cases but some of the x intersections are skipped, primarily when there are more than 2 x intersections in one scanline I think.
Is there a way to fix this, or a better way to do what I described? Thanks