// Start is called before the first frame update protected override void Start() { m_CategoryPagerView.items.Value = m_Categories; var categoryObservable = category as IObservable <CategoryEnum>; var isDragAndDropping = new BoolReactiveProperty(false); // If we have at least one category, start with it if (m_Categories.Length > 0) { categoryObservable = categoryObservable.StartWith(m_Categories[0].category); } // Change the catalogue pager whenever the category button is pressed or the color changes. Observable.Merge( categoryObservable .DistinctUntilChanged() .AsUnitObservable(), flipped.DistinctUntilChanged() .AsUnitObservable(), color.DistinctUntilChanged() .AsUnitObservable() ) .Subscribe(ignored => { var catalogueItems = m_Asset[category.Value, color.Value] .Select(item => new CatalogueItem() { flipped = flipped.Value, asset = item }) .ToArray(); m_CataloguePagerView.items.Value = catalogueItems; if (m_Brush.Value != null) { var index = Array.FindIndex(catalogueItems, item => item.asset.name == m_Brush.Value.catalogueItem.asset.name); if (index >= 0) { // If the color or flip state changed, it now changed here var brush = new BrushItem() { catalogueItem = catalogueItems[index] }; m_Brush.SetValueAndForceNotify(brush); } } var hit = new EventHitBuilder() .SetEventCategory("profile creator") .SetEventAction("brush") .SetEventLabel($"category={category.Value}, color={color.Value}, flipped={flipped.Value}") .SetEventValue(drawingView.stampItems.Count); GoogleAnalyticsV4.getInstance().LogEvent(hit); }) .AddTo(this); category.Value = m_Categories[0].category; // Whenever we click on a catalogue item, set that image as the current brush, then stamp its pixels onto // the drawing image with our brush when it is clicked m_CataloguePagerView.OnCatalogueItemPointerClickAsObservable() .Subscribe(tuple => { // If we clicked instead of dragged the item, we're definitely not dragging isDragAndDropping.Value = false; brush.Value = new BrushItem() { catalogueItem = tuple.Item2 }; }) .AddTo(this); // If we switch into the screen view that contains the editing profile text, copy in the image to it m_UiScreenView.onScreenBeginTransition.AsObservable() .Where(targetScreen => targetScreen == m_EditingProfileTextScreen.screenIndex) .Subscribe(ignored => { Drawing.PostDrawing(drawingView, m_EditingProfileTextDrawingView); }) .AddTo(this); // Drawing code var opaque = new Color(1f, 1f, 1f, 1f); var transparent = new Color(1f, 1f, 1f, m_PreviewBrushTransparency); // Draw a preview of the brush var previewBrush = new GameObject("Preview Brush"); var previewImage = previewBrush.AddComponent <Image>(); // The preview image brush naturally should not receive raycasts / should not block previewImage.raycastTarget = false; var previewBrushTransform = previewBrush.transform as RectTransform; Debug.Assert(previewBrushTransform != null, nameof(previewBrushTransform) + " != null"); // Changes the preview's sprite as long as the brush is not null. The brush is actually set inactive later. // Also reacts to when the flipping setting changes. brush .Where(b => brush.Value != null && brush.Value.sprite != null) .Subscribe(b => { previewImage.sprite = b.sprite; previewImage.rectTransform.localScale = new Vector3(b.flipped ? -1.0f : 1f, 1f, 1f); previewImage.SetNativeSize(); }) .AddTo(this); // Move the preview brush along with the mouse as long as there is a brush selected // Whether or not it will be visible depends on which layer it's on and whether or not we're on a mobile // device. Mobile devices do not show the preview when the item was just clicked. The layer is changed later. Observable.EveryUpdate() .Where(ignored => isActiveAndEnabled) .Subscribe(ignored => { if (brush.Value == null || Application.isMobilePlatform && !isDragAndDropping.Value) { previewBrush.SetActive(false); return; } previewBrush.SetActive(true); var pointer = ContinuousStandaloneInputModule.instance.pointerEventData; var isOverDrawingView = pointer.pointerCurrentRaycast.gameObject == m_DrawingView.raycastTarget.gameObject; previewImage.color = isDragAndDropping.Value ? isOverDrawingView ? opaque : transparent : opaque; previewBrushTransform.transform.position = BrushPosition(pointer); }) .AddTo(this); // When we are drag and dropping, put the preview brush on the root canvas layer so that its totally in // the foreground. Otherwise, put it in the preview layer so it only appears when the user's pointer is // hovering over the drawing canvas isDragAndDropping.StartWith(false) .Subscribe(dragging => { previewBrushTransform.SetParent(dragging ? m_ScreenRectTransform : m_DrawingView.previewLayer); }) .AddTo(this); // Draw the brush when it is stamped var foreground = m_DrawingView.stampLayer; m_DrawingView.OnPointerClickAsObservable() .Where(ignored => brush.Value != null) .Subscribe(pointer => { Stamp(pointer, foreground, brush.Value.flipped); }) .AddTo(this); // Enable drag and dropping a specific sprite. Temporarily switches the brush and activates drag and drop mode m_CataloguePagerView .OnCatalogueItemBeginDragAsObservable() .Subscribe(tuple => { isDragAndDropping.Value = true; brush.Value = new BrushItem() { catalogueItem = tuple.Item2 }; }) .AddTo(this); // Stamp when we stop dragging a catalogue item m_CataloguePagerView .OnCatalogueItemEndDragAsObservable() .Subscribe(tuple => { isDragAndDropping.Value = false; // If we're over the drawing view, we should stamp the sprite var isOverDrawingView = tuple.Item1.pointerCurrentRaycast.gameObject == m_DrawingView.raycastTarget.gameObject; if (isOverDrawingView) { Stamp(tuple.Item1, m_DrawingView.stampLayer, tuple.Item2.flipped); } // Then clear the brush no matter what brush.Value = null; }) .AddTo(this); // Toggle the flip automatically if this particular asset is configured to do so stampEvents.Where(stamp => stamp != null && stamp.brush.flipsAfterStamp) .Subscribe(stamp => { flipped.Value = !flipped.Value; }) .AddTo(this); drawingView.stampItems.ObserveCountChanged(true) .Subscribe(count => { m_CanUndo.Value = count > 0; }) .AddTo(this); // Save as the user stamps stampEvents .Subscribe(stampEvent => { // This throttles internally SaveGameController.instance.Save(); if (stampEvent != null) { // Analytics var hit = new EventHitBuilder() .SetEventCategory("profile creator") .SetEventAction("stamp") .SetEventLabel(stampEvent.brush.sprite.name) .SetEventValue(drawingView.stampItems.Count); GoogleAnalyticsV4.getInstance().LogEvent(hit); } }) .AddTo(this); }
public override void OnEnable() { base.OnEnable(); SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneUnloaded += OnSceneUnloaded; sceneLoaders.OnAdd().Subscribe(entity => { var sceneLoader = entity.GetComponent <SceneLoader>(); entity.OnListenerAsObservable <TriggerEnterEvent>().Select(_ => true) .Merge(entity.OnListenerAsObservable().Select(_ => true)) .Subscribe(_ => { foreach (var setup in sceneLoader.LoadQueue) { if (setup.Operation == SceneLoader.Operation.Load) { EventSystem.Send(new LoadSceneEvent(setup.SceneSetup)); } else if (setup.Operation == SceneLoader.Operation.Unload) { EventSystem.Send(new UnloadSceneEvent(setup.SceneSetup)); } } }).AddTo(this.Disposer).AddTo(sceneLoader.Disposer); }).AddTo(this.Disposer); loadingScreens.OnAdd().Subscribe(entity => { var loadingScreen = entity.GetComponent <LoadingScreen>(); loadingScreen.State.DistinctUntilChanged().Where(state => state == FadeState.FadedOut).Subscribe(_ => { if (loadingScreens.Entities.Select(e => e.GetComponent <LoadingScreen>().State.Value).All(state => state != FadeState.FadingIn && state != FadeState.FadingOut)) { readyToLoad.Value = true; } }).AddTo(this.Disposer).AddTo(loadingScreen.Disposer); }).AddTo(this.Disposer); EventSystem.OnEvent <LoadSceneEvent>().Subscribe(evt => { foreach (var setup in evt.LoadSceneSetup.Setups) { if ((setup.Mode == LoadSceneMode.Additive && SceneManager.GetSceneByPath(setup.Path).isLoaded) || scenesToLoad.Contains(setup)) { continue; } scenesToLoad.Add(setup); } }).AddTo(this.Disposer); EventSystem.OnEvent <UnloadSceneEvent>().Subscribe(evt => { foreach (var setup in evt.UnloadSceneSetup.Setups) { var scene = SceneManager.GetSceneByPath(setup.Path); if (!scene.IsValid() || !scene.isLoaded || scenesToUnload.Contains(setup)) { continue; } scenesToUnload.Add(setup); } }).AddTo(this.Disposer); EventSystem.OnEvent <LoadSceneEvent>().Select(evt => evt.LoadSceneSetup).Merge(EventSystem.OnEvent <UnloadSceneEvent>().Select(evt => evt.UnloadSceneSetup)) .Where(_ => !readyToLoad.Value && scenesToLoad.Count + scenesToUnload.Count > 0).Subscribe(setup => { var isReady = true; foreach (var loadingScreen in loadingScreens.Entities.Select(entity => entity.GetComponent <LoadingScreen>())) { if (setup.LoadingMask.Contains(loadingScreen.Layer)) { loadingScreen.State.Value = FadeState.FadingOut; isReady = false; } } readyToLoad.Value = isReady; }).AddTo(this.Disposer); scenesToLoad.ObserveAdd().Subscribe(evt => { readyToLoad.StartWith(readyToLoad.Value).Where(isReady => isReady).FirstOrDefault().Subscribe(_ => { SceneManager.LoadSceneAsync(evt.Value.Path, evt.Value.Mode); }).AddTo(this.Disposer); }).AddTo(this.Disposer); scenesToUnload.ObserveAdd().Subscribe(evt => { readyToLoad.StartWith(readyToLoad.Value).Where(isReady => isReady).FirstOrDefault().Subscribe(_ => { SceneManager.UnloadSceneAsync(evt.Value.Path); }).AddTo(this.Disposer); }).AddTo(this.Disposer); scenesToLoad.ObserveRemove().Merge(scenesToUnload.ObserveRemove()) .Where(_ => scenesToLoad.Count <= 0 && scenesToUnload.Count <= 0) .Subscribe(_ => { readyToLoad.Value = false; Resources.UnloadUnusedAssets(); foreach (var loadingScreen in loadingScreens.Entities.Select(entity => entity.GetComponent <LoadingScreen>()).Where(loadingScreen => loadingScreen.State.Value == FadeState.FadingOut || loadingScreen.State.Value == FadeState.FadedOut)) { loadingScreen.State.Value = FadeState.FadingIn; } }).AddTo(this.Disposer); }
protected override void Awake() { base.Awake(); var version = new IntReactiveProperty(0); var sentVersion = -1; responses.Observe() .Subscribe(ignored => { version.Value = version.Value + 1; }) .AddTo(this); for (var i = 0; i < m_ChatBoxViews.Length; i++) { var j = i; var view = m_ChatBoxViews[i]; view.button.OnPointerClickAsObservable() .Where(ignored => view.button.interactable) .Subscribe(v => { if (m_PostOwnMessages) { m_ConversationController.Add(new ChatMessage[] { new ChatMessage() { self = true, message = view.data } }); } SetChatBoxesInteractive(false); sentVersion = version.Value; m_Choices.OnNext(new ChatBoxChoice() { index = j, text = view.data }); }) .AddTo(view); } m_InputBox.OnPointerClickAsObservable() .Where(ignored => !m_IsRequestingTextInput) .Subscribe(ignored => { m_Open.Value = !m_Open.Value; m_ConversationController.ThrottledScrollToBottom(); }) .AddTo(this); Observable.Merge( responses.Observe().AsUnitObservable(), m_Open.StartWith(false).AsUnitObservable()) .BatchFrame(1, FrameCountType.Update) .Subscribe(ignored => { var count = responses.Count; var isOpen = m_Open.Value; if (count == 0) { isOpen = false; } else { if (m_Open.Value) { m_ConversationController.StartTyping(true); } else { m_ConversationController.StopTyping(); } } for (var i = 0; i < m_ChatBoxViews.Length; i++) { if (i < count) { m_ChatBoxViews[i].data = responses[i]; } else { m_ChatBoxViews[i].data = null; } m_ChatBoxViews[i].gameObject.SetActive(isOpen && i < count); } m_InputBox.interactable = count > 0; SetChatBoxesInteractive(version.Value != sentVersion); }) .AddTo(this); // The input text that this has is only enabled when the user actually has to type something in. m_SpacerForKeyboard.gameObject.SetActive(false); m_KeyboardConnector.enabled = false; }