コード例 #1
0
ファイル: Form.cs プロジェクト: hammerforgegames/Gorgon
        /// <summary>
        /// Function to build up an animation for the torus.
        /// </summary>
        private void BuildAnimation()
        {
            var builder = new GorgonAnimationBuilder();

            IGorgonTrackKeyBuilder <GorgonKeyTexture2D> track = builder.Edit2DTexture();

            float time       = 0;
            int   frameCount = 0;

            for (int y = 0; y < _torusTexture.Height && frameCount < 60; y += 64)
            {
                for (int x = 0; x < _torusTexture.Width && frameCount < 60; x += 64, frameCount++)
                {
                    DX.RectangleF texCoords = _torusTexture.ToTexel(new DX.Rectangle(x, y, 64, 64));

                    track.SetKey(new GorgonKeyTexture2D(time, _torusTexture, texCoords, 0));

                    // 30 FPS.
                    time += 1 / 30.0f;
                }
            }

            track.EndEdit();

            _torusAnim          = builder.Build("Torus Animation");
            _torusAnim.IsLooped = true;

            _controllerLeft  = new GorgonSpriteAnimationController();
            _controllerRight = new GorgonSpriteAnimationController();

            _controllerLeft.Play(_torusLeft, _torusAnim);
            _controllerRight.Play(_torusRight, _torusAnim);
            _controllerRight.Pause();
        }
コード例 #2
0
        /// <summary>
        /// Function to generate animations for the entities in the application.
        /// </summary>
        private void GenerateAnimations()
        {
            var builder = new GorgonAnimationBuilder();

            IGorgonAnimation planetRotation = builder
                                              .Clear()
                                              .EditRotation()
                                              .SetKey(new GorgonKeyVector3(0, new DX.Vector3(0, 0, 180)))
                                              .SetKey(new GorgonKeyVector3(600, new DX.Vector3(0, 360, 180)))
                                              .EndEdit()
                                              .RotationInterpolationMode(TrackInterpolationMode.Linear)
                                              .Build("PlanetRotation");

            planetRotation.IsLooped          = true;
            _animations[planetRotation.Name] = planetRotation;

            IGorgonAnimation cloudRotation = builder
                                             .Clear()
                                             .EditRotation()
                                             .SetKey(new GorgonKeyVector3(0, new DX.Vector3(0, 0, 180)))
                                             .SetKey(new GorgonKeyVector3(600, new DX.Vector3(100, 180, 180)))
                                             .SetKey(new GorgonKeyVector3(1200, new DX.Vector3(0, 360, 180)))
                                             .EndEdit()
                                             .RotationInterpolationMode(TrackInterpolationMode.Linear)
                                             .Build("CloudRotation");

            cloudRotation.IsLooped          = true;
            _animations[cloudRotation.Name] = cloudRotation;

            GorgonSprite[] frames = Sprites.Where(item => item.Key.StartsWith("Fighter_Engine_F", StringComparison.OrdinalIgnoreCase))
                                    .OrderBy(item => item.Key)
                                    .Select(item => item.Value)
                                    .ToArray();

            IGorgonAnimation engineGlow = builder
                                          .Clear()
                                          .Edit2DTexture()
                                          .SetKey(new GorgonKeyTexture2D(0, frames[0].Texture, frames[0].TextureRegion, frames[0].TextureArrayIndex))
                                          .SetKey(new GorgonKeyTexture2D(0.1f, frames[1].Texture, frames[1].TextureRegion, frames[1].TextureArrayIndex))
                                          .SetKey(new GorgonKeyTexture2D(0.2f, frames[2].Texture, frames[2].TextureRegion, frames[2].TextureArrayIndex))
                                          .SetKey(new GorgonKeyTexture2D(0.3f, frames[1].Texture, frames[1].TextureRegion, frames[1].TextureArrayIndex))
                                          .EndEdit()
                                          .RotationInterpolationMode(TrackInterpolationMode.Linear)
                                          .Build("EngineGlow");

            engineGlow.IsLooped          = true;
            _animations[engineGlow.Name] = engineGlow;
        }
コード例 #3
0
        /// <summary>
        /// Function to read the animation data from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the animation.</param>
        /// <param name="byteCount">The number of bytes to read from the stream.</param>
        /// <returns>A new <see cref="IGorgonAnimation"/>.</returns>
        protected override IGorgonAnimation OnReadFromStream(Stream stream, int byteCount)
        {
            var builder = new GorgonAnimationBuilder();

            var reader = new GorgonChunkFileReader(stream,
                                                   new[]
            {
                CurrentFileHeader
            });
            GorgonBinaryReader binReader = null;

            try
            {
                reader.Open();
                binReader = reader.OpenChunk(AnimationData);
                string name      = binReader.ReadString();
                float  length    = binReader.ReadSingle();
                bool   isLooped  = binReader.ReadBoolean();
                int    loopCount = binReader.ReadInt32();
                reader.CloseChunk();

                int keyCount;

                if (reader.Chunks.Contains(PositionData))
                {
                    binReader = reader.OpenChunk(PositionData);
                    builder.PositionInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditPositions();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(ScaleData))
                {
                    binReader = reader.OpenChunk(ScaleData);
                    builder.ScaleInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditScale();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(RotationData))
                {
                    binReader = reader.OpenChunk(RotationData);
                    builder.RotationInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditRotation();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(SizeData))
                {
                    binReader = reader.OpenChunk(SizeData);
                    builder.SizeInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditSize();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(BoundsData))
                {
                    binReader = reader.OpenChunk(BoundsData);
                    builder.RotationInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyRectangle> track = builder.EditRectangularBounds();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyRectangle(binReader.ReadSingle(), binReader.ReadValue <DX.RectangleF>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(ColorData))
                {
                    binReader = reader.OpenChunk(ColorData);
                    builder.RotationInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyGorgonColor> track = builder.EditColors();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyGorgonColor(binReader.ReadSingle(), binReader.ReadValue <GorgonColor>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                IGorgonAnimation result;
                if (!reader.Chunks.Contains(TextureData))
                {
                    result           = builder.Build(name, length);
                    result.IsLooped  = isLooped;
                    result.LoopCount = loopCount;
                    return(result);
                }

                binReader = reader.OpenChunk(TextureData);
                keyCount  = binReader.ReadInt32();

                IGorgonTrackKeyBuilder <GorgonKeyTexture2D> textureTrack = builder.Edit2DTexture();
                for (int i = 0; i < keyCount; ++i)
                {
                    float time                  = binReader.ReadSingle();
                    byte  hasTexture            = binReader.ReadByte();
                    GorgonTexture2DView texture = null;
                    string textureName          = string.Empty;

                    if (hasTexture != 0)
                    {
                        texture = LoadTexture(binReader, out textureName);

                        if ((texture == null) && (string.IsNullOrWhiteSpace(textureName)))
                        {
                            Renderer.Log.Print("Attempted to load a texture from the data, but the texture was not in memory and the name is unknown.",
                                               LoggingLevel.Verbose);
                            continue;
                        }
                    }

                    if ((texture == null) && (hasTexture != 0))
                    {
                        textureTrack.SetKey(new GorgonKeyTexture2D(time, textureName, binReader.ReadValue <DX.RectangleF>(), binReader.ReadInt32()));
                    }
                    else
                    {
                        textureTrack.SetKey(new GorgonKeyTexture2D(time, texture, binReader.ReadValue <DX.RectangleF>(), binReader.ReadInt32()));
                    }
                }
                textureTrack.EndEdit();
                reader.CloseChunk();

                result           = builder.Build(name, length);
                result.IsLooped  = isLooped;
                result.LoopCount = loopCount;
                return(result);
            }
            finally
            {
                binReader?.Dispose();
                reader.Close();
            }
        }
コード例 #4
0
ファイル: TrackKeyBuilder.cs プロジェクト: ishkang/Gorgon
 /// <summary>
 /// Initializes a new instance of the <see cref="TrackKeyBuilder{T}"/> class.
 /// </summary>
 /// <param name="parent">The parent animation builder.</param>
 public TrackKeyBuilder(GorgonAnimationBuilder parent)
 {
     _parent   = parent;
     _comparer = new KeyframeIndexComparer <T>();
 }
コード例 #5
0
ファイル: Program.cs プロジェクト: hammerforgegames/Gorgon
        // ReSharper disable once InconsistentNaming
        /// <summary>
        /// Function to build our animation... like an 80's music video... this is going to be ugly.
        /// </summary>
        private static void MakeAn80sMusicVideo()
        {
            var animBuilder = new GorgonAnimationBuilder();

            animBuilder.PositionInterpolationMode(TrackInterpolationMode.Spline)
            .ScaleInterpolationMode(TrackInterpolationMode.Spline)
            .RotationInterpolationMode(TrackInterpolationMode.Spline)
            .ColorInterpolationMode(TrackInterpolationMode.Spline)
            // Set up some scaling...
            .EditScale()
            .SetKey(new GorgonKeyVector3(0, new DX.Vector2(1, 1)))
            .SetKey(new GorgonKeyVector3(2, new DX.Vector2(0.5f, 0.5f)))
            .SetKey(new GorgonKeyVector3(4, new DX.Vector2(4.0f, 4.0f)))
            .SetKey(new GorgonKeyVector3(6, new DX.Vector2(1, 1)))
            .EndEdit()
            // Set up some positions...
            .EditPositions()
            .SetKey(new GorgonKeyVector3(0, new DX.Vector2(_screen.Width / 2.0f, _screen.Height / 2.0f)))
            .SetKey(new GorgonKeyVector3(2, new DX.Vector2(200, 220)))
            .SetKey(new GorgonKeyVector3(3, new DX.Vector2(_screen.Width - 2, 130)))
            .SetKey(new GorgonKeyVector3(4, new DX.Vector2(255, _screen.Height - _metal.Height)))
            .SetKey(new GorgonKeyVector3(5, new DX.Vector2(200, 180)))
            .SetKey(new GorgonKeyVector3(6, new DX.Vector2(180, 160)))
            .SetKey(new GorgonKeyVector3(7, new DX.Vector2(150, 180)))
            .SetKey(new GorgonKeyVector3(8, new DX.Vector2(150, 160)))
            .SetKey(new GorgonKeyVector3(9, new DX.Vector2(_screen.Width / 2, _screen.Height / 2)))
            .EndEdit()
            // Set up some colors...By changing the alpha, we can simulate a motion blur effect.
            .EditColors()
            .SetKey(new GorgonKeyGorgonColor(0, GorgonColor.Black))
            .SetKey(new GorgonKeyGorgonColor(2, new GorgonColor(GorgonColor.RedPure, 0.25f)))
            .SetKey(new GorgonKeyGorgonColor(4, new GorgonColor(GorgonColor.GreenPure, 0.5f)))
            .SetKey(new GorgonKeyGorgonColor(6, new GorgonColor(GorgonColor.BluePure, 0.25f)))
            .SetKey(new GorgonKeyGorgonColor(8, new GorgonColor(GorgonColor.LightCyan, 0.25f)))
            .SetKey(new GorgonKeyGorgonColor(10, new GorgonColor(GorgonColor.Black, 1.0f)))
            .EndEdit()
            // And finally, some MuchMusic/MTV style rotation... because.
            .EditRotation()
            .SetKey(new GorgonKeyVector3(0, new DX.Vector3(0, 0, 0)))
            .SetKey(new GorgonKeyVector3(2, new DX.Vector3(0, 0, 180)))
            .SetKey(new GorgonKeyVector3(4, new DX.Vector3(0, 0, 270.0f)))
            .SetKey(new GorgonKeyVector3(6, new DX.Vector3(0, 0, 0)))
            .EndEdit();

            IGorgonTrackKeyBuilder <GorgonKeyTexture2D> trackBuilder = animBuilder.Edit2DTexture();
            float time = 0;

            // Now, add the animation frames from our GIF.
            for (int i = 0; i < _metal.ArrayCount; ++i)
            {
                trackBuilder.SetKey(new GorgonKeyTexture2D(time, _metal, new DX.RectangleF(0, 0, 1, 1), i));
                time += _frameDelays[i];
            }

            float delay = (10.0f - time).Max(0) / 15.0f;

            // Now add in a texture switch with coordinate update... because.
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0));
            time += delay;
            trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0));

            trackBuilder.EndEdit();

            _animation          = animBuilder.Build(@"\m/");
            _animation.IsLooped = true;

            _animController = new GorgonSpriteAnimationController();
        }
コード例 #6
0
        /// <summary>
        /// Function to convert a JSON formatted string into a <see cref="IGorgonAnimation"/> object.
        /// </summary>
        /// <param name="renderer">The renderer for the animation.</param>
        /// <param name="json">The JSON string containing the animation data.</param>
        /// <returns>A new <see cref="IGorgonAnimation"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="renderer"/>, or the <paramref name="json"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="json"/> parameter is empty.</exception>
        /// <exception cref="GorgonException">Thrown if the JSON string does not contain animation data, or there is a version mismatch.</exception>
        public IGorgonAnimation FromJson(Gorgon2D renderer, string json)
        {
            if (renderer == null)
            {
                throw new ArgumentNullException(nameof(renderer));
            }

            if (json == null)
            {
                throw new ArgumentNullException(nameof(json));
            }

            if (string.IsNullOrWhiteSpace(json))
            {
                throw new ArgumentEmptyException(nameof(json));
            }

            string animName   = string.Empty;
            float  animLength = 0;
            int    loopCount  = 0;
            bool   isLooped   = false;

            var colorConvert   = new JsonGorgonColorKeyConverter();
            var textureConvert = new JsonTextureKeyConverter(renderer.Graphics);
            var vec3Converter  = new JsonVector3KeyConverter();
            var rectConverter  = new JsonRectKeyConverter();

            TrackInterpolationMode posInterp   = TrackInterpolationMode.None;
            TrackInterpolationMode scaleInterp = TrackInterpolationMode.None;
            TrackInterpolationMode rotInterp   = TrackInterpolationMode.None;
            TrackInterpolationMode sizeInterp  = TrackInterpolationMode.None;
            TrackInterpolationMode colorInterp = TrackInterpolationMode.None;
            TrackInterpolationMode boundInterp = TrackInterpolationMode.None;

            List <GorgonKeyVector3>     positions = null;
            List <GorgonKeyVector3>     rotations = null;
            List <GorgonKeyVector3>     scales    = null;
            List <GorgonKeyVector3>     sizes     = null;
            List <GorgonKeyGorgonColor> colors    = null;
            List <GorgonKeyRectangle>   bounds    = null;
            List <GorgonKeyTexture2D>   textures  = null;

            using (var baseReader = new StringReader(json))
                using (var reader = new JsonTextReader(baseReader))
                {
                    if (!IsReadableJObject(reader))
                    {
                        throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_JSON_NOT_ANIM);
                    }

                    while (reader.Read())
                    {
                        if (reader.TokenType != JsonToken.PropertyName)
                        {
                            continue;
                        }

                        string propName = reader.Value.ToString().ToUpperInvariant();

                        switch (propName)
                        {
                        case "POSITIONS":
                            positions = ReadVector3(reader, vec3Converter, out posInterp);
                            break;

                        case "SCALES":
                            scales = ReadVector3(reader, vec3Converter, out scaleInterp);
                            break;

                        case "ROTATIONS":
                            rotations = ReadVector3(reader, vec3Converter, out rotInterp);
                            break;

                        case "SIZE":
                            sizes = ReadVector3(reader, vec3Converter, out sizeInterp);
                            break;

                        case "BOUNDS":
                            bounds = ReadRects(reader, rectConverter, out boundInterp);
                            break;

                        case "COLORS":
                            colors = ReadColors(reader, colorConvert, out colorInterp);
                            break;

                        case "TEXTURES":
                            textures = ReadTextures(reader, textureConvert);
                            break;

                        case "NAME":
                            animName = reader.ReadAsString();
                            break;

                        case "LENGTH":
                            animLength = (float)(reader.ReadAsDecimal() ?? 0);
                            break;

                        case "ISLOOPED":
                            isLooped = (reader.ReadAsBoolean() ?? false);
                            break;

                        case "LOOPCOUNT":
                            loopCount = (reader.ReadAsInt32() ?? 0);
                            break;
                        }
                    }
                }

            // There's no name, so it's a broken JSON.
            if (string.IsNullOrWhiteSpace(animName))
            {
                throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_JSON_NOT_ANIM);
            }

            var builder = new GorgonAnimationBuilder();

            if ((positions != null) && (positions.Count > 0))
            {
                builder.PositionInterpolationMode(posInterp)
                .EditPositions()
                .SetKeys(positions)
                .EndEdit();
            }

            if ((scales != null) && (scales.Count > 0))
            {
                builder.ScaleInterpolationMode(scaleInterp)
                .EditScale()
                .SetKeys(scales)
                .EndEdit();
            }

            if ((rotations != null) && (rotations.Count > 0))
            {
                builder.RotationInterpolationMode(rotInterp)
                .EditRotation()
                .SetKeys(rotations)
                .EndEdit();
            }

            if ((sizes != null) && (sizes.Count > 0))
            {
                builder.SizeInterpolationMode(sizeInterp)
                .EditSize()
                .SetKeys(sizes)
                .EndEdit();
            }

            if ((colors != null) && (colors.Count > 0))
            {
                builder.ColorInterpolationMode(colorInterp)
                .EditColors()
                .SetKeys(colors)
                .EndEdit();
            }

            if ((bounds != null) && (bounds.Count > 0))
            {
                builder.RotationInterpolationMode(boundInterp)
                .EditRectangularBounds()
                .SetKeys(bounds)
                .EndEdit();
            }

            if ((textures != null) && (textures.Count > 0))
            {
                builder.Edit2DTexture()
                .SetKeys(textures)
                .EndEdit();
            }

            IGorgonAnimation result = builder.Build(animName, animLength);

            result.LoopCount = loopCount;
            result.IsLooped  = isLooped;
            result.Speed     = 1.0f;

            return(result);
        }
コード例 #7
0
ファイル: Program.cs プロジェクト: hammerforgegames/Gorgon
        /// <summary>
        /// Function to build the animations.
        /// </summary>
        /// <param name="sprites">The list of sprites loaded from the file system.</param>
        private static void BuildAnimations(IReadOnlyDictionary <string, GorgonSprite> sprites)
        {
            var animBuilder = new GorgonAnimationBuilder();

            // Extract the sprites that have the animation frames.
            // We'll use the name of the sprite to determine the type of animation and ordering.
            // If we had an animation editor in the editor application, this would be a lot easier, but for now we'll have to do this.
            // If I create an editor, I'll try to replace this code with the animations in the editor file system.
            GorgonSprite[] upFrames = sprites.OrderBy(item => item.Key)
                                      .Where(item => item.Key.StartsWith("Guy_Up_", StringComparison.OrdinalIgnoreCase))
                                      .Select(item => item.Value)
                                      .ToArray();

            IEnumerable <GorgonSprite> turnFrames = sprites.OrderBy(item => item.Key)
                                                    .Where(item => item.Key.StartsWith("Guy_Turn_", StringComparison.OrdinalIgnoreCase))
                                                    .Select(item => item.Value);

            GorgonSprite[] walkLeftFrames = sprites.OrderBy(item => item.Key)
                                            .Where(item => item.Key.StartsWith("Guy_Left_", StringComparison.OrdinalIgnoreCase))
                                            .Select(item => item.Value)
                                            .ToArray();

            float time = 0;

            // Build animation for walking up.
            for (int i = 0; i < upFrames.Length; ++i)
            {
                GorgonSprite sprite = upFrames[i];

                animBuilder.Edit2DTexture()
                .SetKey(new GorgonKeyTexture2D(time, sprite.Texture, sprite.TextureRegion, 0))
                .EndEdit();

                time += 0.15f;
            }

            // Reverse the animation so we don't get popping as it loops.
            for (int i = upFrames.Length - 2; i >= 1; --i)
            {
                GorgonSprite sprite = upFrames[i];

                animBuilder.Edit2DTexture()
                .SetKey(new GorgonKeyTexture2D(time, sprite.Texture, sprite.TextureRegion, 0))
                .EndEdit();

                time += 0.15f;
            }

            _animations[AnimationName.WalkUp]          = animBuilder.Build("Walk Up");
            _animations[AnimationName.WalkUp].IsLooped = true;


            // Build animation for turning left.
            time = 0;
            animBuilder.Clear();
            foreach (GorgonSprite sprite in turnFrames)
            {
                animBuilder.Edit2DTexture()
                .SetKey(new GorgonKeyTexture2D(time, sprite.Texture, sprite.TextureRegion, 0))
                .EndEdit();

                time += 0.20f;
            }
            _animations[AnimationName.Turn] = animBuilder.Build("Turn Left");

            // Build animation for walking left.
            time = 0;
            animBuilder.Clear();
            for (int i = 0; i < walkLeftFrames.Length; ++i)
            {
                GorgonSprite sprite = walkLeftFrames[i];
                animBuilder.Edit2DTexture()
                .SetKey(new GorgonKeyTexture2D(time, sprite.Texture, sprite.TextureRegion, 0))
                .EndEdit();

                time += 0.15f;
            }

            _animations[AnimationName.WalkLeft]          = animBuilder.Build("Walk Left");
            _animations[AnimationName.WalkLeft].IsLooped = true;

            // Finally, we'll need a controller to play and update the animations over time.
            _controller = new GorgonSpriteAnimationController();
        }