using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Serialization; namespace Ichni.Story.UI { public class StorylineDisplay : MonoBehaviour { [Header("UI References")] public RectTransform content; // Content of ScrollRect public GameObject textBlockPrefab; // Prefab of UI Node public GameObject musicBlockPrefab; public GameObject tutorialBlockPrefab; public GameObject connectionCurvePrefab; // Prefab of connection curve [Header("Layout Settings")] public float marginLeft = 50f; // additive space on the left public float marginRight = 50f; // Extra space on the right public RectTransform connectionContainer; public List generatedBlocks; private void Start() { generatedBlocks = new List(); TutorialBlockUI t0 = GenerateTutorialBlock(new Vector2(100, 0), "ZakoCurse 0"); TextBlockUI b1 = GenerateTextBlock(new Vector2(600, 200), "ZakoCurse 0"); TextBlockUI b2 = GenerateTextBlock(new Vector2(1100, -200), "ZakoCurse 0"); SongBlockUI m0 = GenerateMusicBlock(new Vector2(1600, 0), "Chaos Zone", "Chaos Zone"); TextBlockUI b3_1 = GenerateTextBlock(new Vector2(2100, 300), "ZakoCurse 0"); TextBlockUI b3_2 = GenerateTextBlock(new Vector2(2600, -300), "ZakoCurse 0"); // Generate connections GenerateConnector(t0, b1); GenerateConnector(b1, b2); GenerateConnector(b2, m0); GenerateConnector(m0, b3_1); GenerateConnector(m0, b3_2); SetUpBackground(); connectionContainer.SetParent(content); } public TextBlockUI GenerateTextBlock(Vector2 position, string blockName) { return GenerateTextBlock(position, new Vector2(300, 200), blockName); } public TextBlockUI GenerateTextBlock(Vector2 position, Vector2 size, string blockName) { TextBlockUI block = Instantiate(textBlockPrefab, content).GetComponent(); // Set position and size block.blockRect.anchoredPosition = position + new Vector2(marginLeft, 0); block.blockRect.sizeDelta = size; block.Initialize(blockName, "Zako Curse 0"); generatedBlocks.Add(block); return block; } public TutorialBlockUI GenerateTutorialBlock(Vector2 position, string blockName) { return GenerateTutorialBlock(position, new Vector2(300, 200), blockName); } public TutorialBlockUI GenerateTutorialBlock(Vector2 position, Vector2 size, string blockName) { TutorialBlockUI block = Instantiate(tutorialBlockPrefab, content).GetComponent(); // Set position and size block.blockRect.anchoredPosition = position + new Vector2(marginLeft, 0); block.blockRect.sizeDelta = size; block.Initialize(blockName); generatedBlocks.Add(block); return block; } public SongBlockUI GenerateMusicBlock(Vector2 position, string blockName, string musicName) { return GenerateMusicBlock(position, new Vector2(200, 100), blockName, musicName); } public SongBlockUI GenerateMusicBlock(Vector2 position, Vector2 size, string blockName, string musicName) { SongBlockUI block = Instantiate(musicBlockPrefab, content).GetComponent(); // Set position and size block.blockRect.anchoredPosition = position + new Vector2(marginLeft, 0); block.blockRect.sizeDelta = size; block.Initialize(blockName, musicName); generatedBlocks.Add(block); return block; } public void GenerateConnector(StoryBlockUIBase outBlock, StoryBlockUIBase inBlock) { BlockConnectorUI connector = Instantiate(connectionCurvePrefab, connectionContainer).GetComponent(); Vector2 startPosition = GetLocalUIPosition(outBlock.outPort, GetComponent()); Vector2 endPosition = GetLocalUIPosition(inBlock.inPort, GetComponent()); connector.SetCurve(startPosition, endPosition); } Vector2 GetLocalUIPosition(RectTransform fromPort, RectTransform targetSpace) { Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, fromPort.position); RectTransformUtility.ScreenPointToLocalPointInRectangle(targetSpace, screenPos, null, out Vector2 localPos); return localPos; } public void SetUpBackground() { float maxRight = float.MinValue; foreach (var block in generatedBlocks) { float rightEdge = block.blockRect.anchoredPosition.x + block.blockRect.sizeDelta.x * 0.5f; if (rightEdge > maxRight) { maxRight = rightEdge; } } maxRight += marginRight; Debug.Log(maxRight); if (maxRight < 1920f) { maxRight = 1920f; } content.sizeDelta = new Vector2(maxRight, content.sizeDelta.y); } /// /// Public method to generate nodes /// public void Generate(List positions, List sizes) { if (content == null || textBlockPrefab == null || positions.Count != sizes.Count) { Debug.LogError("NodeScrollGenerator: Invalid input data."); return; } // Clear old nodes foreach (Transform child in content) { Destroy(child.gameObject); } float maxRight = float.MinValue; for (int i = 0; i < positions.Count; i++) { // Calculate right edge float rightEdge = positions[i].x + marginLeft + sizes[i].x * 0.5f; if (rightEdge > maxRight) maxRight = rightEdge; } // Create nodes for (int i = 0; i < positions.Count; i++) { GameObject node = Instantiate(textBlockPrefab, content); RectTransform rectTransform = node.GetComponent(); // Set position and size rectTransform.anchoredPosition = positions[i] + new Vector2(marginLeft, 0); rectTransform.sizeDelta = sizes[i]; // Optionally, you can set the name or other properties of the node here node.name = $"Node_{i}"; node.GetComponent().Initialize("ZakoCurse 0", "Zako Curse 0"); } // Set content width content.sizeDelta = new Vector2(maxRight + marginRight, content.sizeDelta.y); } } }