Collision shapes id (not index...)
by Jonathan Arsenault · in Torque 2D Beginner · 05/28/2013 (11:19 pm) · 20 replies
I have started prototyping a game with Torque2D MIT about a week ago and i really have no idea how all of you guys are able to do anything useful with the collisions the way they currently work, index into a vector are utterly useless if you are to be able to retrieve those collision shape at any point in the future, let alone delete one of them without invalidating the whole shebang. I have changed it to use a hashmap as the backing collection for my shapes and thus have a stable ID for them i can rely on.
https://github.com/jonharson/Torque2D/tree/patch/CollisionID
https://github.com/jonharson/Torque2D/tree/patch/CollisionID
About the author
Made a small foray in the gaming industry working at Citeremis, worked and offered consultation in many other sector since, passing through casino management, the wood transformation industry and the transportation sector. Eat code for breakfast.
#2
There is also change to the hashmap included in there as some of it's function were not const friendly, mainly; [] operator (retrieve without insert), contains, count, find and maybe other i forgot about.
2.)I will look into this, there are still modification to the picking and possibly a quadtree backed scenegraph that i am working on that i might contribute back too once they are in a good enough shape for use.
05/29/2013 (1:16 am)
1.) The main reason i needed this was to be able to associate collision shapes with sprite in a composite sprite so as to be able to remove and/or modify them later. There was no other way that i could see at a quick glance to do this and given that there is no collision picking on composite sprite this was the easiest way to get there, but even with picking on a composite this is still more efficient if you have a 1:1 or close to it association between sprite object and collision object or a complex collision hierarchy that need to be dealt with manually.There is also change to the hashmap included in there as some of it's function were not const friendly, mainly; [] operator (retrieve without insert), contains, count, find and maybe other i forgot about.
2.)I will look into this, there are still modification to the picking and possibly a quadtree backed scenegraph that i am working on that i might contribute back too once they are in a good enough shape for use.
#3
First, when you create a collision shape do one of these (for circles only, but the method should work on all shapes):
This means you can use functions to delete a specific collision shape, or copy it or whatever, and then you can create a new one to replace it with an updated size.
Here's where the engine appears to be lacking though: You cannot merely update an existing collision shape. If you delete one and create a new one it IMMEDIATELY restarts any related collision functions, and it appears to disable any sensor collision shape settings you had applied.
Long story short: We can reference collision shape indexes via the above, but we need a way to update a collision shape without breaking existing on-going collisions.
05/29/2013 (4:52 am)
You should hang around the IRC Channel! I came in last night with this EXACT same problem. I've got a partial solution, but it doesn't help with the end goal, which is to alter a collision shape without utterly destroying it and breaking all related functions.First, when you create a collision shape do one of these (for circles only, but the method should work on all shapes):
%object.CShapeIndex = %object.createCircleCollisionShape( 1 );
%objectCShapeIndex = %object.createCircleCollisionShape( 1 );These save the Collision Shape Index into a variable. The upper one lets you call it from outside functions, the latter from within the function it was created in.
This means you can use functions to delete a specific collision shape, or copy it or whatever, and then you can create a new one to replace it with an updated size.
Here's where the engine appears to be lacking though: You cannot merely update an existing collision shape. If you delete one and create a new one it IMMEDIATELY restarts any related collision functions, and it appears to disable any sensor collision shape settings you had applied.
Long story short: We can reference collision shape indexes via the above, but we need a way to update a collision shape without breaking existing on-going collisions.
#4
Updating the object's size is easy and natural. Attempting to update the circles' collision shapes result in multiple collision shapes attached to each object (creating new circle collision shapes without deleting the original). If I delete the previous collision shapes first it resets the digestion effect timer, which immediately deletes the collision shape and makes a new one, which immediately calls the digestion function and immediately destroys the collision shape and makes a new one.... on and on and on until the Object B is destroyed , or if there are multiple Object B's it overloads and crashes the program.
05/29/2013 (4:59 am)
Oh, and here's my existing scenario for my game: Object A is eating Object B, via a pair of weldjointed sensor objects that apply the digestion affect (shrinking object B) while updating Object A's size. The digestion effect is applied once a second while Object B is within Object A's digestion sensor.Updating the object's size is easy and natural. Attempting to update the circles' collision shapes result in multiple collision shapes attached to each object (creating new circle collision shapes without deleting the original). If I delete the previous collision shapes first it resets the digestion effect timer, which immediately deletes the collision shape and makes a new one, which immediately calls the digestion function and immediately destroys the collision shape and makes a new one.... on and on and on until the Object B is destroyed , or if there are multiple Object B's it overloads and crashes the program.
#5
Read the documents. Chase points out an edge case where scaling would be very desirable and from past experience I can tell you there are others but for the most part the system is entirely useable. For the record, the engine keeps track of the shapes and destroys them when the object they're attached to is destroyed so you can stop worrying about that bit.
As Chase also points out, saving that index in a field on your object lets you hang onto it in a handy fashion - the index is already unique and reliable, you just have to hang on to it.
I see many people come through who immediately panic over how things are apparently not managed - forget all of the books on game engine programming you've seen, that work has already been done here. Examine the source thoroughly, follow the class inheritance chains (I know, they're crazy deep, bad design paradigm and all that - the engine hails back 15 years), look at how it works - then take a deep breath and relax a little. Only a little though; there are still plenty of actual bugs to find and corner cases to address.
05/29/2013 (6:31 am)
The reasoning behind not allowing modification of collision shapes is that it is an expensive operation. I don't know how expensive, but that is what I was told when we first introduced Box2D into the engine at the beginning of last year.Quote: i really have no idea how all of you guys are able to do anything useful with the collisions the way they currently work
Read the documents. Chase points out an edge case where scaling would be very desirable and from past experience I can tell you there are others but for the most part the system is entirely useable. For the record, the engine keeps track of the shapes and destroys them when the object they're attached to is destroyed so you can stop worrying about that bit.
As Chase also points out, saving that index in a field on your object lets you hang onto it in a handy fashion - the index is already unique and reliable, you just have to hang on to it.
I see many people come through who immediately panic over how things are apparently not managed - forget all of the books on game engine programming you've seen, that work has already been done here. Examine the source thoroughly, follow the class inheritance chains (I know, they're crazy deep, bad design paradigm and all that - the engine hails back 15 years), look at how it works - then take a deep breath and relax a little. Only a little though; there are still plenty of actual bugs to find and corner cases to address.
#6
Box2D doesn't allow modification of Collision shapes once they are created; the only way to do it is to delete the collision shape and recreate it how you want it. See here for another explanation.
Our limits are based on how Box2D handles things. I suggest we find a standardized way to easily keep track of multiple collision shapes instead of everyone rolling up their own solution. I would favor also a 'wrapper' for collisionshape IDs as Richard suggested. A hash table sounds like overkill but hey, maybe it's better in the end!
I also suggest checking out the rest of Emanuele Feronato's excellent site; It is mostly AS3-centered but she does really awesome things with Box2D and explains how she does it really well.
www.emanueleferonato.com/
05/29/2013 (8:19 am)
Just to reinforce Richard's point, Box2D doesn't allow modification of Collision shapes once they are created; the only way to do it is to delete the collision shape and recreate it how you want it. See here for another explanation.
Our limits are based on how Box2D handles things. I suggest we find a standardized way to easily keep track of multiple collision shapes instead of everyone rolling up their own solution. I would favor also a 'wrapper' for collisionshape IDs as Richard suggested. A hash table sounds like overkill but hey, maybe it's better in the end!
I also suggest checking out the rest of Emanuele Feronato's excellent site; It is mostly AS3-centered but she does really awesome things with Box2D and explains how she does it really well.
www.emanueleferonato.com/
#7
05/29/2013 (8:54 am)
Actually, Jonathan suggested the wrapper. I just pointed out that the system is not that hard to use if you step back and take a minute to understand it. Console object IDs are kept in a hash and I think the dictionary is a hash as well, so why not collision shape IDs? It would mean that we no longer have to keep track of our shape indexes if we have need of them - they would be tracked automatically. Assuming there is an automatic mapping of scene object to its collision object set....
#8
@Richard an index is far from being "unique and reliable", consider the following scenario, you attach a dozen sprite to a composite along with a dozen collision shape, you then remove sprite 4 and its collision shape, how are you gonna remove sprite/shape 7 afterward when all of your index are invalidated?
05/29/2013 (3:37 pm)
@Chase, no this is not quite the same exact use case, i know all too well not to modify a box2d shape dimension, what this does is make the id (no longer an index) returned by the create*CollisionShape actually useful.@Richard an index is far from being "unique and reliable", consider the following scenario, you attach a dozen sprite to a composite along with a dozen collision shape, you then remove sprite 4 and its collision shape, how are you gonna remove sprite/shape 7 afterward when all of your index are invalidated?
#9
https://github.com/GarageGames/Torque2D/wiki/Physics-Guide#collision-control
05/29/2013 (4:40 pm)
The scene tracks all collision shapes and removes the sprite and its collision shapes. You don't have to.https://github.com/GarageGames/Torque2D/wiki/Physics-Guide#collision-control
#10
05/29/2013 (4:51 pm)
Dude seriously, you do not even understand the issue, every time i mentioned COMPOSITE SPRITE, go try to do the use case i brought up and see how that work out for you... (hint, you can't because the freaking shape inside the composite have no other mean of access other than a weak index to a vector)
#11
When I get a chance I'll check out your repo and watch it crash - from the tone of that last post I expect it to be spectacular! :)
05/29/2013 (4:56 pm)
Then it is an issue with how COMPOSITE SPRITEs handle their collision shapes - in all other cases they work correctly. I'll take your word for it, I'm not doubting your findings - I'm just saying that for all other types of scene objects they function correctly. Simon has a loose task group looking at composite sprites right now so perhaps they can figure it out.When I get a chance I'll check out your repo and watch it crash - from the tone of that last post I expect it to be spectacular! :)
#12
And sorry to disappoint you about the spectacular crashing, here it is working as expected (the rotating cube made out of 4 smaller cube at the end is a composite sprite, just disregard the badly aligned collision shapes). http://www.youtube.com/watch?v=U5fc2DelwJg
05/29/2013 (5:33 pm)
The issue is how scene object handle their collision shape, it get fixed for the composite for free just by using something more sensible than an index.And sorry to disappoint you about the spectacular crashing, here it is working as expected (the rotating cube made out of 4 smaller cube at the end is a composite sprite, just disregard the badly aligned collision shapes). http://www.youtube.com/watch?v=U5fc2DelwJg
#13
The composite sprite was the last thing out the gate, and if you look at the blogs and discussions it's collision handling was only just nailed down. We all should have expected some bumpiness. As I noted, up until this was added to composite sprites everything worked quite well within Box2D's constraints. I've used them extensively since they were introduced to the engine and I've never had a case where deleting a collision shape invalidated all of the others in other SceneObject-derived objects. I think you're the first person to really exercise this functionality in composite sprites so you get to deal with the frustration first!
I'm also not arguing against your solution - just pointing out that the current system worked well until this particular entity came along. Honestly, I think Melv moved on before he got a chance to thoroughly test this - he's usually quite meticulous.
05/29/2013 (10:41 pm)
No no, I was referring to the original bad handling before your fix.The composite sprite was the last thing out the gate, and if you look at the blogs and discussions it's collision handling was only just nailed down. We all should have expected some bumpiness. As I noted, up until this was added to composite sprites everything worked quite well within Box2D's constraints. I've used them extensively since they were introduced to the engine and I've never had a case where deleting a collision shape invalidated all of the others in other SceneObject-derived objects. I think you're the first person to really exercise this functionality in composite sprites so you get to deal with the frustration first!
I'm also not arguing against your solution - just pointing out that the current system worked well until this particular entity came along. Honestly, I think Melv moved on before he got a chance to thoroughly test this - he's usually quite meticulous.
#14
However you are correct when you say that CompositeSprite wasn't tested as much as it could have been. Case in point, Pull request #69.
@Jonathan : Awesome, your demo looks like FTL meets Minecraft with some resource gathering! Can't wait to see more!
As Richard pointed out, you're the first one to speak up about this issue. Doesn't mean it's not important, but we need to wisely prioritize where our time (I'm speaking of the T2D Steering committee's time) is spent.
If you're up for it, I would suggest rallying a few community members to your cause to figure out the ideal solution to this problem. Not just for solving the bug, but trying to figure out what you'd want CompositeSprite's ideal collision functionality to be.
I've tested the waters last week :
www.garagegames.com/community/blogs/view/22283
And in just a few days, we've managed to fix a really important bug in CompositeSprite :
www.garagegames.com/community/forums/viewthread/134153
Keep us posted on your progress!
05/29/2013 (11:17 pm)
@Richard : As far as I know there isn't a difference between how CompositeSprite handles CollisionShapes vs. how SceneObjects handle them.However you are correct when you say that CompositeSprite wasn't tested as much as it could have been. Case in point, Pull request #69.
@Jonathan : Awesome, your demo looks like FTL meets Minecraft with some resource gathering! Can't wait to see more!
As Richard pointed out, you're the first one to speak up about this issue. Doesn't mean it's not important, but we need to wisely prioritize where our time (I'm speaking of the T2D Steering committee's time) is spent.
If you're up for it, I would suggest rallying a few community members to your cause to figure out the ideal solution to this problem. Not just for solving the bug, but trying to figure out what you'd want CompositeSprite's ideal collision functionality to be.
I've tested the waters last week :
www.garagegames.com/community/blogs/view/22283
And in just a few days, we've managed to fix a really important bug in CompositeSprite :
www.garagegames.com/community/forums/viewthread/134153
Keep us posted on your progress!
#15
I figured out a SIMPLE solution to my original problem of having the collision functions being retriggered when deleting and recreating collision shapes: I put the initial function call in with a schedule command to delay when it starts, so that it automatically falls into the timer loop I was shooting for. Also, making a collision shape a sensor right after re-creating it is easy to do, I just didn't have time to try it before posting yesterday.
I'm guessing if other people find the inability to update a collision shape's size a problem they might be able to find a workaround like I did. :)
05/30/2013 (5:49 am)
I'm just throwing this out there, because it's kind of related, and someone might be searching for an answer to the same problem I mentioned earlier in this thread:I figured out a SIMPLE solution to my original problem of having the collision functions being retriggered when deleting and recreating collision shapes: I put the initial function call in with a schedule command to delay when it starts, so that it automatically falls into the timer loop I was shooting for. Also, making a collision shape a sensor right after re-creating it is easy to do, I just didn't have time to try it before posting yesterday.
I'm guessing if other people find the inability to update a collision shape's size a problem they might be able to find a workaround like I did. :)
#16
05/30/2013 (6:28 am)
@Simon - Apparently, the way that collision shapes are handled is not up to the task presented by the composite sprite - hence the problem Jonathan is trying to solve. I actually still haven't had enough free time this week to really look at this but hopefully I can find a minute to do something more constructive than exacerbate Jonathan's frustration. :)
#17
05/31/2013 (6:57 am)
@Jonathan - Greatly appreciate the contribution. I'll help with reviewing the code this weekend. Do you also have any sample scripts you can provide for a use case? It would help reproduce the work on our end to match what you have accomplished.
#18
@Michael i just save the shape id when creating them using something like:
%id = %composite.addSprite(%x SPC %y);
%this.testGridCollision[%id] = %composite.createPolygonBoxCollisionShape(%dimensionX, %dimensionY, %centroid);
i can them delete them using something like:
%spriteId = getWord(%sprites, %i);
%composite.selectSpriteId(%spriteId);
%composite.deleteCollisionShape(%this.testGridCollision[%spriteId]);
%composite.removeSprite();
05/31/2013 (10:30 am)
@Richard haha, the frustration is gone as soon as i got it to do my bidding ;) no worry.@Michael i just save the shape id when creating them using something like:
%id = %composite.addSprite(%x SPC %y);
%this.testGridCollision[%id] = %composite.createPolygonBoxCollisionShape(%dimensionX, %dimensionY, %centroid);
i can them delete them using something like:
%spriteId = getWord(%sprites, %i);
%composite.selectSpriteId(%spriteId);
%composite.deleteCollisionShape(%this.testGridCollision[%spriteId]);
%composite.removeSprite();
#19
05/31/2013 (10:38 am)
@Jonathan - Thanks! That will be useful.
Associate Simon Love
1. Can you describe the basic scenario in which you use this functionality?
2. While we totally appreciate the quick fix, ideally to submit code changes like this you would use git or github and submit a pull request against the official development branch.
If you have no clue what I'm talking about, take a look at our official wiki on the subject
This way of proceeding has several advantages (...for us, anyways :) :
- We can easily test the change and integrate it rapidly into the official engine. (Assuming the change is multi-platform friendly and is a useful feature).
- Anyone can see at a glance what was changed from the original file. That way if people want to use your fix, they can easily make the change instead of having to read the entire files and figuring out what was changed. This allows devs to merge your fixes easily without breaking their code or overwriting changes they might have made locally to the modified files.