Hey people,
I'm creating a game in cocos2d, (I'm very new to it, and was trying to solve this thing)
in the game I'm making I created a "Bomb" class, and a "Player" class,
I want the bomb to check for collision with the player, if a collision detected, explode.
My problem is that I have no idea how to get the player's position from the bomb class,
I'd be happy if you guys could help me out here,
Thanks!
You did add the CCSprites to a CCLayer, didn't you? Then that CCLayer should have the access to both of them. So, you can use the CCLayer's tick function to track the positions of the CCSprites and trigger actions if their bounding boxes overlap.
Some sample code to illustrate:
#interface MyLayer : CCLayer {
BombSprite *bomb;
PlayerSprite *player;
}
...
#end
#implementation MyLayer
- (id)init {
if ((self = [super init])) {
bomb = ...
player = ...
[self schedule:#selector(tick:)];
}
return self;
}
- (id)tick:(ccTime)dt {
if (CGRectContainsRect([bomb boundingBox], [player boundingBox])) {
NSLog(#"Collision!");
// call [player didCollideWith:bomb] or something
...
}
}
#end
Related
I've been struggling for days with that problem: I have CCNode >> StateComponent and in the StateComponent I have a CCSprite as an attribute and add it as a child in StateComponent. When I set the position of an StateComponent object and NOT of the sprite, the bounding box of the StateComponent object appears at the right place. The default values for a sprite position are set on (0,0). The bounding box of the sprite appears at (0,0) but the sprite texture is shifted from (0,0).
I add the StateComponent object afterwards to a CCScene.
Could maybe someone help me with advice: how can I set the sprite position so that the texture and bounding box appears at the same position as the StateComponent object? Later I'd like to detect if there is a touch on the node(sprite) and then rotate the node with the sprite.
Any help would be really appreciated!!!
#interface StateComponent : CCNode {
}
#end
#implementation StateComponent
-(instancetype) initWithGestureStatewithSprite:(CCSprite*) sprite andPosition: (CGPoint) spritePosition RelativeAngle:(float) angle {
self = [super init];
if (!self) {
return nil;
}
self.sprite = sprite;
self.relativeAngle = angle;
self.position = spritePosition;
[self addChild:sprite];
return self;
}
#end
#interface StateViewScene : CCScene {
}
#end
#implementation StateViewScene
-(id) init {
self = [super init];
if (!self) {
return nil;
}
StateComponent * body = [[StateComponent alloc] initWithGestureStatewithSprite [CCSprite spriteWithImageNamed:#"body.png"] andPosition: CGPointMake(512,384) RelativeAngle:0];
[self addChild:body];
return self;
}
Have you tried to set the content Size of the Node to the Sprite content Size?
-(instancetype) initWithGestureStatewithSprite:(CCSprite*) sprite andPosition: (CGPoint) spritePosition RelativeAngle:(float) angle {
...
self.contentSize = sprite.contentSize;
...
I managed to solve the problem by converting to node space the StateComponent position couple of times as I actually have a tree like structure of StateComponents with sprites.
Thanks for the help! :)
---Edit---
This article helped me and might be interesting: http://www.koboldtouch.com/display/IDCAR/Converting+Between+Coordinate+Spaces
I'm currently trying out a few things. I already did this tutorial: https://www.makegameswith.us/tutorials/getting-started-with-spritebuilder/
However I'm a little stuck now.
I created a CCNode in SpriteBuilder and added 3 images. carbody.png and 2 wheel.png.
I made all objects physicsObjects.
In code I tried to connect them with joints and move them. However the carBody moves but the wheels keep staying on their place.
#import "Car.h"
#implementation Skater{
CCNode *_wheel1;
CCNode *_wheel2;
CCNode *_carBody;
CCPhysicsJoint *_bodyWheelJoint1;
CCPhysicsJoint *_bodyWheelJoint2;
}
- (id)init {
self = [super init];
if (self) {
[_wheel1.physicsBody setCollisionGroup: _carBody];
[_wheel2.physicsBody setCollisionGroup: _carBody;
[_carBody.physicsBody setCollisionGroup: _carBody];
_bodyWheelJoint1 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel1.physicsBody bodyB: _carBody.physicsBody anchorA:_wheel1.anchorPointInPoints];
_bodyWheelJoint2 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel2.physicsBody bodyB: _carBody.physicsBody anchorA:_wheel2.anchorPointInPoints];
}
return self;
}
And in Gameplay.m I only did this:
-(void)didLoadFromCCB{
[_car runAction:
[CCActionMoveTo actionWithDuration:10 position:CGPointMake(2000,_car.position.y)]];
}
The carBody moves, the wheels don't...
What am I missing?
Edit:
I made a few changes now but my wheels still keep staying on their place...
#import "Car.h"
#implementation Car{
CCNode *_wheel1;
CCNode *_wheel2;
CCNode *_carBody;
CCPhysicsJoint *_bodyWheelJoint1;
CCPhysicsJoint *_bodyWheelJoint2;
}
- (id)init {
self = [super init];
if (self) {
CCLOG(#"Car created");
[_wheel1.physicsBody setCollisionGroup:_carBody];
[_wheel2.physicsBody setCollisionGroup:_carBody];
[_carBody.physicsBody setCollisionGroup:_carBody];
_bodyWheelJoint1 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel1.physicsBody bodyB:_carBody.physicsBody anchorA:_wheel1.anchorPointInPoints];
_bodyWheelJoint2 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel2.physicsBody bodyB:_carBody.physicsBody anchorA:_wheel2.anchorPointInPoints];
}
return self;
}
-(void)moveCar:(int)distance{
CCLOG(#"Car should move");
CGPoint launchDirection = ccp(1, 0);
CGPoint force = ccpMult(launchDirection, distance);
[self.physicsBody applyForce:force];
}
#end
You're simply missing the point that move (and other) actions bypass physics. Once a node has a physics body, the use of CCAction* classes that change position and rotation is a no-no, and most others (ie scale) will not be applied to the physics body either but can still be used safely.
To move a physics object, apply an impulse or force to the physics body.
I am using tilemap in my box2D game in which I have created powers. When the player hits the power, a score label is displayed on the screen. Along with this I want to remove that power from the tilemap when player hits it. I have displayed label but I am unable to remove the power. Here is some code :
In ContactListener I am calling the method which removes the power from tilemap :
void ContactListener::BeginContact(b2Contact *contact) {
else if(actorA.tag==obj.gamePower.tag) //obj is a DataClass object.
{
[GameScene addPointLabel]; // For displaying score label
[GameScene removePower:actorA];
}
+(void)removePower:(id)sender
{
GameScene *obj=[[GameScene alloc]init];
CCSprite *sprite = (CCSprite *)sender;
[obj removePowerFromScene:sprite];
[obj release];
}
-(void)removePowerFromScene:(id)sender
{
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
}
I have created an object layer on tilemap to display power. But somehow, I am unable to remove it. Can someone help me?
If power is a CCNode why don't you remove it with [power removeFromParentAndCleanup:YES] ?
The (removePower:) does remove nothing because it creates a new scene and remove the sprite from that scene where the sprite does not belong to.
Another notice, be careful with contact listener. Removing o node in BeginContact is potential of crash. Let imagine the case that powerA contacts with both actor1 and actor2. The first call to BeginContact with powerA and actor1 removes powerA, so subsequent call to BeginContact with powerA envolved will crash !
There is a scene in my application which has only two labels and a menu item. When I load this scene using replaceScene method it stays for 3-4 seconds and then gets disappeared or released. I want to keep it until cancel button is pressed. How can I do it? code is:
#implementation MyLayer
+ (id)myScene {
CCScene *aScene = [CCScene node];
MYLayer *myLayer = [MyLayer node];
[aScene addChild:myLayer];
return aScene;
}
- (id) init {
if (self = [super init]) {
//labels and menu here
}
return self;
}
And I am calling it from another scene like this:
[[CCDirector sharedDirector] replaceScene: [MyLayer myScene]];
Maybe the problem is that it's your first scene. Then you should use runWithScene method of CCDirector.
did you try replacing that scene with a "empty" init function to see if it still releases itself? It might be because of the amount of textures you are putting into memory
I did have sort of similar problems before because the images used in the new scene is too big and got auto purged by my app delegate, thus returning me an empty scene sometimes
I am trying to preload an animation in the init method of my layer. I then call the animation if the screen is touched. The app crashes with no error message as soon as I touch the screen and seems it is to do with calling the preloaded animation. I would like to do it this way as it seems expensive to create the animation every time the screen is touched - which does seems to work though. Any tips greatly appreciated.
Sample Code:
In my header:
#interface Test : CCLayer {
NSMutableArray *wake;
CCSprite* ani;
CCAnimate *animate;
}
#end
In my implementation:
-(id) init {
if( (self=[super init])) {
// enable touches
self.isTouchEnabled = YES;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ani.plist" texture:[[CCTexture2D alloc] initWithImage:[UIImage imageNamed:#"ani.png"]]];
ani = [CCSprite spriteWithSpriteFrameName:#"ani1.png"]; //comes from .plist file
ani.anchorPoint=ccp(0,0);
ani.position = ccp(700,65);
[self addChild:ani z:30];
wake = [NSMutableArray array];
for(int i = 1; i <= 4; i++) {
[wake addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"ani%d.png",i]]];
}
animate = [CCAnimate actionWithAnimation:[CCAnimation animationWithFrames:wake delay:1.0f] restoreOriginalFrame:FALSE];
}
return self;
}
Handling the touch:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// run the animation
[ani runAction:animate];
}
Animations in Cocos2d are not designed to be reused. You need to create a new one every time.
Problem solved by creating properties for the array and animation on the class using nonatomic,retain.
You only need to retain the animation but the array can be local.
self.myAnimation = [[CCAnimation animationWithFrames:myAniFramesArray delay:0.1f] retain];
Remember to make the property nonatomic, retain as stated by Chev and to release any objects you retain in the appropriate dealloc method.