CCPhysicsBody Collision not working in cocos2d-swift v3.4 - iphone

Here is code:
#interface MainScene : CCNode<CCPhysicsCollisionDelegate>
//.m
-(void)onEnter
{
[super onEnter];
mPhysicsWorld = [CCPhysicsNode node];
mPhysicsWorld.gravity = ccp(0,0);
mPhysicsWorld.debugDraw = YES;
mPhysicsWorld.collisionDelegate = self;
[self addChild:mPhysicsWorld];
//Body_A
{
CCSprite *sprite = [CCSprite spriteWithImageNamed:#"sprite_1.png"];
sprite.position = ccp(280, 220);
sprite.rotation = 13;
sprite.name = #"Body_A";
sprite.physicsBody.collisionGroup=#"Group1";
sprite.physicsBody.collisionType=#"typeA";
CGRect rect = {CGPointZero, sprite.contentSize};
CCPhysicsBody *body = sprite.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
body.velocity = ccp(1000, 2000);
body.angularVelocity = 1.0;
body.type = CCPhysicsBodyTypeDynamic;
[mPhysicsWorld addChild:sprite];
}
//Body_B
{
CCSprite *sprite = [CCSprite spriteWithImageNamed:#"sprite_2.png"];
sprite.position = ccp(380, 220);
sprite.rotation = 13;
sprite.name = #"Body_B";
sprite.physicsBody.collisionGroup=#"Group2";
sprite.physicsBody.collisionType=#"typeB";
CGSize size = sprite.contentSize;
CGPoint points[] = {
ccp(0, 0),
ccp(size.width, 0),
ccp(size.width/2, size.height),
};
CCPhysicsBody *body = sprite.physicsBody = [CCPhysicsBody bodyWithPolygonFromPoints:points count:3 cornerRadius:0.0];
body.velocity = ccp(1000, -1000);
body.angularVelocity = -1.0;
body.type = CCPhysicsBodyTypeDynamic;
[mPhysicsWorld addChild:sprite];
}
//Delegate method
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair typeA:(CCNode *)nodeA typeB:(CCNode *)nodeB
{
printf("Function Called\n"); //control not coming here
if([nodeA.name isEqualToString:#"Body_A"] && [nodeB.name isEqualToString:#"Body_B"])
{
return YES;
}
return NO;
}
Similar Question: Already tried this similar post but didn't get solution.

you are probably going to 'palm-forehead' , took me a while too :(
For both body A and body B the two lines below
sprite.physicsBody.collisionGroup=#"Group1";
sprite.physicsBody.collisionType=#"typeA";
are executed while physicsBody is still nil. Move the lines under the line :
CCPhysicsBody *body = sprite.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
ob cit. tested and verified, works on sim and device. Good luck with your project.

Related

didBeginContact entering too early

I am trying to stick a ball to a spinner when they collide at the contact point. However, it seems as though the didBeginContact is being called before the contact starts. Image is below showing them both spinning together but there is a big space.
Code is below:
#import "GameScene.h"
#implementation GameScene
#synthesize _flowIsON;
NSString *const kFlowTypeRed = #"RED_FLOW_PARTICLE";
const float kRED_DELAY_BETWEEN_PARTICLE_DROP = 0.01; //delay for particle drop in seconds
static const uint32_t kRedParticleCategory = 0x1 << 0;
static const uint32_t kSpinnnerCategory = 0x1 << 1;
NSString *const kStartBtn = #"START_BTN";
NSString *const kLever = #"Lever";
NSString *const START_BTN_TEXT = #"Start Game";
CFTimeInterval lastTime;
-(void)didMoveToView:(SKView *)view {
_bkgNode = (SKSpriteNode *)[self.scene childNodeWithName:#"Background"];
[self initializeScene];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode: self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:kStartBtn]) {
[node removeFromParent];
//initalize to ON
_flowIsON = YES;
//[self initializeScene];
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(void)update:(CFTimeInterval)currentTime {
float deltaTimeInSeconds = currentTime - lastTime;
//NSLog(#"Time is %f and flow is %d",deltaTimeInSeconds, _flowIsON);
if ((deltaTimeInSeconds > kRED_DELAY_BETWEEN_PARTICLE_DROP)) {
//TBD
SKAction *rotation = [SKAction rotateByAngle: M_PI/8.0 duration:0];
[_spinner runAction:rotation];
//only if its been past 1 second do we set the lasttime to the current time
lastTime = currentTime;
}
}
- (void) initializeScene {
self.physicsWorld.contactDelegate = self;
//create ball
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"Ball"];
ball.size = CGSizeMake(50, 50);
ball.position = CGPointMake(320, 1050);
ball.zPosition = 1;
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:25];
ball.physicsBody.restitution = 0.0;
ball.physicsBody.categoryBitMask = kRedParticleCategory;
ball.physicsBody.contactTestBitMask = kSpinnnerCategory;
ball.physicsBody.collisionBitMask = kSpinnnerCategory;
ball.name = #"Ball";
NSLog(#"Ball size is %f",ball.size.width);
[self addChild:ball];
//Create spinner
_spinner = [SKSpriteNode spriteNodeWithImageNamed:#"Spinner"];
_spinner.size = CGSizeMake(300, 300);
_spinner.position = CGPointMake(320, 500);
_spinner.zPosition = 1;
_spinner.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:150];
_spinner.physicsBody.affectedByGravity = NO;
_spinner.physicsBody.allowsRotation = YES;
_spinner.physicsBody.dynamic = NO;
_spinner.physicsBody.restitution = 0.0;
_spinner.physicsBody.categoryBitMask = kSpinnnerCategory;
_spinner.physicsBody.contactTestBitMask = kRedParticleCategory;
_spinner.physicsBody.collisionBitMask = kRedParticleCategory;
_spinner.name = #"Spinner";
[self addChild:_spinner];
//create pipe
// CGPoint center = CGPointMake(400, 600) ;
//
// UIBezierPath *bezierPath = [UIBezierPath bezierPath];
// [bezierPath addArcWithCenter:center radius:400 startAngle:1.825777 endAngle:2.011118 clockwise:YES];
// [bezierPath addLineToPoint:center];
// [bezierPath closePath];
//
// SKShapeNode *shapeNode = [SKShapeNode shapeNodeWithPath:bezierPath.CGPath];
// shapeNode.strokeColor = [UIColor whiteColor];
// shapeNode.fillColor = [UIColor whiteColor];
// [self addChild:shapeNode];
}
# pragma mark -- SKPhysicsContactDelegate Methods
- (void)didBeginContact:(SKPhysicsContact *) contact {
if ([contact.bodyA.node.name isEqualToString:#"Ball"] && [contact.bodyB.node.name isEqualToString:#"Spinner"]) {
[self connectNode1:(SKSpriteNode *)contact.bodyA.node toNode2:(SKSpriteNode *)contact.bodyB.node withContact:contact];
}
}
- (void)didEndContact:(SKPhysicsContact *) contact {
//NSLog(#"didEndContact called");
}
- (void) connectNode1:(SKSpriteNode *)node1 toNode2:(SKSpriteNode *)node2 withContact: (SKPhysicsContact *)contact
{
SKPhysicsJointFixed *joint = [SKPhysicsJointFixed jointWithBodyA:node1.physicsBody
bodyB:node2.physicsBody
anchor:node2.position];
[self.physicsWorld addJoint:joint];
}
#end
If I comment out the did begin contact method you can see the images are correctly sized becuase when they collide they rest on each other perfectly.
How come the contact.contactPoint is not the same as the point at which both bodys are colliding when I comment out the didEnterContact method? Any idea how to fix?
'didBeginContact' is not called too early.. the problem is that actions are evaluated earlier in the scene cycle: first 'didEvaluateActions()' then 'didSimulatePhysics()'. So, even though your SKactions may look correct, there comes a physics evaluation afterwards.. I suggest not to use actions to make rotation corrections when working with the physics engine.. Perhaps use constraints, those come after the physics update..

Stop node rotation in Sprite Kit

I can't figure out how to stop node from rotating.
Why allowsRotation isn't disabling it?
Here's how I describe my node:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture:[self.spriteAtlas textureNamed:#"test"]];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = NO;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
badguy.physicsBody.velocity = CGVectorMake(0, 0);
badguy.physicsBody.categoryBitMask = CollisionTypeEnemy;
badguy.physicsBody.contactTestBitMask = CollisionTypePlayer | CollisionTypeWall | CollisionTypeEnemy;
badguy.physicsBody.collisionBitMask = CollisionTypeWall | CollisionTypePlayer | CollisionTypeEnemy;
badguy.physicsBody.mass = 10000;
badguy.physicsBody.restitution = 0;
badguy.physicsBody.dynamic = YES;
badguy.zPosition = 10;
On Update I call this method:
-(void)enemiesFollow
{
[self.world enumerateChildNodesWithName:#"badGuy" usingBlock:^(SKNode * _Nonnull badGuyNode, BOOL * _Nonnull stop) {
if((SDistanceBetweenPoints(self.player.position, badGuyNode.position) < 100)&&
(SDistanceBetweenPoints(self.player.position, badGuyNode.position) > 32))
{
SKAction * actionMove = [SKAction moveTo:self.player.position duration:2.0];
[badGuyNode runAction:actionMove];
}else{
[badGuyNode removeAllActions];
}
}];
}
Thanks to Skyler Lauren's suggestion, I am pretty much sure that the problem is in these lines:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture:[self.spriteAtlas textureNamed:#"test"]];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = NO;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
The point is that you can't set properties of a physics body before you create an actual body. So, just move those lines after you create a physics body and you will be good, like this:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(32,32)];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = YES;

Infinite scrolling on a sprite(Parallax)

I am a newbie to the world of cocos2d i am developing my first tutorial and facing one problem
my problem is i have an image (1024 X 320) and my orientation is landscape i need to move that image continuously from right to left for this purpose i have used space shooter tutorial by Ray(Thanks to him) but the image doesn't seem to be appearing again and again.
my code is..
-(id) init
{
if( (self=[super init])) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
// 1) Create the CCParallaxNode
backgroundNode = [CCParallaxNode node];
[self addChild:backgroundNode z:-1];
// 2) Create the sprites we'll add to the CCParallaxNode
Back = [CCSprite spriteWithFile:#"bg_front_spacedust.png"];
//Back.position=ccp(screenSize.width/2, screenSize.height/2);
Back.rotation = -90;
Back1 = [CCSprite spriteWithFile:#"bg_front_spacedust.png"];
Back1.rotation = -90;
// 3) Determine relative movement speeds for space dust and background
CGPoint dustSpeed = ccp(0.1, 0.1);
// 4) Add children to CCParallaxNode
[backgroundNode addChild:Back z:0 parallaxRatio:dustSpeed positionOffset:ccp(screenSize.width/2, screenSize.height/2)];
NSLog(#"back.content width is...%f",Back.contentSize.width);
[backgroundNode addChild:Back1 z:1 parallaxRatio:dustSpeed positionOffset:ccp(screenSize.width/2, screenSize.height*2)];
// 5) Enable updates
[self scheduleUpdate];
}
return self;
}
- (void)update:(ccTime)dt {
// 1) Update background position
CGPoint backgroundScrollVel = ccp(0,-1000);
backgroundNode.position = ccpAdd(backgroundNode.position, ccpMult(backgroundScrollVel, dt));
// 2) Check for background elements moving offscreen
NSArray *spaceDusts = [NSArray arrayWithObjects:Back, Back1, nil];
for (CCSprite *spaceDust in spaceDusts) {
if ([backgroundNode convertToWorldSpace:spaceDust.position].x < -spaceDust.contentSize.width) {
[backgroundNode incrementOffset:ccp(2*spaceDust.contentSize.width,0) forChild:spaceDust];
}
}
}
please help me out of this
Thanks in advance.
try this one
if (backgroundNode.position.y <-screenSize.height*2)
backgroundNode.position = ccp(0,0);
As init method is called only once the approach you are doing will be done only one time you need to again set the Position of the backgroundNode to 0 in your update method.
here the multiple may vary
Try this code it is creating a paralax moving from bottom to top change CGPointMake(0, 1.0) to this CGPointMake(1.0,0) in paraNode addChild line.
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) )
{
float yPos =0.0;
NSMutableString *fileNameString = [[NSMutableString alloc]initWithCapacity:0];
if (IS_IPHONE_5)
{
[fileNameString appendString:#"Background-568h.png"];
yPos= 560.0;
}
else
{
[fileNameString appendString:#"Background.png"];
yPos= 470.0;
}
background1 = [CCSprite spriteWithFile:fileNameString];
background1.tag = 1;
background1.anchorPoint = CGPointMake(0,0);
background2 = [CCSprite spriteWithFile:fileNameString];
background2.tag = 2;
background2.anchorPoint = CGPointMake(0,0);
background3 = [CCSprite spriteWithFile:fileNameString];
background3.tag = 3;
background3.anchorPoint = CGPointMake(0,0);
background4 = [CCSprite spriteWithFile:fileNameString];
background4.tag = 4;
background4.anchorPoint = CGPointMake(0,0);
paraNode = [CCParallaxNode node];
[paraNode addChild:background1 z:1 parallaxRatio:CGPointMake(0, 1.0) positionOffset:CGPointMake(0, 0)];
[paraNode addChild:background2 z:2 parallaxRatio:CGPointMake(0, 1.0) positionOffset:CGPointMake(0, -yPos)];
[paraNode addChild:background3 z:3 parallaxRatio:CGPointMake(0, 1.0) positionOffset:CGPointMake(0, -yPos*2)];
[paraNode addChild:background4 z:4 parallaxRatio:CGPointMake(0, 1.0) positionOffset:CGPointMake(0, -yPos*3)];
[self addChild:paraNode z:-1 tag:123];
[self updateFrameRate:0.7 andYposition:yPos];
[fileNameString release];
fileNameString = nil;
}
return self;
}
-(void)updateFrameRate:(float)speedValue andYposition:(float)yposToSet
{
move1 = [CCMoveBy actionWithDuration:speedValue position:CGPointMake(0, yposToSet)];
move2 = [CCMoveBy actionWithDuration:0.0 position:CGPointMake(0, -yposToSet)];
move3 = [CCMoveBy actionWithDuration:0.0 position:CGPointMake(0, 0)];
CCSequence* sequence = [CCSequence actions:move1,move2,move3, nil];
CCRepeatForever* repeat = [CCRepeatForever actionWithAction:sequence];
[paraNode runAction:repeat];
}

CCSprite overrite on scene cocos2d-iPhone

My App is generating sceenshoot of my game.and when i scale up my sceenshoot(CCSprite), other controls like CCMenu doesn't work.I guess CCSprite(screeenshoot) overrite on my scene.
How to control my CCMenu while CCSprite Scales Down. ?!
here is my code
- (void) showGameOver
{
CCDirector *director = [CCDirector sharedDirector];
appDelegate.screenshootimage = [director screenshotUIImage];
imgsprite = [CCSprite spriteWithCGImage:appDelegate.screenshootimage.CGImage key:#"spriteKey"];
if(flagRescale == false)
{
imgsprite.scaleX = 0.40;
imgsprite.scaleY = 0.40;
flagRescale = true;
}
CCMenuItemImage *image = [CCMenuItemSprite itemFromNormalSprite:imgsprite selectedSprite:nil target:self selector:#selector(imgAction)];
image.position = ccp(40, 50);
imageMenu = [CCMenu menuWithItems:image, nil];
[self addChild:imageMenu];
menu_.visible = true;
menu_.position = ccp(windowCenter_.x, windowCenter_.y - 70);
lblGameOver.visible = true;
lblGameOver.position = ccp(windowCenter_.x, windowCenter_.y + 50);
[[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
}
-(void)imgAction
{
if(flagRescale == TRUE)
{
imgsprite.scaleX = 0.7;
imgsprite.scaleY = 0.7;
flagRescale=false;
}
else
{
imgsprite.scaleX = 0.4;
imgsprite.scaleY = 0.4;
flagRescale=true;
}
}

cocos2d: How do I Control a scrolling map

I made my map to scroll automatically however I would like to know how can I slow down the scrolling before the map reaches the end and when it does I would like the map to stop scrolling. I want to know how to do this because my game is about the player trying to shoot the enemy before he reaches the end of the map where there is shelter for him to hide. I would like that before the enemy reaches the shelter have the scrolling slow down and when the enemy reaches the shelter I would like the map to stop scrolling.
Here is the code:
#implementation GameplayScrollingLayer
// Scrolling with TileMap Layers inside of a Parallax Node
-(void)addScrollingBackgroundWithTileMapInsideParallax {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CGSize levelSize = [[GameManager sharedGameManager]
getDimensionsOfCurrentScene];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
tileMapNode = [CCTMXTiledMap
tiledMapWithTMXFile:#"Level2TileMap.tmx"];
} else {
tileMapNode = [CCTMXTiledMap
tiledMapWithTMXFile:#"Level2TileMapiPhone.tmx"];
}
CCTMXLayer *groundLayer = [tileMapNode layerNamed:#"GroundLayer"];
CCTMXLayer *rockColumnsLayer = [tileMapNode
layerNamed:#"RockColumnsLayer"];
CCTMXLayer *rockBoulderLayer = [tileMapNode
layerNamed:#"RockBoulderLayer"];
parallaxNode = [CCParallaxNode node];
[parallaxNode setPosition:
ccp(levelSize.width/2,screenSize.height/2)];
float xOffset = 0.0f;
xOffset = (levelSize.width/2);
[groundLayer retain];
[groundLayer removeFromParentAndCleanup:NO];
[groundLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[parallaxNode addChild:groundLayer z:30 parallaxRatio:ccp(1,1)
positionOffset:ccp(0,0)];
[groundLayer release];
xOffset = (levelSize.width/2) * 0.8f;
[rockColumnsLayer retain];
[rockColumnsLayer removeFromParentAndCleanup:NO];
[rockColumnsLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[parallaxNode addChild:rockColumnsLayer z:20
parallaxRatio:ccp(0.2,1)
positionOffset:ccp(xOffset, 0.0f)];
[rockColumnsLayer release];
xOffset = (levelSize.width/2) * 0.3f;
[rockBoulderLayer retain];
[rockBoulderLayer removeFromParentAndCleanup:NO];
[rockBoulderLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[parallaxNode addChild:rockBoulderLayer z:30
parallaxRatio:ccp(0.7,1)
positionOffset:ccp(xOffset, 0.0f)];
[rockBoulderLayer release];
[self addChild:parallaxNode z:1];
}
// Accelerometer
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { //new
shipSpeedY = 9.0 + acceleration.x*20;
shipSpeedX = -acceleration.y*20;
}
// Updating ship based on accelerometer
-(void)updateShip {
float maxY = winSize.height - ship.contentSize.height/2;
float minY = ship.contentSize.height/2;
float newY = ship.position.y + shipSpeedY;
newY = MIN(MAX(newY, minY), maxY);
float maxX = winSize.width - ship.contentSize.width/2;
float minX = ship.contentSize.width/2;
float newX = ship.position.x + shipSpeedX;
newX = MIN(MAX(newX, minX), maxX);
ship.position = ccp(newX, newY);
}
// Making background scroll automatically
-(void)update:(ccTime)dt {
[self updateShip];
CGPoint backgroundScrollVel = ccp(-100, 0);
parallaxNode.position = ccpAdd(parallaxNode.position, ccpMult(backgroundScrollVel, dt));
}
// Adding sprite ship
-(id)init {
self = [super init];
if (self != nil) {
winSize = [CCDirector sharedDirector].winSize;
ship=[CCSprite spriteWithFile:#"ship.png"];
ship.position=ccp(60,160);
[self addChild:ship z:100];
self.isAccelerometerEnabled = YES; //new
[self scheduleUpdate]; //new
[self addScrollingBackgroundWithTileMapInsideParallax];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end