This project has moved. For the latest updates, please go here.

Collisions and dynamic joint creation

 Topics: User Forum Wiki Link: [discussion:49588]
 Jerky Mar 9, 2009 at 7:17 AM My first question :).  I'm sure there are many more to come.  Let me start out by saying I am not very good with c# yet, nor xna, and have been working with c#/xna for about two weeks now.  I knew some c# beforehand, so I've picked up the basics rather quickly, but proper design and conceptualization (OO) is something I still lack.  With that out of the way, here goes: So I started prototyping a game idea I had with blocks and their movement.  I have come quite a long ways using your demos and modifying them to fit what I am doing.  Right now, I have a number of these blocks on screen at a time.  Only one of them moves at a time.  I assign a rectangle body and geom to all of them, and they are all playing nicely.  In order to get the movement I wanted, I created a custom OnCollision event, which looks like this:   private bool MyOnCollisionMethod(Geom geom1, Geom geom2, ContactList list) {     float distance;     distance = Vector2.Distance(collisionIndex, list[0].Position);     if (collisionJoint != null)     {         if (distance > 63f)         {             collisionJoint.Dispose();             Vector2 index = list[0].Position;             collisionJoint = JointFactory.Instance.CreatePinJoint(PhysicsSimulator, geom1.Body, geom1.Body.GetLocalPosition(index), geom2.Body, geom2.Body.GetLocalPosition(index));             collisionJoint.Enabled = true;             collisionJoint.Breakpoint = 1f;             index = collisionIndex;         }     }     else if (collisionJoint == null)     {         Vector2 index = list[0].Position;         collisionJoint = JointFactory.Instance.CreatePinJoint(PhysicsSimulator, geom1.Body, geom1.Body.GetLocalPosition(index), geom2.Body, geom2.Body.GetLocalPosition(index));         collisionJoint.Enabled = true;         collisionJoint.Breakpoint = 1f;         index = collisionIndex;     }     return true; }   This works about as good as I could want.  The problem now lies with the inactive blocks.  I made it so that I could switch (cycle) between blocks, and move them all individually.  Now, I want my non-active blocks to adhere to one another.  I figured PinJoints would work, because that is what I am using now.  I setup a new list of static blocks, which I update manually. (I know I could probably add my own custom property/tag to them to do this, and use the built in list from PhysicsSimulator, but I haven't gotten that far yet).  What I want to do is dynamically create these joints on all "blocks" (not all bodies) when they are not currently active.  The active block should continue using the custom OnCollision method above, so that movement still stays consistent.  Also, I don't want each collision on the grid to create a joint.  2 joints per side (for a max of 8 per block) is all I want.  Here is a very ugly (and mostly broken) StaticOnCollisionMethod I created after trying to come up with a solution.  I know some of the problems with it already, but I am really looking for options/alternatives.   private bool StaticOnCollisionMethod(Geom geom1, Geom geom2, ContactList list) {     float distance = 33;     PinJoint tempJoint;     int lastIndex = -1;         for (int i = 0; i < list.Count - 1; i++)     {         if (i != 0 && lastIndex == -1)             distance = Vector2.Distance(list[i].Position, list[i - 1].Position);         else if (i != 0 && lastIndex != -1)             distance = Vector2.Distance(list[i].Position, blockJoints[lastIndex].WorldAnchor1);         else if (i == 0)             distance = 33f;             if (distance >= 32f)         {             Vector2 index = list[i].Position;             tempJoint = new PinJoint(geom1.Body, geom1.Body.GetLocalPosition(index), geom2.Body, geom2.Body.GetLocalPosition(index));             blockJoints.Add(tempJoint);             blockJoints[blockJoints.IndexOf(tempJoint)].Breakpoint = 1f;             lastIndex = blockJoints.IndexOf(tempJoint);         }         else break;     }     return true; }   I have been making videos of my progress, so here is the latest one, where I show you the issue (while narrating): http://erikbriggs.me/blox/prototype/proto_movement10.swf Looking forward to your input. RogueCommanderIX Mar 9, 2009 at 10:09 AM :S. Maybe you could explain what you are trying to make? ill take a look at the video later, maybe that will help. Jerky Mar 10, 2009 at 5:27 AM Edited Mar 10, 2009 at 5:29 AM Yes, watch the video.  It's much easier to understand when you see it.  Essentially, the oncollision of the static blocks just fires and fires, and it starts to bog things down.  I know its because my staticoncollisionmethod is horrible, but I'd also like to see them somehow go into a restful state.  They should fire the collsion until the joints are formed, and then wait to be interacted with by something else.  The blocks in my game idea are on the same team, so to speak, so they shouldnt be so active when they arent in use. The idea is that they adhere to one another when they come into contact, and somehow what works for my active block, isn't working for my static blocks.  The joints create and then break without any force being applied. RogueCommanderIX Mar 10, 2009 at 7:08 AM Edited Mar 10, 2009 at 8:44 AM All right, this is gonna require a bit of work. If you go to the source code page for this project, then click on the Patches link, there is a patch that says that it adds the ability to add a DNC list to geoms. If you download this and copy the files inside into the Collisions subfolder of the FarseerPhysics project and recompile/readd it to your project, then modify the static collision method to include 2 calls to Geom.AddDNC(Geom geom) so that the geoms don't collide with each other. However, the collision event will stop firing and any joints that have been created might be a little hard to get rid of. Maybe you should store the joints in a list and empty that list when you switch it to an active block. You'll want to also clear the DNC list when you switch to an active block as well. by the way, impressive movement! on a side note, how did you do that camera? im guessing it doesn't have anything to do with rendertargets bigger than the screen size? :D Also, if i may take a shot at what your game idea is? you control a bunch of blocks in a game world where you need to use them to work together to get to the exit/solve/puzzles/stuff like that. Jerky Mar 15, 2009 at 10:22 PM Edited Mar 15, 2009 at 10:27 PM Ok, I'm back.  Sorry for the slow reply.  I attempted your RogueCommanderIX's patch and ended up making my blocks fall through the border and off the world.  I do not think that that is going to solve my issue.  I setup a new OnCollision method called the NullOnCollisionMethod which does nothing.  When my blocks have hit the max amount of joints, the should get this oncollisionmethod set, which will stop the additional processing and reprocessing of my other oncollision methods.  This, however isnt ever getting a chance to fire because I am not yet creating dynamically named joints.  What is happening is that the same joint gets recreated, thusly disappearing from where it was first created.  Here is a new video to describe my problem, which is really the same as the old problem and the original question (mp4 is much smaller and better quality than the swf's I was using before): http://erikbriggs.me/blox/prototype/2009-03-15_1504.mp4 MyOnCollisionMethod is the same as above, and remains unchanged.  The StaticOnCollisionMethod is now:  private bool StaticOnCollisionMethod(Geom geom1, Geom geom2, ContactList list) {     float distance = 33;     Joint tempJoint;     int jointCount = 0;     bool twoalready = false;        foreach (PinJoint joint in PhysicsSimulator.JointList)     {         if ((joint.Body1 == geom1.Body && joint.Body2 == geom2.Body) || (joint.Body2 == geom1.Body && joint.Body1 == geom2.Body))             jointCount++;               if (jointCount == 2)         {             twoalready = true;             geom1.OnCollision += NullOnCollisionMethod;             break;         }               if (twoalready == false)         {             Vector2 index = list[0].Position;             tempJoint = JointFactory.Instance.CreatePinJoint(geom1.Body, geom1.Body.GetLocalPosition(index), geom2.Body, geom2.Body.GetLocalPosition(index));             tempJoint.Breakpoint = 5f;         }     }         return true; } What I think I am doing is checking the number of joints in the jointlist between the current two bodies involved in the collision.  I never anticipate the joint list getting massive, so I think that performance here might not be an issue.  The performance issue I ran into trying to create my own jointlist was that it was creating a massive list very quickly.  This time around, since I am checking the PhysicsSimulator.JointList instead of mine, it stay clean because they are getting disposed out of there. Regarding how I do my camera, I use a Clamp on scale, and they create a cameraMatrix like this: MathHelper.Clamp(scale, 1.0f, 1.1f); cameraMatrix = Matrix.Identity *      Matrix.CreateTranslation(-Position.X, -Position.Y, 0.0f) *      Matrix.CreateScale(scale, scale, 0) *      Matrix.CreateTranslation(ScreenManager.Center.X, ScreenManager.Center.Y, 0);       Looking forward to suggestions.  Let me know if I am not making any sense. Tlegion Mar 16, 2009 at 4:21 AM so this camera can create zoom without actually scaling? if this cam can work with farseer can you write a small tut? Jerky Mar 16, 2009 at 5:53 AM By "work with farseer" do you mean making the debug view (PhysicsSimulatorView) match?  If so, then the answer is yes. tlegion Mar 16, 2009 at 5:38 PM yeah because you cant use a simple scaling camera with farseer so if your camera works while maintaining the geometry and bodies then please please please give me help with it : ) RogueCommanderIX Mar 16, 2009 at 11:30 PM Yeah i do a similar thing, but i don't multiply by Matrix.Identity, and i should probably do that second translation. Ill try it and see if it helps. RogueCommanderIX Mar 17, 2009 at 4:27 AM Update: after hammering away at my code, not only did i figure out how to fix my camera, i also made a way to make textures not look pixelated when you zoom in! what you do is make textures that is 4 times the size (or whatever you max zoom in scaling up is, mine is 4) then you apply an additional Matrix.CreateScale(1/maxZoom) * Matrix.CreateTranslation(whateverPosition) to the camera matrix (so its Matrix.CreateScale(1/maxZoom) * Matrix.CreateTranslation(whateverPosition) * cameraMatrix) when feeding it to spriteBatch.Begin(). Then you draw the textures to position 0. (also, this means that you must wrap each draw call that needs a different position in a separate begin and end) tlegion Mar 17, 2009 at 5:25 AM That sounded great, up until the last part, would that meen you are forced to draw all textures to the same position unless you start a new draw call? If it is working though id love to get the source code, if you dont mind me picking at the code a bit. RogueCommanderIX Mar 17, 2009 at 6:08 AM Edited Mar 17, 2009 at 6:10 AM Basically yes but it is the only way to do it without resorting to choppy movement (if you used a destination rectangle for scaling in the draw calls), so theres nothing you can do. Well my source code is across multiple files and if you follow my instructions (assuming you use the method above with the matrices), it should work just fine. Sorry. Also, why are we multiplying our scale/translation/rotationby Matrix.Identity? my version before (which had flawed zoom/rotation admittedly) didn't need that and it worked just fine. Jerky Mar 17, 2009 at 6:21 AM If I tell you about my camera class, will you go back to my question? :P Camera.cs: using   System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; namespace MyNamespace { public class Camera {     public Vector2 Position = Vector2.Zero;     public Matrix TransformMatrix     {         get         {             MathHelper.Clamp(Demo1Screen.scale, 1.0f, 1.1f);             return Matrix.Identity *             Matrix.CreateTranslation(-Position.X, -Position.Y, 0.0f) *             Matrix.CreateScale(Demo1Screen.scale, Demo1Screen.scale, 0) *             Matrix.CreateTranslation(ScreenManager.Center.X, ScreenManager.Center.Y, 0);          }     }         public void LockToTarget(int screenWidth, int screenHeight)     {         Position.X = Demo1Screen.GetSelectedBodyPosition().X;         Position.Y = Demo1Screen.GetSelectedBodyPosition().Y;     }            public void ClampToArea(int minX, int maxX, int minY, int maxY)      {         // This Locks the camera to screen, so you cannot scroll off-screen while moving.         if (Position.X < minX)             Position.X = minX;             if (Position.X > maxX)             Position.X = maxX;             if (Position.Y < minY)             Position.Y = minY;             if (Position.Y > maxY)             Position.Y = maxY;      }   } } So, in my draw method, when I call my spritebatch begin, you call: ScreenManager.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, camera.TransformMatrix); Then, in my GameScreen class, when it calls draw (which only does something when debug is enabled):     public virtual void Draw(GameTime gameTime) {     if (_debugViewEnabled)     {         ScreenManager.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, Demo1Screen.camera.TransformMatrix);         _physicsSimulatorView.Draw(ScreenManager.SpriteBatch);         ScreenManager.SpriteBatch.End();     } } tlegion Mar 17, 2009 at 7:08 AM hahaha im terribly sorry i did not intend for that to happen, thank you very much though for the clear explination i will attempt to implement it into my code. Jerky Mar 17, 2009 at 8:02 AM No worries, glad I could help.  I have sorta fixed my issue.  I'm sure it comes down to me being a noob still ;).  I was reassigning the joint variable with a new joint, so it was disposing the old joint (which is why I ended up with only 1 joint in the world at a time).  To fix it, I just called the JointFactory.Instance to create a new joint each time, which created a new instance of the joint.  This quickly turned in thousands of joints, so I was able to make a max of 2 joints per collision, then set the collision event to my NullOnCollisionMethod.  This seems to work well.  Now that I am past that, I am still in need of some more input.  This latest video should describe it: http://erikbriggs.me/blox/prototype/2009-03-17_0050.mp4 What is happening is that even now with the joints in place (not exactly how I want, but good enough for now), I am unable to create a steady stack of blocks.  The collisions are still happening and creating bouncing between blocks that are jointed together.  The more joints between them, the more jitter (bounce) is happening without any interaction.  Are collision groups the best way to attack this new problem?  I still want the stack to be interacted with by the active block, so marking the inactive blocks as static is not something I would want.  He still should be able to possibly break the joints in a stack if he creates too much force, but they (the blocks in the stack) also need to be steady while not being interacted with. Thoughts? RogueCommanderIX Mar 17, 2009 at 8:35 AM I know you already tried my patch, but you must have been doing something wrong as it only disallows specific geoms from colliding. Did you insert the AddDNC line in the static OnCollision method you have? Also, i can't open MP4 files, so i cant watch it. I know those SWFS were slower and everything but they were easier to see. Can you please switch back? Sorry for derailing your question, but us noobs are not good at making cameras. @TLegion: with a little cleaning up of my code, i could offer you my camera. Jerky's camera looks nice, but a little game specific. I designed my camera to be useful in any XNA game with a minimum of use, so it might work better for you. It also rotates! ^_^ (sorry jerky!) RogueCommanderIX Mar 17, 2009 at 9:50 AM Edited Mar 17, 2009 at 11:02 PM All right heres my camera: (moved to another thread see below) tlegion Mar 17, 2009 at 7:40 PM Edited Mar 17, 2009 at 8:06 PM thank you so much dude it works great, i especially enjoy zooming at my given rate : D but a few questions. 1. what does the size vector do? i changed it around and nothing happened so i have it set to null for now. 2. how do i get the body to be centered, i changed the position to be vector2.zero, body.origin(verts.getcentroid), the screen center. 3. the default zoom rate seems to be 0.1f but when i plug it in or anything even lower it goes much faster, why is that? but i also like being able to set the tracking bodys position in the update method on the fly, im sure ill be glad to utilize that. edit: sorry its off topic again sorry sorry, but perhaps the joints are attempting to reach a certain target angle so they are applying force on eachother, when you create new instances of joints what parameters are you giving them? RogueCommanderIX Mar 17, 2009 at 11:01 PM Edited Mar 17, 2009 at 11:07 PM @TLegion: In the interest of being able to answer jerky's question, I moved the camera stuff to another thread. Now, to reiterate my suggestion: I know you already tried my patch, but you must have been doing something wrong as it only disallows specific geoms from colliding. Did you insert the AddDNC line in the static OnCollision method you have? Also, i can't open MP4 files, so i cant watch it. I know those SWFS were slower and everything but they were easier to see. Can you please switch back? RogueCommanderIX Mar 23, 2009 at 4:42 AM Ok i found the 2 new videos on your site and watched them, and... wow.... that should not be happening at all... maybe if you check to see if your geoms that are colliding both have the proper tags attached to them? Jerky Apr 1, 2009 at 6:56 AM Edited Apr 1, 2009 at 6:58 AM I'm back after a couple busy weeks at work.  I didn't have much time to devote to this.  I spent my time, rather, adding particles and beauty to my prototype.  It's time to get back to the core :). Hmm, I'm not sure I'm following you.  I haven't used Tags at all yet.  I plan to eventually, as I flesh out the game a little more, but I'm not sure I get what tags can do for me here.  Regarding your patch, I probably didn't use it correctly, but I'm not sure I want to turn off collisions.  I think I just want to limit them or at least control how often they happen while the bodies that aren't active are sitting there.  There is no need for them to update at that speed and continue colliding with each other when they bodies should be at some sort of rest.  I guess my question now is how do I make bodies/geoms rest.  I still want things to be able to collide with them, and if other forces from the game act on them, they should still react, but when they are not in use, they need to be able to stand still.  Does that make sense?  If so, what is the best way to do it? RogueCommanderIX Apr 1, 2009 at 10:47 AM Edited Apr 1, 2009 at 11:04 AM Well i suggested my patch so that your code wouldn't freak out when the inactive bodies were contacting each other. The goal was to get your inactive bodies to stop sensing collisions with the bodies it already had stuck to and thus you wouldn't get strange behavior like dropping to 2 frames per second. On a side note, what do you think of my camera? (it can be found here: http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=50483) RogueCommanderIX Apr 8, 2009 at 1:55 AM I had an idea that would really make the look of your fire block look cool (if you don't mind): Distortion effects. Basically you whip up a little shader that takes in a normal map and distorts the stuff under it and then chain this to a particle system so it really looks like your fire block is "heating up the atmosphere around it". Whaddya think? Jerky Apr 8, 2009 at 3:38 AM Haha, thanks.  That one is already on the list.  I have a shader right now that does distortion for an ice-block, which you will be able to see through.  There are a few other problems with my fire one too, which I plan on fixing.  I have a high standard of quality.  If I didn't need help, I wouldn't be showing all this publicly yet, because I know it already doesn't meet my standards ;). About your patch.  Can you explain how it works differently than collision groups and the InactivityController?  From the few minutes I played with it, it seemed like it was supposed to control what can collide with what.  It seems the InactivityController was the immediate answer I was looking for all along (and I'm wondering how genbox & co. missed this thread, because that was obvious (which I found out after stumbling upon it in another thread)).  It was probably my fault for changing topics so many times.  Now, that being said, the InactivityController will be useful, but I have other problems that it cannot fix (which I am working on now).  Combine that with collision groups, and it would seem that the functionality in your patch is already there.  You could just change collision groups to make things not collide (which seems like the purpose of your patch).  I'm not trying to sound rude here, so I hope you don't interpret anything that way, I'm just asking because I probably misunderstand the purpose of your patch. Thanks again for the ideas. RogueCommanderIX Apr 8, 2009 at 5:10 AM Basically, if you decide that 2 specific geoms don't need to collide, then you tell 1 (or both it doesnt really matter except for informational purposes) that you don't want it to collide with this other geom (via AddDNC or whatever i called it). I evaluated the option of attempting bit magic to try and use collision categories, but i figured that A it would be too hard and B it would be too buggy (at least for my purposes). From the way you described your problem, it sounded like that the conditions were specific enough that my patch would help. On a side note, It sounds like your game's gonna be really cool! ill be sure to try it when it comes out.