/// <summary> /// Wall Collision Checker /// </summary> public static bool Wall_Collision(Character character_entity, Shared.Direction direction) { //------------------------------------- // Produce a quick list of terrain entities within a direct radius of the character //------------------------------------- List <Terrain> quick_terrain_list = new List <Terrain>(); // Get the side we're checking int x_side = 1; // 1 = Right side, -1 = Left side if (direction == Shared.Direction.LEFT) { x_side = -1; } //------------------------------------- // Block Adjacent Terrain block1 = Shared.Active_World.Get_Terrain_At( (int)character_entity.Grid_Position.X + x_side, (int)character_entity.Grid_Position.Y); if (block1 != null) { quick_terrain_list.Add(block1); } //------------------------------------- // Block Below Adjacent Terrain block2 = Shared.Active_World.Get_Terrain_At( (int)character_entity.Grid_Position.X + x_side, (int)character_entity.Grid_Position.Y + 1); if (block2 != null) { quick_terrain_list.Add(block2); } //------------------------------------- // Block Above Adjacent Terrain block3 = Shared.Active_World.Get_Terrain_At( (int)character_entity.Grid_Position.X + x_side, (int)character_entity.Grid_Position.Y - 1); if (block3 != null) { quick_terrain_list.Add(block3); } //------------------------------------- if (quick_terrain_list.Count() == 0) { return(false); // There are no blocks worth checking on this side, leave collision check } //------------------------------------- // Retrieve the character entities wall collision bound box //------------------------------------- Rectangle bound_box = new Rectangle ( character_entity.Get_Bounds().X - 3, character_entity.Get_Bounds().Y, character_entity.Get_Bounds().Width + 6, character_entity.Get_Bounds().Height ); //------------------------------------- foreach (Terrain terrain_entity in quick_terrain_list) { if (bound_box.Intersects(terrain_entity.Get_Bounds())) { Rectangle c_bound = bound_box; Rectangle t_bound = terrain_entity.Get_Bounds(); //-------------------- // We should first make sure this intersected peice of terrain isn't cleanly above or below // the character entity //-------------------- if (c_bound.Top > t_bound.Bottom || c_bound.Bottom < t_bound.Top) { return(false); } // Safety check informs us if this is a floor rather than a wall. // ------------------- if ((c_bound.Bottom - t_bound.Top) < 5) { return(false); } //-------------------- if (direction == Shared.Direction.LEFT) { // Left Wall Check // ------------------- if (c_bound.Left < t_bound.Right && c_bound.Right > t_bound.Right) { // This bit helps ensure players don't exploit spam // jumping against hole walls to breach the wall. if (character_entity.Get_Bounds().Left < t_bound.Right) { character_entity.Shift(new Vector2(-1, 0)); } // ------------------- return(true); } // ------------------- } if (direction == Shared.Direction.RIGHT) { // Right Wall Check // ------------------- if (c_bound.Right > t_bound.Left && c_bound.Left < t_bound.Left) { // This bit helps ensure players don't exploit spam // jumping against hole walls to breach the wall. if (character_entity.Get_Bounds().Right > t_bound.Left) { character_entity.Shift(new Vector2(1, 0)); } // ------------------- return(true); } // ------------------- } } } //------------------------------------- return(false); }
/// <summary> /// Determines whether or not an NPC has Line of sight of an input target /// </summary> /// <param name="source">The source NPC</param> /// <param name="target">The target to look for</param> /// <param name="range">The LoS range in blocks</param> /// <returns>Returns true if the target character is within LoS</returns> public static bool Line_Of_Sight(NPC source, Entity target, int range) { // Establish essential calculation data //------------------------------------- //------------------------------------- // The NPC's source of sight. Grid position, plus the eye offset tells us where there 'eyes' are Vector2 NPC_sight_source = new Vector2 ( source.Grid_Position.X + source.Eye_Offset.X, source.Grid_Position.Y + source.Eye_Offset.Y ); //------------------------------------- // The line slope from our target position and the NPC's sight source Vector2 sight_slope = new Vector2 ( target.Grid_Position.X - NPC_sight_source.X, (target.Grid_Position.Y - NPC_sight_source.Y - (int)Math.Floor((target.Get_Bounds().Height / Shared.Block_Dimension / Shared.Pixel_Scale))) ); //------------------------------------- // The absolute of the slope. We need to quantify values later. Vector2 absolute_slope = new Vector2 ( Math.Abs(sight_slope.X), Math.Abs(sight_slope.Y) ); //------------------------------------- // Calculates the amount of blocks we'll need to check based on the // highest vertical or horizontal distance int block_count = (int)Math.Max ( absolute_slope.X, absolute_slope.Y ); //------------------------------------- // In order to prevent falling a block short through odd division, // add an extra block when using odd numbers if (block_count % 2 != 0) { block_count++; } //------------------------------------- //------------------------------------- // Set up some crucial variables int block_X = 0; // The current X position we're checking int block_Y = 0; // The current Y position we're checking bool x_split = false; // Whether we're splitting the horizontal distance bool y_split = false; // or the vertical distance. Distance splitting means we'll // get more natural lines, instead of L shapes int SPLIT_COUNT = 0; // Initialize int split_counter = 0; // Initialize //------------------------------------- //------------------------------------- // Prepare split counting if necessary if (absolute_slope.X > absolute_slope.Y) { // Since the horizontal distance is greater, we'll dispere the vertical increment // evenly throughout the horizontal line to assure we don't get any L shaped LoS lines y_split = true; SPLIT_COUNT = (int)Math.Ceiling(absolute_slope.X / absolute_slope.Y); split_counter = SPLIT_COUNT; } else if (absolute_slope.Y > absolute_slope.X) { // Since the vertical distance is greater, we'll dispere the horizontal increment // evenly throughout the horizontal line to assure we don't get any L shaped LoS lines x_split = true; SPLIT_COUNT = (int)Math.Ceiling(absolute_slope.Y / absolute_slope.X); split_counter = SPLIT_COUNT; } //------------------------------------- //------------------------------------- // Now let's run through all the blocks we need to check! for (int block = 0; block < block_count + 1; block++) { //------------------------------------- // Increment or decrement depending on split & slope split_counter++; if (block_X > sight_slope.X && (!x_split || split_counter == SPLIT_COUNT)) { block_X--; } else if (block_X < sight_slope.X && (!x_split || split_counter == SPLIT_COUNT)) { block_X++; } if (block_Y > sight_slope.Y && (!y_split || split_counter == SPLIT_COUNT)) { block_Y--; } else if (block_Y < sight_slope.Y && (!y_split || split_counter == SPLIT_COUNT)) { block_Y++; } //------------------------------------- //------------------------------------- // Reset split counter if (split_counter > SPLIT_COUNT) { split_counter = 1; } //------------------------------------- //------------------------------------- // Check current block location for solid blocks int check_X = (int)(NPC_sight_source.X + block_X); int check_Y = (int)(NPC_sight_source.Y + block_Y); Terrain terrain = Shared.Active_World.Get_Terrain_At(check_X, check_Y); //------------------------------------- if (terrain is Terrain) { return(false); // A solid block lays in the way of our LoS } //------------------------------------- } return(true); // With all blocks between us and our target clear, we have LoS //------------------------------------- }
/// <summary> /// Ceiling Collision Checker /// </summary> public static bool Ceiling_Collision(Character character_entity) { //------------------------------------- // Check block above character for collision //------------------------------------- List <Terrain> quick_terrain_list = new List <Terrain>(); //------------------------------------- // Block Atop Terrain block1 = Shared.Active_World.Get_Terrain_At( (int)character_entity.Grid_Position.X, (int)character_entity.Grid_Position.Y); if (block1 != null) { quick_terrain_list.Add(block1); } //------------------------------------- // Block Above Terrain block2 = Shared.Active_World.Get_Terrain_At( (int)character_entity.Grid_Position.X, (int)character_entity.Grid_Position.Y - 1); if (block2 != null) { quick_terrain_list.Add(block2); } //------------------------------------- if (quick_terrain_list.Count() == 0) { return(false); // There are no blocks worth checking on this side, leave collision check } // Retrieve the character entities wall collision bound box //------------------------------------- Rectangle bound_box = new Rectangle ( character_entity.Get_Bounds().X + 5, character_entity.Get_Bounds().Y, character_entity.Get_Bounds().Width - 10, character_entity.Get_Bounds().Height ); //------------------------------------- foreach (Terrain block in quick_terrain_list) { if (bound_box.Intersects(block.Get_Bounds())) { // We've found a collision. Let's check if it's a ground collision! //------------------------------------- // Bound Boxes //-------------------- Rectangle c_bound = bound_box; Rectangle t_bound = block.Get_Bounds(); //-------------------- if (c_bound.Top < t_bound.Bottom) { if (c_bound.Bottom > t_bound.Bottom) { return(true); } } } } return(false); //------------------------------------- }