/// <summary>
 /// Places a worldobject at a position with a direction
 /// </summary>
 /// <param name="worldObject">worldobject</param>
 /// <param name="position">position</param>
 /// <param name="wallNormal">direction</param>
 public void Place(WorldObject worldObject, Vector3 position, Vector3 wallNormal)
 {
     BootStrapper.EnvironmentManager.CurrentEnvironment.Place(worldObject, position);
     worldObject.InitialWallNormal = wallNormal;
     worldObject.LookTowardsNormal(wallNormal);
     BarPlacement.RecalcBars();
     StagePlacement.RecalcStages();
 }
        /// <summary>
        /// <para>Returns an int[4] representing the four sides of <paramref name="obj"/></para>
        /// <para>Each number represents if that side is blocked by another WorldObject</para>
        /// <para>[0]: if 1, then left of <paramref name="obj"/> is blocked</para>
        /// <para>[1]: if 1, then right of <paramref name="obj"/> is blocked</para>
        /// <para>[2]: if 1, then up of <paramref name="obj"/> is blocked</para>
        /// <para>[3]: if 1, then down of <paramref name="obj"/> is blocked</para>
        /// </summary>
        /// <param name="obj">The WorldObject you wish to see has blocked sides</param>
        /// <returns>int[4] representing which directions are blocked by other WorldObjects</returns>
        private static int[] directionsBlocked(WorldObject obj)
        {
            Vector3 position = obj.GameObject.transform.position;
            Vector3 offsetX = new Vector3(obj.Size.x/2 + WhiskerDepth, 0, 0);
            Vector3 offsetZ = new Vector3(0, 0, obj.Size.z/2 + WhiskerDepth);

            int[] directionsBlocked = new int[4];
            directionsBlocked[0] = IsSpaceAlreadyOccupied(position - offsetX);
            directionsBlocked[1] = IsSpaceAlreadyOccupied(position + offsetX);
            directionsBlocked[2] = IsSpaceAlreadyOccupied(position - offsetZ);
            directionsBlocked[3] = IsSpaceAlreadyOccupied(position + offsetZ);

            return directionsBlocked;
        }
 /// <summary>
 /// Places a few worldobjects in a line
 /// </summary>
 /// <param name="start">The placement start point</param>
 /// <param name="end">The placement end point</param>
 /// <param name="wallNormal">the direction</param>
 /// <param name="objectName">the object to place</param>
 /// <returns>list of placed worldobjects</returns>
 public WorldObject[] PlaceLine(Vector3 start, Vector3 end, Vector3 wallNormal, String objectName)
 {
     Vector3 step;
     var xDiff = start.x - end.x;
     var zDiff = start.z - end.z;
     int largerDiff;
     if (Mathf.Abs(xDiff) > Mathf.Abs(zDiff)) {
         step = new Vector3(-Mathf.Sign(xDiff), 0, 0);
         largerDiff = (int)Mathf.Abs(xDiff);
     } else {
         step = new Vector3(0, 0, -Mathf.Sign(zDiff));
         largerDiff = (int)Mathf.Abs(zDiff);
     }
     Vector3 position = start;
     WorldObject[] createdWorldObjects = new WorldObject[largerDiff + 1];
     for (int i = 0; i <= largerDiff; i++) {
         var currentWorldObject = WorldObject.DetermineObject(objectName);
         createdWorldObjects[i] = currentWorldObject;
         currentWorldObject.AdjustSizing(wallNormal);
         Place(currentWorldObject, position, wallNormal);
         position += step;
     }
     return createdWorldObjects;
 }
 /// <summary>
 /// Stores relevant information about a particular worldObject to save it to a file
 /// </summary>
 /// <param name="worldObject">the object to save</param>
 public void SaveWorldObject(WorldObject worldObject)
 {
     saveableItems.Add(new WorldObjectBuildInfo(worldObject));
 }
 /// <summary>
 /// Places a worldobject at a position with a direction
 /// </summary>
 /// <param name="worldObject">worldobject</param>
 /// <param name="position">position</param>
 public void Place(WorldObject worldObject, Vector3 position)
 {
     BootStrapper.EnvironmentManager.CurrentEnvironment.Place(worldObject, position);
     BarPlacement.RecalcBars();
     StagePlacement.RecalcStages();
 }
        /// <summary>
        /// Sees if the cursor is over a wall and if a worldobject is placeable on it
        /// </summary>
        /// <param name="normal">normal</param>
        /// <param name="position">position</param>
        /// <param name="cursor">object to place</param>
        /// <returns>true if placement possible</returns>
        public bool WallPlacement(out Vector3 normal, out Vector3 position, WorldObject cursor)
        {
            //is the cursor over a wall
            RaycastHit hit;
            GameObject gameObject;
            if (UserWorldBuilder.Raycast(out hit, out gameObject)) {

                if (gameObject.name.Contains(Wall.IdentifierStatic)) {

                    Vector3 firstWallPosition = hit.transform.position;

                    normal = hit.normal;
                    if (normal.y == 0) { //only wall sides, not the tops
                        //perpendicular vector to normal (right vector from point of view of normal)
                        Vector3 crossRight = Vector3.Cross(Vector3.up, normal).normalized;

                        cursor.LookTowardsNormal(normal);
                        float requiredWidth = cursor.Size.x;

                        Vector3 leftMostWall = firstWallPosition;
                        Vector3 rightMostWall = firstWallPosition;

                        //Scans and checks existance of walls left and right of the selected wall
                        int count = 1;
                        Vector3 scanPosition = firstWallPosition;
                        for (int i = 0; i < requiredWidth - 1; i++) {
                            if (count >= requiredWidth) break;
                            scanPosition += crossRight;
                            if (
                                BootStrapper.EnvironmentManager.CurrentEnvironment.World.PointAlreadyOccupied(
                                    scanPosition)) {
                                count++;
                                rightMostWall = scanPosition;
                            } else {
                                scanPosition = firstWallPosition;
                                for (int j = 0; j < requiredWidth - 1; j++) {
                                    if (count >= requiredWidth) break;
                                    scanPosition -= crossRight;
                                    if (
                                        BootStrapper.EnvironmentManager.CurrentEnvironment.World
                                            .PointAlreadyOccupied(scanPosition)) {
                                        count++;
                                        leftMostWall = scanPosition;
                                    } else {
                                        break;
                                    }
                                }
                                break;
                            }
                        }

                        //if walls are sufficiently wide, then calculate position of wall placed world object
                        if (count >= requiredWidth) {

                            Vector3 centerWall = (leftMostWall + rightMostWall) / 2;
                            Vector3 requiredDepth = normal * (cursor.Size.z / 2);
                            Vector3 wallOffset = normal * (Wall.SizeStatic.z / 2);

                            position = centerWall + requiredDepth + wallOffset;
                            return true;
                        }
                    }
                }
            }
            position = Vector3.zero;
            normal = Vector3.zero;
            return false;
        }
 /// <summary>
 /// Places the <paramref name="worldObject"/> at <paramref name="position"/>
 /// </summary>
 /// <param name="worldObject">the object to place</param>
 /// <param name="position">the position to place it</param>
 public void Place(WorldObject worldObject, Vector3 position)
 {
     Vector3 location;
     if (worldObject.GridPlaceable) {
         location = PositionToGridLocation(position, worldObject.Size);
     } else {
         location = PositionToLocation(position, worldObject.Size);
     }
     World.AddObject(WorldObject.Initialise(worldObject, location, Vector3.zero));
 }
 /// <summary>
 /// Gets the Quaternion result of rotating from <paramref name="obj"/>'s current rotation to the angle of <paramref name="yVal"/>
 /// </summary>
 /// <param name="obj">The Object to rotate</param>
 /// <param name="yVal">The angle to rotate to</param>
 /// <returns>The angle to rotate by</returns>
 private static Quaternion rotateToY(WorldObject obj, int yVal)
 {
     return Quaternion.Euler(obj.GameObject.transform.rotation.eulerAngles.x, yVal,
         obj.GameObject.transform.rotation.eulerAngles.z);
 }
 /// <summary>
 /// Initialise the game object into the environment
 /// </summary>
 /// <param name="worldObject">The world object to initialise</param>
 /// <param name="position">Position within the environment</param>
 /// <param name="wallNormal">The facing direction</param>
 /// <returns>Initialised WorldObject</returns>
 public static WorldObject Initialise(WorldObject worldObject, Vector3 position, Vector3 wallNormal)
 {
     worldObject.InitialWallNormal = Vector3.zero;
     worldObject.GameObject = (GameObject)BootStrapper.Initialise(
         worldObject.Identifier,
         position + worldObject.InitialPositionOffSet,
         worldObject.InitialRotationOffSet
         );
     return worldObject;
 }
        /// <summary>
        /// Basic withinbounds checker, simple AABB collision detection
        /// </summary>
        /// <param name="worldObject">Another world object</param>
        /// <returns>If <paramref name="worldObject"/> is overlapping</returns>
        public bool WithinBounds(WorldObject worldObject)
        {
            Vector3 position = GameObject.transform.position;
            Vector3 halfSize = this.Size / 2;

            Vector3 otherPosition = worldObject.GameObject.transform.position;
            Vector3 otherHalfSize = worldObject.Size / 2;

            var xDifference = Mathf.Abs(position.x - otherPosition.x);
            var zDifference = Mathf.Abs(position.z - otherPosition.z);

            var halfWidthSum = halfSize.x + otherHalfSize.x;
            var halfLengthSum = halfSize.z + otherHalfSize.z;

            return (xDifference < halfWidthSum) && (zDifference < halfLengthSum); //AABB
        }
 /// <summary>
 /// Sets the current placement object
 /// </summary>
 /// <param name="objectName">new placement object</param>
 /// <param name="groundPosition">current ground position</param>
 public void SetPlacementObject(string objectName, Vector3 groundPosition)
 {
     currentItem = objectName;
     DestroyCursors();
     primaryCursor = NewCursor(WorldObject.DetermineObject(objectName), groundPosition);
 }
 /// <summary>
 /// Sets a cursor material to green
 /// </summary>
 /// <param name="cursor">cursor</param>
 private void SetCursorValid(WorldObject cursor)
 {
     cursor.GameObject.GetComponent<Renderer>().material = cursorMaterial;
 }
 /// <summary>
 /// Sets height of cursor
 /// </summary>
 /// <param name="cursor">cursor</param>
 private void SetCursorHeight(WorldObject cursor)
 {
     var position = cursor.GameObject.transform.position;
     cursor.GameObject.transform.position = new Vector3(position.x, cursor.CursorHeight.y, position.z);
 }
 /// <summary>
 /// Creates a new cursor with the given worldobject
 /// </summary>
 /// <param name="worldObject">the world object the cursor should look like</param>
 /// <param name="groundPosition">the position of the cursor</param>
 /// <returns>the new cursor object</returns>
 private WorldObject NewCursor(WorldObject worldObject, Vector3 groundPosition)
 {
     var cursor = WorldObject.Initialise(worldObject, groundPosition, Vector3.zero);
     SetCursorValid(cursor);
     Collider collider = cursor.GameObject.GetComponent<Collider>();
     if (collider != null) collider.enabled = false;
     return cursor;
 }
        /// <summary>
        /// updates ghost cursor
        /// </summary>
        /// <param name="groundPosition">current ground position</param>
        public void UpdateSecondaryCursor(Vector3 groundPosition)
        {
            //secondary cursor for drag to place
            secondCursor = NewCursor(WorldObject.DetermineObject(currentItem), groundPosition);
            Vector3 mousePosition = groundPosition;

            Vector3 secondCursorPosition;
            var xDiff = startPlacement.x - mousePosition.x;
            var zDiff = startPlacement.z - mousePosition.z;
            if (Mathf.Abs(xDiff) > Mathf.Abs(zDiff)) {
                secondCursorPosition = startPlacement + new Vector3(-xDiff, 0, 0);
            }
            else {
                secondCursorPosition = startPlacement + new Vector3(0, 0, -zDiff);
            }

            secondCursor.GameObject.transform.position =
                Environment.Environment.PositionToLocation(secondCursorPosition,
                    primaryCursor.Size);
            SetCursorHeight(secondCursor);
            secondCursor.GameObject.transform.rotation = primaryCursor.GameObject.transform.rotation;

            if (!primaryCursor.GridPlaceable) { // wall placement
                Vector3 position;
                Vector3 normal;
                if (worldBuilderPlacement.WallPlacement(out normal, out position, primaryCursor)) {
                    secondCursor.LookTowardsNormal(normal);
                    SetCursorValid(secondCursor);
                } else {
                    SetCursorInvalid(secondCursor);
                }
            }
        }