简体   繁体   中英

Floating texts in Unity

My 2D platformer game level has treasure chests placed all over the map and when a chest is collected I need to display a message. The messages are contained in a List<string> and they are displayed one by one as the treasures are collected. These messages are to be displayed in a UI>Text gameObject which is anchored to the top-center of the canvas. I want to display these texts as floating up(fading in/out) when the treasures are collected, by updating the text component of this gameObject. However, the problem arises when two or more treasures are collected before the animation for the previous one could be complete. I can easily concatenate the new messages to the existing ones, but I want the old ones to fade out and new ones to fade in. This can be done by creating multiple UI>Texts, but there are a lot of messages and I do not want to create so many redundant gameobjects. Is there any good workaround for this problem? 在此输入图像描述

The way I handled this in a project of mine was to create a queue of messages to display (as immediacy was not a concern, but being able to only display one at a time was). This sounds very similar to your own problem.

// NotificationItem is just a wrapper around some text and accompanying image
private static List<NotificationItem> notificationQueue = new List<NotificationItem>();

// reference to the on-screen object
public GameObject notification;

// "Hey! I want to display a notification!"
public static void ShowNotification(NotificationItem item) {
    notificationQueue.Add(item);
}

// I was using the DO Tween asset here, but the logic can be converted to
// coroutines or straight update cycles
private void Update() {
    // If there is no currently displayed notification (ie the notification object is
    // not being animated) and there is at least one item to display
    if(!DOTween.IsTweening(notification.transform) && notificationQueue.Count > 0) {
        // ...get the first one
        NotificationItem item = notificationQueue[0];
        // ...pop it from the list
        notificationQueue.RemoveAt(0);
        // ...set the notification object to the details
        notification.transform.Find("Title").GetComponent<Text>().text = item.title;
        notification.transform.Find("Text").GetComponent<Text>().text = item.text;
        notification.transform.Find("Img").GetComponent<Image>().sprite = item.image;

        // ...start the animation
        // (in my case, the notification animates down from the top of the screen
        // waits 2.5 seconds, then animates back up)
        notification.transform.DOMoveY(Screen.height - 85, 0.5f, false).SetEase(Ease.InOutQuad).OnComplete(PauseCallback);
    }
}

// An admittedly hacky way of getting the notification to do nothing for 2.5 seconds:
// Animate it to where it already is.
private void PauseCallback() {
    notification.transform.DOMoveY(Screen.height - 85, 2.5f, false).SetEase(Ease.InOutQuad).OnComplete(ReturnCallback);
}

private void ReturnCallback() {
    notification.transform.DOMoveY(Screen.height + 2, 0.5f, false).SetEase(Ease.InOutQuad);
}

The difference between my implementation and yours will be largely in the animation (as well as your Queue lists's type; eg you might be able to just use a List<string> ). You already have your animation coded, all you need is the queue and a way to determine that your animation is complete.

You will not be generating more objects than the system can handle if you utilize the Flyweight pattern (object pooling). Unity has an Object Pooling tutorial on their site.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM