Windows Phone Finger Trail

Few days ago I took a look to “Cut the rope” on html and as many of us, I analyze the graphics and else and I saw how magically is created the cursor trail. I am preparing a new game for windows phone and I decided to add a finger trail. To do that I investigated but, all I found is for empowered machines and not for a windows phone. I tried to add a inkpresenter canvas on the screen but is awful to be reactive and quick. So  I decide to make my own implementation. To start “Touch.FrameReported”. It is fast enough to implement in UI updates without using XNA.

I created first a method to draw circles that descale and dissapears and keeps aprox 10 elements. Another implementation I did is creating a path with multiple points (that came from the Touch Response). And the last one is a collection of lines that increases the thickness and the opacity.

The way to implement on the canvas is simply calling it:

GameCursor CutCursor = new GameCursor(this.Surface);

Where Surface is any Canvas with an ActualWidth and ActualHeight.

/// <summary>
    /// January 2012, Juan Pablo G.C.
    /// Lightweight cursor/finger trail
    /// </summary>
    public class GameCursor
    {
        #region Nodes Fields
        private bool IsLineMode;
        private List<UIElement> Nodes; //For the first option
        private List<Point> Points; //For the second one
        #endregion

        #region UI Fields
        public TouchPoint primaryTouchPoint;
        public Canvas Surface;
        #endregion

        public GameCursor(Canvas SurfaceToWork)
        {
            IsLineMode = true;
            Surface = SurfaceToWork;
            Nodes = new List<UIElement>();
            Points = new List<Point>();
            Touch.FrameReported += (s, e) =>
            {
                try
                {
                    primaryTouchPoint = e.GetPrimaryTouchPoint(Surface);
                    if (primaryTouchPoint != null)
                    {
                        if (IsLineMode)
                            DrawLines(Surface);
                        else
                            Draw(Surface);
                    }

                    TouchPointCollection touchPoints = e.GetTouchPoints(Surface);
                    if (touchPoints.Count > 0 && touchPoints[0].Action == TouchAction.Up)
                    {
                        Surface.Children.Clear();
                        Nodes.Clear();
                        Points.Clear();
                    }
                }
                catch { }
            };
        }

        public void Draw(Canvas Surface)
        {
            Surface.Children.Clear();

            #region Calculate new point
            if (primaryTouchPoint != null)
            {
                Ellipse el = new Ellipse();
                el.SetValue(Canvas.LeftProperty, primaryTouchPoint.Position.X);
                el.SetValue(Canvas.TopProperty, primaryTouchPoint.Position.Y);
                el.Stroke = el.Fill = new SolidColorBrush(Color.FromArgb(120, 255, 0, 0));
                el.RenderTransform = new ScaleTransform() { ScaleX = 1.0f, ScaleY = 1.0f };
                el.StrokeThickness = 1.0;
                el.Width = el.Height = 30;

                Nodes.Add(el);
            }
            #endregion

            #region Scale points
            Nodes.ForEach(node =>
            {
                if ((node.RenderTransform as ScaleTransform).ScaleX > 0.1)
                {
                    (node.RenderTransform as ScaleTransform).ScaleX -= 0.1f;
                    (node.RenderTransform as ScaleTransform).ScaleY -= 0.1f;
                    node.Opacity -= 0.1f;
                    Surface.Children.Add(node);
                }
                else
                {
                    Nodes.Remove(node);
                }
            });
            #endregion
        }

        public void DrawPath(Canvas Surface)
        {
            Surface.Children.Clear();

            #region Calculate new point
            if (primaryTouchPoint != null)
            {
                Points.Add(primaryTouchPoint.Position);
                if (Points.Count > 8)
                    Points.RemoveAt(0);
            }
            #endregion

            #region FirstPath
            Path firstPath = new Path();
            PathFigure pathFigure = new PathFigure();

            firstPath.StrokeThickness = 10.0;
            firstPath.Stroke = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));

            Points.ForEach(p =>
                {
                    LineSegment l = new LineSegment();
                    l.Point = p;
                    pathFigure.Segments.Add(l);
                });

            pathFigure.StartPoint = Points[0];
            firstPath.StrokeStartLineCap = PenLineCap.Round;
            firstPath.StrokeEndLineCap = PenLineCap.Round;
            firstPath.StrokeDashCap = PenLineCap.Round;
            firstPath.StrokeLineJoin = PenLineJoin.Round;

            PathGeometry pathGeometry = new PathGeometry();
            pathGeometry.Figures = new PathFigureCollection();
            pathGeometry.Figures.Add(pathFigure);
            firstPath.Data = pathGeometry;
            Surface.Children.Add(firstPath);
            #endregion

        }

        public void DrawLines(Canvas Surface)
        {
            Surface.Children.Clear();

            #region Calculate new point
            if (primaryTouchPoint != null)
            {
                Points.Add(primaryTouchPoint.Position);
                if (Points.Count > 8)
                    Points.RemoveAt(0);
            }
            #endregion

            Int32 s0 = 4;
            double op = 0.3;
            for(int i=1;i< Points.Count;i++)
            {
                Line l =new Line();
                l.Stroke = new SolidColorBrush(Colors.Red);
                l.StrokeThickness = s0++;
                l.Opacity = op;
                op += 0.1;
                l.X1 = Points[i-1].X;
                l.Y1 = Points[i-1].Y;
                l.X2 = Points[i].X;
                l.Y2 = Points[i].Y;
                l.StrokeDashCap = PenLineCap.Round;
                l.StrokeEndLineCap = PenLineCap.Round;
                l.StrokeStartLineCap = PenLineCap.Round;
                Surface.Children.Add(l);
            }

        }
    }
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s