I have a CCLayer class (yes, it has to be a CCLayer, not CCSprite) that has children CCSprites. I need to change the opacity and the scale of that layer, that in other words is I have to change the opacity and the scale of all children of that layer.
I learnt today that I can extend CClayer class, using this, to deal with the opacity of the children...
#import "CCLayer+Opaque.h"
#implementation CCLayer (CCLayer_Opaque)
// Set the opacity of all of our children that support it
-(void) setOpacity: (GLubyte) opacity
{
for( CCNode *node in [self children] )
{
if( [node conformsToProtocol:#protocol( CCRGBAProtocol)] )
{
[(id<CCRGBAProtocol>) node setOpacity: opacity];
}
}
}
- (GLubyte)opacity {
for (CCNode *node in [self children]) {
if ([node conformsToProtocol:#protocol(CCRGBAProtocol)]) {
return [(id<CCRGBAProtocol>)node opacity];
}
}
return 255;
}
#end
I did that and imported the file in my main class, but I still see this error when I try to set the opacity of that CCLayer: multiple methods named 'opacity' found
I also went beyond that and added this to the class extension:
-(void) setScale: (CGFloat) scale
{
for( CCNode *node in [self children] )
{
[node setScale: scale];
}
}
-(CGFloat) scale
{
for( CCNode *node in [self children] )
{
return [node scale];
}
return 1.0f;
}
To deal with the scale, using the same idea, but also see the message multiple methods named 'scale' found
In resume: how do I extend the CCLayer class to make all children of a CCLayer change scale or change opacity?
thanks
I discovered the problem. I had to cast the class to the CClayer object in order to read or set the opacity...
Example:
[(CCLayer*)obj setScale:0.5f];
Now it is working. Thanks.
Related
So, I want to hold a local reference to a child CCNode in a CCNode custom class without creating a retain cycle or without having the compiler complaining that the property or instance variable may be unpredictable set to nil
For instance with this custom class
#interface MyNode : CCNode
#property (nonatomic, strong) CCNode *background;
+ (id)nodeWithBackground:(id)background;
#end
#implementation MyNode
+ (id)nodeWithBackground:(id)background {
MyNode *node = [MyNode node];
node.background = background;
node.background.scale = 0.01;//(*)
return node;
}
- (void)setBackground:(CCNode *)background {
if (_background) {//(*)
[self removeChild:_background];
}
if (background) {
[self addChild:background];
}
_background = background;
}
#end
...I have a retain cycle creating a node like this
CCSprite *background = [CCSprite ...];
MyNode *node = [MyNode nodeWithBackground:background];
[self addChild:node];
where background and node are never freed from memory when the scene is replaced
Changing the property background to weak causes the compiler to complain in the lines with star (*) in the code above saying that the weak property or instance variable may be unpredictable set to nil
Update:
This is another approach with a weak instance variable and the settler and getter methods, the local strong variable (*) is because if the method uses the weak ivar _background the compiler complains saying that it may be unpredictable set to nil.
#interface MyNode : CCNode {
__weak CCNode *_background;
}
+ (id)nodeWithBackground:(id)background;
- (void)setBackground:(CCNode *)background;
- (CCNode *)background;
#end
#implementation MyNode
+ (id)nodeWithBackground:(id)background {
MyNode *node = [MyNode node];
node.background = background;
node.background.scale = 0.01;
return node;
}
- (void)setBackground:(CCNode *)background {
__strong CCNode *localRef = _background; //(*)
if (localRef) {
[self removeChild:localRef];
}
if (background) {
[self addChild:background];
}
_background = background;
}
- (CCNode *)background {
return _background;
}
#end
Is this approach a good thing to do in this case?
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.
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
I am making my first cocos2D game and i had trouble in tag. i gonna add many sprite to my gamelayer so i used [self addChild:sprite z:1 tag:aTag]; where aTag +=1; each time i increase the tag value. because each sprite should have a unique tag value. sometime i wanna clear all the child in my gamelayer so i remove those sprite by using the tag value like this.
for (int i=10; i<1000; i++) {
CCNode *child = [self getChildByTag:i];
if (child == nil)
NSLog(#"removeChildByTag: child not found!");
else{
NSLog(#"child removed");
[self removeChild:child cleanup:YES];
child=nil;
}
}
and when i add these sprite again like [self addChild:sprite z:1 tag:aTag] to my gamelayer there was error occured "EXE bad Access". why it show the error.
you can directly remove a child by using
[self removeChildByTag:aTag cleanup:YES];
as for the bad access, check if sprite is empty or if the image is empty
Use to define SAFE_REMOVE like this
#define SAFE_REMOVE(p) if (p) [p removeFromParentAndCleanup:YES];
// Remove the the tag
CCNode* node = [self getChildByTag:YOURTAGNAMEHERE];
if (node != nil)
{
SAFE_REMOVE(node);
}