Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - AtomicBob

Pages: 1 [2] 3 4 5
16
NGUI 3 Support / Re: UIButton Sprites prefab serialization bug
« on: April 29, 2014, 02:54:26 PM »
Strange. So, do you know if this particular issue if fixed in 3.5.8? As I said, adding [NonSerialized] didn't actually fix it on my end.

Unfortunately, upgrading isn't an option right now. Too close to launch.

17
NGUI 3 Support / Re: UIButton Sprites prefab serialization bug
« on: April 28, 2014, 11:10:15 AM »
I'm seeing this bug too. My current workaround it is to remove the button component, change the sprite, then add a new button script and set it back up. Not fun. It seems to happen 100% of the time in my current project.

Steps to reproduce:
Create a UISprite, set it to something (I'm using a sliced sprite)
Prefab the object
Add a UIButton (button and sprite are on the same object)
Set the UIButton target to the sprite (Don't bother changing hover
Apply changes, save scene
Change either the button normal sprite, or the sprite itself
Apply changes
Notice the sprite gets reverted the to initial sprite that was set when the UIButton component was added.

I checked the UIButton script as you suggested, the two mentioned fields were private, so they shouldn't be serialized. I added the NonSerialized attribute to be sure and the issue still occurred.

Additional info, in case it helps:
NGUI version: 3.5.5
Version Control: Visible Meta Files
Asset Serialization: Force Text

18
I got this working in a way I'm quite happy with. It's a barebones implementation, but it works. I'd post it here but I had to copy some of the code for drawing the EventDelegate editor so I'll email it instead.

19
I'm poking around with exactly what wom wanted to do in the OP. I'm using a List<EventDelegate> in a custom class that I want to draw in the same way NGUI does. This is actually accomplished quite easily with PropertyDrawers. ArenMook, to answer your question: yes, you can decorate individual fields with an attribute that tells it to use a specific PropertyDrawer. That's exactly what they're for. You don't have to create them on a class-by-class basis.

All that's missing for this to work is a variant of NGUIEditorTools.DrawEvents that can be used by PropertyDrawers (i.e. it can't use GUILayout and EditorGUILayout).

Here's what's need. 1) an attribute we can decorate List<EventDelegate> with:

  1. public class EventDelegateAttribute : PropertyAttribute
  2. {
  3.         public readonly string name;
  4.  
  5.         public EventDelegateAttribute ( string name )
  6.         {
  7.                 this.name = name;
  8.         }
  9. }
  10.  

2) a PropertyDrawer for the above attribute:

  1. [CustomPropertyDrawer(typeof(EventDelegateAttribute))]
  2. public class EventDelegateDrawer : PropertyDrawer
  3. {
  4.         public override float GetPropertyHeight ( SerializedProperty prop, GUIContent label )
  5.         {
  6.                 return NGUIEditorTools.GetEventsDrawerPropertyHeight(prop, label);
  7.         }
  8.  
  9.         public override void OnGUI ( Rect position, SerializedProperty prop, GUIContent label )
  10.         {
  11.                 NGUIEditorTools.DrawEventsPropertyDrawer(position, prop, label);
  12.         }
  13. }
  14.  

3) NGUI methods for drawing the EventDelegate editor in a PropertyDrawer (that part that's missing):

  1. public partial class NGUIEditorTools
  2. {
  3.         static public float GetEventsDrawerPropertyHeight ( SerializedProperty prop, GUIContent label )
  4.         {
  5.                 //Calculate the space needed for the PropertyDrawer
  6.         }
  7.  
  8.         static public void DrawEventsPropertyDrawer ( Rect position, SerializedProperty prop, GUIContent label )
  9.         {
  10.                 UnityEngine.Object undoObject = prop.serializedObject.targetObject;
  11.                 //'prop' is the SerializePoperty of type List<EventDelegate>
  12.  
  13.                 //Use GUI and EditorGUI methods to draw the events inside 'position'
  14.         }
  15. }
  16.  

Then, when we want to use it, all we have to do is:

  1. [EventDelegate("On Click")]
  2. [SerializeField] private List<EventDelegate> onClick = new List<EventDelegate>;
  3.  

and that even applies to custom classes. I tested it in on of my own:

  1. public class GameScreen : MonoBehaviour
  2. {
  3.         [Serializable] public class NavButtonSettings
  4.         {
  5.                 [HideInInspector] public bool isHidden = false;
  6.                 public bool isClickable = true;
  7.                 public UINavButton type;
  8.                 public UINavButtonOverlay overlay;
  9.                 public Justification overlayJustification = Justification.Center;
  10.                 public string text;
  11.                 public Justification textJustification = Justification.Center;
  12.  
  13.                 [EventDelegate("On Click")]
  14.                 public List<EventDelegate> onClick = new List<EventDelegate>();
  15.         }
  16.  
  17.         /* Will be drawn exactly as you would expect. All the fields except
  18.          * 'onClick' draw in their normal way, but when it gets to 'onClick' the
  19.          * EventDelegateDrawer will be used. Hooray!
  20.          */
  21.         [SerializeField] private List<NavButtonSettings> btnSettings = new List<NavButtonSettings>;
  22. }
  23.  

90% of the actual work needed is just the drawing methods, which can mostly be copied from the existing ones with the *Layout methods replaced. I don't know how interested you'd be in this, ArenMook, but I think it'd be a really cool feature.

I'm in a time-crunch at the moment, so I'm just going to slap together half-assed versions of the 2 needed drawing methods for now. If this get's added later, I'll swap to the built in methods.

20
I'm attempting to move an object with several widgets on it to another panel temporarily at runtime. It seems like it should be very straightforward, but I can't get it to work. Here's my best guess at how it's supposed to work:

  1. widget.cachedTransform.parent = newPanel.cachedTransform;
  2. oldPanel.RemoveWidget(widget);
  3. newPanel.AddWidget(widget);
  4.  

Even setting both panels as dirty doesn't work. Anyone know the right way to do this?

EDIT: It does work as expected if you disable the widget(s) before changing the parent, then reenable it afterward. Ditto with the panel's GameObject. I'm not sure this is the intended method, though.

21
NGUI 3 Support / Re: 3.5.5 Issues with UIButton and UIButtonColor
« on: April 04, 2014, 09:58:57 AM »
You are correct, the hover sprite was never set because I'm not using the 'image button' functionality. It wasn't in the hover state, just normal.

In any case, is seems to have worked. Thanks.

You still can't set the sprite directly, since the button will override it. I'm guessing we're stuck with that?

22
NGUI 3 Support / 3.5.5 Issues with UIButton and UIButtonColor
« on: April 03, 2014, 05:46:43 PM »
Just upgraded to get around a bug with tweening (similar to http://www.tasharen.com/forum/index.php?topic=7392) and now I'm having a problem with UIButtons.

UIButtons have a nasty habit changing the sprite in unexpected ways. If you set the sprite.spriteName from code, it doesn't always take effect and sometimes it changes back and forth between sprites on mouseover. If you set button.normalSprite similar things happen. If you set both, it seems to work ok.

It should be pretty easy to reproduce, but if not I'll email a text case.

Also, it'd be nice to be able to use UIButton for the color and OnClick delegate without using 'image button' functionality at all. I know I could use EventTrigger and UIButtonColor separately, but it's nice to have it all on once script and EventTriggers are kinda large visually for just OnClick.

23
I'm not sure what you mean. The object is enabled when all of this happens.

24
No dice. The popup will appear and just freeze at the final state.

If the popup was disabled while visible, it's already at the final state. Playing forward, the tween will then think it's already completed and stop. ResetToBeginning then sets it to the initial state, but it doesn't know to start playing. Hence my reasoning for having Play, ResetToBegining, Play in the original post.

  1. private void Show ()
  2. {
  3.         queue.Dequeue();
  4.  
  5.         tweener.delay = 0;
  6.  
  7.         //Will freeze if the popup was disabled while in the final state
  8.         tweener.Play(true);
  9.         tweener.ResetToBeginning();
  10.         EventDelegate.Add(tweener.onFinished, Hide, true);
  11.  
  12.         isActive = true;
  13.         NGUITools.SetActiveChildren(gameObject, true);
  14. }
  15.  
  16. private void Hide ()
  17. {
  18.         tweener.delay = secondsToDisplay;
  19.         tweener.Play(false);
  20.         EventDelegate.Add(tweener.onFinished, Done, true);
  21. }
  22.  

Further, it's looks like I was right about the events. If I play the tween forward while it's already in the final state, it will instantly finish (which makes sense). If I haven't registered the handler for onFinished, it will obviously not get called. Thus, if it's possible for the tween to already be finished it's important register before playing.

25
Why are you calling Play so many times
The tween may have been playing backwards last, so I have to call Play(true) or ResetToBeginning() may actually reset it to the end. ResetToBeginning() sets mStarted to false, so presumably that stops the tweening (I haven't confirmed that), so I have to call Play(true) again afterward.

why do you register a delegate before calling Play?
Instinct? Usually you register for events before you start the thing that could trigger the event. Presumably, there's some non-zero chance the event could be fired immediately. What happens if you start a tween and it's already in the final state? Again, I haven't explicitly tested this, I just would never have expected it to be an issue.

First call Play, then register your delegate, and do it only once.
I'll give this a shot.

26
As far as I can tell, it's impossible to reset a tween after it has been played in reverse. The easiest way to explain is probably just a code example. I have a popup window that tweens in, waits for a couple seconds, and tweens back out (in reverse). If it's called while already active, it queues the new message and shows it after the current one finishes. If the user leaves the screen it's on, the queue is simply emptied. This means it's possible for the tween to have been disabled in some random state and needs to be reset to it's initial state before being shown.

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3.  
  4. public class PopupTest : MonoBehaviour
  5. {
  6.         #region Editor Interface
  7.  
  8.         [SerializeField] private TweenScale tweener;
  9.         [SerializeField] private int secondsToDisplay;
  10.  
  11.         #endregion
  12.  
  13.         #region Private Fields
  14.  
  15.         private static PopupTest instance;
  16.         private static Queue<string> queue = new Queue<string>();
  17.         private static bool isActive = false;
  18.  
  19.         #endregion
  20.  
  21.         #region MonoBehaviour Methods
  22.  
  23.         private void Awake ()
  24.         {
  25.                 //Enforce the singleton pattern
  26.                 if ( instance != null )
  27.                 {
  28.                         Debug.LogError("Multiple instances of the " + GetType() + " created. There can be only one.");
  29.                 }
  30.                 instance = this;
  31.         }
  32.  
  33.         private void OnDisable ()
  34.         {
  35.                 isActive = false;
  36.                 NGUITools.SetActiveChildren(gameObject, false);
  37.  
  38.                 tweener.onFinished.Clear();
  39.                 tweener.enabled = false;
  40.                 queue.Clear();
  41.         }
  42.  
  43.         private void OnDestroy ()
  44.         {
  45.                 instance = null;
  46.         }
  47.  
  48.         #endregion
  49.  
  50.         #region Public Interface
  51.  
  52.         public static void Display ()
  53.         {
  54.                 if ( !instance.gameObject.activeInHierarchy ) return;
  55.  
  56.                 queue.Enqueue("Test");
  57.  
  58.                 if ( !isActive )
  59.                 {
  60.                         instance.Show();
  61.                 }
  62.         }
  63.  
  64.         #endregion
  65.  
  66.         #region Private Methods
  67.  
  68.         private void Show ()
  69.         {
  70.                 queue.Dequeue();
  71.  
  72.                 EventDelegate.Add(tweener.onFinished, Hide, true);
  73.                 tweener.delay = 0;
  74.  
  75.                 tweener.Play(true);
  76.                 Debug.Log("Scale (play1):" + transform.localScale);
  77.                 tweener.ResetToBeginning();
  78.                 Debug.Log("Scale (reset):" + transform.localScale);
  79.                 tweener.Play(true);
  80.                 Debug.Log("Scale (play2):" + transform.localScale);
  81.  
  82.                 isActive = true;
  83.                 NGUITools.SetActiveChildren(gameObject, true);
  84.         }
  85.  
  86.         private void Hide ()
  87.         {
  88.                 EventDelegate.Add(tweener.onFinished, HideComplete, true);
  89.                 tweener.delay = secondsToDisplay;
  90.                 tweener.Play(false);
  91.         }
  92.  
  93.         private void HideComplete ()
  94.         {
  95.                 isActive = false;
  96.                 NGUITools.SetActiveChildren(gameObject, false);
  97.  
  98.                 if ( queue.Count > 0 )
  99.                 {
  100.                         Show();
  101.                 }
  102.         }
  103.  
  104.         #endregion
  105. }
  106.  

The issues are with Show(). Since the tween could have been disabled while tweening in reverse, I have to play it forward once otherwise ResetToBeginning actually resets it to the end. However, it still doesn't work. If the tween is disabled in the middle of the tween playing in reverse, I can't get it to reset back to the beginning and it will just appear instantly instead of tweening.

Incidentally, if you remove the first Play(true) from Show() the tween will throw an exception when a message is queued.

27
NGUI 3 Support / 3.4.9 ScrollView Issues
« on: February 13, 2014, 01:50:36 PM »
I dynamically populate a ScrollView at one point, and I noticed 2 oddities.

1) ResetPosition doesn't work if the object is disabled in the hierarchy. This is a problem for me since when I go to a new screen, I populate the ScrollView before I enabled the screen. I can work around this, but it'd be much more convenient to be able to reset scrolling position while the object is disabled.

2) In an attempt to work around 1) I noticed several methods throw exceptions if the ScrollView has never been enabled. For example, MoveAbsolute throws an exception because mTrans is null. MoveRelative throw one because panel is null.

28
NGUI 3 Support / Re: EventDelegate.Remove Failing
« on: February 05, 2014, 04:35:31 PM »
Thanks, that works.

It gets the job done, but honestly, I was hoping to be able to use the same EventDelegate.Remove method for this. Using RemoveOnFinished isn't terribly intuitive and it's kind of hidden away in the UITweener class instead of EventDelegate. It requires a bit of NGUI tribal knowledge to use, and while I can tell my coworkers about it, it's bound to give new people a problem when they run into it.

Regardless, thanks for the help.

29
NGUI 3 Support / Re: EventDelegate.Remove Failing
« on: February 05, 2014, 03:29:31 PM »
Quote
Assets/Scripts/GameScreens/GameplayScreen/PauseWindow.cs(118,25): error CS1502: The best overloaded method match for `UITweener.RemoveOnFinished(EventDelegate)' has some invalid arguments
Assets/Scripts/GameScreens/GameplayScreen/PauseWindow.cs(118,25): error CS1503: Argument `#1' cannot convert `method group' expression to type `EventDelegate'

30
NGUI 3 Support / Re: EventDelegate.Remove Failing
« on: February 04, 2014, 03:54:34 PM »
I finally got around to testing this, and I don't quite understand how it's supposed to be used. I need a reference to the EventDelegate created for the method that is registered, but I don't have that. Here's what I tried:

  1. public class PauseWindow : MonoBehaviour
  2. {
  3.         public void Show ()
  4.         {
  5.                 //Pause game
  6.                 GameManager.TimeManager.PauseApplication(true);
  7.  
  8.                 //Standard pop-up stuff
  9.                 UIManager.ToggleUIElement(UIElement.InputBlocker, true);
  10.                 NGUITools.SetActiveChildren(gameObject, true);
  11.  
  12.                 //Start scale tween transiton of the entire window
  13.                 tweener.Play(true);
  14.         }
  15.  
  16.         public void Hide ()
  17.         {
  18.                 EventDelegate.Add(tweener.onFinished, Deactivate);
  19.                 tweener.Play(false);
  20.         }
  21.  
  22.         public void Deactivate ()
  23.         {
  24.                 //Doesn't work
  25.                 //EventDelegate.Remove(tweener.onFinished, Deactivate)
  26.  
  27.                 //Still doesn't work
  28.                 tweener.RemoveOnFinished(tweener.onFinished.Find(del => del.Equals((EventDelegate.Callback)Deactivate)));
  29.  
  30.                 NGUITools.SetActiveChildren(gameObject, false);
  31.  
  32.                 GameManager.TimeManager.PauseApplication(false);
  33.                 UIManager.ToggleUIElement(UIElement.InputBlocker, false);
  34.         }
  35. }
  36.  

It fails though. In the previous system this sort of behavior was intuitive and simple. This pattern in the new system is really throwing me for a loop.

Pages: 1 [2] 3 4 5