private void AddAttachments(IBrushContext context, TileData tile, GameObject tileGO, bool addCollider) { // Add collider to tile game object? if (addCollider) { switch (this.colliderType) { case Tile.ColliderType.BoxCollider2D: tileGO.AddComponent <BoxCollider2D>(); break; case Tile.ColliderType.BoxCollider3D: tileGO.AddComponent <BoxCollider>(); break; } } // Attach prefab to tile? if (this.attachPrefab != null) { GameObject attachment = InstantiatePrefabForTile(this.attachPrefab, tile, context.TileSystem); if (attachment != null) { attachment.transform.SetParent(tileGO.transform); } } }
/// <inheritdoc/> protected internal override void ApplyTransforms(IBrushContext context, TileData tile, Brush transformer) { var tileSystem = context.TileSystem; var tileTransform = tile.gameObject.transform; // Place tile into its respective chunk. // NOTE: Chunk will definately exist at this stage. Transform newParent = tileSystem.GetChunkFromTileIndex(context.Row, context.Column).transform; tileTransform.SetParent(newParent, false); // Calculate position of tile within system. tileTransform.localPosition = tileSystem.LocalPositionFromTileIndex(context.Row, context.Column, true); // Turn tile to face away from system and rotate tile to align with system. tileTransform.localRotation = tileSystem.CalculateSimpleRotation(TileFacing.Sideways, tile.Rotation) * MathUtility.AngleAxis_180_Up; // Adjust scale of tile container. tileTransform.localScale = tileSystem.CalculateCellSizeScale(tile.Rotation); // Transform attachment? if (tileTransform.childCount == 1) { var attachmentTransform = tileTransform.GetChild(0); Matrix4x4 convertSystemToAttachmentSpaceMatrix = tileTransform.worldToLocalMatrix * tileSystem.transform.localToWorldMatrix; int rotation = this.applySimpleRotationToAttachment ? tile.Rotation : 0; Matrix4x4 attachmentMatrix = convertSystemToAttachmentSpaceMatrix * transformer.GetTransformMatrix(tileSystem, context.Row, context.Column, rotation, this.attachPrefab.transform); MathUtility.SetTransformFromMatrix(attachmentTransform, ref attachmentMatrix); } }
/// <inheritdoc/> protected internal override void ApplyTransforms(IBrushContext context, TileData tile, Brush transformer) { // If transforming brush has not already been overridden... if (transformer == this) { // Find nested brush reference? var orientation = this.FindOrientation(tile.orientationMask); if (orientation != null && orientation.VariationCount > 0) { // Note: Do not update variation index in tile data because this may be unintended! int variationIndex = (int)tile.variationIndex; if (variationIndex >= orientation.VariationCount) { variationIndex = 0; } var nestedBrush = orientation.GetVariation(variationIndex) as Brush; // Apply transforms using the nested brush (as would be expected!). if (nestedBrush != null) { nestedBrush.ApplyTransforms(context, tile, this.overrideTransforms ? this : nestedBrush); return; } } base.ApplyTransforms(context, tile, this); } else { base.ApplyTransforms(context, tile, transformer); } }
/// <inheritdoc/> protected internal override void CreateTile(IBrushContext context, TileData tile) { bool addCollider = ((tile.orientationMask & 0x5A) == 0x5A) ? this.addInnerCollider : this.addCollider; // Tile is procedural for autotile brushes regardless. this.CreateProceduralTile(context, tile, addCollider); }
/// <inheritdoc/> protected internal override bool CalculateManualOffset(IBrushContext context, TileData tile, Transform transform, out Vector3 offsetPosition, out Quaternion offsetRotation, out Vector3 offsetScale, Brush transformer) { // If transforming brush has not already been overridden... if (transformer == this && !this.overrideTransforms) { transformer = this.target; } return(this.target.CalculateManualOffset(context, tile, transform, out offsetPosition, out offsetRotation, out offsetScale, transformer)); }
/// <inheritdoc/> protected internal override void ApplyTransforms(IBrushContext context, TileData tile, Brush transformer) { // If transforming brush has not already been overridden... if (transformer == this && !this.overrideTransforms) { transformer = this.target; } this.target.ApplyTransforms(context, tile, transformer); }
/// <inheritdoc/> /// <seealso cref="CustomImmediatePreview"/> public override void OnDrawImmediatePreview(IBrushContext context, TileData previewTile, Material previewMaterial, Brush transformer) { var orientation = this.FindClosestOrientation(previewTile.orientationMask); if (orientation == null || orientation.VariationCount == 0) { return; } // Wrap variation index if necessary. int variationIndex = previewTile.variationIndex; if (variationIndex >= orientation.VariationCount) { variationIndex = 0; } // Randomization is not supported here! if (variationIndex == RANDOM_VARIATION) { variationIndex = 0; } var variationGO = orientation.GetVariation(variationIndex) as GameObject; if (variationGO != null) { var variationTransform = variationGO.transform; Matrix4x4 matrix = ImmediatePreviewUtility.Matrix * transformer.GetTransformMatrix(context.TileSystem, context.Row, context.Column, previewTile.Rotation, variationTransform); // Allow variation to provide a custom immediate preview. var customImmediatePreview = variationGO.GetComponent <CustomImmediatePreview>(); if (customImmediatePreview != null) { // Bail if custom immediate preview was drawn. if (customImmediatePreview.DrawImmediatePreview(context, previewTile, previewMaterial, matrix)) { return; } } ImmediatePreviewUtility.DrawNow(previewMaterial, variationTransform, matrix, context.Brush as IMaterialMappings); return; } var variationBrush = orientation.GetVariation(variationIndex) as Brush; if (variationBrush != null) { // If transforming brush has not already been overridden then... if (transformer == this && !this.overrideTransforms) { transformer = variationBrush; } variationBrush.OnDrawImmediatePreview(context, previewTile, previewMaterial, transformer); return; } }
/// <inheritdoc/> protected internal override void CreateTile(IBrushContext context, TileData tile) { var orientation = this.FindOrientation(tile.orientationMask); if (orientation == null) { Debug.LogWarning(string.Format("Brush '{0}' orientation '{1}' not defined", this.name, OrientationUtility.NameFromMask(tile.orientationMask))); return; } if (orientation.VariationCount == 0) { Debug.LogWarning(string.Format("Brush '{0}' orientation '{1}' has no variations", this.name, OrientationUtility.NameFromMask(tile.orientationMask))); return; } // Note: Do not update variation index in tile data because this may be unintended! int variationIndex = (int)tile.variationIndex; if (variationIndex >= orientation.VariationCount) { variationIndex = 0; } var orientedVariation = orientation.GetVariation(variationIndex); // Orchestrate a "nested" brush? var nestedBrush = orientedVariation as Brush; if (nestedBrush != null) { // Force override flags with that of nested brush? // // Note: Naming a little backwards in this scenario, we want to preserve // flags from nested brush! // if (!this.forceOverrideFlags) { // Remove all user flags, solid flag and replace with flags from nested brush. tile.flags = (tile.flags & ~0x8FFFF) | nestedBrush.TileFlags; } nestedBrush.CreateTile(context, tile); nestedBrush.PostProcessTile(context, tile); return; } var variationPrefab = orientedVariation as GameObject; if (variationPrefab == null) { return; } // Actually create tile! tile.gameObject = InstantiatePrefabForTile(variationPrefab, tile, context.TileSystem); }
/// <summary> /// Get data for immediate tile preview. /// </summary> /// <param name="context">Context in which brush is being used.</param> /// <param name="brush">The brush.</param> /// <param name="rotation">Zero-based index of simple rotation (0 = 0°, 1 = 90°, 2 = 180°, 3 = 270°).</param> /// <returns> /// Data for preview tile. /// </returns> public static TileData GetPreviewTileData(IBrushContext context, Brush brush, int rotation) { s_PreviewTileData.Clear(); s_PreviewTileData.brush = brush; s_PreviewTileData.flags = brush.TileFlags; s_PreviewTileData.PaintedRotation = rotation; s_PreviewTileData.Rotation = rotation; brush.PrepareTileData(context, s_PreviewTileData, 0); return(s_PreviewTileData); }
/// <inheritdoc/> protected internal override void CreateTile(IBrushContext context, TileData tile) { // Tile is procedural regardless of which brush defined it. if (tile.Procedural) { this.CreateProceduralTile(context, tile, this.addCollider); } else { this.CreateNonProceduralTile(context, tile, this.addCollider); } }
/// <inheritdoc/> public override void OnDrawImmediatePreview(IBrushContext context, TileData previewTile, Material previewMaterial, Brush transformer) { if (this.target != null) { // If transforming brush has not already been overridden then... if (transformer == this && !this.overrideTransforms) { transformer = this.target; } this.target.OnDrawImmediatePreview(context, previewTile, previewMaterial, transformer); } }
/// <summary> /// Create procedural tile. /// </summary> /// <remarks> /// <para>Creates container game object for tile when collider and/or attachment /// is to be added. Collider and/or attachment is also added when specified.</para> /// </remarks> /// <param name="context">Describes context of tile that is being painted.</param> /// <param name="tile">The tile.</param> /// <param name="addCollider">Indicates if collider should be added.</param> protected void CreateProceduralTile(IBrushContext context, TileData tile, bool addCollider) { // Attach object to tile? if (addCollider || this.attachPrefab != null) { tile.gameObject = new GameObject("tile"); this.AddAttachments(context, tile, tile.gameObject, addCollider); } else if (this.alwaysAddContainer) { tile.gameObject = new GameObject("tile"); } }
/// <inheritdoc/> protected internal override bool CalculateManualOffset(IBrushContext context, TileData tile, Transform transform, out Vector3 offsetPosition, out Quaternion offsetRotation, out Vector3 offsetScale, Brush transformer) { var orientation = this.FindOrientation(tile.orientationMask); if (orientation != null && orientation.VariationCount != 0) { // Note: Do not update variation index in tile data because this may be unintended! int variationIndex = (int)tile.variationIndex; if (variationIndex >= orientation.VariationCount) { variationIndex = 0; } var nestedBrush = orientation.GetVariation(variationIndex) as Brush; if (nestedBrush != null) { // If transforming brush has not already been overridden then... if (transformer == this && !this.overrideTransforms) { transformer = nestedBrush; } return(nestedBrush.CalculateManualOffset(context, tile, transform, out offsetPosition, out offsetRotation, out offsetScale, transformer)); } var prefab = orientation.GetVariation(variationIndex) as GameObject; if (prefab != null) { Matrix4x4 normalPlacement = transformer.GetTransformMatrix(context.TileSystem, context.Row, context.Column, tile.Rotation, prefab.transform); MathUtility.DecomposeMatrix(ref normalPlacement, out offsetPosition, out offsetRotation, out offsetScale); Vector3 localScale = transform.localScale; offsetPosition = transform.localPosition - offsetPosition; offsetRotation = Quaternion.Inverse(offsetRotation) * transform.localRotation; offsetScale = new Vector3( localScale.x / offsetScale.x, localScale.y / offsetScale.y, localScale.z / offsetScale.z ); return(true); } } return(IdentityManualOffset(out offsetPosition, out offsetRotation, out offsetScale)); }
/// <inheritdoc/> protected internal override void PostProcessTile(IBrushContext context, TileData tile) { if (tile == null) { return; } var go = tile.gameObject; if (go != null) { // Assign tag and layer to tile. go.tag = this.tag; go.layer = this.layer; InternalUtility.HideEditorWireframe(go); } }
/// <inheritdoc/> protected internal override void PrepareTileData(IBrushContext context, TileData tile, int variationIndex) { // Find actual orientation of target tile. int actualOrientation = OrientationUtility.DetermineTileOrientation(context.TileSystem, context.Row, context.Column, context.Brush, tile.PaintedRotation); // Find nearest match, assume default scenario. tile.orientationMask = (byte)this.Tileset.FindClosestOrientation(actualOrientation); tile.Procedural = true; tile.tileset = this.Tileset; tile.tilesetIndex = this.Tileset.IndexFromOrientation(tile.orientationMask); // Is this an inner tile? if ((tile.orientationMask & 0x5A) == 0x5A) { tile.SolidFlag = this.InnerSolidFlag; } }
/// <inheritdoc/> protected internal override void CreateTile(IBrushContext context, TileData tile) { // Attach object to tile? if (this.addCollider || this.alwaysAddContainer) { tile.gameObject = new GameObject("tile"); if (this.addCollider) { switch (this.colliderType) { case Tile.ColliderType.BoxCollider2D: tile.gameObject.AddComponent <BoxCollider2D>(); break; case Tile.ColliderType.BoxCollider3D: tile.gameObject.AddComponent <BoxCollider>(); break; } } } }
/// <summary> /// Helper method to draw immediate preview of tileset tile. /// </summary> /// <remarks> /// <para>Attached prefab will also be included in preview when applicable.</para> /// </remarks> /// <param name="context">Describes context of tile that is being previewed.</param> /// <param name="previewMaterial">Material to use for preview.</param> /// <param name="previewTile">Data for preview tile.</param> /// <param name="transformer">Brush used to transform painted tile. /// The <see cref="Brush.scaleMode"/> and <see cref="Brush.applyPrefabTransform"/> /// fields of transform brush should be used. <c>transformer</c> may refer to this /// brush, or it may refer to another (like alias or oriented for example).</param> protected void DrawImmediateTilePreview(IBrushContext context, Material previewMaterial, TileData previewTile, Brush transformer) { var atlasTexture = Tileset.AtlasTexture; if (atlasTexture == null) { return; } // Prepare mesh for tile background. Rect texCoords = Tileset.CalculateTexCoords(previewTile.tilesetIndex); var mesh = ImmediatePreviewUtility.UpdateQuadPreviewMesh(texCoords); // Compute matrix for tile background. var tileSystem = context.TileSystem; Matrix4x4 matrix; tileSystem.CalculateTileMatrix(out matrix, context.Row, context.Column, TileFacing.Sideways, previewTile.Rotation); MathUtility.MultiplyMatrixByScale(ref matrix, tileSystem.CalculateCellSizeScale(previewTile.Rotation)); matrix = ImmediatePreviewUtility.Matrix * matrix; // Draw tile background. previewMaterial.mainTexture = atlasTexture; ImmediatePreviewUtility.DrawNow(previewMaterial, mesh, matrix); // Draw preview of tile attachment? if (this.attachPrefab != null) { int rotation = this.applySimpleRotationToAttachment ? previewTile.PaintedRotation : 0; var attachmentTransform = this.attachPrefab.transform; matrix = tileSystem.transform.localToWorldMatrix * transformer.GetTransformMatrix(tileSystem, context.Row, context.Column, rotation, attachmentTransform); ImmediatePreviewUtility.DrawNow(previewMaterial, attachmentTransform, matrix, context.Brush as IMaterialMappings); } }
/// <inheritdoc/> protected internal override bool CalculateManualOffset(IBrushContext context, TileData tile, Transform transform, out Vector3 offsetPosition, out Quaternion offsetRotation, out Vector3 offsetScale, Brush transformer) { var tileSystem = context.TileSystem; // Calculate normal position of tile within system. offsetPosition = tileSystem.LocalPositionFromTileIndex(context.Row, context.Column, true); // Turn tile to face away from system and rotate tile to align with system. offsetRotation = tileSystem.CalculateSimpleRotation(TileFacing.Sideways, tile.Rotation) * MathUtility.AngleAxis_180_Up; // Adjust scale of tile container. offsetScale = tileSystem.CalculateCellSizeScale(tile.Rotation); Vector3 localScale = transform.localScale; offsetPosition = transform.localPosition - offsetPosition; offsetRotation = Quaternion.Inverse(offsetRotation) * transform.localRotation; offsetScale = new Vector3( localScale.x / offsetScale.x, localScale.y / offsetScale.y, localScale.z / offsetScale.z ); return(true); }
/// <summary> /// Create non-procedural tile. /// </summary> /// <remarks> /// <para>Creates container game object for tile and adds the mesh filter and /// renderer components for tile mesh. Collider and/or attachment is also added /// when specified.</para> /// </remarks> /// <param name="context">Describes context of tile that is being painted.</param> /// <param name="tile">The tile.</param> /// <param name="addCollider">Indicates if collider should be added.</param> protected void CreateNonProceduralTile(IBrushContext context, TileData tile, bool addCollider) { // Create container object for tile and attach to chunk. var tileGO = new GameObject("tile"); tile.gameObject = tileGO; if (addCollider || this.attachPrefab != null) { this.AddAttachments(context, tile, tileGO, addCollider); } var tileset = tile.tileset; int tilesetIndex = tile.tilesetIndex; if (tileset.tileMeshes != null && tilesetIndex >= 0 && tilesetIndex < tileset.tileMeshes.Length) { var filter = tileGO.AddComponent <MeshFilter>(); filter.sharedMesh = tileset.tileMeshes[tilesetIndex]; var renderer = tileGO.AddComponent <MeshRenderer>(); renderer.sharedMaterial = tileset.AtlasMaterial; } }
/// <inheritdoc/> protected internal override void PrepareTileData(IBrushContext context, TileData tile, int variationIndex) { var tileSystem = context.TileSystem; // Find actual orientation of target tile. int actualOrientation = OrientationUtility.DetermineTileOrientation(tileSystem, context.Row, context.Column, context.Brush, tile.PaintedRotation); // Try to find nearest match, assume default scenario. int bestOrientation = this.FindClosestOrientationMask(actualOrientation); // Select tile for painting using tile brush. var orientation = this.FindOrientation(bestOrientation); if (orientation == null) { Debug.LogWarning(string.Format("Brush '{0}' orientation '{1}' not defined", this.name, OrientationUtility.NameFromMask(bestOrientation))); return; } int orientationVariationCount = orientation.VariationCount; // Randomize variation? if (variationIndex == RANDOM_VARIATION) { if (!tileSystem.BulkEditMode || tileSystem.IsEndingBulkEditMode) { variationIndex = orientation.PickRandomVariationIndex(); } } // Negative offset from variations of orientation. else if (variationIndex < 0) { variationIndex = Mathf.Max(0, orientationVariationCount + variationIndex); } // Ensure variation index is within bounds of orientation! int wrappedVariationIndex = variationIndex; if (wrappedVariationIndex >= orientationVariationCount) { wrappedVariationIndex = 0; } if (orientationVariationCount > 0) { // // Could re-insert following to 'fix' state of randomly selected tiles. // Note: Randomization is lost when erasing tiles from mass filled areas. // //// Persist wrapped variation when painting tile? //if (!system.BulkEditMode || system.IsEndingBulkEditMode) { // variationIndex = wrappedVariationIndex; //} // Fetch nested brush reference (if there is one). var nestedBrush = orientation.GetVariation(wrappedVariationIndex) as Brush; if (nestedBrush != null) { // Prepare tile data using nested brush. nestedBrush.PrepareTileData(context, tile, wrappedVariationIndex); } } tile.orientationMask = (byte)bestOrientation; tile.variationIndex = (byte)variationIndex; // Do not attempt automatic rotation where rotation has been manually specified. int rotation = tile.PaintedRotation + orientation.Rotation; if (rotation > 3) { rotation -= 4; } tile.Rotation = rotation; }
/// <inheritdoc/> protected internal override void PostProcessTile(IBrushContext context, TileData tile) { this.target.PostProcessTile(context, tile); base.PostProcessTile(context, tile); }
/// <inheritdoc/> protected internal override bool CalculateManualOffset(IBrushContext context, TileData tile, Transform transform, out Vector3 offsetPosition, out Quaternion offsetRotation, out Vector3 offsetScale, Brush transformer) { return(IdentityManualOffset(out offsetPosition, out offsetRotation, out offsetScale)); }
/// <inheritdoc/> protected internal override void CreateTile(IBrushContext context, TileData tile) { this.target.CreateTile(context, tile); }
/// <inheritdoc/> protected internal override void PrepareTileData(IBrushContext context, TileData tile, int variationIndex) { this.target.PrepareTileData(context, tile, variationIndex); }
/// <inheritdoc/> public override void OnDrawImmediatePreview(IBrushContext context, TileData previewTile, Material previewMaterial, Brush transformer) { this.DrawImmediateTilePreview(context, previewMaterial, previewTile, transformer); }
/// <summary> /// Method is invoked to draw immediate preview. /// </summary> /// <remarks> /// <para>Immediate preview should be drawn using the <a href="http://docs.unity3d.com/ScriptReference/Graphics.html"><c>Graphics</c></a> /// class from the <c>UnityEngine</c> API.</para> /// </remarks> /// <param name="context">Describes context of tile that is being previewed.</param> /// <param name="previewTile">Data for preview tile.</param> /// <param name="previewMaterial">Material to use for preview.</param> /// <param name="matrix">Matrix which describes transformation of tile.</param> /// <returns> /// A value of <c>true</c> if custom immediate preview was drawn; otherwise a value /// of <c>false</c> indicating that default implementation should be assumed. /// </returns> public abstract bool DrawImmediatePreview(IBrushContext context, TileData previewTile, Material previewMaterial, Matrix4x4 matrix);
/// <inheritdoc/> protected internal override void PrepareTileData(IBrushContext context, TileData tile, int variationIndex) { tile.Procedural = this.IsProcedural; tile.tileset = this.tileset; tile.tilesetIndex = this.tileIndex; }