private void MakeSegmentFollowPath(ObjectPlacementBoxStackSegment segment) { float angleFromFirstSegment = Vector3.Angle(_pathSegments[0].ExtensionDirection, segment.ExtensionDirection); Quaternion rotation = Quaternion.AngleAxis(angleFromFirstSegment, _pathExtensionPlane.Plane.normal); segment.SetRotationForAllStacks(rotation * _startObjectHierarchyWorldOrientedBox.Rotation); }
public static List <ObjectPlacementBoxStack> GetOverlappedStacksInSegment(int segmentIndex, List <ObjectPlacementBoxStackSegment> pathSegments) { var overlappedStacks = new List <ObjectPlacementBoxStack>(pathSegments.Count * 10); ObjectPlacementBoxStackSegment possiblyOverlappedSegment = pathSegments[segmentIndex]; for (int possiblyOverlappingSegmentIndex = segmentIndex - 1; possiblyOverlappingSegmentIndex >= 0; --possiblyOverlappingSegmentIndex) { ObjectPlacementBoxStackSegment possiblyOverlappingSegment = pathSegments[possiblyOverlappingSegmentIndex]; if (possiblyOverlappingSegment.ExtensionVectorIntersects(possiblyOverlappedSegment) || possiblyOverlappingSegment.ExtensionVectorOverlaps(possiblyOverlappedSegment)) { for (int possiblyOverlappedStackIndex = 0; possiblyOverlappedStackIndex < possiblyOverlappedSegment.NumberOfStacks; ++possiblyOverlappedStackIndex) { ObjectPlacementBoxStack possiblyOverlappedStack = possiblyOverlappedSegment.GetStackByIndex(possiblyOverlappedStackIndex); for (int possiblyOverlappingStackIndex = 0; possiblyOverlappingStackIndex < possiblyOverlappingSegment.NumberOfStacks; ++possiblyOverlappingStackIndex) { ObjectPlacementBoxStack possiblyOverlappingStack = possiblyOverlappingSegment.GetStackByIndex(possiblyOverlappingStackIndex); if (IsStackOverlappedBy(possiblyOverlappedStack, possiblyOverlappingStack)) { overlappedStacks.Add(possiblyOverlappedStack); } } } } } return(overlappedStacks); }
public bool ExtensionVectorIntersects(ObjectPlacementBoxStackSegment querySegment) { if (NumberOfStacks == 0 || querySegment.NumberOfStacks == 0) { return(false); } if (_extensionDirection.IsPerpendicularTo(querySegment.ExtensionDirection)) { Plane segmentBasePlane = GetBasePlane(); Vector3 thisSegmentStart = segmentBasePlane.ProjectPoint(FirstStackBasePosition); Vector3 thisSegmentEnd = segmentBasePlane.ProjectPoint(LastStackBasePosition); if (NumberOfStacks == 1) { thisSegmentEnd = thisSegmentStart + _extensionDirection * 0.5f * GetBoxSizeAlongNormalizedDirection(_extensionDirection); } Vector3 querySegmentStart = segmentBasePlane.ProjectPoint(querySegment.FirstStackBasePosition); Vector3 querySegmentEnd = segmentBasePlane.ProjectPoint(querySegment.LastStackBasePosition); if (querySegment.NumberOfStacks == 1) { querySegmentEnd = querySegmentStart + querySegment.ExtensionDirection * 0.5f * querySegment.GetBoxSizeAlongNormalizedDirection(querySegment.ExtensionDirection); } Segment3D thisSegment3D = new Segment3D(thisSegmentStart, thisSegmentEnd); Segment3D querySegment3D = new Segment3D(querySegmentStart, querySegmentEnd); return(thisSegment3D.IntersectsWith(querySegment3D)); } return(false); }
public bool ExtensionVectorOverlaps(ObjectPlacementBoxStackSegment querySegment) { if (NumberOfStacks == 0 || querySegment.NumberOfStacks == 0) { return(false); } if (_extensionDirection.IsAlignedWith(querySegment.ExtensionDirection)) { Plane segmentBasePlane = GetBasePlane(); Vector3 thisSegmentStart = segmentBasePlane.ProjectPoint(FirstStackBasePosition); Vector3 thisSegmentEnd = segmentBasePlane.ProjectPoint(LastStackBasePosition); if (NumberOfStacks == 1) { thisSegmentEnd = thisSegmentStart + _extensionDirection * 0.5f * GetBoxSizeAlongNormalizedDirection(_extensionDirection); } Vector3 querySegmentStart = segmentBasePlane.ProjectPoint(querySegment.FirstStackBasePosition); Vector3 querySegmentEnd = segmentBasePlane.ProjectPoint(querySegment.LastStackBasePosition); if (querySegment.NumberOfStacks == 1) { querySegmentEnd = querySegmentStart + querySegment.ExtensionDirection * 0.5f * querySegment.GetBoxSizeAlongNormalizedDirection(querySegment.ExtensionDirection); } return(querySegmentStart.IsOnSegment(thisSegmentStart, thisSegmentEnd) || querySegmentEnd.IsOnSegment(thisSegmentStart, thisSegmentEnd) || thisSegmentStart.IsOnSegment(querySegmentStart, querySegmentEnd) || thisSegmentEnd.IsOnSegment(querySegmentStart, querySegmentEnd)); } return(false); }
private void CreateFirstSegmentInBlock() { ObjectPlacementBoxStackSegment firstSegmentInBlock = CreateNewSegment(); firstSegmentInBlock.SetExtensionDirection(_segmentExtensionDirection); firstSegmentInBlock.SetFirstStackBasePosition(_startObjectHierarchyWorldOrientedBox.Center); }
private Vector3 CalculateSegmentConnectionOffsetForNoCornerExclusion(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment) { // No offset if the destination segment doesn't have any stacks if (destinationSegment.NumberOfStacks == 0) { return(Vector3.zero); } bool srcPointsInSameDirAsDestination; bool srcExtensionDirAlignedWithDestDir = sourceSegment.ExtensionDirection.IsAlignedWith(destinationSegment.ExtensionDirection, out srcPointsInSameDirAsDestination); float multiplicationSign = 1.0f; if (srcExtensionDirAlignedWithDestDir) { if (!srcPointsInSameDirAsDestination) { multiplicationSign *= -1.0f; } } float destBoxSizeAlongDestExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection); float srcBoxSizeAlongDestExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection); Vector3 offsetAlongDestExtensionDir = destinationSegment.ExtensionDirection * (destBoxSizeAlongDestExtensionDir - srcBoxSizeAlongDestExtensionDir) * 0.5f; float destBoxSizeAlongSrcExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection); float srcBoxSizeAlongSrcExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection); Vector3 offsetAlongSourceExtensionDir = multiplicationSign * sourceSegment.ExtensionDirection * ((srcBoxSizeAlongSrcExtensionDir + destBoxSizeAlongSrcExtensionDir) * 0.5f + _paddingSettings.PaddingAlongExtensionPlane); return(offsetAlongDestExtensionDir + offsetAlongSourceExtensionDir); }
public void AdjustSegmentHeight(ObjectPlacementBoxStackSegment segment, int indexOfFirstStackToAdjust, ObjectPlacementBlockAutomaticRandomHeightAdjustmentSettings automaticRandomHeightAdjustmentSettings) { Range <int> randomValueRange = new Range <int>(automaticRandomHeightAdjustmentSettings.MinHeight, automaticRandomHeightAdjustmentSettings.MaxHeight); int numberOfStacksToAdjust = segment.NumberOfStacks - indexOfFirstStackToAdjust; segment.SetHeightForStacksStartingAt(indexOfFirstStackToAdjust, RandomValueGeneration.GenerateIntRandomValuesInRange(randomValueRange, numberOfStacksToAdjust)); }
private void ReconnectAllSegments() { for (int segmentIndex = 1; segmentIndex < _pathSegments.Count; ++segmentIndex) { ObjectPlacementBoxStackSegment currentSegment = _pathSegments[segmentIndex]; ObjectPlacementBoxStackSegment previousSegment = _pathSegments[segmentIndex - 1]; currentSegment.ConnectFirstStackToLastStackInSegment(previousSegment, CalculateSegmentConnectionOffset(currentSegment, previousSegment)); } }
private void AppendSegments(int numberOfSegmentsToAppend) { for (int segmentIndex = 0; segmentIndex < numberOfSegmentsToAppend; ++segmentIndex) { ObjectPlacementBoxStackSegment lastSegmentInBlock = LastSegment; ObjectPlacementBoxStackSegment segmentToAppend = CreateNewSegment(); segmentToAppend.SetExtensionDirection(_segmentExtensionDirection); segmentToAppend.Extend(FirstSegment.NumberOfStacks); AppendSegmentToSegment(segmentToAppend, lastSegmentInBlock); } }
public void ApplyBordersToAllPathSegments(List <ObjectPlacementBoxStackSegment> pathSegments, ObjectPlacementPathBorderSettings borderSettings) { int totalNumberOfStacksInSegments = ObjectPlacementBoxStackSegmentQueries.GetTotalNumberOfStacksInSegments(pathSegments); int numberOfTraversedStacks = 0; for (int segmentIndex = 0; segmentIndex < pathSegments.Count; ++segmentIndex) { ObjectPlacementBoxStackSegment segment = pathSegments[segmentIndex]; for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { ObjectPlacementBoxStack stack = segment.GetStackByIndex(stackIndex); for (int boxIndex = 0; boxIndex < stack.NumberOfBoxes; ++boxIndex) { ObjectPlacementBox box = stack.GetBoxByIndex(boxIndex); box.ClearHideFlag(ObjectPlacementBoxHideFlags.PathApplyBorders); // Not hidden by default. We have to check against the borders to see if the box needs to be hidden. // Check if the box is outside the bottom and top borders if (boxIndex >= borderSettings.BottomBorderWidth && boxIndex < (stack.NumberOfBoxes - borderSettings.TopBorderWidth)) { // Check special case in which the current segment has the same extension direction as the one which precedes it // but is aiming in the opposite direction. In that case, the first stack will never be masked because it looks // weird. if (stackIndex == 0 && segmentIndex != 0) { ObjectPlacementBoxStackSegment previousSegment = pathSegments[segmentIndex - 1]; bool extendingInSameDirection; if (previousSegment.ExtensionDirection.IsAlignedWith(segment.ExtensionDirection, out extendingInSameDirection)) { // If the segments are aligned but they are extending in opposite directions, it means that // we have to leave the boxes in this stack untouched. if (!extendingInSameDirection) { continue; } } } if (numberOfTraversedStacks >= borderSettings.BeginBorderWidth && numberOfTraversedStacks < totalNumberOfStacksInSegments - borderSettings.EndBorderWidth) { box.SetHideFlag(ObjectPlacementBoxHideFlags.PathApplyBorders); } } } ++numberOfTraversedStacks; } } }
private ObjectPlacementBoxStackSegment CreateNewSegment() { var newSegment = new ObjectPlacementBoxStackSegment(); newSegment.SetExtensionDirection(_blockExtensionPlane.LookAxis); newSegment.SetGrowAxis(_blockExtensionPlane.UpAxis); newSegment.SetRotationForAllStacks(_startObjectHierarchyWorldOrientedBox.Rotation); newSegment.SetBoxSizeForAllStacks(_startObjectHierarchyWorldOrientedBox.ScaledSize); newSegment.SetPaddingAlongStackGrowDirection(_paddingSettings.PaddingAlongGrowDirection); newSegment.SetPaddingAlongExtensionDirection(_paddingSettings.PaddingAlongExtensionPlane); _blockSegments.Add(newSegment); return(newSegment); }
private void AdjustHeightForStackRangeInSegment(ObjectPlacementBoxStackSegment segment, int indexOfFirstStackToAdjust) { ObjectPlacementPathHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode; if (heightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.Manual) { _manualHeightAdjuster.AdjustSegmentHeight(segment, indexOfFirstStackToAdjust, _currentManualPathHeight); } else if (heightAdjustmentMode == ObjectPlacementPathHeightAdjustmentMode.AutomaticRandom) { _automaticRandomHeightAdjuster.AdjustSegmentHeight(segment, indexOfFirstStackToAdjust, _heightAdjustmentSettings.AutomaticRandomHeightAdjustmentSettings); } else { _automaticPatternHeightAdjuster.AdjustSegmentHeight(segment, _pathSegments, _heightAdjustmentSettings.AutomaticPatternHeightAdjustmentSettings, ObjectPlacementPathHeightPatternDatabase.Get().ActivePattern); } }
private Vector3 CalculateSegmentConnectionOffset(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment) { if (!CanExcludeCorners()) { return(CalculateSegmentConnectionOffsetForNoCornerExclusion(sourceSegment, destinationSegment)); } else { // Note: Corner exclusion is applied only if the 2 segments are perpendicular. if (sourceSegment.ExtensionDirection.IsPerpendicularTo(destinationSegment.ExtensionDirection)) { return(CalculateSegmentConnectionOffsetForCornerExclusion(sourceSegment, destinationSegment)); } else { return(CalculateSegmentConnectionOffsetForNoCornerExclusion(sourceSegment, destinationSegment)); } } }
public void AdjustSegmentHeight(ObjectPlacementBoxStackSegment segment, List <ObjectPlacementBoxStackSegment> allPathSegments, ObjectPlacementPathAutomaticPatternHeightAdjustmentSettings automaticPatternHeightAdjustmentSettings, ObjectPlacementPathHeightPattern heightPattern) { int initialHeightValueIndex = 0; if (automaticPatternHeightAdjustmentSettings.ApplyPatternsContinuously) { int indexOfSegmentToAdjust = allPathSegments.FindIndex(0, item => item == segment); if (indexOfSegmentToAdjust >= 0) { initialHeightValueIndex = ObjectPlacementBoxStackSegmentQueries.GetTotalNumberOfStacksInSegments(allPathSegments, indexOfSegmentToAdjust - 1); } } bool wrapPattern = automaticPatternHeightAdjustmentSettings.WrapPatterns; for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { segment.GetStackByIndex(stackIndex).SetHeight(heightPattern.GetHeightValue(initialHeightValueIndex + stackIndex, wrapPattern)); } }
public void Attach2NewSegments() { if (_isActive) { RemoveSegmentsWithNoStacks(); // First create the 2 new segments which will replace the current penultimate and last segments ObjectPlacementBoxStackSegment oldLastSegment = LastSegment; ObjectPlacementBoxStackSegment newPenultimateSegment = CreateNewSegment(); CreateNewSegment(); // We will want the first stack in the new penultimate segment to replace the last stack in 'LastSegment'. // Otherwise, when this function is called, an additional box will suddenly appear in the scene apparently // out of nowhere and it doesn't look very good. Not to mention that it can be quite confusing :). oldLastSegment.Shrink(1); newPenultimateSegment.Extend(1); newPenultimateSegment.SetExtensionDirection(oldLastSegment.ExtensionDirection); if (CanRotateObjectsToFollowPath()) { newPenultimateSegment.SetRotationForAllStacks(oldLastSegment.StackRotation); MakeSegmentFollowPath(LastSegment); } newPenultimateSegment.ConnectFirstStackToLastStackInSegment(oldLastSegment, CalculateSegmentConnectionOffset(newPenultimateSegment, oldLastSegment)); AdjustHeightForEntireSegment(PenultimateSegment); UpdateStackOverlapDataForLast2Segments(); if (_borderSettings.UseBorders) { _borderApplyOperation.ApplyBordersToAllPathSegments(_pathSegments, _borderSettings); } if (_tileConnectionSettings.UseTileConnections) { UpdateTileConnectionInformation(); } } }
private Vector3 CalculateSegmentConnectionOffsetForCornerExclusion(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment) { bool srcPointsInSameDirAsDestination; bool srcExtensionDirAlignedWithDestDir = sourceSegment.ExtensionDirection.IsAlignedWith(destinationSegment.ExtensionDirection, out srcPointsInSameDirAsDestination); float multiplicationSign = 1.0f; if (srcExtensionDirAlignedWithDestDir) { if (!srcPointsInSameDirAsDestination) { multiplicationSign *= -1.0f; } } float destBoxSizeAlongDestExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection); float srcBoxSizeAlongDestExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(destinationSegment.ExtensionDirection); Vector3 offsetAlongDestExtensionDir = destinationSegment.ExtensionDirection * Mathf.Abs((destBoxSizeAlongDestExtensionDir + srcBoxSizeAlongDestExtensionDir) * 0.5f); float destBoxSizeAlongSrcExtensionDir = destinationSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection); float srcBoxSizeAlongSrcExtensionDir = sourceSegment.GetBoxSizeAlongNormalizedDirection(sourceSegment.ExtensionDirection); Vector3 offsetAlongSourceExtensionDir = multiplicationSign * sourceSegment.ExtensionDirection * (srcBoxSizeAlongSrcExtensionDir + destBoxSizeAlongSrcExtensionDir) * 0.5f; return(offsetAlongDestExtensionDir + offsetAlongSourceExtensionDir); }
public void ApplySubdivisionToEntireBlock(List <ObjectPlacementBoxStackSegment> allBlockSegments, ObjectPlacementBlockSubdivisionSettings subdivisionSettings) { // No subdivision required? if (!subdivisionSettings.SubdivideAlongGrowDirection && !subdivisionSettings.SubdivideAlongExtensionRight && !subdivisionSettings.SubdivideAlongExtensionLook) { return; } // Note: The following code assumes the segments' stacks extend along the extension plane right axis // and the segments themselves are arranged along the plane's look axis. for (int segmentIndex = 0; segmentIndex < allBlockSegments.Count; ++segmentIndex) { int numberOfTraversedSegments = segmentIndex + 1; ObjectPlacementBoxStackSegment segment = allBlockSegments[segmentIndex]; segment.ClearHideFlagInAllStacks(ObjectPlacementBoxHideFlags.BlockApplySubdivisions); // If we must subdivide along the extension look axis, we may need to hide the entire segment based // on the number of segments we have traversed so far. if (subdivisionSettings.SubdivideAlongExtensionLook) { // First calculate the remainder of how many pairs of <subidvision, gap> we have traversed int subdivisionGapPairSize = subdivisionSettings.SubdivisionGapSizeAlongExtensionLook + subdivisionSettings.SubdivisionSizeAlongExtensionLook; int remainder = numberOfTraversedSegments % subdivisionGapPairSize; // If the remainder is 0 it means we are at the end of a pair and the end of a pair is always a gap. So we activate // the hide flags. We also activate the hide flags if the remainder is bigger than the subdivision size. In that case // it means we reside somewhere inside the gap. if (remainder == 0 || remainder > subdivisionSettings.SubdivisionSizeAlongExtensionLook) { segment.SetHideFlagInAllStacks(ObjectPlacementBoxHideFlags.BlockApplySubdivisions); } } for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { int numberOfTraversedStacks = stackIndex + 1; ObjectPlacementBoxStack stack = segment.GetStackByIndex(stackIndex); if (subdivisionSettings.SubdivideAlongExtensionRight) { int subdivisionGapPairSize = subdivisionSettings.SubdivisionGapSizeAlongExtensionRight + subdivisionSettings.SubdivisionSizeAlongExtensionRight; int remainder = numberOfTraversedStacks % subdivisionGapPairSize; if (remainder == 0 || remainder > subdivisionSettings.SubdivisionSizeAlongExtensionRight) { stack.SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockApplySubdivisions); } } for (int boxIndex = 0; boxIndex < stack.NumberOfBoxes; ++boxIndex) { int numberOfTraversedBoxes = boxIndex + 1; if (subdivisionSettings.SubdivideAlongGrowDirection) { int subdivisionGapPairSize = subdivisionSettings.SubdivisionGapSizeAlongGrowDirection + subdivisionSettings.SubdivisionSizeAlongGrowDirection; int remainder = numberOfTraversedBoxes % subdivisionGapPairSize; if (remainder == 0 || remainder > subdivisionSettings.SubdivisionSizeAlongGrowDirection) { stack.GetBoxByIndex(boxIndex).SetHideFlag(ObjectPlacementBoxHideFlags.BlockApplySubdivisions); } } } } } }
private void AppendSegmentToSegment(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment) { sourceSegment.ConnectFirstStackToFirstStackInSegment(destinationSegment, GetSegmentConnectionOffsetForAppendOperation()); }
public List <ObjectPlacementData> Calculate() { if (_path == null || _path.NumberOfSegments == 0 || !ObjectPlacementGuide.ExistsInScene) { return(new List <ObjectPlacementData>()); } Prefab placementGuidePrefab = ObjectPlacementGuide.Instance.SourcePrefab; Vector3 placementGuideWorldScale = ObjectPlacementGuide.Instance.WorldScale; float objectMissChance = _path.Settings.ManualConstructionSettings.ObjectMissChance; Vector3 yOffsetVector = _path.ExtensionPlane.normal * _path.Settings.ManualConstructionSettings.OffsetAlongGrowDirection; bool allowObjectIntersection = ObjectPlacementSettings.Get().ObjectIntersectionSettings.AllowIntersectionForPathPlacement; Quaternion placementGuideRotation = ObjectPlacementGuide.Instance.WorldRotation; bool rotateObjectsToFollowPath = _path.Settings.ManualConstructionSettings.RotateObjectsToFollowPath; Vector3 pathExtensionPlaneNormal = _path.ExtensionPlane.normal; Vector3 firstSegmentExtensionDir = _path.GetSegmentByIndex(0).ExtensionDirection; Quaternion firstSegmentRotation = Quaternion.LookRotation(firstSegmentExtensionDir, pathExtensionPlaneNormal); bool randomizePrefabs = _path.Settings.ManualConstructionSettings.RandomizePrefabs; PrefabCategory activePrefabCategory = PrefabCategoryDatabase.Get().ActivePrefabCategory; var objectPlacementDataInstances = new List <ObjectPlacementData>(_path.NumberOfSegments * 10); for (int segmentIndex = 0; segmentIndex < _path.NumberOfSegments; ++segmentIndex) { ObjectPlacementBoxStackSegment segment = _path.GetSegmentByIndex(segmentIndex); Quaternion worldRotation = placementGuideRotation; if (rotateObjectsToFollowPath) { // Note: ObjectPlacementPathManualConstructionSession.cs line 451. The design is a wreck. AGAIN :) if ((segmentIndex == 0 && _path.NumberOfSegments > 1 && segment.NumberOfStacks == 1)) { Vector3 dirBetweenStacks = segment.GetStackByIndex(0).BasePosition - _path.GetSegmentByIndex(1).GetStackByIndex(0).BasePosition; dirBetweenStacks.Normalize(); Quaternion segmentRotation = Quaternion.LookRotation(dirBetweenStacks, pathExtensionPlaneNormal); Quaternion fromPlacementGuideRotationToThis = QuaternionExtensions.GetRelativeRotation(placementGuideRotation, segmentRotation); worldRotation = fromPlacementGuideRotationToThis * worldRotation; } else if (segmentIndex != 0) { Quaternion segmentRotation = Quaternion.LookRotation(segment.ExtensionDirection, pathExtensionPlaneNormal); Quaternion fromFirstToThis = QuaternionExtensions.GetRelativeRotation(firstSegmentRotation, segmentRotation); worldRotation = fromFirstToThis * worldRotation; } } for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { ObjectPlacementBoxStack stack = segment.GetStackByIndex(stackIndex); if (stack.IsOverlappedByAnotherStack) { continue; } for (int stackBoxIndex = 0; stackBoxIndex < stack.NumberOfBoxes; ++stackBoxIndex) { ObjectPlacementBox box = stack.GetBoxByIndex(stackBoxIndex); if (box.IsHidden) { continue; } if (ObjectPlacementMissChance.Missed(objectMissChance, ObjectPlacementPathManualConstructionSettings.MinObjectMissChance, ObjectPlacementPathManualConstructionSettings.MaxObjectMissChance)) { continue; } if (!allowObjectIntersection && ObjectQueries.IntersectsAnyObjectsInScene(box.OrientedBox, true)) { continue; } Vector3 worldScale = placementGuideWorldScale; Prefab prefab = placementGuidePrefab; if (randomizePrefabs && activePrefabCategory.NumberOfPrefabs != 0) { int randomPrefabIndex = UnityEngine.Random.Range(0, activePrefabCategory.NumberOfPrefabs); Prefab randomPrefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); if (randomPrefab != null && randomPrefab.UnityPrefab != null) { prefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); worldScale = prefab.UnityPrefab.transform.lossyScale; } } var objectPlacementData = new ObjectPlacementData(); objectPlacementData.WorldPosition = ObjectPositionCalculator.CalculateObjectHierarchyPosition(prefab, box.Center + yOffsetVector, worldScale, worldRotation); objectPlacementData.WorldScale = worldScale; objectPlacementData.WorldRotation = worldRotation; objectPlacementData.Prefab = prefab; objectPlacementDataInstances.Add(objectPlacementData); } } } return(objectPlacementDataInstances); }
private void AdjustCornerExlcusionHideFlagsInSegment(ObjectPlacementBoxStackSegment segment) { segment.GetStackByIndex(0).SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners); segment.GetStackByIndex(LastSegment.NumberOfStacks - 1).SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners); }
public void AdjustSegmentHeight(ObjectPlacementBoxStackSegment segment, int indexOfFirstStackToAdjust, int desiredHeight) { segment.SetHeightForStacksStartingAt(indexOfFirstStackToAdjust, desiredHeight); }
public List <ObjectPlacementData> Calculate() { if (_block == null || _block.NumberOfSegments == 0 || !ObjectPlacementGuide.ExistsInScene) { return(new List <ObjectPlacementData>()); } Prefab placementGuidePrefab = ObjectPlacementGuide.Instance.SourcePrefab; Vector3 placementGuideWorldScale = ObjectPlacementGuide.Instance.WorldScale; Quaternion placementGuideWorldRotation = ObjectPlacementGuide.Instance.WorldRotation; float objectMissChance = _block.Settings.ManualConstructionSettings.ObjectMissChance; ObjectRotationRandomizationSettings blockObjectRotationRandomizationSettings = _block.Settings.ManualConstructionSettings.ObjectRotationRandomizationSettings; bool randomizeRotations = blockObjectRotationRandomizationSettings.RandomizeRotation; Vector3 objectOffsetAlongExtensionPlaneNormal = _block.Settings.ManualConstructionSettings.OffsetAlongGrowDirection * _block.ExtensionPlane.normal; bool allowObjectIntersection = ObjectPlacementSettings.Get().ObjectIntersectionSettings.AllowIntersectionForBlockPlacement; bool randomizePrefabs = _block.Settings.ManualConstructionSettings.RandomizePrefabs; PrefabCategory activePrefabCategory = PrefabCategoryDatabase.Get().ActivePrefabCategory; var objectPlacementDataInstances = new List <ObjectPlacementData>(_block.NumberOfSegments * 10); for (int segmentIndex = 0; segmentIndex < _block.NumberOfSegments; ++segmentIndex) { ObjectPlacementBoxStackSegment segment = _block.GetSegmentByIndex(segmentIndex); for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { ObjectPlacementBoxStack stack = segment.GetStackByIndex(stackIndex); if (stack.IsOverlappedByAnotherStack) { continue; } for (int stackBoxIndex = 0; stackBoxIndex < stack.NumberOfBoxes; ++stackBoxIndex) { ObjectPlacementBox box = stack.GetBoxByIndex(stackBoxIndex); if (box.IsHidden) { continue; } if (ObjectPlacementMissChance.Missed(objectMissChance, ObjectPlacementBlockManualConstructionSettings.MinObjectMissChance, ObjectPlacementBlockManualConstructionSettings.MaxObjectMissChance)) { continue; } if (!allowObjectIntersection && ObjectQueries.IntersectsAnyObjectsInScene(box.OrientedBox, true)) { continue; } Quaternion worldRotation = placementGuideWorldRotation; if (randomizeRotations) { worldRotation = ObjectRotationRandomization.GenerateRandomRotationQuaternion(blockObjectRotationRandomizationSettings); } Vector3 worldScale = placementGuideWorldScale; Prefab prefab = placementGuidePrefab; if (randomizePrefabs && activePrefabCategory.NumberOfPrefabs != 0) { int randomPrefabIndex = UnityEngine.Random.Range(0, activePrefabCategory.NumberOfPrefabs); Prefab randomPrefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); if (randomPrefab != null && randomPrefab.UnityPrefab != null) { prefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); worldScale = prefab.UnityPrefab.transform.lossyScale; } } var objectPlacementData = new ObjectPlacementData(); objectPlacementData.WorldPosition = ObjectPositionCalculator.CalculateObjectHierarchyPosition(prefab, box.Center + objectOffsetAlongExtensionPlaneNormal, worldScale, placementGuideWorldRotation); objectPlacementData.WorldScale = worldScale; objectPlacementData.WorldRotation = worldRotation; objectPlacementData.Prefab = prefab; objectPlacementDataInstances.Add(objectPlacementData); } } } return(objectPlacementDataInstances); }
public void AdjustSegmentHeight(ObjectPlacementBoxStackSegment segment, int desiredHeight) { segment.SetHeightForAllStacks(desiredHeight); }
public List <ObjectPlacementData> Calculate() { if (_block == null || _block.NumberOfSegments == 0 || !ObjectPlacementGuide.ExistsInScene) { return(new List <ObjectPlacementData>()); } Prefab placementGuidePrefab = ObjectPlacementGuide.Instance.SourcePrefab; Vector3 placementGuideWorldScale = ObjectPlacementGuide.Instance.WorldScale; Quaternion placementGuideWorldRotation = ObjectPlacementGuide.Instance.WorldRotation; float objectMissChance = _block.Settings.ManualConstructionSettings.ObjectMissChance; ObjectRotationRandomizationSettings blockObjectRotationRandomizationSettings = _block.Settings.ManualConstructionSettings.ObjectRotationRandomizationSettings; bool randomizeRotations = blockObjectRotationRandomizationSettings.RandomizeRotation; Vector3 objectOffsetAlongExtensionPlaneNormal = _block.Settings.ManualConstructionSettings.OffsetAlongGrowDirection * _block.ExtensionPlane.normal; bool allowObjectIntersection = ObjectPlacementSettings.Get().ObjectIntersectionSettings.AllowIntersectionForBlockPlacement; bool randomizePrefabs = _block.Settings.ManualConstructionSettings.RandomizePrefabs; PrefabCategory activePrefabCategory = PrefabCategoryDatabase.Get().ActivePrefabCategory; ObjectPlacementBlockProjectionSettings projectionSettings = _block.Settings.BlockProjectionSettings; bool canProject = projectionSettings.ProjectOnSurface && (projectionSettings.CanProjectOnMesh || projectionSettings.CanProjectOnTerrain); var objectPlacementDataInstances = new List <ObjectPlacementData>(_block.NumberOfSegments * 10); for (int segmentIndex = 0; segmentIndex < _block.NumberOfSegments; ++segmentIndex) { ObjectPlacementBoxStackSegment segment = _block.GetSegmentByIndex(segmentIndex); for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { ObjectPlacementBoxStack stack = segment.GetStackByIndex(stackIndex); if (stack.IsOverlappedByAnotherStack || stack.NumberOfBoxes == 0) { continue; } Vector3 projectionOffset = Vector3.zero; Vector3 projectionDirection = Vector3.zero; Quaternion prjAlignRotation = Quaternion.identity; GameObjectRayHit projectionSurfaceHit = null; if (canProject) { Vector3 rayOrigin = stack.GetBoxByIndex(0).Center; Vector3 rayDir = Vector3.zero; if (projectionSettings.ProjectionDirection == ObjectBlockProjectionDir.BlockUp) { rayDir = _block.ExtensionPlane.normal; } else { rayDir = -_block.ExtensionPlane.normal; } projectionDirection = rayDir; Ray ray = new Ray(rayOrigin, rayDir); GameObjectRayHit closestMeshHit = null; GameObjectRayHit closestTerrainHit = null; if (projectionSettings.CanProjectOnMesh) { closestMeshHit = Octave3DScene.Get().RaycastAllMeshClosest(ray); } if (projectionSettings.CanProjectOnTerrain) { closestTerrainHit = Octave3DScene.Get().RaycastAllTerainsClosest(ray); } // Ignore stack if no surface was found and non-projectables must be rejected if (closestMeshHit == null && closestTerrainHit == null) { if (projectionSettings.RejectNonProjectables) { continue; } } else { projectionSurfaceHit = closestMeshHit; if (closestMeshHit == null || (closestTerrainHit != null && closestMeshHit.HitEnter > closestTerrainHit.HitEnter)) { projectionSurfaceHit = closestTerrainHit; } } if (projectionSurfaceHit != null) { ObjectPlacementBox projectionBox = stack.GetBoxByIndex(0); projectionOffset = projectionSurfaceHit.HitPoint - stack.GetBoxByIndex(0).Center; if (projectionOffset.sqrMagnitude > (projectionSurfaceHit.HitPoint - stack.GetBoxByIndex(stack.NumberOfBoxes - 1).Center).sqrMagnitude) { projectionBox = stack.GetBoxByIndex(stack.NumberOfBoxes - 1); projectionOffset = projectionSurfaceHit.HitPoint - projectionBox.Center; } if (!projectionSettings.AlignToSurfaceNormal) { var oobb = projectionBox.OrientedBox; Vector3 oldCenter = oobb.Center; GameObjectExtensions.EmbedObjectBoxInSurface(oobb, projectionDirection, projectionSurfaceHit.HitObject); projectionOffset = oobb.Center - oldCenter; } } } for (int stackBoxIndex = 0; stackBoxIndex < stack.NumberOfBoxes; ++stackBoxIndex) { ObjectPlacementBox box = stack.GetBoxByIndex(stackBoxIndex); if (box.IsHidden) { continue; } if (ObjectPlacementMissChance.Missed(objectMissChance, ObjectPlacementBlockManualConstructionSettings.MinObjectMissChance, ObjectPlacementBlockManualConstructionSettings.MaxObjectMissChance)) { continue; } if (!allowObjectIntersection && ObjectQueries.IntersectsAnyObjectsInScene(box.OrientedBox, true)) { continue; } Quaternion worldRotation = placementGuideWorldRotation; if (randomizeRotations) { worldRotation = ObjectRotationRandomization.GenerateRandomRotationQuaternion(blockObjectRotationRandomizationSettings); } Vector3 worldScale = placementGuideWorldScale; Prefab prefab = placementGuidePrefab; if (randomizePrefabs && activePrefabCategory.NumberOfPrefabs != 0) { int randomPrefabIndex = UnityEngine.Random.Range(0, activePrefabCategory.NumberOfPrefabs); Prefab randomPrefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); if (randomPrefab != null && randomPrefab.UnityPrefab != null) { prefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); worldScale = prefab.UnityPrefab.transform.lossyScale; } } Vector3 boxCenter = box.Center + objectOffsetAlongExtensionPlaneNormal + projectionOffset; if (projectionSurfaceHit != null) { if (projectionSettings.AlignToSurfaceNormal) { worldRotation = AxisAlignment.CalculateRotationQuaternionForAxisAlignment(worldRotation, projectionSettings.AlignmentAxis, projectionSurfaceHit.HitNormal); OrientedBox prefabWorldOOBB = prefab.UnityPrefab.GetHierarchyWorldOrientedBox(); Vector3 oobbSize = prefabWorldOOBB.ScaledSize; int axisIndex = (int)((int)(projectionSettings.AlignmentAxis) * 0.5f); boxCenter = projectionSurfaceHit.HitPoint + projectionSurfaceHit.HitNormal * oobbSize[axisIndex] * 0.5f + (oobbSize[axisIndex] * stackBoxIndex * projectionSurfaceHit.HitNormal); } } var objectPlacementData = new ObjectPlacementData(); objectPlacementData.WorldPosition = ObjectPositionCalculator.CalculateObjectHierarchyPosition(prefab, boxCenter, worldScale, worldRotation); objectPlacementData.WorldScale = worldScale; objectPlacementData.WorldRotation = worldRotation; objectPlacementData.Prefab = prefab; objectPlacementDataInstances.Add(objectPlacementData); } } } return(objectPlacementDataInstances); }
public Quaternion Calculate(ObjectPlacementPathTileConnectionGridCell tileConnectionGridCell) { ObjectPlacementPath path = tileConnectionGridCell.TileConnectionPath; ObjectPlacementPathTileConnectionSettings tileConnectionSettings = path.Settings.TileConnectionSettings; Plane extensionPlane = path.ExtensionPlane; ObjectPlacementBoxStackSegment tileConnectionSegment = tileConnectionGridCell.TileConnectionSegment; ObjectPlacementBoxStack tileConnectionStack = tileConnectionGridCell.TileConnectionStack; bool usingSprites = tileConnectionSettings.UsesSprites(); float yAxisRotationInDegrees = ObjectPlacementPathTileConnectionYAxisRotations.GetAngleInDegrees(tileConnectionSettings.GetSettingsForTileConnectionType(tileConnectionGridCell.TileConnectionType).YAxisRotation); Quaternion yAxisRotation = Quaternion.AngleAxis(yAxisRotationInDegrees, extensionPlane.normal); Quaternion defaultRotation = Quaternion.LookRotation(path.ExtensionPlaneLookAxis, extensionPlane.normal); if (usingSprites) { defaultRotation = Quaternion.LookRotation(extensionPlane.normal, path.ExtensionPlaneLookAxis); } ObjectPlacementPathTileConnectionType tileConnectionType = tileConnectionGridCell.TileConnectionType; if (tileConnectionType == ObjectPlacementPathTileConnectionType.Autofill) { return(yAxisRotation * defaultRotation); } else if (tileConnectionType == ObjectPlacementPathTileConnectionType.Begin) { if (tileConnectionGridCell.NumberOfNeighbours == 0) { return(yAxisRotation * defaultRotation); } else { ObjectPlacementBoxStack neighbour = tileConnectionGridCell.GetFirstNeighbour().TileConnectionStack; Vector3 toNeighbour = tileConnectionStack.GetNormalizedBasePositionConnectionVectorTo(neighbour); if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, toNeighbour)); } return(yAxisRotation * Quaternion.LookRotation(toNeighbour, extensionPlane.normal)); } } else if (tileConnectionType == ObjectPlacementPathTileConnectionType.End) { ObjectPlacementBoxStack neighbour = tileConnectionGridCell.GetFirstNeighbour().TileConnectionStack; Vector3 toEndTile = neighbour.GetNormalizedBasePositionConnectionVectorTo(tileConnectionStack); if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, toEndTile)); } return(yAxisRotation * Quaternion.LookRotation(toEndTile, extensionPlane.normal)); } else if (tileConnectionType == ObjectPlacementPathTileConnectionType.Cross) { return(yAxisRotation * defaultRotation); } else if (tileConnectionType == ObjectPlacementPathTileConnectionType.TJunction) { ObjectPlacementBoxStack baseOfTJunction = null; if (tileConnectionGridCell.RightNeighbour != null && tileConnectionGridCell.LeftNeighbour != null) { baseOfTJunction = tileConnectionGridCell.ForwardNeighbour != null ? tileConnectionGridCell.ForwardNeighbour.TileConnectionStack : tileConnectionGridCell.BackNeighbour.TileConnectionStack; } else { baseOfTJunction = tileConnectionGridCell.RightNeighbour != null ? tileConnectionGridCell.RightNeighbour.TileConnectionStack : tileConnectionGridCell.LeftNeighbour.TileConnectionStack; } Vector3 toTJunction = baseOfTJunction.GetNormalizedBasePositionConnectionVectorTo(tileConnectionStack); if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, toTJunction)); } return(yAxisRotation * Quaternion.LookRotation(toTJunction, extensionPlane.normal)); } else if (tileConnectionType == ObjectPlacementPathTileConnectionType.Forward) { if (tileConnectionSegment.NumberOfStacks == 1) { if (tileConnectionGridCell.HasForwardAndBackNeightbours()) { ObjectPlacementBoxStack forwardNeighbour = tileConnectionGridCell.ForwardNeighbour.TileConnectionStack; ObjectPlacementBoxStack backNeighbour = tileConnectionGridCell.BackNeighbour.TileConnectionStack; Vector3 toForwardNeighbour = backNeighbour.GetNormalizedBasePositionConnectionVectorTo(forwardNeighbour); if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, toForwardNeighbour)); } return(yAxisRotation * Quaternion.LookRotation(toForwardNeighbour, extensionPlane.normal)); } else { ObjectPlacementBoxStack leftNeighbour = tileConnectionGridCell.LeftNeighbour.TileConnectionStack; ObjectPlacementBoxStack rightNeighbour = tileConnectionGridCell.RightNeighbour.TileConnectionStack; Vector3 toRightNeighbour = leftNeighbour.GetNormalizedBasePositionConnectionVectorTo(rightNeighbour); if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, toRightNeighbour)); } return(yAxisRotation * Quaternion.LookRotation(toRightNeighbour, extensionPlane.normal)); } } else { if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, tileConnectionSegment.ExtensionDirection)); } return(yAxisRotation * Quaternion.LookRotation(tileConnectionSegment.ExtensionDirection, extensionPlane.normal)); } } else { ObjectPlacementBoxStack firstNeighbour, secondNeighbour; if (tileConnectionGridCell.RightNeighbour != null) { firstNeighbour = tileConnectionGridCell.RightNeighbour.TileConnectionStack; secondNeighbour = tileConnectionGridCell.ForwardNeighbour != null ? tileConnectionGridCell.ForwardNeighbour.TileConnectionStack : tileConnectionGridCell.BackNeighbour.TileConnectionStack; } else if (tileConnectionGridCell.LeftNeighbour != null) { firstNeighbour = tileConnectionGridCell.LeftNeighbour.TileConnectionStack; secondNeighbour = tileConnectionGridCell.ForwardNeighbour != null ? tileConnectionGridCell.ForwardNeighbour.TileConnectionStack : tileConnectionGridCell.BackNeighbour.TileConnectionStack; } else if (tileConnectionGridCell.ForwardNeighbour != null) { firstNeighbour = tileConnectionGridCell.ForwardNeighbour.TileConnectionStack; secondNeighbour = tileConnectionGridCell.RightNeighbour != null ? tileConnectionGridCell.RightNeighbour.TileConnectionStack : tileConnectionGridCell.LeftNeighbour.TileConnectionStack; } else { firstNeighbour = tileConnectionGridCell.BackNeighbour.TileConnectionStack; secondNeighbour = tileConnectionGridCell.RightNeighbour != null ? tileConnectionGridCell.RightNeighbour.TileConnectionStack : tileConnectionGridCell.LeftNeighbour.TileConnectionStack; } Vector3 tileLook, tileRight; tileLook = firstNeighbour.GetNormalizedBasePositionConnectionVectorTo(tileConnectionStack); tileRight = tileConnectionStack.GetNormalizedBasePositionConnectionVectorTo(secondNeighbour); Vector3 tileUp = Vector3.Cross(tileLook, tileRight); if (Vector3.Dot(tileUp, extensionPlane.normal) < 0.0f) { tileLook = -tileRight; } if (usingSprites) { return(yAxisRotation * Quaternion.LookRotation(extensionPlane.normal, tileLook)); } return(yAxisRotation * Quaternion.LookRotation(tileLook, extensionPlane.normal)); } }
public void ConnectFirstStackToFirstStackInSegment(ObjectPlacementBoxStackSegment destinationSegment, Vector3 connectionOffset) { Vector3 newFirstStackBasePos = destinationSegment.FirstStackBasePosition + connectionOffset; SetFirstStackBasePosition(newFirstStackBasePos); }
public void AdjustSegmentHeight(ObjectPlacementBoxStackSegment segment, ObjectPlacementPathAutomaticRandomHeightAdjustmentSettings automaticRandomHeightAdjustmentSettings) { Range <int> randomValueRange = new Range <int>(automaticRandomHeightAdjustmentSettings.MinHeight, automaticRandomHeightAdjustmentSettings.MaxHeight); segment.SetHeightForAllStacks(RandomValueGeneration.GenerateIntRandomValuesInRange(randomValueRange, segment.NumberOfStacks)); }