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); }
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); }