Cocos2d-x 3 - Disable collision between two bodies and detect when them separate each other - cocos2d-x

I'm developing a cocos2d-x game (version 3.8). My game uses chipmunk physics and it has a static body that works like an interruptor. This interruptor is enabled when another body is over it. The interruptor is disabled when bodies separate each other.
I want to:
Moving body don't collision with interruptor. It has to cross interruptor with no bounce
I want to detect when moving body separates the interruptor
My first approach was implementing onContactBegin method. I return false when those two bodies get in touch. This way the body crosses the interruptor and does not bounce.
The problem is onContactSeparate method is not called, because contact did not happen.
If I return true in onContactBegin method, onContactSeparate is called and I can detect it. The problem is the body does not cross the interruptor, it bounces.
[EDIT] More info
This is the scenario where two sprites are separated. The ball can move and interruptor is a static body. Ball could be over the interruptor.
This is the scenario where two sprites are in contact and object1 (the ball) is over the interruptor. I want to detect where two sprites separate each other.
Any help would be appreciated!

It seems to me like you are using Box2D within cocos, so I'll answer with that as my base assumption.
This is what i would do.
My interrupter would be a b2Body* with no BodyDef dimensions defined or just a 0x0 dimension def.
I would set the user data for the bodyDef to a rectangle that describes my interruption area. This way you can always have your interruption area represented, but will not collide with anything.
(Optional) If you want the interruption area to move around based on the fake body you assigned to it, you can updated it just after the step function using something like below.
world->Step(delta, 10, 10);
for (auto physicsBody = _world->GetBodyList(); physicsBody; physicsBody = physicsBody->GetNext())
{
auto userData = static_cast<Node*>(physicsBody->GetUserData());
if(userData != NULL)
{
// Set interruptor area rectangle = physicsBody->GetPosition();
}
}
To let the rest of the system know when I have left the interrupter I would store a function pointer to the function I want to call when this happens, When a object enters the interruption area I would flag it saying "I'm in the area" after that, the first update step you get when it's not in the area anymore I would fire the callback and reset the flags I used to get to that point.
I hope this helps. You are not giving a lot of context for what you want to do, an image would be helpful. Especially when it comes to looking for help with code that has a visual representation as well.
[EDIT]
Based on the behaviour you want this is the way I did this. The first thing to know is that you don't need physics collisions for the behaviour you want. You can do this by using bounding box intersection tests and use flags and callbacks to figure out the rest.
I have an object that knows about both the ball and my interrupter nodes. In the update loop of this object I check if the two intersects. I set a flag indicating "I am in the interrupter", the next frame that I am not in the interrupter and my flag is still true I call the function that I assigned with my "leaving logic" in it, and set then flag back to false.

Related

Collision Detection - Ordering - Which collision goes first?

So I am making a physics engine that only uses rectangles (axis-aligned bounding boxes) as shapes. I have implemented a method from christer ericsons book that returns the collision time and normal of two moving aabbs. I also have made another method that takes two aabbs velocities, positions and a normal that responds to the collision and give the aabbs new velocities.
The actual problem now is is that I don't know how the loop, that checks the collisions between all aabbs and responds to them, should look like. Simply I don't understand how to order the collisions by the time of impact, and which collision I should respond to.
A loop written in pseudo code that shows how to order all collisions would be really helpful.
Another thing I've mentioned is that it's possible thata moving box could bounce between two static boxes hundreds of times in a single frame if it's velocity is really high, how do you handle that?
You should let a simple priority queue take care of the right order of execution. Conceptually, this would end up looking something like this:
queue<CollisionEvent> q = new empty queue
while (!q.isEmpty) {
nextCollision = q.dequeueMinimum
/* run animation until nextCollision.time
...
*/
newMovingParticles = nextCollision.movingParticles
newCollisions = computeCollisionEvents(newMovingParticles, allOtherParticles);
for each event in newCollisions {
q.enqueue(event, event.time);
}
}
What about boxes that move with large velocities: I don't know. Physically, it would make sense to just accept that it can happen that there is a sequence of very frequent collision events. I can not explain why, but for some reason I do not expect any infinite loops or zeno-type-problems. I would rather expect that even frontal collisions of very heavy boxes with very light boxes, where the light box is trapped between the heavy box and the wall, end in finitely many steps. This is what makes the rigid bodies rigid, I think one should just accept this as a feature.

Object changing layer when going between frames?

I have a child of an object that stays on the scene when the frame changes. So I gotoAndStop(2); and the object is still there. However, when I come back to frame one. The object is on the lowest layer, despite the fact that I originally added it using addChildAt(character, 1); I think this adds it to the first layer? Anyone know how I can fix this issue of keeping a movieclip object on the top layer despite changing frames? Thanks.
In AS3/Flash, the bottom most layer is 0. So doing addChildAt(character, 1) would make your character the second to the bottom layer. addChildAt(character, 0) would make it the very bottom/back layer.
If you want to make it the top most layer, you do any one of the following:
addChild(character); //this is the shortest amount of code
addChildAt(character, numChildren-1); //the is exactly the same as above
setChildIndex(character, numChildren-1); //this is also the same but requires the character already be present on the display list
The latter (setChildIndex) may be preferred IF your character originates on the timeline (eg not created through code). The reason being, if you change through code the parentage of something created on the timeline, it will not go away when no longer present on the timeline.
If you want a way to force something to always be on top, you can do something along these lines:
this.addEventListener(Event.ADDED, bringToTop);
function bringToTop(e:Event):void {
setChildIndex(character, numChildren-1);
}
Doing that, makes it so whenever any other object is added as a child of this, it will set the character to the very top most layer/z-index.

cocos2dx - sub layer that covers its parent partially keep capturing all touches

In my cocos2dx game, I have a CCLayer that contains another CCLayer. The sublayer just cover part of the container layer. I 'think' I achieve this through:
this->setContentSize( CCSizeMake( 100, 200 ) );
however, the sublayer always capture touches even though it is outside its size and position area... Is it common?
I can filter through the touches position by comparing it inside the ccTouch** functions, but I think it is a hack, what is the proper way to set the sublayer to properly cover just the partial area of its parent?
The only thing i can think of straight away is making this inner layer a CCNODE and also extent it with CCTouchDelegate.
Now with this, when u register with the TouchDispatcher, you make sure it doesn't Swallowtouches(the boolean value given as the last parameter)...
This way when you receive a touch ... just see if it is within the boundary of this inner layer of urs and if it is not, send let the parent class use this touch.
Hope this helps.

Creating a nicely coded level select screen

Currently developing my first full flash game, and I'm now implementing multiple levels, which means I have to make a level select screen. I have no problem with actually accomplishing this, but the only way I know how to do this would be to make a different level select screen available every time somebody passed a new level (ie, after passing level 2, now there are 2 buttons available, for level 1 and 2 instead of just level 1).
Of course, this is highly inefficient. I want to be able to do this for all my levels in one go. I already know in advance that I will be having 9 levels, so a 3x3 grid system of buttons is possible (maybe using 2 for loops, for x and y position?).
Navigating between level select and other pages is no problem, I should be able to do that. My real problem is creating the actual level select screen to display different amounts of clickable buttons depending on how far one has progressed in the game. I mean I'm guessing I just create some boolean values for the user, and once a level is passed I change those booleans to true, then link the boolean to creating a button instead of a static text field. Then would I just position each button individually on the level select screen? If somebody could shed some light ( and by light I mean code =p ) about how to accomplish making this type of level select screen, it would be greatly appreciated, particularly the part about adding the buttons to the stage vs. the textfields.
Also, is it a waste to create 9 different buttons? It would be nice to just create 1 button and then just change the text field on them to display the level number. Can I accomplish this using a dynamic text field and just altering the text in that text field?
Basically yes, you can do whatever you see fit, just prepare for all of this. This is mostly architecture question than actual programming question. About progress, you can either track the highest available level and only display those that are available, or display level progress (say one level was complete with 1 star, the other with 2 stars, and you make buttons with stars on them), etc. Also, you might look at say Angry Birds level selector, it has 15 buttons, why could you not make 9?
About how to add a custom button to stage - first, it's better if you wrap the whole level selector into a Sprite, write AS3 code for it having level buttons placed at specific coordinates, a close button (aka "no I want to review other options before selecting level" one), other data like a text field with level name, etc etc, whatever you see fit. An example (with only level buttons, mostly in pseudocode):
public class LevelSelector extends Sprite {
private static const thumbnailClasses:Array=[Level01Bitmap,Level02Bitmap,...];
// embed these
private var gridXOffset:Number=60;
private var gridYOffset:Number=60;
private var gridXDimension:int=3; // how many buttons in row
private var gridXBase:Number=30;
private var gridYBase:Number=10;
// other initialized data
private var buttons:Vector.<LevelButton>; // buttons stored here
public function LevelSelector() {
buttons=new Vector.<LevelButton>();
// other initialization
for (var i:int=0;i<thumbnailClasses.length;i++) {
var b:LevelButton=new LevelButton();
b.x=(i%gridXDimension)*gridXOffset+gridXBase;
b.y=Math.floor(i/gridXDimension)*gridYOffset+gridYBase;
b.picture=(new thumbnailClasses[i]()).bitmapData;
// assuming thumbnails are embedded bitmap class names
addChild(b);
b.enabled=levelIsAvailable(i); // query level availability
b.stars=getLevelPerformance(i); // query how many stars to draw
b.addEventListener(MouseEvent.CLICK,buttonPressed); // listen for mouse
buttons.push(b);
}
}
private function buttonPressed(e:MouseEvent):void {
var level:int=buttons.indexOf(e.target);
var b:LevelButton=e.target; // if need to do something with the button
// query correctness and navigate to level screen
}
}
It sounds like you need to break the problem down into smaller steps. I'm not sure if you're using the Flash timeline or external .as Classes. I'd recommend using Classes as you can be much more flexible about what you display on screen. If you're not used to using Classes, the following probably won't make much sense...
In your main Document.as Class you could keep track of which levels the player has completed (perhaps in an Array of Boolean values corresponding to the level numbers). When a LevelSelect page is needed, make a new LevelSelect page and pass the _levelsCompleted Array as a parameter. The passed array can be used by the LevelSelect Class instance to determine how many LevelButtons are needed. Loop through the passed Boolean array and if an index value is true, add a LevelButton. Each LevelButton could be passed its level number (the loop counter) which could be used in its TextField to identify it (remember Array indexes are zero indexed, so level '1' might actually be '0').
If this doesn't make any sense, let me know.

nested collision starling as3

I am using starling and tweenMax frameworks in my project.
The trouble I am running into is this:
For the purpose of animating along different paths, I am using tweenmax.
There is one _leaderEnemy that animates along a path and I am pushing several other _shooterEnemy (they are of the same class) into it.
public function createEnemies(enemyNo:int, path:Array, offset:int):void
{
for(var i:uint=1;i<=enemyNo;i++){
if (i==1){
_leaderCount++;
_leaderEnemy = new ShooterEnemy();
_leaderEnemy.x=600;
_leaderEnemy.y=300;
_leaderEnemy.name="_shooterEnemy"+_leaderCount;
this.addChild(_leaderEnemy);
leaderEnemyArray.push(_leaderEnemy);
}
else
{
_leaderCount++;
_shooterEnemy= new ShooterEnemy();
_shooterEnemy.x=0;
_shooterEnemy.y=(offset*(i-1));
_shooterEnemy.name="_shooterEnemy"+_leaderCount;
trace("no: "+_shooterEnemy.name);
leaderEnemyArray.push(_shooterEnemy);
_leaderEnemy.addChild(_shooterEnemy);
}
}
Now I want to check for collision using starling between each of the _leaderEnemy and the _shooterEnemy inside it with _shooterHero.
Running this array successfully checks collision with the whole group i.e. _leaderEnemy but not the individual ones inside it.
Technically, I should be able to do this just by:
var Track:Object;
for(var i:uint=0;i<leaderEnemyArray.length;i++) {
Track=leaderEnemyArray[i];
if (Track.bounds.intersects(_shooterHero.bounds)){
Track.rotation=deg2rad(70);
}
}
It may be something stupid I am doing. But I have not been able to solve this.
Any help on this would be appreciated.
Some other questions I have:
Can I check for collision with _shooterHero from inside the _shooterEnemy's class?
I have tried:
if (this.bounds.intersects(stage.getChildByName("_hero"))){
}
although it did not work.
Can I check for collision of one Enemy with everything on stage, so I can assign individual functions for his each contact?
For example: hit with hero: die; hit with another enemy: turn around
If you need more info, I will be happy to provide it.
Thank You.
Can I check for collision of one Enemy with everything on stage, so I can assign individual functions for his each contact? For example: hit with hero: die; hit with another enemy: turn around
Of course you can. You should! This is approximatively how collision engines works.
Running this array successfully checks collision with the whole group i.e. _leaderEnemy but not the individual ones inside it.
Nope. It won't work. Because the bounds property use the parent coordinates.
Meaning you can intersect each child display (of same container) with each other.
But you shouldn't intersect a child display of A with a child display of B.
Except if you convert every bounds coordinates (which are local) to global.
http://doc.starling-framework.org/core/starling/display/DisplayObject.html#localToGlobal()
Using Track.bounds.intersects is one way of checking collosions. Another would be to use hitTest method of starling.displayDisplayObject
You could also check the distance of your hero and other enemies calculated by a pythagorean theorem type calculation.
Are you checking enemies against each other? If you have many enemies you might want to look into "flocking" algorithms. Keith Petes covers this subject nicely in his book Advanced Actionscript Animation.