/// <summary> /// Recalculate peak to make ground flat /// </summary> /// <param name="groundMesh">GroundMesh</param> protected void RecalculatePeak(GroundMesh groundMesh, Vector3 origin) { int nbVertex = groundMesh.computedVertex.Length; Vector3[] planPoints = new Vector3[3]; int ite = 0; for (int i = 0; i < nbVertex; i++) { if (groundMesh.computedVertex[i] != groundMesh.centerPosition) { planPoints[ite] = groundMesh.computedVertex[i]; ite++; if (ite >= 3) { break; } } } Vector4 groundPlan = MathCustom.GetPlaneValues(planPoints[0], planPoints[1], planPoints[2]); Vector3 newCenterPosition = MathCustom.LineCutPlaneCoordinates(origin, groundMesh.centerPosition * int.MaxValue, groundPlan); for (int i = 0; i < nbVertex; i++) { if (groundMesh.computedVertex[i] == groundMesh.centerPosition) { groundMesh.centerPosition = newCenterPosition; groundMesh.computedVertex[i] = newCenterPosition; } } }
private void MakeGroundMesh() { Vector3 startPos = new Vector3(-0.5f * CellSide, 0, -0.5f * CellSide); GroundMesh mesh = new GroundMesh(startPos, Length, Width, xVertices, zVertices, Seed); groundMesh.mesh.vertices = mesh.Vertices; groundMesh.mesh.triangles = mesh.Triangles; groundMesh.mesh.RecalculateNormals(); GetComponent <MeshCollider>().sharedMesh = groundMesh.mesh; }
/// <summary> /// Apply a new cell state /// </summary> /// <param name="groundMesh"></param> /// <param name="state"></param> public void SetCellState(GroundMesh groundMesh, CellState state) { _state = state; InitColor(); int length = groundMesh.smoothVertex.Length; for (int i = 0; i < length; i++) { SetVertexColors(); } }
/// <summary> /// Create the GameObject and the mesh of a DatagroundList /// </summary> /// <param name="groundMeshs">DataGround list</param> protected void CreateGroundMesh(List <DataGround> groundMeshs) { Vector3 origin = gameObject.transform.position; int index = 0; foreach (DataGround ground in groundMeshs) { GroundMesh newGround = TrianglesToGroundMesh(ground); DualTransformation(newGround); RecalculatePeak(newGround, origin); allGroundMesh.Add(newGround); index++; } }
/// <summary> /// Convert a GroundMesh from a DataGround /// </summary> /// <param name="dataMesh">Dataground</param> /// <returns></returns> protected GroundMesh TrianglesToGroundMesh(DataGround dataMesh) { int nbTriangle = dataMesh.triangles.Length; GroundMesh groundMesh = new GroundMesh(nbTriangle * 3, nbTriangle + 1, dataMesh.center); groundMesh.refTriangles = dataMesh.triangles; int[] lTriangles = new int[groundMesh.triangles.Length]; Vector3[] lVertex = new Vector3[nbTriangle + 1]; Vector3[] lNormals = new Vector3[nbTriangle + 1]; Vector2[] lUvs = new Vector2[nbTriangle + 1]; int ite = 0; for (int i = 0; i < nbTriangle; i++) { for (int j = 0; j < 3; j++) { int index = CustomGeneric.ArrayContain(lVertex, refVertices[dataMesh.triangles[i].verticesindex[j]]); if (index < 0) { lVertex[ite] = refVertices[dataMesh.triangles[i].verticesindex[j]]; lNormals[ite] = refNormals[dataMesh.triangles[i].verticesindex[j]]; ite++; } } } for (int i = 0; i < nbTriangle; i++) { Vector3 center = groundMesh.centerPosition; for (int j = 0; j < 3; j++) { lTriangles[i * 3 + j] = CustomGeneric.ArrayContain(lVertex, refVertices[dataMesh.triangles[i].verticesindex[j]]); } } groundMesh.vertex = lVertex; groundMesh.normals = lNormals; groundMesh.triangles = lTriangles; return(groundMesh); }
/// <summary> /// First init /// </summary> public void Init(GroundMesh meshObject) { meshObject.centerIndex = CustomGeneric.ArrayContain(meshObject.smoothVertex, meshObject.centerPosition); _indexes = meshObject.indexes; _stateHealth = 1; _walkable = true; _elevation = 1f; _isElevating = false; _neighborElevationID = -1; _groundMesh = meshObject; _poluted = false; _deforested = false; _axis = GetCenterPosition(); _personnalMesh = GetComponent <MeshFilter>().mesh; _personnalCollider = GetComponents <MeshCollider>(); _state = CellState.MOSS; UpdateHeight(0); InitColor(); }
/// <summary> /// Generate UV mapping /// </summary> /// <param name="groundMesh"></param> protected void GenerateTextureMap(GroundMesh groundMesh) { Vector3 cross = Vector3.Cross(Vector3.up, groundMesh.centerPosition); Vector3 py = groundMesh.centerPosition + cross; Vector3 pz = groundMesh.centerPosition + Vector3.Cross(cross, groundMesh.centerPosition); Vector4 cellPlan = MathCustom.GetPlaneValues(groundMesh.centerPosition, py, pz); for (int i = 0; i < groundMesh.smoothVertex.Length; i++) { Vector3 vertex = groundMesh.smoothVertex[i]; if (vertex == groundMesh.centerPosition) { groundMesh.UVs[i] = new Vector2(0.5f, 0.5f); } else { Vector3 planeCoord = MathCustom.LineCutPlaneCoordinates(Vector3.zero, vertex, cellPlan); Vector3 cartesianPos = Quaternion.FromToRotation(groundMesh.centerPosition, Vector3.up) * planeCoord; float lRadius; float lPolar; float lElevation; MathCustom.CartesianToSpherical(cartesianPos, out lRadius, out lPolar, out lElevation); float xAngle = Vector3.SignedAngle(groundMesh.centerPosition, vertex, groundMesh.centerPosition); float yAngle = Vector3.SignedAngle(Vector3.Cross(groundMesh.centerPosition, -Vector3.up), vertex, groundMesh.centerPosition); if (CustomGeneric.IntArrayContain(groundMesh.indexes.internVertexIndex, i) != -1) { groundMesh.UVs[i] = new Vector2(0.5f + (Mathf.Cos(lPolar) * 0.9f), 0.5f + (Mathf.Sin(lPolar) * 0.9f)); } else { groundMesh.UVs[i] = new Vector2(0.5f + Mathf.Cos(lPolar), 0.5f + Mathf.Sin(lPolar)); } } } }
/// <summary> /// Return a list containing the internvertex linked to an edgevertex /// </summary> /// <param name="groundMesh"></param> /// <param name="edgeIndex"></param> /// <returns></returns> public static List <int> GetLinkedInternVertexIndexes(GroundMesh groundMesh, int edgeIndex) { int nbTriangle = groundMesh.smoothTriangles.Length / 3; List <int> linkedInternVertex = new List <int>(); for (int i = 0; i < nbTriangle; i++) { Vector3 v1 = groundMesh.smoothVertex[groundMesh.smoothTriangles[i * 3]]; Vector3 v2 = groundMesh.smoothVertex[groundMesh.smoothTriangles[i * 3 + 1]]; Vector3 v3 = groundMesh.smoothVertex[groundMesh.smoothTriangles[i * 3 + 2]]; if (v1 == groundMesh.smoothVertex[edgeIndex] || v2 == groundMesh.smoothVertex[edgeIndex] || v3 == groundMesh.smoothVertex[edgeIndex]) { foreach (int finternIndex in groundMesh.indexes.internVertexIndex) { if (groundMesh.smoothVertex[finternIndex] == v1 || groundMesh.smoothVertex[finternIndex] == v2 || groundMesh.smoothVertex[finternIndex] == v3) { linkedInternVertex.Add(finternIndex); } } } } return(linkedInternVertex); }
/// <summary> /// Get the dual transformation of a GroundMesh /// </summary> /// <param name="groundMesh">GroundMesh</param> protected void DualTransformation(GroundMesh groundMesh) { Vector3[] computedVertices = new Vector3[groundMesh.computedVertex.Length]; Vector3[] computedNormals = new Vector3[groundMesh.computedVertex.Length]; for (int i = 0; i < groundMesh.triangles.Length / 3; i++) { Vector3 addVector = Vector3.zero + groundMesh.centerPosition; if (groundMesh.vertex[groundMesh.triangles[i * 3]] != groundMesh.centerPosition) { addVector += groundMesh.vertex[groundMesh.triangles[i * 3]]; } if (groundMesh.vertex[groundMesh.triangles[i * 3 + 1]] != groundMesh.centerPosition) { addVector += groundMesh.vertex[groundMesh.triangles[i * 3 + 1]]; } if (groundMesh.vertex[groundMesh.triangles[i * 3 + 2]] != groundMesh.centerPosition) { addVector += groundMesh.vertex[groundMesh.triangles[i * 3 + 2]]; } computedVertices[i] = addVector.normalized * radius; computedNormals[i] = computedVertices[i].normalized; } computedVertices[computedVertices.Length - 2] = Vector3.zero; computedNormals[computedNormals.Length - 2] = -groundMesh.centerPosition.normalized; computedVertices[computedVertices.Length - 1] = groundMesh.centerPosition; computedNormals[computedNormals.Length - 1] = groundMesh.centerPosition.normalized; groundMesh.computedVertex = computedVertices; groundMesh.computedNormals = computedNormals; // Creation of the dual triangles array int nbTriangle = groundMesh.triangles.Length / 3; VertexCouple[] couples = new VertexCouple[nbTriangle]; for (int i = 0; i < nbTriangle; i++) { couples[i] = new VertexCouple(Vector3.zero, Vector3.zero); } int ite = 0; for (int j = 0; j < groundMesh.computedVertex.Length; j++) { for (int k = 0; k < groundMesh.computedVertex.Length; k++) { if (groundMesh.computedVertex[j] != groundMesh.centerPosition && groundMesh.computedVertex[k] != groundMesh.centerPosition && groundMesh.computedVertex[j] != Vector3.zero && groundMesh.computedVertex[k] != Vector3.zero) { float angle = Vector3.Angle(groundMesh.centerPosition - groundMesh.computedVertex[j], groundMesh.centerPosition - groundMesh.computedVertex[k]); if (angle > 2 && angle < 70) { VertexCouple newCouple = new VertexCouple(groundMesh.computedVertex[j], groundMesh.computedVertex[k]); if (!CoupleExist(couples, newCouple)) { couples[ite] = newCouple; ite++; } } } } } int[] lTriangles = new int[groundMesh.triangles.Length * 2]; for (int i = 0; i < couples.Length; i++) { Vector3 surfaceNormal = Vector3.Cross(groundMesh.centerPosition + couples[i].vertices[0], groundMesh.centerPosition + couples[i].vertices[1]); float angle = Vector3.Angle(gameObject.transform.position + groundMesh.centerPosition, surfaceNormal); if (angle < 90) { lTriangles[i * 3] = ArrayContain(groundMesh.computedVertex, groundMesh.centerPosition); lTriangles[i * 3 + 1] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[0]); lTriangles[i * 3 + 2] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[1]); } else { lTriangles[i * 3] = ArrayContain(groundMesh.computedVertex, groundMesh.centerPosition); lTriangles[i * 3 + 1] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[1]); lTriangles[i * 3 + 2] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[0]); } Vector4 face = MathCustom.GetPlaneValues(Vector3.zero, couples[i].vertices[1], couples[i].vertices[0]); if (MathCustom.GetDistanceToPlane(groundMesh.centerPosition, face) > 0) { lTriangles[groundMesh.triangles.Length + i * 3] = ArrayContain(groundMesh.computedVertex, Vector3.zero); lTriangles[groundMesh.triangles.Length + i * 3 + 1] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[0]); lTriangles[groundMesh.triangles.Length + i * 3 + 2] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[1]); } else { lTriangles[groundMesh.triangles.Length + i * 3] = ArrayContain(groundMesh.computedVertex, Vector3.zero); lTriangles[groundMesh.triangles.Length + i * 3 + 1] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[1]); lTriangles[groundMesh.triangles.Length + i * 3 + 2] = ArrayContain(groundMesh.computedVertex, couples[i].vertices[0]); } } groundMesh.computedTriangles = lTriangles; }
private void Update() { if (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1)) { GameManager.Instance.Map.CommandManager.FinishAction(); } RaycastHit raycast = LayoutManager.Instance.CurrentCamera.CurrentRaycast; if (!raycast.transform) { return; } OverlayMesh overlayMesh = raycast.transform.GetComponent <OverlayMesh>(); GroundMesh groundMesh = raycast.transform.GetComponent <GroundMesh>(); TileEntity tileEntity = raycast.transform.GetComponent <TileEntity>(); Wall wallEntity = tileEntity as Wall; bool automaticReverse = automaticReverseToggle.isOn; bool reverse = reverseToggle.isOn; int floor = 0; int x = -1; int y = -1; bool horizontal = false; bool propertiesNeedSaving = false; if (automaticReverse != Properties.Instance.WallAutomaticReverse) { Properties.Instance.WallAutomaticReverse = automaticReverse; propertiesNeedSaving = true; } if (reverse != Properties.Instance.WallReverse) { Properties.Instance.WallReverse = reverse; propertiesNeedSaving = true; } if (propertiesNeedSaving) { Properties.Instance.SaveProperties(); } if (wallEntity && wallEntity.Valid) { floor = tileEntity.Floor; if (LayoutManager.Instance.CurrentCamera.Floor == floor + 1) { floor++; } x = tileEntity.Tile.X; y = tileEntity.Tile.Y; EntityType type = tileEntity.Type; horizontal = (type == EntityType.Hwall || type == EntityType.Hfence); } else if (overlayMesh || groundMesh) { if (overlayMesh) { floor = LayoutManager.Instance.CurrentCamera.Floor; } else if (groundMesh) { floor = 0; } TileSelectionHit tileSelectionHit = TileSelection.PositionToTileSelectionHit(raycast.point, TileSelectionMode.Borders); TileSelectionTarget target = tileSelectionHit.Target; if (target == TileSelectionTarget.Nothing) { return; } x = tileSelectionHit.X; y = tileSelectionHit.Y; horizontal = (target == TileSelectionTarget.BottomBorder); } if (Input.GetMouseButton(0)) { Floor currentFloor = GameManager.Instance.Map[x, y].GetTileContent(floor) as Floor; bool shouldReverse = false; if (automaticReverse && horizontal) { Floor nearFloor = GameManager.Instance.Map[x, y - 1].GetTileContent(floor) as Floor; shouldReverse = currentFloor && !nearFloor; } else if (automaticReverse && !horizontal) { Floor nearFloor = GameManager.Instance.Map[x - 1, y].GetTileContent(floor) as Floor; shouldReverse = !currentFloor && nearFloor; } if (reverse) { shouldReverse = !shouldReverse; } WallData data = GuiManager.Instance.WallsTree.SelectedValue as WallData; if (horizontal) { GameManager.Instance.Map[x, y].SetHorizontalWall(data, shouldReverse, floor); } else { GameManager.Instance.Map[x, y].SetVerticalWall(data, shouldReverse, floor); } } else if (Input.GetMouseButton(1)) { if (floor != LayoutManager.Instance.CurrentCamera.Floor) { return; } if (horizontal) { GameManager.Instance.Map[x, y].SetHorizontalWall(null, false, floor); } else { GameManager.Instance.Map[x, y].SetVerticalWall(null, false, floor); } } }
/// <summary> /// Cut the mesh to create a smoothable cell /// </summary> /// <param name="groundMesh">GroundMesh</param> protected void PrepareMeshForSmooth(GroundMesh groundMesh) { Vector3[] internVertex = new Vector3[2]; Vector3 midEdgeVertex = Vector3.zero; Vector3[] edgeVertex = new Vector3[2]; Vector3[] smoothVertex = new Vector3[(groundMesh.triangles.Length * 4) + groundMesh.triangles.Length]; int iterator = 0; for (int i = 0; i < groundMesh.computedTriangles.Length / 3; i++) { if (groundMesh.computedVertex[groundMesh.computedTriangles[i * 3]] == Vector3.zero) { continue; } Vector3 ver1 = groundMesh.computedVertex[groundMesh.computedTriangles[(i * 3) + 1]]; Vector3 ver2 = groundMesh.computedVertex[groundMesh.computedTriangles[(i * 3) + 2]]; internVertex[0] = (groundMesh.centerPosition + ver1) / 2f; internVertex[1] = (groundMesh.centerPosition + ver2) / 2f; Vector3 vDir1 = (internVertex[0] - groundMesh.centerPosition); Vector3 vDir2 = (internVertex[1] - groundMesh.centerPosition); internVertex[0] = internVertex[0] + (vDir1 * CellWidth); internVertex[1] = internVertex[1] + (vDir2 * CellWidth); float d = Vector3.Distance(internVertex[0], internVertex[1]) / 2f; midEdgeVertex = (ver1 + ver2) / 2f; edgeVertex[0] = midEdgeVertex + (midEdgeVertex - ver1).normalized * d; edgeVertex[1] = midEdgeVertex + (midEdgeVertex - ver2).normalized * d; for (int j = 0; j < 5; j++) { switch (j) { case 0: smoothVertex[iterator * 3] = groundMesh.centerPosition; smoothVertex[(iterator * 3) + 1] = internVertex[0]; smoothVertex[(iterator * 3) + 2] = internVertex[1]; break; case 1: smoothVertex[iterator * 3] = internVertex[0]; if (Vector3.Distance(ver1, internVertex[0]) > Vector3.Distance(ver2, internVertex[0])) { smoothVertex[iterator * 3 + 1] = ver2; } else { smoothVertex[iterator * 3 + 1] = ver1; } if (Vector3.Distance(edgeVertex[0], internVertex[0]) > Vector3.Distance(edgeVertex[1], internVertex[0])) { smoothVertex[iterator * 3 + 2] = edgeVertex[1]; } else { smoothVertex[iterator * 3 + 2] = edgeVertex[0]; } break; case 2: smoothVertex[iterator * 3] = internVertex[1]; if (Vector3.Distance(edgeVertex[0], internVertex[1]) > Vector3.Distance(edgeVertex[1], internVertex[1])) { smoothVertex[iterator * 3 + 1] = edgeVertex[1]; } else { smoothVertex[iterator * 3 + 1] = edgeVertex[0]; } if (Vector3.Distance(ver1, internVertex[1]) > Vector3.Distance(ver2, internVertex[1])) { smoothVertex[iterator * 3 + 2] = ver2; } else { smoothVertex[iterator * 3 + 2] = ver1; } break; case 3: smoothVertex[iterator * 3] = internVertex[1]; smoothVertex[iterator * 3 + 1] = internVertex[0]; if (Vector3.Distance(edgeVertex[0], internVertex[1]) > Vector3.Distance(edgeVertex[1], internVertex[1])) { smoothVertex[iterator * 3 + 2] = edgeVertex[1]; } else { smoothVertex[iterator * 3 + 2] = edgeVertex[0]; } break; case 4: smoothVertex[iterator * 3] = internVertex[0]; smoothVertex[iterator * 3 + 1] = edgeVertex[1]; smoothVertex[iterator * 3 + 2] = edgeVertex[0]; break; } iterator++; } } iterator = 0; int coordNumber = smoothVertex.Length; for (int i = 0; i < coordNumber; i++) { int found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, smoothVertex[i]); if (found == -1) { groundMesh.smoothVertex[iterator] = smoothVertex[i]; groundMesh.smoothNormals[iterator] = smoothVertex[i].normalized; groundMesh.smoothTriangles[i] = CustomGeneric.ArrayContain(groundMesh.smoothVertex, smoothVertex[i]); iterator++; } else { groundMesh.smoothTriangles[i] = found; } } for (int i = 0; i < groundMesh.computedTriangles.Length / 3; i++) { if (groundMesh.computedVertex[groundMesh.computedTriangles[i * 3]] == Vector3.zero) { continue; } Vector3 ver1 = groundMesh.computedVertex[groundMesh.computedTriangles[(i * 3) + 1]]; Vector3 ver2 = groundMesh.computedVertex[groundMesh.computedTriangles[(i * 3) + 2]]; internVertex[0] = (groundMesh.centerPosition + ver1) / 2f; internVertex[1] = (groundMesh.centerPosition + ver2) / 2f; Vector3 vDir1 = (internVertex[0] - groundMesh.centerPosition); Vector3 vDir2 = (internVertex[1] - groundMesh.centerPosition); internVertex[0] = internVertex[0] + (vDir1 * CellWidth); internVertex[1] = internVertex[1] + (vDir2 * CellWidth); float d = Vector3.Distance(internVertex[0], internVertex[1]) / 2f; midEdgeVertex = (ver1 + ver2) / 2f; edgeVertex[0] = midEdgeVertex + (midEdgeVertex - ver1).normalized * d; edgeVertex[1] = midEdgeVertex + (midEdgeVertex - ver2).normalized * d; int found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, edgeVertex[0]); if (found != -1) { groundMesh.indexes.edgeVertexIndex[i * 2] = found; } found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, edgeVertex[1]); if (found != -1) { groundMesh.indexes.edgeVertexIndex[i * 2 + 1] = found; } found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, ver1); if (found != -1) { groundMesh.indexes.cornerVertexIndex[i] = found; } found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, ver2); if (found != -1) { groundMesh.indexes.cornerVertexIndex[i] = found; } found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, internVertex[0]); if (found != -1) { groundMesh.indexes.internVertexIndex[i] = found; } found = CustomGeneric.ArrayContain(groundMesh.smoothVertex, internVertex[1]); if (found != -1) { groundMesh.indexes.internVertexIndex[i] = found; } } }
/// <summary> /// Get all the typed vertex link to a vertex /// </summary> /// <param name="indexArray">custom vertex type array</param> /// <param name="testPos"></param> /// <returns></returns> public static Vector3 GetNearestTypedVertex(int[] indexArray, Vector3 testPos, GroundMesh pGroundMesh) { Vector3 nearest = Vector3.zero; float dist = float.PositiveInfinity; foreach (int index in indexArray) { Vector3 vertex = pGroundMesh.smoothVertex[index]; if (vertex != pGroundMesh.centerPosition) { float lDist = Math.Abs(Vector3.Distance(testPos, vertex)); if (lDist < dist) { nearest = vertex; dist = lDist; } } } return(nearest); }
private void Update() { bool snapToGrid = snapToGridToggle.isOn; bool rotationSnapping = rotationSnappingToggle.isOn; float rotationEditSensitivity = 1; float.TryParse(rotationSensitivityInput.text, NumberStyles.Any, CultureInfo.InvariantCulture, out rotationEditSensitivity); bool propertiesNeedSaving = false; if (Math.Abs(rotationEditSensitivity - Properties.Instance.DecorationRotationSensitivity) > float.Epsilon) { Properties.Instance.DecorationRotationSensitivity = rotationEditSensitivity; propertiesNeedSaving = true; } if (snapToGrid != Properties.Instance.DecorationSnapToGrid) { Properties.Instance.DecorationSnapToGrid = snapToGrid; propertiesNeedSaving = true; } if (rotationSnapping != Properties.Instance.DecorationRotationSnapping) { Properties.Instance.DecorationRotationSnapping = rotationSnapping; propertiesNeedSaving = true; } if (propertiesNeedSaving) { Properties.Instance.SaveProperties(); } RaycastHit raycast = LayoutManager.Instance.CurrentCamera.CurrentRaycast; if (!raycast.transform) { if (ghostObject) { ghostObject.SetActive(false); } return; } DecorationData data = (DecorationData)GuiManager.Instance.ObjectsTree.SelectedValue; bool dataChanged = data != lastFrameData; lastFrameData = data; if (!data) { return; } OverlayMesh overlayMesh = raycast.transform.GetComponent <OverlayMesh>(); GroundMesh groundMesh = raycast.transform.GetComponent <GroundMesh>(); TileEntity tileEntity = raycast.transform.GetComponent <TileEntity>(); Material ghostMaterial = GraphicsManager.Instance.GhostMaterial; if (dataChanged) { CoroutineManager.Instance.QueueCoroutine(data.Model.CreateOrGetModel(ghostMaterial, OnGhostCreated)); return; } if (!ghostObject) { return; } int targetFloor = LayoutManager.Instance.CurrentCamera.Floor; if (tileEntity && tileEntity.Valid && tileEntity.GetType() == typeof(Floor)) { targetFloor = tileEntity.Floor; } if (data.CenterOnly || data.Tree || data.Bush) { targetFloor = 0; } Map map = GameManager.Instance.Map; if (!placingDecoration) { position = CalculateCorrectedPosition(raycast.point, data, snapToGrid); targetedTile = null; if (overlayMesh) { int tileX = Mathf.FloorToInt(position.x / 4f); int tileY = Mathf.FloorToInt(position.z / 4f); targetedTile = map[tileX, tileY]; position.y = map.GetInterpolatedHeight(position.x, position.z); if (data.Floating) { position.y = Mathf.Max(position.y, 0); } else { float floorHeight = 3f; position.y += targetFloor * floorHeight; } } else if (tileEntity && tileEntity.Valid) { targetedTile = tileEntity.Tile; } } bool canPlaceNewObject = overlayMesh || groundMesh || (tileEntity && tileEntity.Valid && tileEntity.GetType() == typeof(Floor)); if (canPlaceNewObject || placingDecoration) { ghostObject.gameObject.SetActive(true); ghostObject.transform.position = position; } else { ghostObject.gameObject.SetActive(false); } bool placementAllowed = true; Vector2 position2d = new Vector2(position.x, position.z); IEnumerable <Decoration> nearbyDecorations = GetAllNearbyDecorations(targetedTile); foreach (Decoration decoration in nearbyDecorations) { Vector3 decorationPosition3d = decoration.transform.position; Vector2 decorationPosition2d = new Vector2(decorationPosition3d.x, decorationPosition3d.z); float distance = Vector2.Distance(position2d, decorationPosition2d); if (distance < minimumPlacementGap) { placementAllowed = false; break; } } ToggleGhostPropertyBlock(placementAllowed ? allowedGhostPropertyBlock : disabledGhostPropertyBlock); if (Input.GetMouseButtonDown(0) && placementAllowed) { placingDecoration = true; dragStartPos = LayoutManager.Instance.CurrentCamera.MousePosition; } if (Input.GetMouseButton(0) && placingDecoration) { Vector2 dragEndPos = LayoutManager.Instance.CurrentCamera.MousePosition; Vector2 difference = dragEndPos - dragStartPos; rotation = -difference.x * rotationEditSensitivity; if (rotationSnapping) { rotation = Mathf.Round(rotation / 45f) * 45f; } ghostObject.transform.localRotation = Quaternion.Euler(0, rotation, 0); } if (Input.GetMouseButtonUp(0) && placingDecoration) { float decorationPositionX = position.x - targetedTile.X * 4f; float decorationPositionY = position.z - targetedTile.Y * 4f; Vector2 decorationPosition = new Vector2(decorationPositionX, decorationPositionY); targetedTile.SetDecoration(data, decorationPosition, rotation * Mathf.Deg2Rad, targetFloor, data.Floating); map.CommandManager.FinishAction(); placingDecoration = false; ghostObject.transform.localRotation = Quaternion.identity; } if (Input.GetMouseButtonDown(1)) { placingDecoration = false; ghostObject.transform.localRotation = Quaternion.identity; } if (Input.GetMouseButtonDown(1) && !placingDecoration) { IEnumerable <Decoration> decorationsOnTile = targetedTile.GetDecorations(); foreach (Decoration decoration in decorationsOnTile) { targetedTile.SetDecoration(null, decoration.Position, decoration.Rotation, targetFloor); } map.CommandManager.FinishAction(); } }