Displaying some text on the screen using the Framework Cocos2D - objective-c

I want to display a text on the screen using the framework Cocos2D.
I'm thinking off using the draw method. But I don't know the exact way of doing that.
I would be glad if anyone could help me on this topic.

The simplest way would be to create a CCLabelTTF node and add it to your scene.

Here is a possible way :
This code is within a simple scene class :
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) )
{
// create and initialize a Label
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Hello World" fontName:#"Marker Felt" fontSize:64];
// ask director for the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label on the center of the screen
label.position = ccp( size.width /2 , size.height/2 );
// add the label as a child to this Layer
[self addChild: label];
}
return self;
}
Hope it can help you !

Related

CALayer doesn't display

(I already read this page, but it didn't help me CALayer not displaying)
I have a class called Image that has this field data:
uint8_t *data;
I already use this data to display this Image on a CALayer that I got gathering code from the internet.
I saw how to create another windows in my application, and I put a NSView inside it to display an Image using the method, I intend to display the histogram latter, but now I'm just trying to display again the same image:
-(void)wrapImageToCALayer: (CALayer*) layer{
if(!layer) return;
CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate(data, width, height, 8, step, grayColorSpace, kCGImageAlphaNone);
CGImageRef dstImage = CGBitmapContextCreateImage(context);
dispatch_sync(dispatch_get_main_queue(), ^{
layer.contents = (__bridge id)dstImage;
});
CGImageRelease(dstImage);
CGContextRelease(context);
CGColorSpaceRelease(grayColorSpace);
}
And this is my Window Controler:
#implementation HistogramControllerWindowController
#synthesize display;
- (id)initWithWindow:(NSWindow *)window{
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
}
return self;
}
- (void)windowDidLoad
{
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
[super windowDidLoad];
histogramDisplayLayer = [CALayer layer];
[histogramDisplayLayer setContentsGravity:AVLayerVideoGravityResizeAspectFill];
histogramDisplayLayer.position = CGPointMake(display.frame.size.width/2., display.frame.size.height/2.);
[histogramDisplayLayer setNeedsDisplay];
[display.layer addSublayer: histogramDisplayLayer];
}
#end
And I'm calling this way:
[frame wrapImageToCALayer:histogramDisplayLayer];
Note that histogramDisplayLayer is an external (CALayer *)
Your histogramDisplayLayer have no size defined, you just set a position but not its size. So init its frame, and this should fix your problem.
Just insert:
[display setWantsLayer:YES]; // view's backing store is using a Core Animation Layer
Before:
[display.layer addSublayer: histogramDisplayLayer];
[ Best way to change the background color for an NSView ]

Cocos2d, moving a sprite to a touch location

myself and my friend have been told Stackoverflow is the place to ask questions regarding code. :)
We're pretty new to Objective-C, Xcode and Cocos2d and are trying to complete simple tasks to further our knowledge.
Looking at our code below, we have made an Ant Object and placed him on screen. We now want to use a touch location to move the ant to to location the user touches.
We're unsure what the correct way to go about it is. At the moment we're staying away from creating classes so have all the code in one place but we can't figure out how to get the ant that's on screen to go to the touch location.
Can anyone help?
//
// HelloWorldLayer.m
// Timer
//
// Created by Lion User on 06/06/2012.
// Copyright __MyCompanyName__ 2012. All rights reserved.
//
// Import the interfaces
#import "HelloWorldLayer.h"
// HelloWorldLayer implementation
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super initWithColor:ccc4(225, 225, 225, 255)])) {
// enable touches
self.isTouchEnabled=YES;
// ask director the the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// set time to zero
myTime = currentTime;
timeLabel = [CCLabelTTF labelWithString:#"00:00" fontName:#"Arial" fontSize:48];
timeLabel.position = CGPointMake(size.width / 2, size.height);
// set label color
timeLabel.color = ccBLACK;
// Adjust the label's anchorPoint's y position to make it align with the top.
timeLabel.anchorPoint = CGPointMake(0.5f, 1.0f);
// Add the time label
[self addChild:timeLabel];
// run create ant method
[self createAnt];
//update
[self schedule:#selector(update:)];
}
return self;
}
-(void)update:(ccTime)dt{
totalTime += dt;
currentTime = (int)totalTime;
if (myTime < currentTime)
{
myTime = currentTime;
[timeLabel setString:[NSString stringWithFormat:#"%02d:%02d", myTime/60, myTime%60]];
}
}
////* method for creating an ant and moving it*////
-(void)createAnt{
////*requirements for animation setup*////
// create cache object to store spritesheet in
CCSpriteFrameCache *cache=[CCSpriteFrameCache sharedSpriteFrameCache];
// add the sprite list to the cache object
[cache addSpriteFramesWithFile:#"antatlas.plist"];
// create frame array to store the frames in
NSMutableArray *framesArray=[NSMutableArray array];
//loop through each frame
for (int i=1; i<3; i++){
// increment the name to include all frames in sprite sheet
NSString *frameName=[NSString stringWithFormat:#"ant%d.png", i];
// create frame object set it to the cache object and add the frameNames to the cache
id frameObject=[cache spriteFrameByName:frameName];
// add the frame object into the array
[framesArray addObject:frameObject];
}
////* setup the actions for running the animation*////
// create animation object and pass the list of frames to it (it expects this as an array)
id animObject=[CCAnimation animationWithFrames:framesArray delay:0.05];
// setup action to run the animation do not return to frame 1
id animationAction=[CCAnimate actionWithAnimation:animObject restoreOriginalFrame:NO];
//loop the animation indefinitely
animationAction = [CCRepeatForever actionWithAction:animationAction];
// move ant action
id moveAnt=[CCMoveTo actionWithDuration:3 position:ccp(60, 160)];
// create sprite, set location and add to layer (starts with the name of the first frame in the animation
CCSprite *ant=[CCSprite spriteWithSpriteFrameName:#"ant1.png"];
ant.position=ccp(240, 160);
[self addChild:ant];
//run animation action
[ant runAction: animationAction];
// run move ant action
[ant runAction:moveAnt];
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch=[touches anyObject];
CGPoint loc=[touch locationInView:[touch view]];
loc=[[CCDirector sharedDirector]convertToGL:loc];
NSLog(#"touch (%g,%g)",loc.x,loc.y);
// Move ant to point that was pressed
[ant runAction:[CCSequence actions:
[CCMoveTo actionWithDuration:realMoveDuration position:loc],
[CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)],
nil]];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
#end
Seems like your ant is local to your createAnt method. So in the touchesBegan statement, it doesn't "see" the ant. Go over to your header file, and in the #interface declare the ant...
CCSprite *ant;
Then back in your createAnt statement, you can just write...
ant=[CCSprite spriteWithSpriteFrameName:#"ant1.png"];
Now any other method in the implementation ( .m ) file will know what you mean when you write "ant"
Hope it helps!

Rotating, scaling Cocos2d inherited layer with 2 sprites as children

Straight to the point, I have a class which is basically inherited from CCLayer and has 2 sprites as children.
some_layer.h
#interface some_layer : CCLayer {
CCSprite *back;
CCSprite *front;
}
some_layer.mm
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init])) {
back = [CCSprite spriteWithFile:#"back.png"];
front = [CCSprite spriteWithFile:#"front.png"];
[front setOpacity:0];
[self addChild:back];
[self addChild:front];
//this is after modification
back.positionInPixels = CGPointMake(winSizeInPixels.width/2,winSizeInPixels.height/2);
front.positionInPixels = CGPointMake(winSizeInPixels.width/2,winSizeInPixels.height/2);
}
return self;
}
//after the edit
-(void) setPositionInPixels:(CGPoint)positionInPixels {
[super setPositionInPixels:CGPointMake(positionInPixels.x -(winSizeInPixels.width/2), positionInPixels.y -(winSizeInPixels.height/2))];
}
-(void) setPosition:(CGPoint)position {
[super setPosition:CGPointMake(position.x -(winSize.width/2), position.y -(winSize.height/2))];
}
Of course that is not all the implementation of the layer, but that code is the only one related to the problem, let me know if you think you need more.
Now in some part of the parent layer am trying to do this
float x = winSizeInPixels.width/2;
float y = winSizeInPixels.height/2;
[self setPositionInPixels:CGPointMake(x, y)];
mylayer = [[some_layer alloc] init];
[mylayer setPositionInPixels:CGPointMake(-offset, -offset)];
[self addChild:mylayer];
[mylayer runAction:[CCEaseInOut actionWithAction:[CCRotateTo actionWithDuration:speed*20 angle:angle] rate:4]];
The output of this code, is that I can see the sprites rotating, but not around the center of some_layer, I want them to rotate and stay in their place (rotate around themselves), what am trying to do is rotate, scale them at the same time while keeping their positions the same on screen,
The sprites are keeping in rotating around some random point ( Maybe around parent of their parent which is self in the last code )
BTW, I'm not touching the sprites back and front positions, I only deal with that "some_layer", I tried setting their positions to (0,0)
The only time the position of "some_layer" is correct is when it's rotation angle is 0, and it's scale is 1.0, if there's something unclear please let me know, thanks a lot, I can provide some screen shots
Edit : I modified the code above, it works properly as a workaround, but I think this is not the right way of doing it!!! Please check the comments, I don't know what's strange happening!!
Thank you!
Edit 2: Answer found
Answer to my self
Add this to the init method of some_layer.mm
[self setContentSize:CGSizeMake(0, 0)];
Thanks for everyone who tried to help me :)
Analysing the code is the best solution!
BTW I deleted the overridden methodes for both setPos and deleted the code that changes the Sprites positions, it's like this now
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init])) {
back = [CCSprite spriteWithFile:#"back.png"];
front = [CCSprite spriteWithFile:#"front.png"];
[front setOpacity:0];
[self addChild:back];
[self addChild:front];
[self setContentSize:CGSizeMake(0, 0)];
}
return self;
}
Are you setting some anchorPoint for the Layer or Sprite which you are using. if yes then please check that the anchor point should be set at center :
someSprite.anchorPoint=ccp(0.5,0.5);
For more details : http://www.qcmat.com/understanding-anchorpoint-in-cocos2d/

strange problem playing cocos2d animation from another class?

strange thing. if someone could please,please help me. its 3 days, and i think i am going to be fired :(
i have cocos2d class with animation function,and another xcode class.
if i call from the cocos2d class init function to animation function, the animation is being played when app is starts.
if i call from another class to the cocos2d class-animation, so it does the init function and enter the animation,but i cant see it playing.
so the animation is working only if called from within the cocos class only.
WHY ?
this is how i call the animation :
ran=[[HelloWorld alloc] init];
[ran animation];
this is the animation:
-(void)animation
{
//[self removeChild:background cleanup:YES];
//[b_pic.parent removeChild:b_pic cleanup:YES];
//animation
CCSpriteBatchNode *danceSheet = [ CCSpriteBatchNode batchNodeWithFile:#"head.png"];
[self addChild:danceSheet];
CCSprite *danceSprite = [CCSprite spriteWithTexture:danceSheet.texture rect:CGRectMake(0, 0, 480, 320)];
[danceSheet addChild:danceSprite];
//danceSprite.anchorPoint=CGPointMake(0, 0);
CGSize s = [[CCDirector sharedDirector] winSize];
danceSprite.position = ccp(s.width/2,s.height/2);
CCAnimation *danceAnimation = [CCAnimation animation];
[danceAnimation setDelay:0.1f];
int frameCount = 0;
for (int y = 0; y < 4; y++)
{
NSLog(#"%#",animation);
for (int x = 0; x < 5; x++)
{
CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:danceSheet.texture rect:CGRectMake(x*320,y*440,320,440)];
[danceAnimation addFrame:frame];
frameCount++;
if (frameCount == 25)
break;
}
}
Can you call the animation function twice within that same class...Try
[self animation];
and
[[CCScheduler sharedScheduler] scheduleSelector:#selector(animation) forTarget:self
interval:10 paused:NO];
and see if the animation gets called the second time.
If it doesn't which at this point I don't think it will, you should define all that you can in the init and then only run the pieces you need in the animation method (i.e. add the batchNode and Sprite in the init as ivars and reuse them in the animation).
solved , and i dont know why.
but if you want to call a cocos2d function from the outside, you have to do :
[(HelloWorld*)[[[CCDirector sharedDirector] runningScene] getChildByTag:42] HardwareEvent:DollPart];
and tag your layer like :
layer.tag=42;
on the scene method !
thats the only way it works great.

Stop drawing of CATiledLayer

Is is possible to stop CATiledLayer to draw (drawLayer:inContext)?
It draws asynchronously and when i try to release CGPDFDocumentRef, which is used by CATiledLayer, the app crashes (EXC_BAD_ACCESS).
That's my view:
#implementation TiledPDFView
- (id)initWithFrame:(CGRect)frame andScale:(CGFloat)scale{
if ((self = [super initWithFrame:frame])) {
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 4;
tiledLayer.tileSize = CGSizeMake(512.0, 512.0);
myScale = scale;
}
return self;
}
// Set the layer's class to be CATiledLayer.
+ (Class)layerClass {
return [CATiledLayer class];
}
- (void)stopDrawing{
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
[tiledLayer removeFromSuperlayer];
tiledLayer.delegate = nil;
}
// Set the CGPDFPageRef for the view.
- (void)setPage:(CGPDFPageRef)newPage
{
CGPDFPageRelease(self->pdfPage);
self->pdfPage = CGPDFPageRetain(newPage);
//self->pdfPage = newPage;
}
-(void)drawRect:(CGRect)r
{
}
// Draw the CGPDFPageRef into the layer at the correct scale.
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
// First fill the background with white.
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,self.bounds);
CGContextSaveGState(context);
// Flip the context so that the PDF page is rendered
// right side up.
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Scale the context so that the PDF page is rendered
// at the correct size for the zoom level.
CGContextScaleCTM(context, myScale,myScale);
CGContextDrawPDFPage(context, pdfPage);
CGContextRestoreGState(context);
}
// Clean up.
- (void)dealloc {
CGPDFPageRelease(pdfPage);
[super dealloc];
}
And this is where i try to stop and release PDF in view controller:
v is instance of TiledPDFView
-(void) stopDwaring {
[v stopDrawing];
[v removeFromSuperview];
[v release];
[self.view removeFromSuperview];
self.view = nil;
CGPDFDocumentRelease(pdf);
}
this post helped me solving my own trouble with CATiledLayer. I used TiledPDFview.m from Apple's documentation as example.
Since I need to redraw the entire view and all tiles at some point, I use a CATiledLayer as property.
When exiting and deallocating the viewcontroller, it crashed with [CATiledLayer retain]: Message sent to deallocated instance.
Here is my dealloc method of the view controller:
- (void)dealloc {
self.tiledLayer.contents=nil;
self.tiledLayer.delegate=nil;
[self.tiledLayer removeFromSuperlayer];
// note: releasing the layer still crashes-
// I guess removeFromSuperlayer releases it already,
// but couldn't find documentation so far.
// So that's why it's commented out:
// [self.tiledLayer release], self.tiledLayer=nil;
//release the other viewcontroller stuff...
[super dealloc];
}
That works for me. Hope it helps someone.
Remove the CATiledLayer from its superlayer before releasing the CGPDFDocumentRef.
[yourTiledLayer removeFromSuperlayer];
Dont forget to set it's delegate to nil too.
yourTiledLayer.delegate = nil;
After that, you can safely release your CGPDFDocumentRef.
Edit after OP adds code:
Did you get pdfPage using CGPDFDocumentGetPage()? If so, you shouldn't release it, it is an autoreleased object.
Regarding how to add it as sublayer:
You don't actually need TiledPDFView. In your view controller, you can simply do this:
CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.delegate = self; //sets where tiledLayer will look for drawLayer:inContext:
tiledLayer.tileSize = CGSizeMake(512.0f, 512.0f);
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 4;
tiledLayer.frame = CGRectIntegral(CGRectMake(0.0f, 0.0f, 512.0f, 512.0f));
[self.view.layer addSublayer:tiledLayer];
Then move your drawLayer:inContext: implementation to your view controller.
Then in your view controller's dealloc, release it as:
[tiledLayer removeFromSuperlayer];
tiledLayer.delegate = nil;
CGPDFDocumentRelease(pdf);
Note that you can't do this on a UIView subclass, as the drawLayer:inContext: will conflict with the UIView's main layer.
object.layer.contents = Nil
This should wait for the thread to finish. It helped in my case.
TiledPDFView *pdfView;
In dealloc of pdfView's superview class, write below line of codes.
- (void)dealloc {
if (nil != self.pdfView.superview) {
self.pdfView.layer.delegate = nil;
[self.pdfView removeFromSuperview];
}
}
This works for me. Hope it will help.
I've had a similar problem.
I ended up setting a float variable "zoom" in my TiledPDFView which I set as the zoomScale of PDFScrollView in the UIScrollview Delegate method: scrollViewDidZoom
Then in my drawLayer method inside TiledPDFView I only called the contents of that method if the float variable "zoom" was above 2.
This fixes any issues of someone leaving the view without zooming. It may not be ideal for your case as this error still occurs if someone zooms above 2 then releases the viewcontroller quickly, but you might be able to find a similar technique to cover all bases.
It looks like you're doing the same thing I am, which is borrowing the ZoomingPDFView code and integrating it into your project. If your UIScrollView delegate methods in PDFScrollView are unchanged, you can solve your problem by just commenting both lines of your dealloc method (in TiledPDFView). That stuff should only be happening when you kill the parent view, anyway.