void ModelBuildPreviewUpdate() { if (!modelBuildPreview || !crosshairOnBlock || modelBuildItem == null) { return; } Vector3 forward = env.cameraMain.transform.forward; modelBuildPreviewPosition = crosshairHitInfo.voxelCenter; modelBuildPreviewOffset += Input.GetAxis("Mouse ScrollWheel") * wheelSensibility; if (modelBuildPreviewOffset < 0) { modelBuildPreviewOffset = 0; } modelBuildPreviewPosition.y += (int)modelBuildPreviewOffset; // Orient voxel to player modelBuildRotation = 0; if (Mathf.Abs(forward.x) > Mathf.Abs(forward.z)) { if (forward.x > 0) { modelBuildRotation = 90; } else { modelBuildRotation = 270; } } else if (forward.z < 0) { modelBuildRotation = 180; } modelBuildPreviewGO = env.ModelHighlight(modelBuildItem, modelBuildPreviewPosition - Quaternion.Euler(0, modelBuildRotation, 0) * Misc.vector3half); modelBuildPreviewGO.transform.localRotation = Quaternion.Euler(0, modelBuildRotation, 0); }
/// <summary> /// Implements building stuff /// </summary> /// <param name="camPos">The camera position OR the character position in a 3rd person controller</param>"> protected void DoBuild(Vector3 camPos, Vector3 forward, Vector3 hintedPlacePos) { if (player.selectedItemIndex < 0 || player.selectedItemIndex >= player.items.Count) { return; } InventoryItem inventoryItem = player.GetSelectedItem(); ItemDefinition currentItem = inventoryItem.item; switch (currentItem.category) { case ItemCategory.Voxel: // Basic placement rules bool canPlace = crosshairOnBlock; Voxel existingVoxel = crosshairHitInfo.voxel; VoxelDefinition existingVoxelType = existingVoxel.type; Vector3 placePos; if (currentItem.voxelType.renderType == RenderType.Water && !canPlace) { canPlace = true; // water can be poured anywhere placePos = camPos + forward * 3f; } else { placePos = crosshairHitInfo.voxelCenter + crosshairHitInfo.normal; if (canPlace && crosshairHitInfo.normal.y == 1) { // Make sure there's a valid voxel under position (ie. do not build a voxel on top of grass) canPlace = (existingVoxelType != null && existingVoxelType.renderType != RenderType.CutoutCross && (existingVoxelType.renderType != RenderType.Water || currentItem.voxelType.renderType == RenderType.Water)); } } VoxelDefinition placeVoxelType = currentItem.voxelType; // Check voxel promotion bool isPromoting = false; if (canPlace) { if (existingVoxelType == currentItem.voxelType) { if (existingVoxelType.promotesTo != null) { // Promote existing voxel env.VoxelDestroy(crosshairHitInfo.voxelCenter); placePos = crosshairHitInfo.voxelCenter; placeVoxelType = existingVoxelType.promotesTo; isPromoting = true; } else if (crosshairHitInfo.normal.y > 0 && existingVoxelType.biomeDirtCounterpart != null) { env.VoxelPlace(crosshairHitInfo.voxelCenter, existingVoxelType.biomeDirtCounterpart); } } } // Compute rotation int textureRotation = 0; if (placeVoxelType.placeFacingPlayer && placeVoxelType.renderType.supportsTextureRotation()) { // Orient voxel to player if (Mathf.Abs(forward.x) > Mathf.Abs(forward.z)) { if (forward.x > 0) { textureRotation = 1; } else { textureRotation = 3; } } else if (forward.z < 0) { textureRotation = 2; } } // Final check, does it overlap existing geometry? if (canPlace && !isPromoting) { Quaternion rotationQ = Quaternion.Euler(0, Voxel.GetTextureRotationDegrees(textureRotation), 0); canPlace = !env.VoxelOverlaps(placePos, placeVoxelType, rotationQ, 1 << env.layerVoxels); if (!canPlace) { PlayCancelSound(); } } #if UNITY_EDITOR else if (env.constructorMode) { placePos = hintedPlacePos; placeVoxelType = currentItem.voxelType; canPlace = true; } #endif // Finally place the voxel if (canPlace) { // Consume item first if (!env.buildMode) { player.ConsumeItem(); } // Place it float amount = inventoryItem.quantity < 1f ? inventoryItem.quantity : 1f; env.VoxelPlace(placePos, placeVoxelType, true, placeVoxelType.tintColor, amount, textureRotation); // Moves back character controller if voxel is put just on its position const float minDist = 0.5f; float distSqr = Vector3.SqrMagnitude(camPos - placePos); if (distSqr < minDist * minDist) { MoveTo(transform.position + crosshairHitInfo.normal); } } break; case ItemCategory.Torch: if (crosshairOnBlock) { GameObject torchAttached = env.TorchAttach(crosshairHitInfo); if (!env.buildMode && torchAttached != null) { player.ConsumeItem(); } } break; case ItemCategory.Model: if (!modelBuildInProgress) { if (modelBuildPreview) { ModelPreviewCancel(); // check if building position is in frustum, otherwise cancel building Vector3 viewportPos = env.cameraMain.WorldToViewportPoint(modelBuildPreviewPosition); if (viewportPos.x < 0 || viewportPos.x > 1f || viewportPos.y < 0 || viewportPos.y > 1f || viewportPos.z < 0) { return; } modelBuildInProgress = true; env.ModelPlace(modelBuildPreviewPosition, currentItem.model, currentItem.model.buildDuration, modelBuildRotation, 1f, true, FinishBuilding); player.ConsumeItem(); } else { if (crosshairOnBlock) { modelBuildPreviewPosition = crosshairHitInfo.voxelCenter + new Vector3(0f, 1f, 0f); // Orient voxel to player modelBuildRotation = 0; if (Mathf.Abs(forward.x) > Mathf.Abs(forward.z)) { if (forward.x > 0) { modelBuildRotation = 1; } else { modelBuildRotation = 3; } } else if (forward.z < 0) { modelBuildRotation = 2; } modelBuildRotation = (int)Voxel.GetTextureRotationDegrees(modelBuildRotation); modelBuildPreviewGO = env.ModelHighlight(currentItem.model, crosshairHitInfo.voxelCenter + new Vector3(0.5f, -0.5f, 0.5f)); modelBuildPreviewGO.transform.localRotation = Quaternion.Euler(0, modelBuildRotation, 0); modelBuildPreview = true; } } } break; case ItemCategory.General: ThrowCurrentItem(camPos, forward); break; } }