Add audio to dialogues

This commit is contained in:
Michal Pikulski
2025-10-17 15:20:29 +02:00
parent 2fe872d8dc
commit c3c9fd95a4
14 changed files with 322 additions and 46 deletions

View File

@@ -11,33 +11,44 @@ namespace Dialogue.Editor
{
// Height constants
private const float TypeSelectorHeight = 20f;
private const float PropertySpacing = 2f;
private const float PropertySpacing = 2f; // Reduced spacing for tighter layout
private const float TextFieldHeight = 40f; // Taller for multi-line text
private const float ImageFieldHeight = 18f;
private const float AudioFieldHeight = 18f;
private const float PreviewHeight = 64f;
// Track the last assigned sprite to detect changes
private static Sprite lastAssignedSprite;
private static string lastAssignedPropertyPath;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var contentTypeProperty = property.FindPropertyRelative("_contentType");
var imageProperty = property.FindPropertyRelative("_image");
// Start with base height for type selector
var height = TypeSelectorHeight + PropertySpacing;
// Add height based on content type
if (contentTypeProperty.enumValueIndex == (int)DialogueContentType.Text)
{
height += TextFieldHeight;
height += TextFieldHeight + PropertySpacing;
}
else // Image
{
height += ImageFieldHeight;
height += ImageFieldHeight + PropertySpacing;
// Add preview height if an image is assigned
var imageProperty = property.FindPropertyRelative("_image");
// Add preview height if an image is assigned - make sure it's AFTER the image field
// but BEFORE the audio field
if (imageProperty.objectReferenceValue != null)
{
height += PropertySpacing + PreviewHeight;
height += PreviewHeight + PropertySpacing;
}
}
// Add height for audio field (always displayed)
height += AudioFieldHeight;
return height;
}
@@ -54,15 +65,58 @@ namespace Dialogue.Editor
var contentTypeProperty = property.FindPropertyRelative("_contentType");
var textProperty = property.FindPropertyRelative("_text");
var imageProperty = property.FindPropertyRelative("_image");
var audioProperty = property.FindPropertyRelative("_audio");
// Calculate rects
var typeRect = new Rect(contentRect.x, contentRect.y, contentRect.width, TypeSelectorHeight);
// Check for sprite changes and force repaint if needed
var currentSprite = imageProperty.objectReferenceValue as Sprite;
if (currentSprite != lastAssignedSprite && property.propertyPath == lastAssignedPropertyPath)
{
// Sprite changed, force a layout recalculation
EditorUtility.SetDirty(property.serializedObject.targetObject);
GUI.changed = true;
}
// Track current y position as we add controls
float currentY = contentRect.y;
// Calculate type rect
var typeRect = new Rect(contentRect.x, currentY, contentRect.width, TypeSelectorHeight);
currentY += TypeSelectorHeight + PropertySpacing;
// Calculate content field rect based on the content type
var contentHeight = contentTypeProperty.enumValueIndex == (int)DialogueContentType.Text ?
TextFieldHeight : ImageFieldHeight;
var contentFieldRect = new Rect(
contentRect.x,
contentRect.y + TypeSelectorHeight + PropertySpacing,
currentY,
contentRect.width,
contentTypeProperty.enumValueIndex == (int)DialogueContentType.Text ? TextFieldHeight : ImageFieldHeight);
contentHeight);
currentY += contentHeight + PropertySpacing;
// If we have an image and it's selected, calculate preview rect
Rect previewRect = Rect.zero;
if (contentTypeProperty.enumValueIndex == (int)DialogueContentType.Image &&
imageProperty.objectReferenceValue != null)
{
previewRect = new Rect(
contentRect.x,
currentY,
contentRect.width,
PreviewHeight);
currentY += PreviewHeight + PropertySpacing;
}
// Calculate audio field rect
var audioFieldRect = new Rect(
contentRect.x,
currentY,
contentRect.width,
AudioFieldHeight);
// Now draw all the controls
// Draw the content type dropdown
EditorGUI.PropertyField(typeRect, contentTypeProperty, GUIContent.none);
@@ -78,8 +132,27 @@ namespace Dialogue.Editor
}
else // Image
{
// Store the sprite before drawing the field to detect changes
var previousSprite = imageProperty.objectReferenceValue as Sprite;
// Draw the image field
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(contentFieldRect, imageProperty, GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
// Image changed, store the property path so we can detect which property changed
lastAssignedPropertyPath = property.propertyPath;
lastAssignedSprite = imageProperty.objectReferenceValue as Sprite;
// Force an inspector update to recalculate layout
EditorUtility.SetDirty(property.serializedObject.targetObject);
// Mark the scene as dirty to ensure serialization and proper layout refresh
if (!EditorApplication.isPlaying)
{
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(
UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
}
}
// Draw a preview if an image is assigned
if (imageProperty.objectReferenceValue != null)
@@ -87,44 +160,58 @@ namespace Dialogue.Editor
var sprite = imageProperty.objectReferenceValue as Sprite;
if (sprite != null)
{
var previewRect = new Rect(
contentRect.x,
contentFieldRect.y + contentFieldRect.height + PropertySpacing,
contentRect.width,
PreviewHeight);
// Draw the preview with preserved aspect ratio
DrawSpritePreview(previewRect, sprite);
}
}
}
// Draw the audio field (always displayed regardless of content type)
EditorGUI.PropertyField(audioFieldRect, audioProperty, new GUIContent("Audio"));
// Restore indent
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
private void DrawSpritePreview(Rect position, Sprite sprite)
// Helper method to draw a sprite preview with preserved aspect ratio
private void DrawSpritePreview(Rect rect, Sprite sprite)
{
if (sprite == null || sprite.texture == null) return;
if (sprite == null || sprite.texture == null)
return;
var texture = sprite.texture;
var spriteRect = sprite.rect;
var aspectRatio = spriteRect.width / spriteRect.height;
// Calculate aspect-preserved rect
float aspectRatio = sprite.rect.width / sprite.rect.height;
float targetWidth = Mathf.Min(position.width, position.height * aspectRatio);
float targetHeight = targetWidth / aspectRatio;
// Calculate preview rect while preserving aspect ratio within our fixed area
Rect previewRect = rect;
// Center the preview
Rect previewRect = new Rect(
position.x + (position.width - targetWidth) * 0.5f,
position.y + (position.height - targetHeight) * 0.5f,
targetWidth,
targetHeight
);
// Limit the display size to the allocated space while maintaining aspect ratio
if (aspectRatio > 1f) // Wider than tall
{
previewRect.height = Mathf.Min(rect.width / aspectRatio, rect.height);
previewRect.y += (rect.height - previewRect.height) * 0.5f;
}
else // Taller than wide or square
{
previewRect.width = Mathf.Min(rect.height * aspectRatio, rect.width);
previewRect.x += (rect.width - previewRect.width) * 0.5f;
}
// Draw the sprite preview
EditorGUI.DrawPreviewTexture(previewRect, sprite.texture, null, ScaleMode.ScaleToFit);
// Constrain the preview to the allocated space
previewRect.height = Mathf.Min(previewRect.height, rect.height);
previewRect.width = Mathf.Min(previewRect.width, rect.width);
// Draw a border around the preview
GUI.Box(previewRect, GUIContent.none);
// Draw preview with a dark background for better visibility
EditorGUI.DrawRect(rect, new Color(0.1f, 0.1f, 0.1f, 1f));
GUI.DrawTexture(previewRect, texture, ScaleMode.ScaleToFit);
// Draw sprite bounds
EditorGUI.DrawRect(new Rect(previewRect.x, previewRect.y, previewRect.width, 1), Color.gray);
EditorGUI.DrawRect(new Rect(previewRect.x, previewRect.y + previewRect.height - 1, previewRect.width, 1), Color.gray);
EditorGUI.DrawRect(new Rect(previewRect.x, previewRect.y, 1, previewRect.height), Color.gray);
EditorGUI.DrawRect(new Rect(previewRect.x + previewRect.width - 1, previewRect.y, 1, previewRect.height), Color.gray);
}
}
}