Exemplo n.º 1
0
        public PhysicsSprite AddPhysicsBody(PhysicsObjectMain physObject)
        {
            FrameworkElement element = physObject.VisualElement;

            string thisName = element.GetValue(Canvas.NameProperty).ToString();

            element.SetValue(Canvas.TagProperty, thisName);

            // special case: if we are adding a UserControl _AND_ the UserControl contains one or more
            // Physics Controllers, then we handle that UserControl as a "nested" canvas!
            if (BoundaryHelper.IsInsideNestedUsercontrol(element))  //element is UserControl)
            {
                UserControl ucParent         = BoundaryHelper.GetParentUserControl(element);
                Canvas      cnvNestedPhysics = FindPhysicsCanvas(ucParent);
                if (cnvNestedPhysics != null)
                {
                    EnsureUniqueNames(cnvNestedPhysics);
                    if (element is UserControl)
                    {
                        AddPhysicsBodyForCanvasWithBehaviors(cnvNestedPhysics);
                        return(null);
                    }
                }
            }

            // look to see if we have processed this object before, and if so,
            // use its point collection instead of recalculating
            List <Point> points = FindMatchingUIElement(element);

            string           nameKey         = (string)element.GetValue(Canvas.NameProperty);
            FrameworkElement boundaryElement = null;

            if (physObject.BoundaryElement != null && physObject.BoundaryElement != string.Empty)
            {
                boundaryElement = element.FindName(physObject.BoundaryElement) as FrameworkElement;
            }

            if (nameKey == string.Empty)
            {
                nameKey      = GetUniqueSpriteName();
                element.Name = nameKey;
            }

            PhysicsSprite sprite = new PhysicsSprite(Simulator, _parentCanvas, element, points, DebugMode, (float)FrictionDefault, boundaryElement);

            sprite.Name = nameKey;
            if (sprite.OutlinePoints != null)
            {
                sprite.Collision += new PhysicsSprite.CollisionHandler(polygon_Collision);
                _parentCanvas.Children.Add(sprite);
                PhysicsObjects.Add(sprite.Name, sprite);
                sprite.Update();
            }

            sprite.MouseLeftButtonDown += new MouseButtonEventHandler(polygon_MouseLeftButtonDown);
            sprite.MouseLeftButtonUp   += new MouseButtonEventHandler(polygon_MouseLeftButtonUp);
            sprite.MouseMove           += new MouseEventHandler(polygon_MouseMove);

            sprite.GeometryObject.CollisionGroup = physObject.CollisionGroup;
            sprite.BodyObject.IsStatic           = physObject.IsStatic;

            if (physObject.RestitutionCoefficient != 0)
            {
                sprite.GeometryObject.RestitutionCoefficient = (float)physObject.RestitutionCoefficient;
            }
            if (physObject.FrictionCoefficient != 0)
            {
                sprite.GeometryObject.FrictionCoefficient = (float)physObject.FrictionCoefficient;
            }
            if (physObject.MomentOfIntertia != 0)
            {
                sprite.BodyObject.MomentOfInertia = (float)physObject.MomentOfIntertia;
            }
            if (physObject.Mass != 0)
            {
                sprite.BodyObject.Mass = (float)physObject.Mass;
            }

            return(sprite);
        }
Exemplo n.º 2
0
        public PhysicsSprite(PhysicsSimulator physicsSim, Canvas parentCanvas, UIElement element, List <Point> points, bool showDebug, float defaultFriction, UIElement boundaryElement)
        {
#if SILVERLIGHT
            RootCanvas = (Canvas)System.Windows.Markup.XamlReader.Load(xaml);
#else
            using (System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(new System.IO.StringReader(xaml)))
                RootCanvas = (Canvas)System.Windows.Markup.XamlReader.Load(xmlReader);
#endif
            this.Content      = RootCanvas;
            this.InsideCanvas = (Canvas)RootCanvas.FindName("InsideCanvas");

            Simulator            = physicsSim;
            RotationTransform    = RootCanvas.FindName("rotateSprite") as RotateTransform;
            TranslationTransform = RootCanvas.FindName("translateTransform") as TranslateTransform;

            IsNestedUsercontrol = BoundaryHelper.IsInsideNestedUsercontrol(element);
            OriginalNestedLeft  = 0; OriginalNestedTop = 0;
            OriginalElementName = element.GetValue(Canvas.NameProperty).ToString();
            OriginalCanvasName  = parentCanvas.GetValue(Canvas.NameProperty).ToString();

            if (IsNestedUsercontrol)
            {
                // this is a user control with nested physics elements.
                // store it's offset for later positioning
                Canvas      cnvParent           = (element as FrameworkElement).Parent as Canvas;
                UserControl ucParentUserControl = (cnvParent.Parent as UserControl);
                OriginalUserControlName = ucParentUserControl.Name;
                OriginalNestedLeft      = Convert.ToInt32(ucParentUserControl.GetValue(Canvas.LeftProperty));
                OriginalNestedTop       = Convert.ToInt32(ucParentUserControl.GetValue(Canvas.TopProperty));

                // we'll process the storyboards so that they point to element references
                foreach (DictionaryEntry item in ucParentUserControl.Resources)
                {
                    if (item.Value is Storyboard)
                    {
                        Storyboard sb = item.Value as Storyboard;
                        foreach (Timeline tl in sb.Children)
                        {
                            //if (tl.GetValue(Storyboard.TargetNameProperty) == element.GetValue(Canvas.NameProperty))
                            string    target        = tl.GetValue(Storyboard.TargetNameProperty).ToString();
                            UIElement targetElement = ucParentUserControl.FindName(target) as UIElement;
                            if (targetElement != null)
                            {
                                Storyboard.SetTarget(sb, targetElement);
                            }
                        }
                    }
                }
            }

            // do we want to use a different element to determine boundary outline?
            UIElement elementBoundary = element;
            if (boundaryElement != null)
            {
                elementBoundary = boundaryElement;
            }


            if (points == null)
            {
                points = BoundaryHelper.GetPointsForElement(elementBoundary, element, false);
            }
            else
            {
                BoundaryHelper.GetPointsForElement(elementBoundary, element, true);
            }

            if (points == null || points.Count == 0)
            {
                return;
            }

            OutlinePoints = new List <Point>();
            OutlinePoints.AddRange(points);


            // let's clean up the number of points, for a little performance boost..
            int   distanceThreshold = 5;
            Point ptLast            = points[points.Count - 1];
            for (int i = points.Count - 2; i >= 0; i--)
            {
                if (points.Count < 10)
                {
                    break;
                }

                if (PhysicsController.DistanceBetweenTwoPoints(ptLast, points[i]) < distanceThreshold)
                {
                    points.Remove(points[i]);
                }
                else
                {
                    ptLast = points[i];
                }
            }

            // get the overall dimensions
            double width, height, minX, minY;
            PhysicsController.GetPointDimensions(points, out width, out height, out minX, out minY);


            // make the canvas size match the path it contains
            this.Width  = width;
            this.Height = height;
            RootCanvas.SetValue(Canvas.WidthProperty, width);
            RootCanvas.SetValue(Canvas.HeightProperty, height);

            // nested user control elements are removed from their user control
            // and copied into the main game canvas
            if (BoundaryHelper.IsInsideNestedUsercontrol(element))
            {
                UserControl ucParent = BoundaryHelper.GetParentUserControl(element);

                Canvas cnvParent = (element as FrameworkElement).Parent as Canvas;
                cnvParent.Children.Remove(element);
            }

            // draw the polygon
            if (uiElement != null)
            {
                RootCanvas.Children.Remove(uiElement);
                uiElement = null;
            }

            // create the physics body
            Vertices vertices = new Vertices();

            double centerX = (this.Width / 2);
            double centerY = (this.Height / 2);


            foreach (Point point in points)
            {
                // note vertices are based on 0,0 at center of body
                double x, y;

                // first we need to remove the offset position of the drawn shape on the main canvas
                x = Convert.ToDouble(point.X) - Convert.ToDouble(element.GetValue(Canvas.LeftProperty));                //minX;
                y = Convert.ToDouble(point.Y) - Convert.ToDouble(element.GetValue(Canvas.TopProperty));                 //minY;

                // we need to make points relative to origin (center) of object
                x = x - centerX;
                y = y - centerY;

                vertices.Add(new Vector2((float)x, (float)y));
            }

            // if there are too few points, then subdivide the edges
            if (vertices.Count <= 4)
            {
                vertices.SubDivideEdges(6);
            }

            _offsetCentroid = vertices.GetCentroid();


            // initialize the polygon sprite
            BodyObject     = BodyFactory.Instance.CreateBody(physicsSim, 0.5f, vertices.GetMomentOfInertia());
            GeometryObject = GeomFactory.Instance.CreatePolygonGeom(physicsSim, BodyObject, vertices, 0);

            GeometryObject.FrictionCoefficient = defaultFriction;
            GeometryObject.OnCollision        += new FarseerGames.FarseerPhysics.Collisions.CollisionEventHandler(HandleCollision);

            BodyObject.Enabled = true;
            BodyObject.ClearForce();
            BodyObject.ClearTorque();

            // adjust position to take into consideration origin at middle
            Vector2 position = new Vector2((float)minX, (float)minY);
            position.X = (position.X + ((float)getWidth / 2));
            position.Y = (position.Y + ((float)getHeight / 2));

            // adjust for centroid
            bool bAdjustCentroid = true;
            if ((element is Image) && (element as Image).Clip != null)
            {
                bAdjustCentroid = false;
            }

            if (bAdjustCentroid)
            {
                position.X = position.X + _offsetCentroid.X;
                position.Y = position.Y + _offsetCentroid.Y;
            }

            BodyObject.Position = position;

            Update();

            uiElement = element;
#if SILVERLIGHT
            parentCanvas.Children.Remove(uiElement);
#else
            if (parentCanvas == System.Windows.Media.VisualTreeHelper.GetParent(element))
            {
                parentCanvas.Children.Remove(uiElement);
            }
            else
            {
                Canvas cnv = (Canvas)System.Windows.Media.VisualTreeHelper.GetParent(element);
                if (cnv == null)
                {
                    parentCanvas.Children.Remove(uiElement);
                }
                else
                {
                    cnv.Children.Remove(element);
                }
            }
#endif

            uiElement.SetValue(Canvas.LeftProperty, -(width / 2));
            uiElement.SetValue(Canvas.TopProperty, -(height / 2));

            TranslateTransform trans = new TranslateTransform();
            trans.X = width / 2;
            trans.Y = height / 2;
            uiElement.RenderTransform = trans;

            InsideCanvas.Children.Add(uiElement);

            uiElement.SetValue(Canvas.LeftProperty, (double)(-((width / 2) + _offsetCentroid.X)));
            uiElement.SetValue(Canvas.TopProperty, (double)(-((height / 2) + _offsetCentroid.Y)));

            if (IsNestedUsercontrol)
            {
                BodyObject.Position = new Vector2((float)(BodyObject.Position.X + OriginalNestedLeft), (float)(BodyObject.Position.Y + OriginalNestedTop));
                Update();
            }

            if (showDebug)
            {
                _pathDebug         = PhysicsController.CreatePathFromVertices(vertices, getWidth, getHeight);
                _pathDebug.Opacity = 0.7;
                RootCanvas.Children.Add(_pathDebug);
            }


            SetDebug(showDebug);
        }