How to Stroke a line in Cocos2d? Is it possible to convert the stroke into sprite?
You can draw lines by overriding the "draw" method, which would in turn result in the "stroke" effect you appear to be after. The question is a bit lacking in detail, so I'll try to make the best of it.
Let's say you want to draw a simple line on the screen, you could do the following:
#interface MyLine: CCNode
{
CGRect lineRect;
}
#property(nonatomic) CGRect lineRect;
+(id)lineWithRect:(CGRect)rect;
#end
#implementation MyLine
#synthesize lineRect
+(id)lineWithRect:(CGRect)rect
{
MyLine *node = [MyLine node];
[node setRect: rect];
return node];
}
-(void)draw
{
glEnable(GL_LINE_SMOOTH);
ccDrawLine(ccp(rect.origin.x, rect.origin.y), ccp(rect.size.width, rect.size.height));
}
#end
With this class, you'd be able to call:
MyLine *line = [MyLine lineWithRect:CGRectMake(0, 0, winSize.width, winSize.height)];
Which would then draw a line from the bottom left of the screen to the top right of the screen.
You would not convert this into a "sprite", as it would be unnecessary to do so - but you could then treat this as if it were any other graphic in your game, as it is now it's own subclass of CCNode ... containing all the goodness that comes with that (positioning, etc).
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 clipping my sprite with this code:
//At my CCSprite subclass m.
-(void)visit
{
CGPoint worldOrg = [self convertToWorldSpace:ccp(0, 0)];
CGPoint dest = [self convertToWorldSpace:ccp(self.contentSize.width, self.contentSize.height)];
CGPoint dims = ccpSub(dest, worldOrg);
glEnable(GL_SCISSOR_TEST);
glScissor(worldOrg.x, worldOrg.y, dims.x, dims.y);
#define SHOW_CLIPPED_AREA 1
#if SHOW_CLIPPED_AREA
//Draws a red rectangle showing clipped area
ccDrawSolidRect(ccp(0, 0), ccp(1024, 1024), ccc4f(64, 0, 0, 128));
#endif
[super visit];
glDisable(GL_SCISSOR_TEST);
}
Then just create the sprite as usual, adjust the sprite.contentSize property to whatever I need:
CCSprite aSprite = [CCSprite spriteWith...];
aSprite.contentSize = CGSizeMake(20,20);
//Add it to my layer
[self addChild:aSprite];
And it works as expected!
Problem...
When adding it to a CCSpriteBatchNode, it wont clip the sprite... it shows the sprite but without clipping it.
Can someone please help me out with this, I've googled everywhere with no answer to this.
I've also used the ClippingNode class from Steffen Itterheim, but I'm also having issues adding it to a CCSpriteBatchNode.
Any help will be appreciated.
Clipping or any custom drawing won't work with sprite-batched sprites.
The CCSpriteBatchNode will not call visit (nor draw) methods on their children because the batch node takes over rendering of the children. Therefore any code you write in draw or visit methods of a CCSprite will have no effect when you sprite-batch the sprite.
I've got to sprites, essentially a nucleus (parent) and an electron (child). I'm trying to find a way to have the electron orbit the nucleus. I've found a few posts here and there on moving anchor points, but that is apparently related to the texture of the sprite, not the sprite itself.
This is my current init method for my parent sprite:
self = [super init];
if (self) {
CCSprite *orbitAnchor = [CCSprite new];
[self addChild:orbitAnchor];
orbitAnchor.position = ccp(32,32);
CCSprite *orbiter = [CCSprite spriteWithFile:#"line.png" rect:CGRectMake(0, 0, 8, 8)];
[orbitAnchor addChild:orbiter];
orbiter.position = ccp(40,40);
CCAction *orbitAction = [CCRepeatForever actionWithAction:[CCRotateTo actionWithDuration:1 angle:720]];
[orbitAnchor runAction:orbitAction];
[self initAnimations];
}
return self;
Those numbers are all totally arbitrary though - I just stuck them in there and got what looked best. I'm sure there's a more programatic way to do what I want.
Basically, I'm looking for a way to set the child's axis point at the center of the parent, and then have it rotate around that point. It seems like a relatively simple thing to do using CCRotate and such, but I think I'm missing what to search for in order to move the anchor point of the child. Any suggestions/other posts?
Thanks
You have [CCSprite new] which is an unusual use, probably not supported. Unless the orbit anchor node should display a texture, you can just use a CCNode as anchor.
Technically you're doing everything correct from what I can see. You might want to try without the rotate actions and instead change the direction manually in a scheduled update method.
CCNode *orbitAnchor = [CCNode node];
[self addChild:orbitAnchor z:0 tag:1];
orbitAnchor.position = ccp(32,32);
CCSprite *orbiter = [CCSprite spriteWithFile:#"line.png" rect:CGRectMake(0, 0, 8, 8)];
[orbitAnchor addChild:orbiter z:0 tag:2];
orbiter.position = ccp(40,40);
[self scheduleUpdate];
Update method:
-(void) update:(ccTime)delta
{
CCNode* orbitAnchor = [self getChildByTag:1];
orbitAnchor.direction += 5;
}
From the image filename it looks like you're trying to draw a line from the orbitAnchor to the orbiter. You can do that with ccDrawLine:
-(void) draw
{
CCNode* orbitAnchor = [self getChildByTag:1];
CCNode* orbiter = [self getChildByTag:2];
ccDrawLine(orbitAnchor.position, orbiter.position);
}
Anchor points. Automatically, objects are placed based on the center of an object right? with anchor points you can move that around, so if you rotate the object it will rotate around the anchorpoint. http://www.qcmat.com/understanding-anchorpoint-in-cocos2d/
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
how can i clip/crop/mask or just set the frame of a CCSprite in Cocos2D?
Something similar to:
setting the frame for UIView, with clipping subviews = TRUE
My CCSprite Main Sprite have multiple Child Sprite added to it.
I only want Mask part of that Main Sprite Sprite visible.
Is there a way to clip or use a mask for CCSprite?
I could cut the background and layer that on top, leaving only that visible area, but is that the only way?!
here's a sample image demonstrating what I'm trying to achieve:
(source: dnamique.com)
I ended up using GL_SCISSOR.
in MainSprite I impemented:
- (void) visit
{
if (!self.visible) {
return;
}
glEnable(GL_SCISSOR_TEST);
glScissor(x, y, width, height);
[super visit];
glDisable(GL_SCISSOR_TEST);
}
This will clip or mask the specified area.
The only tricky bit is that in Landscape mode Cocos2D has 0,0 at the bottom-left side of the screen, while OpenGL has it at the bottom-right corner as it doesn't consider the orientation of the screen.
In other words, for OpenGL consider you have a rotated portrait Screen.
I wrote a ClippingNode class which does exactly that. You can add other nodes (sprites, labels, etc.) to the ClippingNode and they will only be drawn in the region specified by the ClippingNode. It also takes device rotation into account.
Internally it uses GL_SCISSOR_TEST like in Bach's answer.
http://www.learn-cocos2d.com/2011/01/cocos2d-gem-clippingnode/
I tried using Steffen Itterheim's ClippingNode, but was unable to get to work in a sufficiently robust
enough fashion for my needs.
Believe it or not, the below code works fairly well and should be code complete. It handles device orientation changes, anchorPoint, position, scale (scaleX, scaleY). For cocos2d v2, you may just need to
comment out the glPushMatrix and glPopMatrix calls..
To use, simply set the position and contentSize properties and add the child/children you want clipped to this ClippingNode instance. The contentSize property is used to define the dimensions of the clipping region.
example of usage:
ClippingNode *clipNode = [[ClippingNode alloc] init];
clipNode.anchorPoint = ccp(0.5f, 0);
clipNode.position = ccp(100, 25);
clipNode.contentSize = CGSizeMake(120, 120);
// add clipNode to your node hierarchy.
[parentNode addChild:clipNode];
// add one or more children to your clipNode:
[clipNode addChild:child1];
// ClippingNode.h
// CC0 - (public domain. Use in anyway you see fit.)
// No warranty of any kind is expressed or implied.
//
// by UChin Kim.
//
// the caller can simply set the regular cocos2d
// properties: position and contentSize to define the clipping region implicitly (i.e. the
// position and contentSize of the ClippingNode is the clipping region to be used).
// as an added bonus, position seems to work as expected (relative to parent node, instead of
// requiring absolute positioning).
//
// also, anchorPoint and scale properties seem to work as expected as well..
// no special code is neeed to handle device orientation changes correctly..
//
// To visually see exactly what is being clipped, set the following #define
// #define SHOW_CLIPPED_REGION_IN_LIGHT_RED 1
//
#import "cocos2d.h"
#interface ClippingNode : CCNode
#end
//
// ClippingNode.m
//
#import "ClippingNode.h"
#implementation ClippingNode
-(void) visit
{
CGPoint worldOrg = [self convertToWorldSpace:ccp(0, 0)];
CGPoint dest = [self convertToWorldSpace:ccp(self.contentSize.width, self.contentSize.height)];
CGPoint dims = ccpSub(dest, worldOrg);
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(worldOrg.x, worldOrg.y, dims.x, dims.y);
#if SHOW_CLIPPED_REGION_IN_LIGHT_RED
glColor4ub(64, 0, 0, 128);
ccDrawSolidRect(ccp(0, 0), ccp(1024, 1024));
#endif
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
#end