draw function causes app to lag - iphone

I'm using a draw function to highlight the score inserted into a table of highscores but i find that it makes my app lag when i try to leave the highscore layer. I'm still relatively new to cocos2d so I was wondering if there is a better way so it doesn't cause any lag. I find if i comment out this function that the isn't any lag. Heres my code:
- (void)draw {
[super draw];
if(currentScorePosition < 0 || currentScore==0) return;
float w = 320.0f;
float h = 20.0f;
float x = (320.0f - w) / 2.0f;
float y = 230.0f - currentScorePosition * h;
CGPoint vertices[4];
vertices[0] = ccp(x, y);
vertices[1] = ccp(x+w, y);
vertices[2] = ccp(x+w, y+h);
vertices[3] = ccp(x, y+h);
CCDrawNode *draw = [[[CCDrawNode alloc] init] autorelease];
[draw drawPolyWithVerts:vertices count:4 fillColor:ccc4f(0.5, 0.5, 0.8, 0.5) borderWidth:2.0 borderColor:ccc4f(0.0, 0.0, 0.0, 0.0)];
[self addChild:draw z:0 ];
}

You're creating a new CCDrawNode every frame. Over time this will slow down the game as it has to draw more and more draw nodes.
Solution: create one draw node up front and add it as child. Keep a reference to it in an ivar. Perform drawing with just this single draw node.
Note that the draw methods of CCDrawNode are still additive. If you want to draw just this one polygon and update it over time, then you'll have to call clear before drawing:
[theDrawNode clear];
[theDrawNode drawPolyWithVerts:vertices
count:4
fillColor:ccc4f(0.5, 0.5, 0.8, 0.5)
borderWidth:2.0
borderColor:ccc4f(0.0, 0.0, 0.0, 0.0)];
Another note: you can use the draw node outside the draw method. In fact if you run the code like you did, the draw node won't be drawn until the next frame and thus it'll always lag 1 frame behind. Use a scheduled update method to update the draw node.

Related

SpriteKit 1 Dimensional Movement

I'm using apple's Sprite Kit and I need to move a SKSprite Node in horizontal movement only. I want the rest of the physics to apply but only in the horizontal component.
Context: This is for an object supposedly on a slider that can bounce back and forth. I have everything done but if it is hit the end the wrong way it simply floats off vertically, how can I simply make it ignore all forces in the vertical direction.
By putting the node's position back at the desired Y coordinate every frame after physics has been simulated:
-(void) didSimulatePhysics
{
CGPoint pos = horizontalMoveNode.position;
pos.y = fixedVerticalPosY;
horizontalMoveNode.position = pos;
}
Add this method to your scene class and apply it to whichever node(s) you want to lock in at a given Y coordinate.
You could use constraints for this purpose. I made a short sample with a node that only moves in a fixed X range and never leaves a specified Y position:
SKSpriteNode* node = [SKSpriteNode node];
node.color = [SKColor greenColor];
node.size = CGSizeMake(20, 20);
SKRange* rangeX = [[SKRange alloc] initWithLowerLimit: 100 upperLimit: 400];
SKRange* rangeY = [SKRange rangeWithConstantValue: 100];
SKConstraint* positionConstraint = [SKConstraint positionX: rangeX Y: rangeY];
NSArray* constraintArray = [NSArray arrayWithObject: positionConstraint];
node.constraints = constraintArray;
[self addChild: node];
This method is from SKAction class to move objects only on Horizontal or X-axis:-
[mySpriteNode runAction:[SKAction moveToX:260 duration:0.5]];
I hope this work's for you.

Drawing a circle with cocos2d?

I am trying to draw a circle in my scene with :
- (void) draw
{
ccDrawColor4F(100, 100, 100, 255);
CGPoint center = ccp(winSize.width/2, winSize.height/2);
CGFloat radius = 10.f;
CGFloat angle = 0.f;
NSInteger segments = 10;
BOOL drawLineToCenter = YES;
ccDrawCircle(center, radius, angle, segments, drawLineToCenter);
}
Well, I get some white,small circle, not filled, with some line from the center to the circle (like a clock).
So, first why are the colors are not as requested, how can I fill it with my own color? whats the line in the middle?
And, what if i want to change the color after a second? whats the best way to do that? Set a timer with a global variable?
#import <OpenGLES/ES1/gl.h>
- (void) draw
{
glLineWidth(5*CC_CONTENT_SCALE_FACTOR()); //set the thickness to 5 pixels for example
ccDrawColor4F(0.4,0.4,0.4, 1);
ccDrawLine([self anchorPoint], _peg.position);
CGPoint center = ccp(winSize.width/2, winSize.height/2);
CGFloat radius = 10.0;
CGFloat angle = 360;
NSInteger segments = 360;
BOOL drawLineToCenter = NO;
ccDrawCircle(center, radius, angle, segments, drawLineToCenter);
}
If you want to update the circle's color every second, schedule the update method and implement it as follows :
-(void) update:(float)dt
{
if(startTime == 0){
startTime = [NSDate timeIntervalSinceReferenceDate];
}
double elapsedTime = [NSDate timeIntervalSinceReferenceDate] - startTime;
if(elapsedTime > 1){
//update ccDrawColor4F here, for example just changing the Red component:
ccDrawColor4F((float)arc4random() / UINT_MAX,0.4,0.4, 1);
startTime = [NSDate timeIntervalSinceReferenceDate];
}
}
This should fix your issue. Hope it helps.
The colour values are floats not bytes, so you need to pass in something more like
ccDrawColor4F(0.4f, 0.4f, 0.4f, 1.f);
You may also want to reset the colour back to white after you've called your draw methods just for the sake of consistency.
To get a filled circle, use this function instead
void ccDrawSolidCircle( CGPoint center, float r, float a, NSUInteger segs, ccColor4F color);
The circle is always drawn from the middle, so presumably if you choose 4 segments, you'll get 4 lines drawn from the middle. Although I'm not too sure on that, I don't use primitives very much at all. As for the colour change, yes I would opt for some form of timer to change the values passed into the ccDrawColor4F method. But bear in mind that you want as little non-drawing code in the draw method as possible, so perhaps work out the colour change in another update related function.

CATransform3D - go back to previous state

Hi I`m working with CATransform3D.
Every time that I call the following method with the variable radian the UIImageView is rotated “radian * M_PI” from the previous angle.
I trying to go back to the original state. There is any way to do that?
I mind I want to sent a radian value i.e. 10 and that the view maintain these angle if is called more than once.
METHOD:
CATransform3D rotatedTransform = self.needleB.layer.transform;
rotatedTransform = CATransform3DRotate(rotatedTransform, radian * M_PI / 180.0, 0.0f, 0.0f, 1.0f);
self.needleB.layer.transform = rotatedTransform;
self.needleB.layer.anchorPoint = CGPointMake(0.5, 0.9);
self.needleB.center = CGPointMake(160, 250);
Thanks !!
To undo all transforms, assign the transform property of your layer to CATransform3DIdentity.

iPhone skew a CALayer

I'm a beginner and I am doing some exercises to familiarize myself with CALayer ...
I just want to know how to "incline" (or skew) a CALayer 45° angle ?
Thank you.
CALayers have a property, affineTransform that takes a CAAffineTransform. That documentation explicitly notes that:
Scaling, rotation, and translation are
the most commonly used manipulations
supported by affine transforms, but
skewing is also possible.
(emphasis mine, obviously)
There's no built in helper to construct a skew transform, but you could do something like (untested):
CGAffineTransform CGAffineTransformMakeSkew(CGFloat skewAmount)
{
CGAffineTransform skewTransform = CGAffineTransformIdentity;
skewTransform.b = skewAmount;
return skewTransform;
}
Then, for a skew such that things that were verticals stand at 45 degrees to the horizontal you'd use:
layer.affineTransform = CGAffineTransformMakeSkew(1.0f);
CALayers can be transformed using matrix operations. The skew transformation is represented by the following matrix
So if you want to do a skew transformation along the x axis you can use the following sample.
CALayer* layer = [CALayer layer];
layer.frame = CGRectMake(50,50,50,50);
layer.backgroundColor = [UIColor blueColor].CGColor;
[self.window.layer addSublayer:layer];
float theta = -45.0f;
CGAffineTransform t = CGAffineTransformIdentity;
t.b = tan(theta*M_PI/180.0f);
layer.transform = CATransform3DMakeAffineTransform(t);
The following sample will result in a layer that looks like the following
You could do this but you would have to mess with the layer's transform property, which is a struct CATransform3D. You're going to have to do some vector math to do this, as you . See the compute_transform_matrix(...) function from this answer for more details.
You'll want to do something like this:
CGRect r = layer.bounds;
layer.transform = compute_transform_matrix(r.origin.x, r.origin.y, r.size.width, r.size.height,
r.size.height, r.origin.y, r.size.width + r.size.height, r.origin.y,
r.origin.x, r.origin.y + r.size.height, r.size.width, r.origin.y );
Check my math on this. It should be right.
There are a lot of resources on how transforms work and it takes a bit of time to really understand them (at least for me!), here is some straight-to-the-point code that makes sure to indicate to which axis the transform is applied.
/*!
* Positive `skewX` creates a shift to the left.
* Negative `skewX` creates a shift to the right.
*
* `skewX` is NOT pixel based. Test values of 0.0f - 1.0f.
*/
CGAffineTransform CGAffineTransformMakeSkewX(CGFloat skewX)
{
return CGAffineTransformMakeSkew(skewX, 0.0f);
}
/*!
* Positive `skewY` creates a shift to the bottom.
* Negative `skewY` creates a shift to the top.
*
* `skewY` is NOT pixel based. Test values of 0.0f - 1.0f.
*/
CGAffineTransform CGAffineTransformMakeSkewY(CGFloat skewY)
{
return CGAffineTransformMakeSkew(0.0f, skewY);
}
/*!
* Positive `skewX` creates a shift to the left.
* Negative `skewX` creates a shift to the right.
*
* Positive `skewY` creates a shift to the bottom.
* Negative `skewY` creates a shift to the top.
*
* The skew values are NOT pixel based. Test values of 0.0f - 1.0f.
*/
CGAffineTransform CGAffineTransformMakeSkew(CGFloat skewX, CGFloat skewY)
{
return CGAffineTransformMake(1.0f, skewY, skewX, 1.0f, 0.0f, 0.0f);
}

Draw line or rectangle on cocos2d Layer

Can you let me know what is the best way to draw a line or rectangle on a scene layer using Cocos2d ios4 iphone.
So far have tried Texture2d, but it is more like a paint brush and is not so good. Tried drawing a line using draw method, but previous line disappears on drawing another line.
Basically want to draw multiple horizontal ,vertical, oblique beams. Please suggest. Any code would help a lot .
The code to draw using texture is below:
CGPoint start = edge.start;
CGPoint end = edge.end;
// begin drawing to the render texture
[target begin];
// for extra points, we'll draw this smoothly from the last position and vary the sprite's
// scale/rotation/offset
float distance = ccpDistance(start, end);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
[brush setPosition:ccp(start.x + (difx * delta), start.y + (dify * delta))];
[brush setScale:0.3];
// Call visit to draw the brush, don't call draw..
[brush visit];
}
}
// finish drawing and return context back to the screen
[target end];
The rendering is not good esp. with oblique lines as the scaling affects the quality.
Cheers
You could create a separate layer and call the draw method like this:
-(void) draw
{
CGSize s = [[Director sharedDirector] winSize];
drawCircle( ccp(s.width/2, s.height/2), circleSize, 0, 50, NO);
It's for a circle but the principle is the same. This is from a project I made a while back and it worked then. Don't know if anything has changed since.
You need to add draw method to your layer:
-(void) draw {
// ...
}
Inside it you can use some openGL like functions and cocos2d wrapper methods for openGL.
Hint: other methods can be called inside draw method.
But keep in mind that using other name for method
containing openGL instructions, that's not called inside draw mentioned above simply won't work.
Even when called from update method or other method used by scheduleUpdate selector.
So you will end up with something like this:
-(void) draw {
glEnable(GL_LINE_SMOOTH);
glColor4ub(255, 0, 100, 255);
glLineWidth(4);
CGPoint verts[] = { ccp(0,200), ccp(300,200) };
ccDrawLine(verts[0], verts[1]);
[self drawSomething];
[self drawSomeOtherStuffFrom:ccp(a,b) to:ccp(c,d)];
[someObject doSomeDrawingAsWell];
}
For more information check out cocos2d-iphone programming guide :
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:draw_update?s[]=schedule#draw