// ------------------------------------------------------- @HoverHeight // -- Animate the Height of target element to desired value on hover -- // -------------------------------------------------------------------- public static void HoverHeight(this VisualElement target, float initialHeight = 0f, float desiredHeight = 100f, int duration = 1000, Action hoverCallback = null, Action leaveCallback = null, bool afterAnimation = false) { initialHeight = initialHeight == 0f ? target.resolvedStyle.height : initialHeight; var enterAnim = new ValueAnimation <StyleValues>(); var leaveAnim = new ValueAnimation <StyleValues>(); void MouseEnter() { enterAnim = afterAnimation ? target.AnimateHeight(initialHeight, desiredHeight, duration, hoverCallback) : target.AnimateHeight(initialHeight, desiredHeight, duration); } // @formatter:off void MouseLeave() { leaveAnim = target.AnimateHeight(desiredHeight, initialHeight, duration); } // @formatter:on target.RegisterCallback <MouseOverEvent>(evt => { if (enterAnim.isRunning) { enterAnim.Stop(); } if (leaveAnim.isRunning) { leaveAnim.Stop(); } MouseEnter(); if (!afterAnimation) { hoverCallback?.Invoke(); } evt.StopPropagation(); }); target.RegisterCallback <MouseLeaveEvent>(evt => { if (enterAnim.isRunning) { enterAnim.Stop(); } if (leaveAnim.isRunning) { leaveAnim.Stop(); } MouseLeave(); evt.StopPropagation(); target.schedule.Execute(leaveCallback).StartingIn(duration); }); }
public void ShowDamageText(int value) { Debug.Log("Face Dir=" + transform.localScale.x); GameObject obj = GameObject.Instantiate(valueTextPrefab); obj.transform.SetParent(transform); obj.transform.localPosition = mDamageSpawnPosTF.localPosition; ValueAnimation valueAnime = obj.GetComponent <ValueAnimation>(); valueAnime.autoDestroy = true; valueAnime.Show(value); }
private void TaskFinished(BehaviourTask task) { if (_currentHighlights.TryGetValue(task.Index, out var highlight)) { _currentHighlights.Remove(task.Index); var anim = ValueAnimation <float> .Create(highlight, (a, b, t) => Mathf.Lerp(a, b, Easing.OutQuad(t))); anim.from = 1f; anim.to = 0f; anim.durationMs = 500; anim.OnCompleted(highlight.RemoveFromHierarchy); anim.valueUpdated = (e, value) => e.style.opacity = value; anim.Start(); } }
async void Hit() { var material = Node.GetComponent <StaticModel>().GetMaterial(); if (material == null) { return; } material.SetShaderParameter("MatSpecColor", new Color(0, 0, 0, 0)); var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f)); specColorAnimation.SetKeyFrame(0.1f, new Color(0, 0, 0, 0)); material.SetShaderParameterAnimation("MatSpecColor", specColorAnimation, WrapMode.Once, 1.0f); await Node.RunActionsAsync(new DelayTime(1f)); }
Material CreateSelectionMaterial() { var mat = Material.FromColor(Color.Blue); mat.FillMode = FillMode.Wireframe; var specColorAnimation = new ValueAnimation(); Color color = new Color(0.8f, 0.8f, 0.1f); Color fade = new Color(0.5f, 0.5f, 0.5f); specColorAnimation.SetKeyFrame(0.0f, fade); specColorAnimation.SetKeyFrame(0.5f, color); specColorAnimation.SetKeyFrame(1.0f, fade); mat.SetShaderParameterAnimation("MatDiffColor", specColorAnimation, WrapMode.Loop, 1.0f); //mat.AddRef(); return(mat); }
public void StartFadeOutAnimation(VisualElement container, int duration) { if (m_animation != null) { m_animation.Stop(); m_animation.durationMs = duration; m_animation.Start(); } else { m_animation = container.experimental.animation.Start(defaultAlpha, 0, duration, (ve, value) => { alpha = value; ve.MarkDirtyRepaint(); }).Ease(Easing.OutCubic).KeepAlive(); } }
async void Hit() { var material = Node.GetComponent <StaticModel>().GetMaterial(0); if (material == null) { return; } //NOTE: the material should not be cached (Clone() should be called) or all object with it will be blinking material.SetShaderParameter("MatSpecColor", new Color(0, 0, 0, 0)); var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f)); specColorAnimation.SetKeyFrame(0.1f, new Color(0, 0, 0, 0)); material.SetShaderParameterAnimation("MatSpecColor", specColorAnimation, WrapMode.Once, 1.0f); await Node.RunActionsAsync(new DelayTime(1f)); }
private async void Hit() { var material = Node.GetComponent <StaticModel>().GetMaterial(0); if (material == null) { return; } // il materiale non dev'essere memorizzato nella cache (Clone dev'essere chiamato) o tutti gli oggetti con esso blinking material.SetShaderParameter("MatSpecColor", new Color(0, 0, 0, 0)); var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f)); specColorAnimation.SetKeyFrame(0.1f, new Color(0, 0, 0, 0)); material.SetShaderParameterAnimation("MatSpecColor", specColorAnimation, WrapMode.Once, 1.0f); await Node.RunActionsAsync(new DelayTime(1f)); }
public override void OnSurfaceAddedOrUpdated(SpatialMeshInfo surface, Model generatedModel) { bool isNew = false; StaticModel staticModel = null; Node node = environmentNode.GetChild(surface.SurfaceId, false); if (node != null) { isNew = false; staticModel = node.GetComponent <StaticModel>(); } else { isNew = true; node = environmentNode.CreateChild(surface.SurfaceId); staticModel = node.CreateComponent <StaticModel>(); } node.Position = surface.BoundsCenter; node.Rotation = surface.BoundsRotation; staticModel.Model = generatedModel; Material mat; Color startColor; Color endColor = new Color(0.8f, 0.8f, 0.8f); if (isNew) { startColor = Color.Blue; mat = Material.FromColor(endColor); staticModel.SetMaterial(mat); } else { startColor = Color.Red; mat = staticModel.GetMaterial(0); } mat.FillMode = wireframe ? FillMode.Wireframe : FillMode.Solid; var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, startColor); specColorAnimation.SetKeyFrame(1.5f, endColor); mat.SetShaderParameterAnimation("MatDiffColor", specColorAnimation, WrapMode.Once, 1.0f); }
protected void CreateValueTextObject() { GameObject obj = GameObject.Instantiate(valueTextPrefab); if (parentTransform != null) { obj.transform.SetParent(parentTransform); } obj.transform.localPosition = position; ValueAnimation valueAnime = obj.GetComponent <ValueAnimation>(); if (valueAnime != null) { valueAnime.autoDestroy = true; } mValueAnimation = valueAnime; }
public void Pan(PanDirection dir, bool animate = false) { var direction = GetVectorForDirection(dir, animate); if (animate) { ValueAnimation panAnimation = new ValueAnimation(); panAnimation.InterpolationMethod = InterpMethod.Linear; panAnimation.SetKeyFrame(0.0f, App.RootNode.Position); panAnimation.SetKeyFrame(0.3f, App.RootNode.Position + direction); ObjectAnimation mainNodeAnimation = new ObjectAnimation(); mainNodeAnimation.AddAttributeAnimation("Position", panAnimation, WrapMode.Once, 1f); App.RootNode.ObjectAnimation = mainNodeAnimation; } else { App.RootNode.Position += direction; } }
/// <summary> /// Tests if a single animation runs for the specified amount of time /// at the specified framerate. /// </summary> /// /// <param name="framerate"> /// the framerate that the test animation should run. This framerate /// is used to determine how much the animation can overshoot its /// time frame. /// </param> /// /// <param name="duration"> /// the amount of time in milliseconds the animation should run. /// </param> private void AnimationDurationTestCase(int framerate, long duration) { // Setup the animation. var animation = new ValueAnimation(0, 0, duration); Animator.Instance.Framerate = framerate; // Create a stopwatch to time the animation. var stopwatch = new Stopwatch(); // Have the stopwatch stopped at the end of the animation. animation.AnimationEnded += (_, __) => stopwatch.Stop(); // Start the stopwatch and animation. stopwatch.Start(); animation.Start(); // Wait for the animation to stop. while (stopwatch.IsRunning) { ; } // The error must be within the acceptable amount. var elapsed = stopwatch.ElapsedMilliseconds; var error = Math.Abs(elapsed - animation.Duration); var acceptableError = Animator.Instance.FrameDuration; Assert.IsTrue( error <= acceptableError, string.Format( "Animation lasted {0} milliseconds instead of {1} milliseconds with a framerate of {2} FPS " + " with an allotted error of {3} milliseconds.", elapsed, animation.Duration, framerate, acceptableError ) ); }
/// <summary> /// Animate the background color of target element to desired value after delay /// </summary> /// <param name="target">VisualElement to animate</param> /// <param name="startColor">Initial color of element</param> /// <param name="endColor">The desired end result color which to animate</param> /// <param name="durationMs">The length of time in milliseconds in which the animation will occur</param> /// <param name="delayMs">The length of time in milliseconds to wait before starting animation</param> /// <param name="callback">Function that can be called when the animation is completed</param> /// <param name="easing">Controls the animation timing curve mathematically</param> public static ValueAnimation <StyleValues> AnimateBackgroundColorDelayed(this VisualElement target, Color startColor, Color endColor, int durationMs = 500, int delayMs = 0, Action callback = null, Func <float, float> easing = null) { ValueAnimation <StyleValues> anim = new ValueAnimation <StyleValues>(); if (easing == null) { easing = Easy.EaseInOutQuint; } target.parent.schedule.Execute(() => { anim = target.experimental.animation .Start(new StyleValues { backgroundColor = startColor }, new StyleValues { backgroundColor = endColor }, durationMs) .Ease(easing) .OnCompleted(callback); }).StartingIn(delayMs); return(anim); }
public async void ClickAnimation() { Color originalColor = Color.Cyan; Color clickColor = Color.Yellow; CursorModelNode.RemoveAllActions(); var staticModel = CursorModelNode.GetComponent <StaticModel>(); if (staticModel != null) { var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, originalColor); specColorAnimation.SetKeyFrame(0.2f, clickColor); specColorAnimation.SetKeyFrame(0.4f, originalColor); var mat = staticModel.GetMaterial(0); mat?.SetShaderParameterAnimation("MatDiffColor", specColorAnimation, WrapMode.Once, 1.0f); } await CursorModelNode.RunActionsAsync(new ScaleTo(0.2f, 0.07f), new ScaleTo(0.4f, 0.04f)); RunIdleAnimation(); }
public void Zoom(ZoomDirection dir, bool animate = false) { if (animate) { var factor = (dir == ZoomDirection.In) ? _zoomInFactor : _zoomOutFactor; ValueAnimation zoomAnimation = new ValueAnimation(); zoomAnimation.InterpolationMethod = InterpMethod.Linear; zoomAnimation.SetKeyFrame(0.0f, App.Camera.Zoom); zoomAnimation.SetKeyFrame(0.3f, App.Camera.Zoom * factor); ObjectAnimation cameraAnimation = new ObjectAnimation(); cameraAnimation.AddAttributeAnimation("Zoom", zoomAnimation, WrapMode.Once, 1f); App.Camera.ObjectAnimation = cameraAnimation; } else { var factor = (dir == ZoomDirection.In) ? _zoomInFactorSmall : _zoomOutFactorSmall; App.Camera.Zoom *= factor; } }
/// <summary> /// Tests if awaiting a specified amount of time for a single animation lasting the /// specified amount of time waits for the appropriate amount of time. /// </summary> /// /// <param name="animationDuration"> /// the duration of the animation in milliseconds. /// </param> /// /// <param name="awaitduration"> /// the amount of time to await after the animation finishes. /// </param> public void AnimationAwaitTestCase(long animationDuration, int awaitduration) { // Setup the animation. var animation = new ValueAnimation(0, 0, animationDuration); // Time the waiting time. var stopwatch = new Stopwatch(); // Start the animation. animation.Start(); stopwatch.Start(); // Await animation.Await(awaitduration); // Stop the stopwatch. stopwatch.Stop(); // The error must be within the acceptable amount. var elapsed = stopwatch.ElapsedMilliseconds; var error = Math.Abs(elapsed - animationDuration) - awaitduration; var acceptableError = Animator.Instance.FrameDuration; Assert.IsTrue( error <= acceptableError, String.Format( "Waited for {0} milliseconds instead of {1} milliseconds for an animation lasting {2} " + "milliseconds and await time of {3} milliseconds with an allotted error of {4} milliseconds.", elapsed, animationDuration + awaitduration, animationDuration, awaitduration, acceptableError ) ); }
// --------------------------------------------------- @HoverColor // --------------------------------------------------------------- /// <summary> /// Adds forecolor hover capability that will not be lost like CSS:hover when programatically setting background color /// </summary> /// <example> /// <code> /// var originalColor = ColorUtil.FromHex("#BABABA"); /// var hoverColor = ColorUtil.FromHex("#2F569C"); /// /// label.HoverColor(originalColor, hoverColor); /// </code> /// </example> /// <param name="target">The element in which this function will be applied</param> /// <param name="original">The original color of the element being changed. Can be obtained and passed via 'visualElement.style.backgroundColor.value'</param> /// <param name="hoverColor">The color to fade to when element is hovered</param> /// <param name="condition">Create a condition to pass to this function. Example: bool Condition(VisualElement sRow) => selectedRow == packageListRow;</param> /// <param name="conditionElement">The element in which the optional condition will be evaluated. Ex. in the example of 'bool Condition(VisualElement sRow) => selectedRow == packageListRow;', the conditionalElement would be 'VisualElement selectedRow'</param> /// <param name="animate">Whether to animate the transition of the background color</param> /// <param name="unregister">Whether this command is issued to register or unregister this event</param> public static void HoverColor <T>(this T target, StyleColor original, Color hoverColor, Func <T, bool> condition = null, T conditionElement = null, bool animate = false, bool unregister = false) where T : VisualElement { ValueAnimation <StyleValues> mouseOver = new ValueAnimation <StyleValues>(); ValueAnimation <StyleValues> mouseOut = new ValueAnimation <StyleValues>(); target.RegisterCallback <MouseOverEvent>(evt => { var tar = (VisualElement)evt.target; if (animate) { mouseOver = tar.AnimateColor(original.value, hoverColor, 250); mouseOver.KeepAlive(); } if (condition != null && condition(conditionElement)) { return; } if (mouseOut.isRunning) { mouseOut.Stop(); } if (animate) { tar.schedule.Execute(() => { mouseOver.Start(); }).StartingIn(50); } else { tar.style.color = hoverColor; } evt.StopPropagation(); }); target.RegisterCallback <MouseOutEvent>(evt => { var tar = (VisualElement)evt.target; if (animate) { mouseOut = tar.AnimateColor(hoverColor, original.value, 250); mouseOut.KeepAlive(); } if (condition != null && condition(conditionElement)) { return; } if (mouseOver.isRunning) { mouseOver.Stop(); } if (animate) { tar.schedule.Execute(() => { mouseOut.Start(); }).StartingIn(50); } else { tar.style.color = original; } evt.StopPropagation(); }); if (!unregister) { return; } { target.UnregisterCallback <MouseOverEvent>(evt => { var tar = (VisualElement)evt.target; if (condition != null && condition(conditionElement)) { return; } if (mouseOut.isRunning) { mouseOut.Stop(); } if (animate) { tar.schedule.Execute(() => { mouseOver.Start(); }).StartingIn(50); } else { tar.style.color = hoverColor; } evt.StopPropagation(); }); target.UnregisterCallback <MouseOutEvent>(evt => { var tar = (VisualElement)evt.target; if (condition != null && condition(conditionElement)) { return; } if (mouseOver.isRunning) { mouseOver.Stop(); } if (animate) { tar.schedule.Execute(() => { mouseOut.Start(); }).StartingIn(50); } else { tar.style.color = original; } evt.StopPropagation(); }); } }
HoverBorderPulse( this VisualElement target, Color pulseStartColor, Color pulseEndColor, Color original = default, bool addBorder = false, Vector2 borderStartEndWidth = default, int colorDuration = 1000, bool includeChildren = true, bool stopPropagation = true, TrickleDown useTrickleDown = TrickleDown.NoTrickleDown, AnimatedItems <MouseOverEvent, MouseOutEvent> animatedItems = null, params ValueAnimation <StyleValues>[] animRunCheck) { if (borderStartEndWidth == default) { borderStartEndWidth = new Vector2(1, 0); } var doHover = false; var pulseIn = new ValueAnimation <StyleValues>(); var pulseOut = new ValueAnimation <StyleValues>(); IVisualElementScheduledItem repeatedAnim = null; if (animatedItems == null) { animatedItems = new AnimatedItems <MouseOverEvent, MouseOutEvent>(target); } EventCallback <MouseOverEvent> mouseOverEvent = evt => { if (animRunCheck.Length > 0) { if (animRunCheck.Any(t => t.isRunning)) { return; } } if (!animatedItems.AllowRun) { return; } repeatedAnim = null; doHover = true; if (addBorder) { target.style.borderBottomWidth = borderStartEndWidth.x; target.style.borderLeftWidth = borderStartEndWidth.x; target.style.borderRightWidth = borderStartEndWidth.x; target.style.borderTopWidth = borderStartEndWidth.x; } // -- Pulse color will fade original => desired color -- // -- via the AnimateTo local function. Once completed -- // -- the AnimateFrom function is called animating back -- // -- to the original color. This is then repeated for -- // -- as long as the mouse is hovered over the target -- void PulseIn(in ValueAnimation <StyleValues> pulse) { if (pulse.isRunning) { pulse.Stop(); } pulseIn = target.AnimateBorderColor(pulseStartColor, pulseEndColor, colorDuration, () => PulseOut(pulseIn)); } void PulseOut(in ValueAnimation <StyleValues> pulse) { if (pulse.isRunning) { pulse.Stop(); } pulseOut = target.AnimateBorderColor(pulseEndColor, pulseStartColor, colorDuration); } if (pulseIn.isRunning) { pulseIn.Stop(); } if (pulseOut.isRunning) { pulseOut.Stop(); } repeatedAnim = target.schedule.Execute(() => PulseIn(pulseOut)).StartingIn(0).Every(colorDuration * 2 + 20).Until(() => !doHover); if (stopPropagation) { evt.StopPropagation(); } }; EventCallback <MouseOutEvent> mouseOutEvent = evt => { if (!animatedItems.AllowRun) { return; } doHover = false; if (pulseIn.isRunning) { pulseIn?.Stop(); } if (pulseOut.isRunning) { pulseOut?.Stop(); } if (repeatedAnim != null && repeatedAnim.isActive) { repeatedAnim.Pause(); } if (addBorder) { target.style.borderBottomWidth = borderStartEndWidth.y; target.style.borderLeftWidth = borderStartEndWidth.y; target.style.borderRightWidth = borderStartEndWidth.y; target.style.borderTopWidth = borderStartEndWidth.y; } if (pulseIn.isRunning) { pulseIn.Stop(); } if (pulseOut.isRunning) { pulseOut.Stop(); } target.style.borderBottomColor = original; target.style.borderLeftColor = original; target.style.borderRightColor = original; target.style.borderTopColor = original; if (stopPropagation) { evt.StopPropagation(); } }; target.RegisterCallback(mouseOverEvent, includeChildren, useTrickleDown); target.RegisterCallback(mouseOutEvent, includeChildren, useTrickleDown); animatedItems.AnimatedItemList = new List <ValueAnimation <StyleValues> > { pulseIn, pulseOut }; animatedItems.EventCallbacks = (mouseOverEvent, mouseOutEvent); return(animatedItems); }
async void Hit() { var material = Node.GetComponent<StaticModel>().GetMaterial(0); if (material == null) return; //NOTE: the material should not be cached (Clone() should be called) or all object with it will be blinking material.SetShaderParameter("MatSpecColor", new Color(0, 0, 0, 0)); var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f)); specColorAnimation.SetKeyFrame(0.1f, new Color(0, 0, 0, 0)); material.SetShaderParameterAnimation("MatSpecColor", specColorAnimation, WrapMode.Once, 1.0f); await Node.RunActionsAsync(new DelayTime(1f)); }
void OnEnable() { easingCurvesFuncs[0] = this.SampleCurve; var asset = AssetDatabase.LoadAssetAtPath <VisualTreeAsset>("Assets/Examples/Editor/Transitions.uxml"); var root = this.rootVisualElement; var top = asset.CloneTree(); top.StretchToParentSize(); top.styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>("Assets/Examples/Editor/transitions-style.uss")); root.Add(top); canvas = root.Q <VisualElement>("canvas"); var valueContainer = root.Q <VisualElement>("value-container"); PopupField <string> easingPopup = new PopupField <string>(easingcurves, 0); easingPopup.label = "Easing"; easingPopup.RegisterValueChangedCallback((evt) => SetEasingCurve(easingPopup.value)); valueContainer.Insert(0, easingPopup); customCurveField = root.Q <CurveField>(); customCurveField.value = customCurve; durationField = root.Q <IntegerField>(); startButton = root.Q <Button>("start-button"); startButton.clickable.clicked += OnButtonClicked; startButton.name = "start-button"; cursor = new VisualElement(); canvas.Add(cursor); cursor.style.width = cursorSize; cursor.style.height = cursorSize; cursor.style.backgroundColor = Color.red; targetElement = new VisualElement() { name = "target" }; targetElement.style.position = Position.Absolute; canvas.Add(targetElement); int defaultDurationMs = 1000; xAnim = canvas.experimental.animation.Start(0, 1, defaultDurationMs, (e, v) => OnXChanged(v)).Ease(Easing.Linear).KeepAlive(); xAnim.Stop(); xAnim.onAnimationCompleted += UpdateButtonText; durationField.SetValueWithoutNotify(xAnim.durationMs); yAnim = canvas.experimental.animation.Start(0, 1, defaultDurationMs, (e, v) => OnYChanged(v)).Ease(Easing.Linear).KeepAlive(); yAnim.Stop(); cursor.RegisterCallback <GeometryChangedEvent>((e) => UpdateCursorTrail()); easingPopup.value = easingcurves[easingcurves.Count - 1]; SetEasingCurve(easingPopup.value); targetElement.style.right = 0; }
void CreateScene() { var cache = GetSubsystem <ResourceCache>(); scene = new Scene(); // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically // optimizing manner scene.CreateComponent <Octree>(); // Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple // plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger // (100 x 100 world units) Node planeNode = scene.CreateChild("Plane"); planeNode.Scale = new Vector3(100.0f, 1.0f, 100.0f); StaticModel planeObject = planeNode.CreateComponent <StaticModel>(); planeObject.Model = (cache.Get <Model>("Models/Plane.mdl")); planeObject.SetMaterial(cache.Get <Material>("Materials/StoneTiled.xml")); // Create a directional light to the world so that we can see something. The light scene node's orientation controls the // light direction; we will use the SetDirection() function which calculates the orientation from a forward direction vector. // The light will use default settings (white light, no shadows) Node lightNode = scene.CreateChild("DirectionalLight"); lightNode.SetDirection(new Vector3(0.6f, -1.0f, 0.8f)); // The direction vector does not need to be normalized Light light = lightNode.CreateComponent <Light>(); light.LightType = LightType.LIGHT_DIRECTIONAL; // Create more StaticModel objects to the scene, randomly positioned, rotated and scaled. For rotation, we construct a // quaternion from Euler angles where the Y angle (rotation about the Y axis) is randomized. The mushroom model contains // LOD levels, so the StaticModel component will automatically select the LOD level according to the view distance (you'll // see the model get simpler as it moves further away). Finally, rendering a large number of the same object with the // same material allows instancing to be used, if the GPU supports it. This reduces the amount of CPU work in rendering the // scene. Material mushroomMat = cache.Get <Material>("Materials/Mushroom.xml"); // Apply shader parameter animation to material ValueAnimation specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, new Color(0.1f, 0.1f, 0.1f, 16.0f)); specColorAnimation.SetKeyFrame(1.0f, new Color(1.0f, 0.0f, 0.0f, 2.0f)); specColorAnimation.SetKeyFrame(2.0f, new Color(1.0f, 1.0f, 0.0f, 2.0f)); specColorAnimation.SetKeyFrame(3.0f, new Color(0.1f, 0.1f, 0.1f, 16.0f)); // Optionally associate material with scene to make sure shader parameter animation respects scene time scale mushroomMat.Scene = scene; mushroomMat.SetShaderParameterAnimation("MatSpecColor", specColorAnimation, WrapMode.WM_LOOP, 1.0f); const uint numObjects = 200; for (uint i = 0; i < numObjects; ++i) { Node mushroomNode = scene.CreateChild("Mushroom"); mushroomNode.Position = (new Vector3(NextRandom(90.0f) - 45.0f, 0.0f, NextRandom(90.0f) - 45.0f)); mushroomNode.Rotation = new Quaternion(0.0f, NextRandom(360.0f), 0.0f); mushroomNode.SetScale(0.5f + NextRandom(2.0f)); StaticModel mushroomObject = mushroomNode.CreateComponent <StaticModel>(); mushroomObject.Model = (cache.Get <Model>("Models/Mushroom.mdl")); mushroomObject.SetMaterial(mushroomMat); } // Create a scene node for the camera, which we will move around // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically) CameraNode = scene.CreateChild("Camera"); CameraNode.CreateComponent <Camera>(); // Set an initial position for the camera scene node above the plane CameraNode.Position = (new Vector3(0.0f, 5.0f, 0.0f)); }
void CreateScene() { var cache = ResourceCache; scene = new Scene(); // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically // optimizing manner scene.CreateComponent<Octree>(); // Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple // plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger // (100 x 100 world units) Node planeNode = scene.CreateChild("Plane"); planeNode.Scale=new Vector3(100.0f, 1.0f, 100.0f); StaticModel planeObject = planeNode.CreateComponent<StaticModel>(); planeObject.Model = (cache.GetModel("Models/Plane.mdl")); planeObject.SetMaterial(cache.GetMaterial("Materials/StoneTiled.xml")); // Create a point light to the world so that we can see something. Node lightNode = scene.CreateChild("PointLight"); Light light = lightNode.CreateComponent<Light>(); light.LightType = LightType.Point; light.Range = (10.0f); // Create light animation ObjectAnimation lightAnimation=new ObjectAnimation(); // Create light position animation ValueAnimation positionAnimation=new ValueAnimation(); // Use spline interpolation method positionAnimation.InterpolationMethod= InterpMethod.Spline; // Set spline tension positionAnimation.SplineTension=0.7f; positionAnimation.SetKeyFrame(0.0f, new Vector3(-30.0f, 5.0f, -30.0f)); positionAnimation.SetKeyFrame(1.0f, new Vector3(30.0f, 5.0f, -30.0f)); positionAnimation.SetKeyFrame(2.0f, new Vector3(30.0f, 5.0f, 30.0f)); positionAnimation.SetKeyFrame(3.0f, new Vector3(-30.0f, 5.0f, 30.0f)); positionAnimation.SetKeyFrame(4.0f, new Vector3(-30.0f, 5.0f, -30.0f)); // Set position animation lightAnimation.AddAttributeAnimation("Position", positionAnimation, WrapMode.Loop, 1f); // Create text animation ValueAnimation textAnimation=new ValueAnimation(); textAnimation.SetKeyFrame(0.0f, "WHITE"); textAnimation.SetKeyFrame(1.0f, "RED"); textAnimation.SetKeyFrame(2.0f, "YELLOW"); textAnimation.SetKeyFrame(3.0f, "GREEN"); textAnimation.SetKeyFrame(4.0f, "WHITE"); var uiElement = UI.Root.GetChild("animatingText", false); uiElement.SetAttributeAnimation("Text", textAnimation, WrapMode.Loop, 1f); // Create light color animation ValueAnimation colorAnimation=new ValueAnimation(); colorAnimation.SetKeyFrame(0.0f, Color.White); colorAnimation.SetKeyFrame(1.0f, Color.Red); colorAnimation.SetKeyFrame(2.0f, Color.Yellow); colorAnimation.SetKeyFrame(3.0f, Color.Green); colorAnimation.SetKeyFrame(4.0f, Color.White); // Set Light component's color animation lightAnimation.AddAttributeAnimation("@Light/Color", colorAnimation, WrapMode.Loop, 1f); // Apply light animation to light node lightNode.ObjectAnimation=lightAnimation; // Create more StaticModel objects to the scene, randomly positioned, rotated and scaled. For rotation, we construct a // quaternion from Euler angles where the Y angle (rotation about the Y axis) is randomized. The mushroom model contains // LOD levels, so the StaticModel component will automatically select the LOD level according to the view distance (you'll // see the model get simpler as it moves further away). Finally, rendering a large number of the same object with the // same material allows instancing to be used, if the GPU supports it. This reduces the amount of CPU work in rendering the // scene. const uint numObjects = 200; for (uint i = 0; i < numObjects; ++i) { Node mushroomNode = scene.CreateChild("Mushroom"); mushroomNode.Position = (new Vector3(NextRandom(90.0f) - 45.0f, 0.0f, NextRandom(90.0f) - 45.0f)); mushroomNode.Rotation=new Quaternion(0.0f, NextRandom(360.0f), 0.0f); mushroomNode.SetScale(0.5f + NextRandom(2.0f)); StaticModel mushroomObject = mushroomNode.CreateComponent<StaticModel>(); mushroomObject.Model = (cache.GetModel("Models/Mushroom.mdl")); mushroomObject.SetMaterial(cache.GetMaterial("Materials/Mushroom.xml")); } // Create a scene node for the camera, which we will move around // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically) CameraNode = scene.CreateChild("Camera"); CameraNode.CreateComponent<Camera>(); // Set an initial position for the camera scene node above the plane CameraNode.Position = (new Vector3(0.0f, 5.0f, 0.0f)); }
public static void HoverBorderPulseUnregister( this VisualElement target, Color pulseStartColor, Color pulseEndColor, Color original = default, bool addBorder = false, Vector2 borderStartEndWidth = default, int colorDuration = 1000, bool includeChildren = true, bool stopPropagation = true, TrickleDown useTrickleDown = TrickleDown.NoTrickleDown) { if (borderStartEndWidth == default) { borderStartEndWidth = new Vector2(1, 0); } var pulseIn = new ValueAnimation <StyleValues>(); var pulseOut = new ValueAnimation <StyleValues>(); IVisualElementScheduledItem repeatedAnim = null; var doHover = false; target.UnregisterCallback <MouseOverEvent>(evt => { repeatedAnim = null; doHover = true; if (addBorder) { target.style.borderBottomWidth = borderStartEndWidth.x; target.style.borderLeftWidth = borderStartEndWidth.x; target.style.borderRightWidth = borderStartEndWidth.x; target.style.borderTopWidth = borderStartEndWidth.x; } // -- Pulse color will fade original => desired color -- // -- via the AnimateTo local function. Once completed -- // -- the AnimateFrom function is called animating back -- // -- to the original color. This is then repeated for -- // -- as long as the mouse is hovered over the target -- void PulseIn(in ValueAnimation <StyleValues> pulse) { if (pulse.isRunning) { pulse.Stop(); } pulseIn = target.AnimateBorderColor(pulseStartColor, pulseEndColor, colorDuration, () => PulseOut(pulseIn)); } void PulseOut(in ValueAnimation <StyleValues> pulse) { if (pulse.isRunning) { pulse.Stop(); } pulseOut = target.AnimateBorderColor(pulseEndColor, pulseStartColor, colorDuration); } if (pulseIn.isRunning) { pulseIn.Stop(); } if (pulseOut.isRunning) { pulseOut.Stop(); } repeatedAnim = target.schedule.Execute(() => PulseIn(pulseOut)).StartingIn(0).Every(colorDuration * 2 + 20).Until(() => !doHover); if (stopPropagation) { evt.StopPropagation(); } }, includeChildren); target.UnregisterCallback <MouseOutEvent>(evt => { doHover = false; if (pulseIn.isRunning) { pulseIn?.Stop(); } if (pulseOut.isRunning) { pulseOut?.Stop(); } if (repeatedAnim.isActive) { repeatedAnim.Pause(); } if (addBorder) { target.style.borderBottomWidth = borderStartEndWidth.y; target.style.borderLeftWidth = borderStartEndWidth.y; target.style.borderRightWidth = borderStartEndWidth.y; target.style.borderTopWidth = borderStartEndWidth.y; } if (pulseIn.isRunning) { pulseIn.Stop(); } if (pulseOut.isRunning) { pulseOut.Stop(); } target.style.borderBottomColor = original; target.style.borderLeftColor = original; target.style.borderRightColor = original; target.style.borderTopColor = original; if (stopPropagation) { evt.StopPropagation(); } }, includeChildren); }
public override void OnSurfaceAddedOrUpdated(SpatialMeshInfo surface, Model generatedModel) { bool isNew = false; StaticModel staticModel = null; Node node = environmentNode.GetChild(surface.SurfaceId, false); if (node != null) { isNew = false; staticModel = node.GetComponent<StaticModel>(); } else { isNew = true; node = environmentNode.CreateChild(surface.SurfaceId); staticModel = node.CreateComponent<StaticModel>(); } node.Position = surface.BoundsCenter; node.Rotation = surface.BoundsRotation; staticModel.Model = generatedModel; Material mat; Color startColor; Color endColor = new Color(0.8f, 0.8f, 0.8f); if (isNew) { startColor = Color.Blue; mat = Material.FromColor(endColor); staticModel.SetMaterial(mat); } else { startColor = Color.Red; mat = staticModel.GetMaterial(0); } mat.FillMode = wireframe ? FillMode.Wireframe : FillMode.Solid; var specColorAnimation = new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, startColor); specColorAnimation.SetKeyFrame(1.5f, endColor); mat.SetShaderParameterAnimation("MatDiffColor", specColorAnimation, WrapMode.Once, 1.0f); }
// -------------------------------------------------- @HoverBorder // --------------------------------------------------------------- /// <summary> /// Pulse the border of an element between two colors /// /// ** To help combat your element shifting position slightly when a border is applied on hover, /// it is a good idea to add a border to your element before hand and just set color to 'initial' /// so that it is transparent, then keep 'addBorder' parameter as false. /// </summary> /// <param name="element">The element in which this function will be applied</param> /// <param name="color1">Color 1 in which to pulse between</param> /// <param name="color2">Color 2 in which to pulse between</param> /// <param name="original">The original color of the element being changed. Can be obtained and passed via 'visualElement.style.backgroundColor.value'</param> /// <param name="color1DurationMs">The amount of time it takes in milliseconds to complete the first color animation</param> /// <param name="color2DurationMs">The amount of time it takes in milliseconds to complete the second color animation</param> /// <param name="addBorder">Adds a border if the element does not have one already</param> /// <param name="borderStartEndWidth">The width in which the borders should be when displaying</param> /// <param name="callback">Function that can be called when the animation is completed</param> /// <param name="borderSelection">The parameters of the Vector4(1-4) represent which borders should have their colors changed: 1(x) = left, 2(y) = top, 3(z) = right, 4(w) = bottom. /// If only the top and bottom borders are desired to pulse, you would pass new Vector4(0, 1, 0, 1)</param> public static IVisualElementScheduledItem AnimBorderPulse(this VisualElement element, Color color1, Color color2, Color original = default, int color1DurationMs = 1000, int color2DurationMs = 1000, bool addBorder = false, Vector2 borderStartEndWidth = default, Action callback = null, Vector4 borderSelection = default, IVisualElementScheduledItem repeatedAnim = default ) { if (borderStartEndWidth == default) { borderStartEndWidth = new Vector2(1, 0); } bool doBorderPulse; var pulseIn = new ValueAnimation <StyleValues>(); var pulseOut = new ValueAnimation <StyleValues>(); pulseIn.autoRecycle = true; pulseOut.autoRecycle = true; pulseIn.KeepAlive(); pulseOut.KeepAlive(); doBorderPulse = true; if (addBorder) { element.SetBorderWidth(borderStartEndWidth.x); } var borderValues = new Vector4(); var paddingValues = new Vector4(); void SetBorderValues() { if (borderSelection.x == 0) { element.style.paddingLeft = paddingValues.x + borderValues.x; element.style.borderLeftWidth = 0; } if (borderSelection.y == 0) { element.style.paddingTop = paddingValues.y + borderValues.y; element.style.borderTopWidth = 0; } if (borderSelection.z == 0) { element.style.paddingRight = paddingValues.z + borderValues.z; element.style.borderRightWidth = 0; } if (borderSelection.w == 0) { element.style.paddingBottom = paddingValues.w + borderValues.w; element.style.borderBottomWidth = 0; } } void ReplaceBorderValues() { if (borderSelection.x == 0) { element.style.paddingLeft = paddingValues.x; element.style.borderLeftWidth = borderValues.x; } if (borderSelection.y == 0) { element.style.paddingTop = paddingValues.y; element.style.borderTopWidth = borderValues.y; } if (borderSelection.z == 0) { element.style.paddingRight = paddingValues.z; element.style.borderRightWidth = borderValues.z; } if (borderSelection.w == 0) { element.style.paddingBottom = paddingValues.w; element.style.borderBottomWidth = borderValues.w; } } if (borderSelection != default) { borderValues = new Vector4( element.style.borderLeftWidth.value, element.style.borderTopWidth.value, element.style.borderRightWidth.value, element.style.borderBottomWidth.value); paddingValues = new Vector4( element.resolvedStyle.paddingLeft, element.resolvedStyle.paddingTop, element.resolvedStyle.paddingRight, element.resolvedStyle.paddingBottom); SetBorderValues(); } void DoCleanup() { if (pulseOut.isRunning) { pulseOut.Stop(); } if (pulseIn.isRunning) { pulseIn.Stop(); } element.SetBorderColor(); if (addBorder) { element.SetBorderWidth(borderStartEndWidth.y); } if (borderSelection != default) { ReplaceBorderValues(); } callback?.Invoke(); } // @formatter:off // -- Pulse color will fade original => desired color -- // -- via the AnimateTo local function. Once completed -- // -- the AnimateFrom function is called animating back -- // -- to the original color. This is then repeated for -- // -- as long as the mouse is hovered over the target -- void PulseIn(IVisualElementScheduledItem repeated) { if (!repeated.isActive) { DoCleanup(); return; } if (pulseOut.isRunning) { pulseOut.Stop(); } pulseIn = element.AnimateBorderColor( color1, color2, color1DurationMs, () => PulseOut(repeated)).KeepAlive(); } void PulseOut(IVisualElementScheduledItem repeated) { if (!repeated.isActive) { DoCleanup(); return; } if (pulseIn.isRunning) { pulseIn.Stop(); } pulseOut = element.AnimateBorderColor( color2, color1, color2DurationMs, () => { if (!repeated.isActive) { DoCleanup(); } }).KeepAlive(); } // @formatter:on var recurring = color1DurationMs + color2DurationMs + 20; repeatedAnim = element.schedule .Execute(() => { PulseIn(repeatedAnim); }) .StartingIn(0) .Every(recurring) .Until(() => !doBorderPulse); return(repeatedAnim); }
// -------------------------------------------------------- @HoverWidth // -- Animate the width of target element to desired value on hover -- // -------------------------------------------------------------------- public static AnimatedItems <MouseOverEvent, MouseOutEvent> HoverWidth( this VisualElement target, float initialWidth = 0f, float desiredWidth = 100f, int duration = 1000, Action hoverCallback = null, Action leaveCallback = null, bool afterAnimation = false, bool includeChildren = true, bool stopPropagation = true, TrickleDown useTrickleDown = TrickleDown.NoTrickleDown) { initialWidth = initialWidth == 0f ? target.resolvedStyle.width : initialWidth; var enterAnim = new ValueAnimation <StyleValues>(); var leaveAnim = new ValueAnimation <StyleValues>(); enterAnim = afterAnimation ? target.AnimateWidth(initialWidth, desiredWidth, duration, callback: hoverCallback) : target.AnimateWidth(initialWidth, desiredWidth, duration); enterAnim.KeepAlive(); leaveAnim = target.AnimateWidth(desiredWidth, initialWidth, duration, easing: Easy.EaseInOutQuint); leaveAnim.KeepAlive(); void MouseEnter() { enterAnim.Start(); } // @formatter:off void MouseLeave() { leaveAnim.Start(); } // @formatter:on EventCallback <MouseOverEvent> mouseOverEvent = evt => { if (enterAnim.isRunning) { enterAnim.Stop(); } if (leaveAnim.isRunning) { leaveAnim.Stop(); } MouseEnter(); if (!afterAnimation) { hoverCallback?.Invoke(); } if (stopPropagation) { evt.StopPropagation(); } }; EventCallback <MouseOutEvent> mouseOutEvent = evt => { if (enterAnim.isRunning) { enterAnim.Stop(); } if (leaveAnim.isRunning) { leaveAnim.Stop(); } MouseLeave(); if (stopPropagation) { evt.StopPropagation(); } target.schedule.Execute(leaveCallback).StartingIn(duration); }; target.RegisterCallback(mouseOverEvent, includeChildren, useTrickleDown); target.RegisterCallback(mouseOutEvent, includeChildren, useTrickleDown); return(new AnimatedItems <MouseOverEvent, MouseOutEvent>(target) { AnimatedItemList = new List <ValueAnimation <StyleValues> > { enterAnim, leaveAnim }, EventCallbacks = (mouseOverEvent, mouseOutEvent) });
private ValueAnimation <StyleValues> Start(Func <VisualElement, StyleValues> fromValueGetter, StyleValues to, int durationMs) { return(StartAnimation(ValueAnimation <StyleValues> .Create(this, Lerp.Interpolate), fromValueGetter, to, durationMs, AssignStyleValues)); }
void CreateScene() { var cache = ResourceCache; scene = new Scene(); // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically // optimizing manner scene.CreateComponent <Octree>(); // Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple // plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger // (100 x 100 world units) Node planeNode = scene.CreateChild("Plane"); planeNode.Scale = new Vector3(100.0f, 1.0f, 100.0f); StaticModel planeObject = planeNode.CreateComponent <StaticModel>(); planeObject.Model = (cache.GetModel("Models/Plane.mdl")); planeObject.SetMaterial(cache.GetMaterial("Materials/StoneTiled.xml")); // Create a point light to the world so that we can see something. Node lightNode = scene.CreateChild("PointLight"); Light light = lightNode.CreateComponent <Light>(); light.LightType = LightType.Point; light.Range = (10.0f); // Create light animation ObjectAnimation lightAnimation = new ObjectAnimation(); // Create light position animation ValueAnimation positionAnimation = new ValueAnimation(); // Use spline interpolation method positionAnimation.InterpolationMethod = InterpMethod.Spline; // Set spline tension positionAnimation.SplineTension = 0.7f; positionAnimation.SetKeyFrame(0.0f, new Vector3(-30.0f, 5.0f, -30.0f)); positionAnimation.SetKeyFrame(1.0f, new Vector3(30.0f, 5.0f, -30.0f)); positionAnimation.SetKeyFrame(2.0f, new Vector3(30.0f, 5.0f, 30.0f)); positionAnimation.SetKeyFrame(3.0f, new Vector3(-30.0f, 5.0f, 30.0f)); positionAnimation.SetKeyFrame(4.0f, new Vector3(-30.0f, 5.0f, -30.0f)); // Set position animation lightAnimation.AddAttributeAnimation("Position", positionAnimation, WrapMode.Loop, 1f); // Create text animation ValueAnimation textAnimation = new ValueAnimation(); textAnimation.SetKeyFrame(0.0f, "WHITE"); textAnimation.SetKeyFrame(1.0f, "RED"); textAnimation.SetKeyFrame(2.0f, "YELLOW"); textAnimation.SetKeyFrame(3.0f, "GREEN"); textAnimation.SetKeyFrame(4.0f, "WHITE"); var uiElement = UI.Root.GetChild("animatingText", false); uiElement.SetAttributeAnimation("Text", textAnimation, WrapMode.Loop, 1f); // Create light color animation ValueAnimation colorAnimation = new ValueAnimation(); colorAnimation.SetKeyFrame(0.0f, Color.White); colorAnimation.SetKeyFrame(1.0f, Color.Red); colorAnimation.SetKeyFrame(2.0f, Color.Yellow); colorAnimation.SetKeyFrame(3.0f, Color.Green); colorAnimation.SetKeyFrame(4.0f, Color.White); // Set Light component's color animation lightAnimation.AddAttributeAnimation("@Light/Color", colorAnimation, WrapMode.Loop, 1f); // Apply light animation to light node lightNode.ObjectAnimation = lightAnimation; // Create more StaticModel objects to the scene, randomly positioned, rotated and scaled. For rotation, we construct a // quaternion from Euler angles where the Y angle (rotation about the Y axis) is randomized. The mushroom model contains // LOD levels, so the StaticModel component will automatically select the LOD level according to the view distance (you'll // see the model get simpler as it moves further away). Finally, rendering a large number of the same object with the // same material allows instancing to be used, if the GPU supports it. This reduces the amount of CPU work in rendering the // scene. const uint numObjects = 200; for (uint i = 0; i < numObjects; ++i) { Node mushroomNode = scene.CreateChild("Mushroom"); mushroomNode.Position = (new Vector3(NextRandom(90.0f) - 45.0f, 0.0f, NextRandom(90.0f) - 45.0f)); mushroomNode.Rotation = new Quaternion(0.0f, NextRandom(360.0f), 0.0f); mushroomNode.SetScale(0.5f + NextRandom(2.0f)); StaticModel mushroomObject = mushroomNode.CreateComponent <StaticModel>(); mushroomObject.Model = (cache.GetModel("Models/Mushroom.mdl")); mushroomObject.SetMaterial(cache.GetMaterial("Materials/Mushroom.xml")); } // Create a scene node for the camera, which we will move around // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically) CameraNode = scene.CreateChild("Camera"); CameraNode.CreateComponent <Camera>(); // Set an initial position for the camera scene node above the plane CameraNode.Position = (new Vector3(0.0f, 5.0f, 0.0f)); }
// -------------------------------------------------- @HoverBorder // --------------------------------------------------------------- /// <summary> /// Pulse the border of an element between two colors /// /// ** To help combat your element shifting position slightly when a border is applied on hover, /// it is a good idea to add a border to your element before hand and just set color to 'initial' /// so that it is transparent, then keep 'addBorder' parameter as false. /// </summary> /// <param name="target">The element in which this function will be applied</param> /// <param name="pulseStartColor">Color 1 of 2 in which to pulse between</param> /// <param name="pulseEndColor">Color 2 of 2 in which to pulse between</param> /// <param name="original">The original color of the element being changed. Can be obtained and passed via 'visualElement.style.backgroundColor.value'</param> /// <param name="startColorDurationMs">The amount of time it takes in milliseconds to complete the first color animation</param> /// <param name="endColorDurationMs">The amount of time it takes in milliseconds to complete the second color animation</param> /// <param name="addBorder">Adds a border if the element does not have one already</param> /// <param name="borderStartEndWidth">The width in which the borders should be when displaying</param> public static IVisualElementScheduledItem AnimBorderPulse(this VisualElement target, Color pulseStartColor, Color pulseEndColor, Color original = default, int startColorDurationMs = 1000, int endColorDurationMs = 1000, bool addBorder = false, Vector2 borderStartEndWidth = default, Action callback = null) { if (borderStartEndWidth == default) { borderStartEndWidth = new Vector2(1, 0); } var pulseIn = new ValueAnimation <StyleValues>(); var pulseOut = new ValueAnimation <StyleValues>(); IVisualElementScheduledItem repeatedAnim = null; doBorderPulse = true; if (addBorder) { target.SetBorderWidth(borderStartEndWidth.x); } void DoCleanup() { if (pulseOut.isRunning) { pulseOut.Stop(); } if (pulseIn.isRunning) { pulseIn.Stop(); } target.SetBorderColor(); callback?.Invoke(); } // -- Pulse color will fade original => desired color -- // -- via the AnimateTo local function. Once completed -- // -- the AnimateFrom function is called animating back -- // -- to the original color. This is then repeated for -- // -- as long as the mouse is hovered over the target -- void PulseIn(IVisualElementScheduledItem repeated) { if (!repeated.isActive) { DoCleanup(); return; } if (pulseOut.isRunning) { pulseOut.Stop(); } callback?.Invoke(); pulseIn = target.AnimateBorderColor(pulseStartColor, pulseEndColor, startColorDurationMs, () => PulseOut(repeated)); } void PulseOut(IVisualElementScheduledItem repeated) { if (!repeated.isActive) { DoCleanup(); return; } if (pulseIn.isRunning) { pulseIn.Stop(); } callback?.Invoke(); pulseOut = target.AnimateBorderColor(pulseEndColor, pulseStartColor, endColorDurationMs); } var recurring = startColorDurationMs + endColorDurationMs + 20; repeatedAnim = target.schedule.Execute(() => PulseIn(repeatedAnim)).StartingIn(0).Every(recurring).Until(() => !doBorderPulse); return(repeatedAnim); }
void CreateScene() { var cache = ResourceCache; scene = new Scene(); // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically // optimizing manner scene.CreateComponent<Octree>(); // Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple // plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger // (100 x 100 world units) Node planeNode = scene.CreateChild("Plane"); planeNode.Scale=new Vector3(100.0f, 1.0f, 100.0f); StaticModel planeObject = planeNode.CreateComponent<StaticModel>(); planeObject.Model = (cache.GetModel("Models/Plane.mdl")); planeObject.SetMaterial(cache.GetMaterial("Materials/StoneTiled.xml")); // Create a directional light to the world so that we can see something. The light scene node's orientation controls the // light direction; we will use the SetDirection() function which calculates the orientation from a forward direction vector. // The light will use default settings (white light, no shadows) Node lightNode = scene.CreateChild("DirectionalLight"); lightNode.SetDirection(new Vector3(0.6f, -1.0f, 0.8f)); // The direction vector does not need to be normalized Light light = lightNode.CreateComponent<Light>(); light.LightType = LightType.Directional; // Create more StaticModel objects to the scene, randomly positioned, rotated and scaled. For rotation, we construct a // quaternion from Euler angles where the Y angle (rotation about the Y axis) is randomized. The mushroom model contains // LOD levels, so the StaticModel component will automatically select the LOD level according to the view distance (you'll // see the model get simpler as it moves further away). Finally, rendering a large number of the same object with the // same material allows instancing to be used, if the GPU supports it. This reduces the amount of CPU work in rendering the // scene. Material mushroomMat = cache.GetMaterial("Materials/Mushroom.xml"); // Apply shader parameter animation to material ValueAnimation specColorAnimation=new ValueAnimation(); specColorAnimation.SetKeyFrame(0.0f, new Color(0.1f, 0.1f, 0.1f, 16.0f)); specColorAnimation.SetKeyFrame(1.0f, new Color(1.0f, 0.0f, 0.0f, 2.0f)); specColorAnimation.SetKeyFrame(2.0f, new Color(1.0f, 1.0f, 0.0f, 2.0f)); specColorAnimation.SetKeyFrame(3.0f, new Color(0.1f, 0.1f, 0.1f, 16.0f)); // Optionally associate material with scene to make sure shader parameter animation respects scene time scale mushroomMat.Scene=scene; mushroomMat.SetShaderParameterAnimation("MatSpecColor", specColorAnimation, WrapMode.Loop, 1.0f); const uint numObjects = 200; for (uint i = 0; i < numObjects; ++i) { Node mushroomNode = scene.CreateChild("Mushroom"); mushroomNode.Position = (new Vector3(NextRandom(90.0f) - 45.0f, 0.0f, NextRandom(90.0f) - 45.0f)); mushroomNode.Rotation=new Quaternion(0.0f, NextRandom(360.0f), 0.0f); mushroomNode.SetScale(0.5f + NextRandom(2.0f)); StaticModel mushroomObject = mushroomNode.CreateComponent<StaticModel>(); mushroomObject.Model = (cache.GetModel("Models/Mushroom.mdl")); mushroomObject.SetMaterial(mushroomMat); } // Create a scene node for the camera, which we will move around // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically) CameraNode = scene.CreateChild("Camera"); CameraNode.CreateComponent<Camera>(); // Set an initial position for the camera scene node above the plane CameraNode.Position = (new Vector3(0.0f, 5.0f, 0.0f)); }
ValueAnimation <Quaternion> ITransitionAnimations.Start(Func <VisualElement, Quaternion> fromValueGetter, Quaternion to, int durationMs, Action <VisualElement, Quaternion> onValueChanged) { return(StartAnimation(ValueAnimation <Quaternion> .Create(this, Lerp.Interpolate), fromValueGetter, to, durationMs, onValueChanged)); }