}//eom public static Tuple <List <Node2D>, List <Spring2D> > CreateMesh(float px, float py, int w, int h, float dx, float dy, float m, float restD1 = -1, float restD2 = -1, float k = -3) { List <Node2D> meshNodes = new List <Node2D>(); List <Spring2D> springs = new List <Spring2D>(); // Creating nodes for (int y = 1; y <= h; y++) { for (int x = 1; x <= w; x++) { Node2D node = new Node2D(new Vector2(px + x * dx, py + y * dy), m); meshNodes.Add(node); } //end for } //end for for (int i = 0; i < w - 1; i++) { for (int j = 0; j < h; j++) { Spring2D spr = new Spring2D(meshNodes[i + w * j], meshNodes[i + 1 + w * j], restD1, k); springs.Add(spr); } //end for } //end for for (int i = 0; i < h - 1; i++) { for (int j = 0; j < w; j++) { Spring2D spr = new Spring2D(meshNodes[i * w + j], meshNodes[(i + 1) * w + j], restD1, k); springs.Add(spr); } //end for } //end for // Diagonally // \ for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { Spring2D spr = new Spring2D(meshNodes[x + y * w], meshNodes[x + (y + 1) * w + 1], restD2, k); springs.Add(spr); } //end for } //end for // / for (int y = 0; y < h - 1; y++) { for (int x = 1; x < w; x++) { Spring2D spr = new Spring2D(meshNodes[x + y * w], meshNodes[x + (y + 1) * w - 1], restD2, k); springs.Add(spr); } //end for } //end for return(new Tuple <List <Node2D>, List <Spring2D> >(meshNodes, springs)); }//eom
public static Tuple <List <Node2D>, List <Spring2D> > CreatePendulum(float x1, float y1, float m1, float x2, float y2, float m2, float restD = -1, float k = -3) { List <Node2D> nodes = new List <Node2D>(); List <Spring2D> springs = new List <Spring2D>(); Node2D node1 = new Node2D(new Vector2(x1, y1), m1); Node2D node2 = new Node2D(new Vector2(x2, y2), m2); nodes.Add(node1); nodes.Add(node2); Spring2D spring = new Spring2D(node1, node2, restD, k); springs.Add(spring); return(new Tuple <List <Node2D>, List <Spring2D> >(nodes, springs)); }//eom
public MainWindow() { InitializeComponent(); EasingList.ItemsSource = easings.Keys; EasingList.SelectionChanged += (sender, e) => Animate(Ball); MouseLeftButtonDown += async(sender, e) => { // Ball.Tween().FadeTo(0.5); // Ball.Tween().FadeOut(); // TODO: Spring end detection. await Ball.Spring().Duration(500).Out() .MoveBy(e.GetPosition(Ball).X, e.GetPosition(Ball).Y) .FadeIn().OnStart(() => Title += "+"); await EasingList.SpringAll(t => t.FadeIn(), 50); //await EasingList.TweenAll(t => t.FadeIn(), 50); // Ball.Tween().RotateBy(Math.PI); // Ball.Tween().SpinOnce(); // Ball.Tween().Spin(); // Ball.Tween().ScaleBy(1.5, 2.0); }; var spring = new Spring2D(); Ball.GetAnimatable().FrameTimer.OnTick(dt => { spring.Update(dt); //Ball.GetAnimatable().Position = spring.Value; return(false); }); MouseMove += (sender, e) => { spring.Target = new Vector2( e.GetPosition(this).X - 500, e.GetPosition(this).Y - 200); }; }
}//eom public static Tuple <List <Node2D>, List <Spring2D> > CreateCircle(float cx, float cy, float r, int count, float cm, float m, float restD1 = -1, float restD2 = -1, float k = -3) { List <Node2D> circleNodes = new List <Node2D>(); List <Spring2D> springs = new List <Spring2D>(); Vector2 center = new Vector2(cx, cy); Node2D centerNode = new Node2D(center, cm); float step = (float)(Math.PI * 2f) / count; for (var i = 0; i < count; i++) { var t = i * step; var temp = new Node2D(cx + r * (float)Math.Sin(t), cy + r * (float)Math.Cos(t), m); circleNodes.Add(temp); }//end for for (int i = 0; i < circleNodes.Count - 1; i++) { Spring2D spr = new Spring2D(circleNodes[i], circleNodes[i + 1], restD2, k); springs.Add(spr); }//end for foreach (Node2D b in circleNodes) { Spring2D spr2 = new Spring2D(b, centerNode, restD1, k); springs.Add(spr2); }//end for Spring2D sprr = new Spring2D(circleNodes.First(), circleNodes.Last(), restD2, k); springs.Add(sprr); circleNodes.Add(centerNode); return(new Tuple <List <Node2D>, List <Spring2D> >(circleNodes, springs)); } //eom
public void Init() { if (soft.masses == null) { soft.masses = new List <Mass2D>(); } soft.masses.Clear(); float ms = Mass / (float)(NumMasses); int ax = (int)axis; Vector2 pos = Vector2.zero; //DampingRatio = Mathf.Clamp01(DampingRatio); damp = (DampingRatio * 0.45f) * (2.0f * Mathf.Sqrt(ms * spring)); for (int i = 0; i < NumMasses; i++) { float alpha = (float)i / (float)(NumMasses - 1); pos.x = Mathf.Lerp(bbox.min[ax], bbox.max[ax], alpha); //Debug.Log("m[" + i + "] alpha " + alpha + " " + pos.x); Mass2D rm = new Mass2D(ms, pos); soft.masses.Add(rm); } masspos = new Vector2[soft.masses.Count + 2]; for (int i = 0; i < soft.masses.Count; i++) { masspos[i + 1] = soft.masses[i].pos; } if (soft.springs == null) { soft.springs = new List <Spring2D>(); } soft.springs.Clear(); if (soft.constraints == null) { soft.constraints = new List <Constraint2D>(); } soft.constraints.Clear(); for (int i = 0; i < soft.masses.Count - 1; i++) { Spring2D spr = new Spring2D(i, i + 1, spring, damp, soft); //float len = spr.restLen; spr.restLen *= SpringCompress; soft.springs.Add(spr); if (Constraints) { // Do we use restLen or len here? Constraint2D lcon = Constraint2D.CreateLenCon(i, i + 1, spr.restLen); soft.constraints.Add(lcon); } } #if true if (BendSprings) { int gap = 2; for (int i = 0; i < soft.masses.Count - gap; i++) { float alpha = (float)i / (float)soft.masses.Count; Spring2D spr = new Spring2D(i, i + gap, stiffspring * stiffnessCrv.Evaluate(alpha), stiffdamp * stiffnessCrv.Evaluate(alpha), soft); soft.springs.Add(spr); Constraint2D lcon = Constraint2D.CreateLenCon(i, i + gap, spr.restLen); soft.constraints.Add(lcon); } } #endif // Apply fixed end constraints Constraint2D pcon; //if ( left ) //{ // pcon = Constraint2D.CreatePointTargetCon(0, left); //} //else { pos.x = bbox.min[ax]; pos.y = 0.0f; pcon = Constraint2D.CreatePointCon(0, pos); } pconl = soft.constraints.Count; soft.constraints.Add(pcon); //if ( right ) //{ // pcon = Constraint2D.CreatePointTargetCon(soft.masses.Count - 1, left); //} //else { pos.x = bbox.max[ax]; pcon = Constraint2D.CreatePointCon(soft.masses.Count - 1, pos); } pconr = soft.constraints.Count; soft.constraints.Add(pcon); soft.DoConstraints(); }
public void Init() { if ( soft.masses == null ) soft.masses = new List<Mass2D>(); soft.masses.Clear(); float ms = Mass / (float)(NumMasses); int ax = (int)axis; Vector2 pos = Vector2.zero; //DampingRatio = Mathf.Clamp01(DampingRatio); damp = (DampingRatio * 0.45f) * (2.0f * Mathf.Sqrt(ms * spring)); for ( int i = 0; i < NumMasses; i++ ) { float alpha = (float)i / (float)(NumMasses - 1); pos.x = Mathf.Lerp(bbox.min[ax], bbox.max[ax], alpha); //Debug.Log("m[" + i + "] alpha " + alpha + " " + pos.x); Mass2D rm = new Mass2D(ms, pos); soft.masses.Add(rm); } masspos = new Vector2[soft.masses.Count + 2]; for ( int i = 0; i < soft.masses.Count; i++ ) masspos[i + 1] = soft.masses[i].pos; if ( soft.springs == null ) soft.springs = new List<Spring2D>(); soft.springs.Clear(); if ( soft.constraints == null ) soft.constraints = new List<Constraint2D>(); soft.constraints.Clear(); for ( int i = 0; i < soft.masses.Count - 1; i++ ) { Spring2D spr = new Spring2D(i, i + 1, spring, damp, soft); //float len = spr.restLen; spr.restLen *= SpringCompress; soft.springs.Add(spr); if ( Constraints ) { // Do we use restLen or len here? Constraint2D lcon = Constraint2D.CreateLenCon(i, i + 1, spr.restLen); soft.constraints.Add(lcon); } } #if true if ( BendSprings ) { int gap = 2; for ( int i = 0; i < soft.masses.Count - gap; i++ ) { float alpha = (float)i / (float)soft.masses.Count; Spring2D spr = new Spring2D(i, i + gap, stiffspring * stiffnessCrv.Evaluate(alpha), stiffdamp * stiffnessCrv.Evaluate(alpha), soft); soft.springs.Add(spr); Constraint2D lcon = Constraint2D.CreateLenCon(i, i + gap, spr.restLen); soft.constraints.Add(lcon); } } #endif // Apply fixed end constraints Constraint2D pcon; //if ( left ) //{ // pcon = Constraint2D.CreatePointTargetCon(0, left); //} //else { pos.x = bbox.min[ax]; pos.y = 0.0f; pcon = Constraint2D.CreatePointCon(0, pos); } pconl = soft.constraints.Count; soft.constraints.Add(pcon); //if ( right ) //{ // pcon = Constraint2D.CreatePointTargetCon(soft.masses.Count - 1, left); //} //else { pos.x = bbox.max[ax]; pcon = Constraint2D.CreatePointCon(soft.masses.Count - 1, pos); } pconr = soft.constraints.Count; soft.constraints.Add(pcon); soft.DoConstraints(); }
}//eom protected override void Update(GameTime gameTime) { if (!IsActive) { return; } KeyboardState keyboardState = Keyboard.GetState(); #region Handling Keyboard // Exit on Esc if (keyboardState.IsKeyDown(Keys.Escape)) { Exit(); } // Toggle isString property in all springs if (keyboardState.IsKeyDown(Keys.Space) && prevKS.IsKeyUp(Keys.Space)) { stringMode = !stringMode; foreach (Spring2D spr in springs) { spr.StringMode = stringMode; } }//end if if (keyboardState.IsKeyDown(Keys.Up)) { stiffness += 0.02f; stiffness = stiffness.Clamp(0.5f, 3f); foreach (Spring2D spr in springs) { spr.Stiffness = -stiffness; } }//end if else if (keyboardState.IsKeyDown(Keys.Down)) { stiffness -= 0.02f; stiffness = stiffness.Clamp(0.5f, 3f); foreach (Spring2D spr in springs) { spr.Stiffness = -stiffness; } }//end else if (keyboardState.IsKeyDown(Keys.F1) && prevKS.IsKeyUp(Keys.F1)) { helpVisible = !helpVisible; }//end if #endregion #region Handling Mouse MouseState mouseState = Mouse.GetState(); mousePos = new Vector2(mouseState.X, mouseState.Y); #region Left Mouse Button Logic bool mouseDownL = (mouseState.LeftButton == ButtonState.Pressed && prevMs.LeftButton == ButtonState.Released); bool mouseUpL = (mouseState.LeftButton == ButtonState.Released && prevMs.LeftButton == ButtonState.Pressed); bool mouseDragL = (mouseState.LeftButton == ButtonState.Pressed && prevMs.LeftButton == ButtonState.Pressed); if (mouseDownL) { nodeL = PickNode(mousePos); // a signle click picks a node // Checking double clicks to remove a node long currentTime = gameTime.TotalGameTime.Milliseconds; float dt = currentTime - clickTimeL; float dp = Vector2.Distance(clickPosL, mousePos); if (nodeL != null && dt < 500 && dp < 10) { nodes.Remove(nodeL); // Remove all springs attached to the deleted node for (int i = 0; i < springs.Count; i++) { Spring2D spr = springs[i]; if (spr.node1 == nodeL || spr.node2 == nodeL) { springs.RemoveAt(i); i--; } //end if } //end for nodeL = null; } //end if clickTimeL = currentTime; clickPosL = mousePos; }//end if else if (mouseDragL) { if (nodeL != null) { // We make sure the selected node is always at the same position of the mouse nodeL.a = Vector2.Zero; nodeL.v = Vector2.Zero; nodeL.p = mousePos; } //end if } //end else #endregion #region Right Mouse Button Logic bool mouseDownR = (mouseState.RightButton == ButtonState.Pressed && prevMs.RightButton == ButtonState.Released); bool mouseUpR = (mouseState.RightButton == ButtonState.Released && prevMs.RightButton == ButtonState.Pressed); if (mouseDownR) { clickPosR = mousePos; nodeR = PickNode(mousePos); }//end if else if (mouseUpR) { float dist = Vector2.Distance(mousePos, clickPosR); if (nodeR == null && dist < 10) // Simple right click { nodes.Add(new Node2D(mousePos, 1f)); }//end if else if (nodeR != null && dist > 20) // Right button drag\drop { // Check if dropped on an existing node, if not then create a new one, then link them Node2D target = PickNode(mousePos); if (target == null) { target = new Node2D(mousePos, 1f); nodes.Add(target); }//end if Spring2D spr = new Spring2D(target, nodeR, Vector2.Distance(target.p, nodeR.p) * 0.80f); spr.StringMode = stringMode; springs.Add(spr); }//end else nodeR = null; }//end if #endregion #region Mouse Wheel Logic // Change mass from 1 to 500 using mouse wheel if (nodeL != null) { float wheelDelta = mouseState.ScrollWheelValue - prevMs.ScrollWheelValue; nodeL.Mass += wheelDelta / 50f; //if (mass < 1) mass = 1; else if (mass > 500) mass = 500; }//end if #endregion #endregion if (keyboardState.IsKeyDown(Keys.P) && prevKS.IsKeyUp(Keys.P)) { paused = !paused; } if (keyboardState.IsKeyDown(Keys.F5) && prevKS.IsKeyUp(Keys.F5)) { InitLab(); return; }//end if //if (prevMs.LeftButton == ButtonState.Released && mouseState.LeftButton == ButtonState.Pressed && linkRect.Contains(mouseState.X, mouseState.Y)) VisitBlog(); prevKS = keyboardState; prevMs = mouseState; if (paused && keyboardState.IsKeyUp(Keys.Right)) { return; } #region Physics Update // First update all springs, this will only update the objects' acceleration foreach (Spring2D spr in springs) { spr.Update(); } // Second update objects, this will affect acceleration, velocity and position foreach (Node2D node in nodes) { node.Update(); } #endregion base.Update(gameTime); }//eom