MMF2CHAIN0F:\Web\UltimateWalrus\uwexamples\springchain.mfa4(@0ATNFJArialAPMSASUMAGMI """)))UUUMMMBBB999|PP3f333f3333f3ffffff3f̙3ff333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffff3ffff̙fff3fffff3fff333f3f3ff3ff33f̙̙3̙ff̙̙̙3f̙3f333f3333f3ffffff3f̙3f3f3f333f3333f3ffffff3f̙3f3ffffffffff!___wwwB00 h hpppph`@qxaxaxExpp`xÀI,0Qqqiph0$À$(mq4U444Uep`$IŽqUUuq$pHiÀ0YYYY888 xXDZmu8YY8U444UuuYyyyya`eÀm88Uqq4u8Y4ahÀDZ840Q4uY4aP,UMMIzizzzz {,{M{U<}}<yx8ax0uUQ ,m``E)}}Y $#W 51uO ~% ,;@= /&{m?S 5#P +*S}D 1U4_ Mk"8X )Th{> ){~L3jخvQ) 8WeO1  $&''&"  xAxAxAx㐂pppX$Ү0QqMAxhHÀiUUuUax`〆4YY8u$hu8U488puUQӎ0Ӽ<<$`axMUm)s͞c  `[  q= P2pO-AhppqmEumx4QӮq  2$.chnfrc 2|       2        h0 |l%"Arial  @  2(  @  2(  .  2 .  2 h|l%"Arial T.  2 8 2  d8 2  dh|l%"Arialz 4&  d4&  dRems This example is based on an emulation of a physical chain of masses attached by springs. Each one of these masses is affected by four forces: 1.) Gravity. 2.) Air friction. 3.) The spring attached to the mass above it. 4.) The spring attached to the mass below it. For gravity, we simply apply a constant force. For friction, we apply a force in the opposite direction of movement proportional to the object's speed. For the springs, we use Hooke's law. This law states: F=-kx where F is the amount of force, x is the amount of displacement from the spring's equilibrium, and k is the spring constant. For this example, we will assume that the spring's equilibrium is at 0 and the spring constant is 1.In order to implement this in MMF, we have a number of "nodes" which are each given an ID indicating their position of the chain (via spread value).dFor accuracy reasons, the X and Y positions are stored as 100 times what they actually are onscreen.pWe store the X and Y positions of the nodes behind and in front of the node we are currently planning on moving. Then, we use these values to apply the appropriate force. The force is stored in two components --- Fx is the force parallel to the X axis, and Fy is the force parallel to the Y axis. The basic formula for these expressions is: Force from previous spring + Force from next spring + Air friction For the Y equation, we also add gravity. Remember F=ma, so we add Mass*Gravity. Finally, apply the force components to every node's velocity, and apply the velocity to each node's x and y position. Note that this is done outside the loop; we want each node to decide how the other nodes will act on it before we start moving them. Set the first node to the mouse:KRemember, the X and Y positions are stored as 100 times their actual value:This event will initialize the prevX and prevY values to the position of the first node, since this won't get initialized in the loop. Because the first node doesn't have a previous spring, we can keep it from being affected by setting prevX and prevY to its own coordinates (if that makes any sense). This will happen automatically with the last node, so we don't need to worry about it.EvObActiveSpriteChainSprite StringTextString 2TextEvEd EvTsEvLsEvCs,!DNE!#% Frame 1`{׻kϻ[ǻwwwcccSSSCCC333oSKC;{3k+Ww#G_7K'3 kWCw;k3_+S#C7g+K 3ssccSSGG;;33s++_##K7#ۧϏ{gWG7{+osccW WGK;;//ssKK##kS;#ۻÓoG#gc[WO;/s_K ;CϳÛscSwGg7W+K#ߧϏwwggSWCG3;w'/g#[K ; +ӃkgSK73# o_SC7'{cK7'o _##'#'#'#'##skkSS??ۧןϓLJsgߏ[ӃSsKgCW;K3?+{3#o+_OC3 '{k_OC3' w ??Active4IDFxFybigXbigYxvelyvel Movement #122 Chain 4INVERSE_AIR_FRICTION NODE_MASS CHAIN_GRAVITY prevXprevYnextXnextYWALL_BOUNCE_PERCENTAGE2 Movement #122String 2 Movement #1:[Notice how the chain now bounces off the bottom, left, and right. Press space to continue.pp p m  Evts 6" 2 j< 2$  d< 2$  dh.  2 . 2 . 2  :-chnfrc (-chnfrcN  24.chnfrc . 2 . 2  (-chnfrcN  24.chnfrc . 2 . 2 L(-chnfrc>  2$.chnfrc 2|       2         @  2(  @  2(  .  2 .  2 T .  2 8 2  d8 2  dz  4&  d4&  dh |l%"Arial, .  2 , 2 l 2T    d :  2  d8 2  dl 2T    d :  2  d8 2  dl 2T    dRems?This is the only difference here. I made it so the nodes can bounce off the left, right, and bottom sides of the play area. This is pretty simple if you remember that the BigX and BigY values are 100 times what the actual onscreen coordinates are. Once we detect a node has left the frame, we put it back and reverse the component of the velocity that is perpendicular to the wall; then, we multiply it by the WALL_BOUNCE value. A value of 100% means that the velocity is just reversed; A value of 75% would mean that the velocity is reversed and then dampened by 25%.EvObActiveSpriteChainSprite String 2TextEvEd EvTsEvLsEvCs,!DNE!#% Frame 1IN{׻kϻ[ǻwwwcccSSSCCC333oSKC;{3k+Ww#G_7K'3 kWCw;k3_+S#C7g+K 3ssccSSGG;;33s++_##K7#ۧϏ{gWG7{+osccW WGK;;//ssKK##kS;#ۻÓoG#gc[WO;/s_K ;CϳÛscSwGg7W+K#ߧϏwwggSWCG3;w'/g#[K ; +ӃkgSK73# o_SC7'{cK7'o _##'#'#'#'##skkSS??ۧןϓLJsgߏ[ӃSsKgCW;K3?+{3#o+_OC3 '{k_OC3' w??Active4IDFxFybigXbigYxvelyvelnewAngle Movement #122 Chain 4INVERSE_AIR_FRICTION NODE_MASS CHAIN_GRAVITY prevXprevYnextXnextYWALL_BOUNCE_PERCENTAGE2 Movement #122String 2 Movement #10[The nodes are "connected" by stretching and rotating the sprites. Press space to continue.pp p a  Evts6" 2 j< 2$  d< 2$  dh.  2 . 2 . 2  :-chnfrc (-chnfrcN  24.chnfrc . 2 . 2  (-chnfrcN  24.chnfrc . 2 . 2 L(-chnfrc>  2$.chnfrc 2|       2        h |l%"Arialh |l%"Arialh |l%"Arial$ (-chnfrc>  2$.chnfrc4&  d4&  dh |l%"Arial* (-chnfrc>  2$.chnfrc6 &  d, 2 Z* (-chnfrc>  2$.chnfrc6 &  d, 2 z(-chnfrc>  2$.chnfrc6 &  d 2 h"??  Y@B  Y@B*(-chnfrc>  2$.chnfrc6 &  d,  2 h0|l%"Arial(-chnfrc>  2$.chnfrc8X  ^V<    d   d   d   d @@ h|l%"Arial @  2(  @  2(  .  2 .  2 T.  2 8 2  d8 2  d,.  2 , 2 l 2T    d:  2  d8 2  dl 2T    d:  2  d8 2  dl 2T    dRems[The events enclosed in orange comments are the ones that have changed since the last frame.For the sake of easier calculations, I set the X and Y position here. This doesn't really change anything, since the BigX and BigY values are what affect the main events.These next events find the angle from the node to the next node, so that it can be "stretched" to cover that distance. I'm not gonna go into detail about how this angle is found.Here's where I set the angle and X Scale of the object. I find the distance between the current node and the next node, and divide by 5 (since the object is 5 pixels wide). I also added 4 to the distance so that the objects would "fit together" better.EvObActiveSpriteChainSprite String 2TextEvEd EvTsEvLsEvCs,!DNE!#% Frame 1IN{׻kϻ[ǻwwwcccSSSCCC333oSKC;{3k+Ww#G_7K'3 kWCw;k3_+S#C7g+K 3ssccSSGG;;33s++_##K7#ۧϏ{gWG7{+osccW WGK;;//ssKK##kS;#ۻÓoG#gc[WO;/s_K ;CϳÛscSwGg7W+K#ߧϏwwggSWCG3;w'/g#[K ; +ӃkgSK73# o_SC7'{cK7'o _##'#'#'#'##skkSS??ۧןϓLJsgߏ[ӃSsKgCW;K3?+{3#o+_OC3 '{k_OC3' w ??Active 4IDFxFybigXbigYxvelyvelnewAngle Movement #122 Chain 4 INVERSE_AIR_FRICTION NODE_MASS CHAIN_GRAVITY prevXprevYnextXnextYWALL_BOUNCE_PERCENTAGE2 draggingID oldXMouse oldYMouse Movement #122String 3 Movement #1DTry grabbing the chain by clicking and holding the mouse. You can even grab it in the middle (I'll admit it's hard). Press space to exit.pp p f  EvtsV6" 2 j< 2$  d< 2$  dh.  2 . 2 . 2  :-chnfrc (-chnfrcN  24.chnfrc . 2 . 2  (-chnfrcN  24.chnfrc . 2 . 2 L(-chnfrc>  2$.chnfrc 2|       2        $(-chnfrc>  2$.chnfrc4&  d4&  d* (-chnfrc>  2$.chnfrc6 &  d, 2 Z* (-chnfrc>  2$.chnfrc6 &  d, 2 z (-chnfrc>  2$.chnfrc6 &  d 2 h"??  Y@B  Y@B* (-chnfrc>  2$.chnfrc6 &  d,  2  (-chnfrc>  2$.chnfrc8X  ^V<    d   d   d   d @@   @  2(  @  2(  .  2 .  2 h|l%"Arialh|l%"Arial& . 2 h |l%"Arial  ,, 2 h`|l%"Arial 0  2 8 2  d8 2  d: 2"  : 2"   ( 2 ( 2 h|l%"Arial,.  2 , 2 l 2T    d:  2  d8 2  dl 2T    dV  2<  dT 2<  dl 2T    dRemsNWhen the user clicks on one of the nodes, we store its ID value in a variable. lWhen the user isn't holding the mouse, we "let go" by setting the value out-of-bounds of the node ID values. If the ID matches the draggingID, then this is the node we want to set to the mouse. We also set xvel and yvel, on the chance that the user is going to let go next time. These xvel and yvel values are based on how fast the mouse itself is moving. This is calculated by comparing the cursor's current coordinates with its coordinates from last cycle, which we save in oldXMouse and oldYMouse.EvObActiveSpriteChainSprite String 3TextEvEd EvTsEvLsEvCs,!DNE!#% 08 ACHK1 D<Ʒ@D