microsoft / WindowsCompositionSamples

The Windows Composition Samples have moved here: https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/SceneGraph
https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/SceneGraph
MIT License
1.13k stars 287 forks source link

Which is the best timer for 'manual' updates for Composition? #34

Closed juanpaexpedite closed 8 years ago

juanpaexpedite commented 8 years ago

I do not want to continue with my apps until the #Build2016, so I am experimenting, in this case https://github.com/juanpaexpedite/MasterDetailsComposition/tree/master/CompPac I am developing the Pacman using Composition. (Yes I know I can use the CanvasAnimatedControl of Win2D). But I want to test just using Composition.

Instead a dispatcher timer I have added CompositionTarget.Rendering. (That I know it for long time ago).

1.- Is there a better way to update composition properties like Offset and RotationAngle using this event?, because I think a DispatcherTimer is not the best option, it has an small flickering that I do not know if can be improved. 2.- For X,Y translations should I use just Offset or TransformMatrix?.

I want to learn in deep the capabilities of Composition and doing this kind of examples I think is it a good way, any advice will be welcome. Thanks Juan Pablo

tomzorz commented 8 years ago

Probably this won't be applicable for all your issues, but this is what I did in one of my tests:

1) create/grab a random hidden visual 2) create a normal keyframe animation from 0 to Double.Max, with a timespan of Double.Max seconds (or instead Double.Max, just use a very large number) 3) apply this animation to the RotationInDegrees property of the visual from step no.1

This way you have a "timer" that you can use in other expression animations. I did this to try code physics simulations in expression animations.

robmikh commented 8 years ago

I've actually been writing a game in my spare time using the Composition api, but I've been doing it in a frameworkless app instead of using XAML (similar to the CompositionVisual sample). Instead of the dispatch timer, I use the Threading Timer. However, it is important to note that this version of the Timer will have concurrency, and that it calls your callback every interval regardless if you're doing work. Because of that, I did something like this:

using System.Threading;

public void Run()
{
    //
    // We use the timer as a way to "schedule" a tick. If we just
    // allowed the timer call the callback normally, we would have
    // concurency. This causes input problems, as well as tiling
    // problems, and many more.
    //
    _gameLoopTimer = new Timer(GameLoop, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}

private void GameLoop(Object state)
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    // ***************************
    // * Game related code here. *
    // ***************************

    //
    // Schedule another callback to be either in the normal
    // interval, or less in case we took too long.
    //
    _gameLoopTimer.Change((int)Math.Max(0, TIME_INTERVAL_IN_MILLISECONDS - stopwatch.ElapsedMilliseconds), Timeout.Infinite);
}

private Timer _gameLoopTimer;
private static readonly int TIME_INTERVAL_IN_MILLISECONDS = 16;

This works pretty well for what I'm doing. I have loads of visuals that represent "tiles" in an overworld, and move their container visual (with the Offset property) around when the player moves. NPCs and the Player are represented by some visuals that I also manipulate through their Offset and Opacity properties.

You should still be able to use this in a XAML app as well, but if you want to call out to XAML objects while in the timer callback you'll have to ask the CoreDispatcher for the UI thread to do work on your behalf, as UIElements are only marshaled for that thread. Hover, if you're only manipulating non XAML objects in the callback, you should be fine.

As for your second question: if you're just manipulating X and Y, Offset is a fine way to go. There's not much of a difference for you between the two, and in the compositor we end up multiplying these things into a final matrix before drawing anyway. Thus, you should really do what is easier and more readable for you, and in most cases this will be using the Offset property. The same goes for the transform components (RotationAngle, RotationAngleInDegrees, RotationAxis, etc).

@tomzorz Your solution reminds me of what I used to do in the WarCraft III map editor back in the day ;) Tried and true. It's awesome hearing the creative ways people approach these scenarios!

Good luck on Pacman!

Edit: The "input problems, as well as tiling problems, and many more" comment refers to code specific to my game's code.

Edit2: I found the StackOverflow answer that influenced my design when I originally wrote the code. You can find it here.

robmikh commented 8 years ago

Just wanted to mention something that totally slipped my mind... waiting for VSyncs! This can be done with Win2D in C# by calling WaitForVerticalBlank on a swap chain object. Be careful with this call! This will wait on the current thread until the next vertical blank from the monitor, don't do this on the UI thread!

You can find a sample of this in the Win2D samples here.

juanpaexpedite commented 8 years ago

Interesting at this moment I am testing 2d tile game using AnimatedCanvasControl, it is really smooth,I will also try that old school trick :). thanks

pgills commented 8 years ago

@juanpaexpedite Let us know how your experiences go with Win2D and Composition!

Closing this issue.