Collision detection Objective-C (cocos2d) - objective-c

I´m making an iphone app in objective-c with cocos2d, in the code below I try to detect a collision and then run an animation. (The box1 is moved by touch)
When the "[self getChildByTag:d]" and "box1" collide AND overlap I get the "JUMP NOW!" displayed but I don't get the jump itself, but when the box1 is moved away from the "[self getChildByTag:d]" the jump occurs.
I understand that this probably has to do with the fact that the action is called many times, but please explain to me exactly what happens and please help me with a solution!
- (void)update:(ccTime)dt {
for (int d = lowestAvailableTag; d <= highestAvailableTag; d++) {
if ([self getChildByTag:d].position.y < (box1.position.y+45)&&
[self getChildByTag:d].position.x > (box1.position.x-45) &&
[self getChildByTag:d].position.x < (box1.position.x+45) ) {
NSLog(#"JUMP NOW!");
if ([self getChildByTag:d].position.x < 150) {
[[self getChildByTag:d] runAction:
[CCJumpTo actionWithDuration:1.5
position:ccp(240, 140) height:110 jumps:1]];
}
}
}
}
//albar

You can add some BOOL flag to detect if your jump occured. Smth like:
- (void) update:(ccTime)dt
{
if( jumpOccured == false )
{
BOOL needToJump = // your jump condition
if( needToJump == true )
{
// your jump code
jumpOccured = true;
}
}
}
by the way, if you have many possible collisions, you can use box2d to detect them

Related

SpriteKit Detect End of Contact After Detecting Begin of Contact

This is what I try to accomplish:
Two sprite nodes in the scene, and self is an edge loop.
If nodeA touches nobeB, and stop. >> Win
If nodeA touches self. >> Lose
If nodeA touches nobeB but didn't stop and touches self. >> Lose
Therefore I need something that works like this:
typedef NS_OPTIONS(aero, SpriteNodeCategory)
{
SpriteNodeCategoryA = 1 << 0,
SpriteNodeCategoryB = 1 << 1,
};
-(void)didBeginContact:(SKPhysicsContact *)contact
{
aero collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (SpriteNodeCategoryA|SpriteNodeCategoryB)) {
//something here I don't know...
}
if (collision == (SpriteNodeCategoryA|SpriteNodeCategoryB)) {
NSLog(#"FAIL");
}
}
You have another method delegate (SKPhysicsContactDelegate) which do the job you asking about:
- (void)didEndContact:(SKPhysicsContact *)contact
Okay so this is going to be a little difficult.
First of, you can use "didSimulatePhysics" to get the update of your simulation
-(void)didSimulatePhysics
{
if (_yourNode.physicsBody.angularVelocity == 0 && newGame) {
if (_yourNode.userData[#"winningCondition"]) {
[self win];
};
}
}
this does is that it updates and see if you have a winning condition - which is gotten from collision (think: reverse engineering)
P.S. _yourNode.physicsBody.angularVelocity == 0 meaning your node is completely still
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (CNPhysicsCategoryNodeA|CNPhysicsCategoryNodeB)) {
_yourNode.userData = [#{#"winningCondition":#(YES)} mutableCopy];
}
if (collision == (CNPhysicsCategoryNodeA|CNPhysicsCategoryEdge)) {
[self lose];
}
}
-(void)didEndContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (CNPhysicsCategoryNodeA|CNPhysicsCategoryNodeB)) {
_yourNode.userData = [#{#"winningCondition":#(NO)} mutableCopy];
}
}
So basically when A touches B, it gives you a winning condition through adding a "userData" to your node.
The rest is pretty straight forward. I think you get it.

For loop in Sprite Kit seems to be emptying an array?

I'm just starting to wrap my brain around Sprite Kit and I am encountering a very strange error when attempting to change the property of a node in a for loop im using.
I have two SKSpriteNode objects, one is the child of a SKScene (BLATheBugs) and the other is a child of the first (BLAEmptySpaces). I have a grid laid out with BLAEmptySpaces, and BLATheBugs on top of those empty spaces which are supposed to take UITouch, and move to an empty space if its bool isOccpupied property == False. When the scene is set up, the SKScene triggers a method in TheBugs:
-(void) spawnEmptySpacesInitialize
{
[self addChild:[self spawnEmptySpaces]];
}
which in turn triggers:
-(BLAEmptySpaces *) spawnEmptySpaces
{
emptySpace = [[BLAEmptySpaces alloc] init];
emptySpace.numberOfEmptySpacesNeeded = 12;
[emptySpace spawnEmptySpaces];
[emptySpace positionTheEmptySpaces];
return emptySpace;
}
which finally triggers a method in the EmptySpaces object:
-(BLAEmptySpaces *) spawnEmptySpaces
{
_emptySpacesArray = [NSMutableArray new];
for (int x = 0; x < _numberOfEmptySpacesNeeded; x++)
{
_anEmptySpace = [[BLAEmptySpaces alloc] initWithImageNamed:#"BlueLight.png"];
_anEmptySpace.zPosition = 50;
[_emptySpacesArray addObject:_anEmptySpace];
[self addChild: _anEmptySpace];
}
return self;
}
everything seems fine, (except for needing the additional "addChild" in the EmptySpaces object to get them to be drawn on the screen which i have also been trying to fix) but when i call the method to move TheBugs:
-(void) moveLeftOneSpace
{
NSLog(#"%d", emptySpace.emptySpacesArray.count);
for (emptySpace in emptySpace.emptySpacesArray)
{
NSLog(#"cycle");
if (emptySpace.isOccupied == NO)
{
for (_yellowBug in yellowBugArray)
{
if (_positionOfFingerTouchX > _yellowBug.position.x - variableOne && _positionOfFingerTouchX < _yellowBug.position.x + variableTwo && _positionOfFingerTouchY > _yellowBug.position.y - variableOne && _positionOfFingerTouchY < _yellowBug.position.y + variableTwo && emptySpace.position.x == _yellowBug.position.x - 80 && emptySpace.position.y == _yellowBug.position.y)
{
_yellowBug.position = CGPointMake(_yellowBug.position.x - spaceBetweenBugs, _yellowBug.position.y);
emptySpace.isOccupied = YES;
NSLog(#"execute");
}
}
}
}
}
It at first tells me there are 12 objects in the array and runs the operation. if I try to move any piece again, it tells me there are now NO objects in the array (yellowBugArray). It is also probably worth noting that it will not let me access emptySpace.anEmptySpace. Throws me an error.
Sorry for the long post, but hopefully somewhere in here is the cause of my problem.
Thank you very much guys!

Getting two images to appear in random sequence iOS

I am new to the community, so let me know if my question is unclear. I am trying to make a choice reaction exercise on the iPAD. There are two images that should appear in random sequence on the left and right of the screen, and the user will respond by tapping a button that corresponds to the position of the appeared image. Here's the problem, I tried to get the two images to appear at random order using the following way:
- (void) viewDidAppear:(BOOL)animated
{
for(int n = 1; n <= 20; n = n + 1)
{
int r = arc4random() % 2;
NSLog(#"%i", r);
if(r==1)
{
[self greenCircleAppear:nil finished:nil context: nil];
}
else
{
[self redCircleAppear:nil finished:nil context: nil];
}
}
}
However, 20 random numbers get generated while only 1 set of animation is run. Is there a way to let the animation finish running in each loop before the next loop begins? Any help is appreciated, thanks in advance!
When you say "only one set of animation is run" I'm assuming that means greenCircleAppear and redCircleAppear begin the sequence of images appearing and the user pressing a button. If that's the case, I'd recommend not using a for loop in viewDidAppear but instead have viewDidAppear initialize the current state and call a method that presents the next animation. When the animation is finished, have it call the method that presents the next animation. Something along these lines:
Add this to the interface:
#interface ViewController ()
#property NSInteger currentIteration;
#end
This is in the implementation:
- (void)viewDidAppear:(BOOL)animated {
self.currentIteration = 0;
[self showNextAnimation];
}
- (void)greenCircleAppear:(id)arg1 finished:(id)arg2 context:(id)arg3 {
//perform animation
NSLog(#"green");
[self showNextAnimation];
}
- (void)redCircleAppear:(id)arg1 finished:(id)arg2 context:(id)arg3 {
//perform animation
NSLog(#"red");
[self showNextAnimation];
}
- (void)showNextAnimation {
self.currentIteration = self.currentIteration + 1;
if (self.currentIteration <= 20) { //you should replace '20' with a constant
int r = arc4random() % 2;
NSLog(#"%i", r);
if(r==1)
{
[self greenCircleAppear:nil finished:nil context: nil];
}
else
{
[self redCircleAppear:nil finished:nil context: nil];
}
}
else {
//do what needs to be done after the last animation
}
}

Simple Cocos2d Box2d Action On Collision

I have been looking for weeks for an OBJ-C based tutorial on how to call a method when a specific b2body collides with something else (not everything).
Basically, a block falls to the ground every second. This works fine, but when it hits the ground or the player, the block should get deleted and pieces of it (different object) should be spawned.
Can anyone tell me how to do this?
Any help would be hot
Thanks
I think this is the one that you need..You need to include MycontactListener
-(void) checkForHit{
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
bodyA = contact.fixtureA->GetBody();
bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
spriteA = (CCSprite *) bodyA->GetUserData();
spriteB = (CCSprite *) bodyB->GetUserData();
//NSLog(#”sprite tag is %d”,spriteA.tag);
if (spriteA.tag == 50) {
if (std::find(toDestroy.begin(), toDestroy.end(), bodyB) == toDestroy.end()) {
toDestroy.push_back(bodyB);
}
}
std::vector<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
b2Body *body = *pos2;
if (body->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *) body->GetUserData();
[self removeChild:sprite cleanup:YES];
}
_world->DestroyBody(body);
}
or if you dont't want to use contact listener.you can create a fixture for ground body and a body that u want to destroy and use the following code to check if it is intersecting and destroy it...
if((contact.fixtureA == groundFixture && contact.fixtureB == bodyFixture) ||
(contact.fixtureA == bodyFixture&& contact.fixtureB == groundFixture ))
{
//destroy the body
}
I have realized that as my object fall to the ground, i could create my own VERY simple physics by creating a start velocity, and then increasing it in the update method by a specific amount.
For the collision, my objects all fit in a 48pt wide grid so i could do simple rectangular collision detection.

creating a loop with multiple sprites?

i've got a column of sprites as one sprite goes off the screen i want the same sprite to wrap around the opposite side so that two sprites are showing simultaneously, as one moves of the screen the other comes onto the screen and the other sprite that goes off is no longer visible. I was told to make a ccnode in which to do everything here is my code so far, but none of it works so i think i will need to start from scratch again.
Here is a link to my last question on this for more info: When sliding sprite, if sprite disappears off the side, it will wrap around to the opposite side?
here is my code anyways:
for (int i =0; i<16; ++i) {
MyNode *currentSprite = [c1array objectAtIndex:i];
if (currentSprite.contentSize.height>=320 || currentSprite.position.y-currentSprite.contentSize.height/2<=0 ){
MyNode *Bsprite = currentSprite;
MyNode *Tsprite = currentSprite;
Bsprite.scale = 1.0;
Tsprite.scale = 1.0;
if(currentSprite.position.y >=253){
Bsprite.position = ccp(currentSprite.position.x,-35);
[self addChild:Bsprite];
Bsprite.visible = TRUE;
}
if (currentSprite.position.y <=0) {
Tsprite.position = ccp(currentSprite.position.x,324);
[self addChild:Tsprite];
Tsprite.visible = TRUE;
}
MyNode *isChanging;
if ((Tsprite.visible == TRUE && currentSprite.visible == TRUE) || (Bsprite.visible == TRUE && currentSprite.visible == TRUE)) {
isChanging = TRUE;
}
if (isChanging == FALSE) {
[self removeChild:Tsprite cleanup:YES];
[self removeChild:Bsprite cleanup:YES];
}
}
}
BSprite and TSprite are pointers to the same object (currentSprite). You actually need two separate objects, either by cloning currentSprite or by creating another array in the same manner as c1array.