/// <summary> /// This helper function checks to see if there are any object in curIndex cooridnate index. If there are none, /// the origIndex must have had a perimeter wall and the wallsToPlace map is acoordingly updated. However, if /// there were objects at the curIndex coordinate index, the search continues on and a mutually recursive /// call back to GetPerimeterWalls is made. /// </summary> /// <param name="curIndex">The current coordinate index.</param> /// <param name="direction">The direction of the perimeter wall to test for.</param> /// <param name="wallsToPlace">The current threaded map of perimeter walls to place.</param> /// <param name="visited">The current list of coordinate Indices already visited.</param> /// <param name="origIndex"> The coordinate index one step before this, where the perimeter wall will be placed.</param> /// <param name="sceneGraphManager"> The active Scene Graph.</param> private static void GetPerimeterWallsHelper(IntVector3 curIndex, WWWalls direction, Dictionary <IntVector3, WWWalls> wallsToPlace, List <IntVector3> visited, IntVector3 origIndex, SceneGraphManager sceneGraphManager) { // TODO potentially filter out non Floor tiles, and Props. List <WWObject> objects = sceneGraphManager.GetObjectsInCoordinateIndex(new Coordinate(curIndex)); if (objects.Count == 0) // empty coordinate index, must have originated from an coordinate index with a perimeter { if (wallsToPlace.ContainsKey(origIndex)) { // append by OR to existing perimeter walls at the coordinate index wallsToPlace[origIndex] = direction | wallsToPlace[origIndex]; } else { // add a new entry into wallsToPlace wallsToPlace.Add(origIndex, direction); } } else // search further for a perimeter { GetPerimeterWalls(wallsToPlace, visited, curIndex, sceneGraphManager); } }
/// <summary> /// Serializable boolean values are used to make editing metadata in the inspector easier, /// but they must be converted to the enum bitflag for use. /// </summary> /// <returns>WWWalls equivalent to the serializable boolean values set in the inspector.</returns> public WWWalls GetWallsEnum() { WWWalls result = 0; if (north) { result = result | WWWalls.North; } if (east) { result = result | WWWalls.East; } if (south) { result = result | WWWalls.South; } if (west) { result = result | WWWalls.West; } if (top) { result = result | WWWalls.Top; } if (bottom) { result = result | WWWalls.Bottom; } return(result); }
/// <see cref="SceneGraphManager.GetWallsAtCoordinate"/> public WWWalls GetWallsAtCoordinate(Coordinate coordinate) { List <WWObject> objects = GetObjectsInCoordinateIndex(coordinate); WWWalls walls = 0; foreach (WWObject obj in objects) { walls = walls | obj.GetWallsWRotationApplied(); } return(walls); }
public static WWWalls GetRotatedWWWalls(WWResourceMetadata metadata, int rotation) { int yRotation = rotation % 360 + (rotation < 0 ? 360 : 0); // rotation should only be 1 of 4 discrete values, 0, 90, 180, and 270 bool isvalidRotation = yRotation == 0 || yRotation == 90 || yRotation == 180 || yRotation == 270 || yRotation == 360; if (!isvalidRotation) { Debug.LogError(string.Format("WWWallsHelper : {0} is an invalid rotation.", yRotation)); } bool north; bool east; bool south; bool west; if (yRotation == 0 || yRotation == 360) { north = metadata.wwTileMetadata.wwWallMetadata.north; east = metadata.wwTileMetadata.wwWallMetadata.east; south = metadata.wwTileMetadata.wwWallMetadata.south; west = metadata.wwTileMetadata.wwWallMetadata.west; } else if (yRotation == 90) { north = metadata.wwTileMetadata.wwWallMetadata.west; east = metadata.wwTileMetadata.wwWallMetadata.north; south = metadata.wwTileMetadata.wwWallMetadata.east; west = metadata.wwTileMetadata.wwWallMetadata.south; } else if (yRotation == 180) { north = metadata.wwTileMetadata.wwWallMetadata.south; east = metadata.wwTileMetadata.wwWallMetadata.west; south = metadata.wwTileMetadata.wwWallMetadata.north; west = metadata.wwTileMetadata.wwWallMetadata.east; } else // (yRotation == 270) { north = metadata.wwTileMetadata.wwWallMetadata.east; east = metadata.wwTileMetadata.wwWallMetadata.south; south = metadata.wwTileMetadata.wwWallMetadata.west; west = metadata.wwTileMetadata.wwWallMetadata.north; } bool top = metadata.wwTileMetadata.wwWallMetadata.top; bool bottom = metadata.wwTileMetadata.wwWallMetadata.bottom; var rotatedMetaData = new WWWallMetadata(north, east, south, west, top, bottom); WWWalls walls = rotatedMetaData.GetWallsEnum(); return(walls); }
/// <summary> /// Loads from the resourceTag a WWObject, then attempts to find a valid rotation for the WWObject, /// such that it fits with existing Objects at the specified Coordinate Index, and finally places and /// adds the WWObject wall to the active Scene Graph. /// </summary> /// <param name="coordIndex">The coordinate index for this perimeter wall</param> /// <param name="perimeterWallOpening">The direction for the perimeter wall</param> /// <param name="resourceTag">The resource tag for of the WWObject to place as the perimeter wall.</param> private static void TryToPlaceWall(IntVector3 coordIndex, WWWalls perimeterWallOpening, string resourceTag) { // the collisions that need to be taken into account to see if the WWObject belonging to resourceTag can fit WWWalls wallsToFit = ~perimeterWallOpening | ManagerRegistry.Instance.GetAnInstance <SceneGraphManager>(). GetWallsAtCoordinate(new Coordinate(coordIndex)); WWResource resource = WWResourceController.GetResource(resourceTag); WWResourceMetadata resourceMetadata = resource.GetMetaData(); // Try possible rotations for the resource, and place the resource at the first rotation that fits. for (var r = 0; r < 360; r += 90) // only rotations of 90 degrees are valid { WWWalls wallToPlace = WWWallsHelper.GetRotatedWWWalls(resourceMetadata, r); bool doesCollide = Convert.ToBoolean(wallToPlace & wallsToFit); // should be 0 or False if no collision if (!doesCollide) { PlaceWallObject(coordIndex, r, resourceTag); // add the wall to the active Scene Graph return; // a valid rotation was found for the WWObject, no need to try further rotations } } }
/// <summary> /// Given a resourceTag, loads the WWObject belonging to the resource and returns a list of all possible /// valid rotations for the WWObject that do not collide with existing WWObjects at the given position /// in the active Scene Graph. Useful for assisting the player with auto rotation of tiles. /// </summary> /// <param name="position">The Unity Space position to convert to Coordinate Index to determine valid rotations in.</param> /// <param name="resourceTag">The resourceTag belonging to the desired WWObject.</param> /// <returns></returns> public static List <int> GetPossibleRotations(Vector3 position, string resourceTag) { var result = new List <int>(); // the resulting list of possible rotations, currently empty Coordinate coordinate = CoordinateHelper.UnityCoordToWWCoord(position); WWWalls wallsToFit = ManagerRegistry.Instance.GetAnInstance <SceneGraphManager>().GetWallsAtCoordinate(coordinate); // check to see if any of the 4 possible rotations would fit given resource's walls WWResource resource = WWResourceController.GetResource(resourceTag); WWResourceMetadata resourceMetadata = resource.GetMetaData(); for (var r = 0; r < 360; r += 90) // only rotations of 90 degrees are valid { WWWalls newWalls = WWWallsHelper.GetRotatedWWWalls(resourceMetadata, r); bool doesCollide = Convert.ToBoolean(newWalls & wallsToFit); // should be 0 or False if no collision if (!doesCollide) { result.Add(r); } } return(result); }
/// <summary> /// Consumes a WWObject and determines whether this object can fit at its current coordinate, /// taking into consideration rotation, or if it collides with other WWObjects being maintained /// by this data structure. This is private method and it safe to assume that the WWObject being tested /// for collision has not yet been added to this data structure. Note: it would be easy to do a Guid /// comparison before checking collision if the use case ever arises in the future. /// </summary> /// <param name="wwObject">The object to test for collision.</param> /// <returns>True if the WWObject can fit without colliding given its current coordinate.</returns> private bool Collides(WWObject wwObject) { if (coordinates.ContainsKey(wwObject.GetCoordinate().Index)) // any objects at coordinate? { List <WWObject> objectsAtCoord = GetObjects(wwObject.GetCoordinate()); WWWalls totalWalls = 0; // this is a bit mask which will keep the running total of wall collisions foreach (WWObject obj in objectsAtCoord) // only need to do collision checking at the coordinate index { if (obj.ResourceMetadata.wwObjectMetadata.type.Equals(WWType.Tile)) // ignore non Tile types { // get the walls of the WWObject after applying its rotation transformation WWWalls walls = WWWallsHelper.GetRotatedWWWalls(obj.ResourceMetadata, obj.GetRotation()); totalWalls = totalWalls | walls; // OR the walls with the running sum stored in totalWalls } } // now get the walls for the object that is being collision checked for WWWalls newWalls = WWWallsHelper.GetRotatedWWWalls(wwObject.ResourceMetadata, wwObject.GetRotation()); bool doesCollide = Convert.ToBoolean(newWalls & totalWalls); // 0 or False if no collision return(doesCollide); } return(false); // if there are no objects at the index, obviously there are no collisions }