//-------------------------------------------------------------------------- // Add supplemental (non-static/non-land) items into the obstruction matrix; // this is very cheap in comparison to the cost of processing land and statics //-------------------------------------------------------------------------- public void ProcessMatrixItems( Point3D beholder, VisibilityMatrix v ) { // double start = DateTime.Now.Ticks / 10000000.0; // for(int i=0; i<100000; i++) // { int eyelevel = beholder.Z + 12; foreach ( Item item in m_map.GetItemsInRange( new Point3D( beholder.X, beholder.Y, 0 ), 15 )) { // cutpoint optimization; if the cell is in shadow, don't bother with // any more tests; such a test would be irrelevant: if( !v.IsVisible( beholder, item.Location.X, item.Location.Y )) { int xOffset = item.Location.X - beholder.X; int yOffset = item.Location.Y - beholder.Y; // this check solves the diagonal problem mentioned in the // previous function comments; we don't "cut" for the diagonals. if( Math.Abs( xOffset - yOffset ) <= 1) continue; } if( ItemBlocksVis( item, eyelevel, beholder ) ) v.ProcessObstructionAt( beholder, item.Location.X, item.Location.Y ); } //} // double stop = DateTime.Now.Ticks / 10000000.0; // double elapsed = stop - start; // Console.WriteLine( "ProcessMatrixItems: " + elapsed ); }
//-------------------------------------------------------------------------- // Test the Player's visibility matrix to see if they can see things at the // target point. This is the main part of our LOS "can see" function. //-------------------------------------------------------------------------- public bool Visible( Point3D beholder, Point3D beheld ) { //---------------------------------------------------------------------- // The center of the visibility matrix, which is always the anchor // point of the player mobile, is cell [range+1-1,range+1-1]. E.g., // to calculate where the player mobile is in the 37x37 matrix, use // 18+1-1 = 18. 0-17,0-17 are leftwards and upwards, 18,18 is the middle, // and 19-36,19-36 are rightwards and downwards. //---------------------------------------------------------------------- bool visible = false; //double start = DateTime.Now.Ticks / 10000000.0; //for(int i=0; i<500; i++) //{ int key = beholder.X * m_map.Width * m_map.Height + beholder.Y * m_map.Height + beholder.Z; //---------------------------------------------------------------------- // First see if we have a matrix in the cache: //---------------------------------------------------------------------- VisibilityMatrix baseMatrix = m_cache.Hit( key ); //---------------------------------------------------------------------- // If we don't, create it and put it in the cache: //---------------------------------------------------------------------- if( baseMatrix == null ) { baseMatrix = CreateBaseMatrix( beholder ); m_cache.Store( key, baseMatrix ); } //---------------------------------------------------------------------- // Rapidly create a clone of the matric fetched from the cache for // temporary use (this copy is implemented by cheap memcpy in the // CLR, don't wory much about it) //---------------------------------------------------------------------- VisibilityMatrix v = new VisibilityMatrix( baseMatrix ); //---------------------------------------------------------------------- // Add in the obstructions from items into the cache //---------------------------------------------------------------------- ProcessMatrixItems( beholder, v ); //---------------------------------------------------------------------- // Now finally do the test for visibility: //---------------------------------------------------------------------- visible = v.IsVisible( beholder, beheld.X, beheld.Y ); //} // double stop = DateTime.Now.Ticks / 10000000.0; // double elapsed = stop - start; // Console.WriteLine( "VisibleTime: " + elapsed ); return visible; }
//-------------------------------------------------------------------------- // Create the base matrix; this is the "cacheable" portion of the matrix, // the stuff like land and statics that never really change. //-------------------------------------------------------------------------- public VisibilityMatrix CreateBaseMatrix( Point3D beholder ) { VisibilityMatrix v = new VisibilityMatrix( 15 ); // VisibilityMatrix v = null; // for performance testing--leave in // double start = DateTime.Now.Ticks / 10000000.0; // for(int i=0; i<500; i++) // { int eyelevel = beholder.Z + 12; // v = new VisibilityMatrix( 15 ); //---------------------------------------------------------------------- // This is a spiral search pattern from center; the reason we do this // is that starting from the center allows us to benefit from // not having to load up data relating tiles and so forth further out // if x,y cursor is in the shadow of a prior obstruction... //---------------------------------------------------------------------- int locX = beholder.X; int locY = beholder.Y; for( int j = 0; j < m_SpiralPattern.Length; j++) { int xOffset = m_SpiralPattern[j][0]; int yOffset = m_SpiralPattern[j][1]; int x = locX + xOffset; int y = locY + yOffset; //------------------------------------------------------------------ // the spiral pattern could make us walk off the edge of the // map; break out of that here: //------------------------------------------------------------------ if( x < 0 || x > m_map.Width || y < 0 || y > m_map.Height ) goto cutpoint; //------------------------------------------------------------------ // Here we optimize by skipping the pulling up of tiles in the // event we are in a shadow; it turns out that in certain diagonal // 'L' cases (corners), this doesn't work perfectly, hence the check // for matching abs. x/y offsets ... we don't cut point those. //------------------------------------------------------------------ if ( !v.IsVisible( beholder, x, y ) && Math.Abs( xOffset - yOffset ) <= 1 ) goto cutpoint; //------------------------------------------------------------------ // Now process statics: //------------------------------------------------------------------ StaticTile[] staticTiles = m_map.Tiles.GetStaticTiles( x, y, true ); foreach (StaticTile staticTile in staticTiles) { if( TileBlocksVis( staticTile, eyelevel, x, y, beholder ) ) { v.ProcessObstructionAt( beholder, x, y ); goto cutpoint; // further obstructions irrelevant } } //------------------------------------------------------------------ // Now process land: //------------------------------------------------------------------ LandTile landTile = m_map.Tiles.GetLandTile( x, y ); if( LandBlocksVis( landTile, x, y, eyelevel+5, beholder ) ) { v.ProcessObstructionAt( beholder, x, y ); goto cutpoint; // further obstructions irrelevant } //------------------------------------------------------------------ // Now process "invalid" tiles (the black areas in dungeons): //------------------------------------------------------------------ if( IsVizBlockingInvalidLand( landTile, staticTiles, x, y ) ) { v.ProcessObstructionAt( beholder, x, y ); goto cutpoint; // further obstructions irrelevant } //------------------------------------------------------------------ // Items left deliberately out here (that's a follow up stage) //------------------------------------------------------------------ //------------------------------------------------------------------ cutpoint:; // sorry about the evil goto; please leave this alone for now // think of it this way; this is like a destionation for "continue", // where code can be if needed. //------------------------------------------------------------------ } //} // double stop = DateTime.Now.Ticks / 10000000.0; // double elapsed = stop - start; // Console.WriteLine( "CreateBaseMatrixInternalTime: " + elapsed ); return v; }