void ComputeAndMergeAnOctant(Octant octant) { /* * 计算并合并第一行(因为要考虑到观察者的影响但又不能过度消耗计算量) * * 向前走直到地图边界 * if(阴影没有完全覆盖八分角) * 计算并合并每一行 * else * 填充整行的阴影 */ bool isFullShadow = false; ShadowLine shadowLine = new ShadowLine(); ComputeAndMergeStartLine(octant, shadowLine); // 因为观察者自身对视线的遮挡会导致各种问题,所以单独拿出一行来处理 for (int mainStep = 1; _visibleMap.Contains(octant.GetPosition(mainStep, 0)); mainStep++) // 第一行单独处理了,这里从距离1开始 { if (!isFullShadow) { isFullShadow = ComputeAndMergeALineAndGetIsFullShadow(octant, mainStep, shadowLine); } else { FillALineShadow(octant, mainStep); } } }
void UpdateShadowLine(Vector2 position, ShadowLine shadowLine, Shadow projection) { if (IsBlockView(position, shadowLine, projection)) { shadowLine.AddShadow(projection); } }
void DrawShadow(ShadowLine shadowLine, Vector2 currentPosition, Shadow projection) { if (!IsVisible(projection, shadowLine)) { _viewField.SetVisible(currentPosition, false); } //因为阴影以八分圆为单位绘制,无论如何都会发生在边缘读取不到八分角外的墙而导致的判断不准确 //在前面为了解决八分角边缘对角墙透视问题时增加了一格的判断用来补上这部分影子,但如果按照可见存true不可见存false的方法存储,则会不可避免的发生一部分计算正确的影子被不正确的可见覆盖 //幸运的是这个算法在一开始就把整个视野设为可见, 因此只要在这里只绘制阴影就不会发生不正确可见覆盖不可见的问题了 }
void ComputeAndMergeStartLine(Octant octant, ShadowLine shadowLine) { int mainStep = 0; Vector2 currentPosition; for (int sideStep = 1; sideStep <= LINE_PATCH && _visibleMap.Contains(currentPosition = octant.GetPosition(mainStep, sideStep)); sideStep++) // 边缘方向从1开始,跳过观察者所在的位置 { Shadow projection = ShadowLine.GetQuadProjection(mainStep, sideStep); DrawShadow(shadowLine, currentPosition, projection); UpdateShadowLine(currentPosition, shadowLine, projection); } }
bool ComputeAndMergeALineAndGetIsFullShadow(Octant octant, int mainStep, ShadowLine shadowLine) { /* * 循环到一行结束或地图边界 * { * 获取投影 * 通过投影判断可见度并存入视野 * 通过投影判断是否遮挡视线并存入阴影线 * } * 返回阴影是否覆盖了整个八分角 */ Vector2 currentPosition; for (int sideStep = 0; sideStep <= mainStep + LINE_PATCH && _visibleMap.Contains(currentPosition = octant.GetPosition(mainStep, sideStep)); sideStep++) { Shadow projection = ShadowLine.GetQuadProjection(mainStep, sideStep); DrawShadow(shadowLine, currentPosition, projection); UpdateShadowLine(currentPosition, shadowLine, projection); } return(shadowLine.IsFullShadow()); }
bool IsBlockView(Vector2 position, ShadowLine shadowLine, Shadow shadow) { return(!_visibleMap.IsTransparent(position) && !shadowLine.Contains(shadow)); // 很明显的,只要一个东西没有被完全挡住,他又不是透明的,那他就一定会遮挡视线 }
bool IsVisible(Shadow projection, ShadowLine shadowLine) { return(!shadowLine.Contains(projection)); // 我觉得如果是一个经验丰富的观察者,就算只能看见一小部分也是能判断出看到了什么的,那就只要没有被完全遮挡就视为可见 }