I am working on rotating the 3d object in my application by using the application downloaded from here.I succeed on stopping the rotating object as below, but I can't rotate the object again from the stopped position.Below is the piece of code I've worked from the downloaded project
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
{
if (aRotate) {
[self startOrStopAutorotation:nil];
}
if ([[event touchesForView:self.view] count] > 1) // Pinch gesture, possibly two-finger movement
{
//CGPoint directionOfPanning = CGPointZero;
}
else{
CGPoint currentMovementPosition = [[touches anyObject] locationInView:glView_];
[self renderByRotatingAroundX:(lastMovementPosition.x - currentMovementPosition.x) rotatingAroundY: (lastMovementPosition.y - currentMovementPosition.y) scaling:1.0f translationInX:0.0f translationInY:0.0f];
lastMovementPosition = currentMovementPosition;
}
}
}
- (void)renderByRotatingAroundX:(float)xRotation rotatingAroundY:(float)yRotation scaling:(float)scaleF translationInX:(float)xTranslation translationInY:(float)yTranslation{
glView_ = [[REGLView alloc] initWithFrame:CGRectMake(0, 0, 320, 320) colorFormat:kEAGLColorFormatRGBA8 multisampling:YES];
[self.view addSubview:glView_];
camera_ = [[RECamera alloc] initWithProjection:kRECameraProjectionOrthographic];
camera_.position = CC3VectorMake(0, 0, 320);
camera_.upDirection = CC3VectorMake(0, 1, 0);
camera_.lookDirection = CC3VectorMake(0, 0, -1);
camera_.frustumNear = 10;
camera_.frustumFar = 640;
camera_.frustumLeft = -glView_.frame.size.width / 2.0;
camera_.frustumRight = glView_.frame.size.width / 2.0;
camera_.frustumBottom = -glView_.frame.size.height / 2.0;
camera_.frustumTop = glView_.frame.size.height / 2.0;
scene_ = [[REScene alloc] init];
scene_.camera = camera_;
world_ = [[REWorld alloc] init];
[scene_ addChild:world_];
director_ = [[REDirector alloc] init];
director_.view = glView_;
director_.scene = scene_;
// currentCalculatedMatrix = CATransform3DIdentity;
GLfloat currentModelViewMatrix[16] = {0.402560,0.094840,0.910469,0.000000, 0.913984,-0.096835,-0.394028,0.000000, 0.050796,0.990772,-0.125664,0.000000, 0.000000,0.000000,0.000000,1.000000};
currentCalculatedMatrix = CATransform3DScale(currentCalculatedMatrix, 0.5, 0.5 * (320.0/480.0), 0.5);
//// if ((xRotation != 0.0) || (yRotation != 0.0))
//{
GLfloat totalRotation = sqrt(xRotation*xRotation + yRotation*yRotation);
CATransform3D temporaryMatrix = CATransform3DRotate(currentCalculatedMatrix, totalRotation * M_PI / 180.0,
((xRotation/totalRotation) * currentCalculatedMatrix.m12 + (yRotation/totalRotation) * currentCalculatedMatrix.m11),
((xRotation/totalRotation) * currentCalculatedMatrix.m22 + (yRotation/totalRotation) * currentCalculatedMatrix.m21),
((xRotation/totalRotation) * currentCalculatedMatrix.m32 + (yRotation/totalRotation) * currentCalculatedMatrix.m31));
if ((temporaryMatrix.m11 >= -100.0) && (temporaryMatrix.m11 <= 100.0))
currentCalculatedMatrix = temporaryMatrix;
float currentScaleFactor = sqrt(pow(currentCalculatedMatrix.m11, 2.0f) + pow(currentCalculatedMatrix.m12, 2.0f) + pow(currentCalculatedMatrix.m13, 2.0f));
xTranslation = xTranslation / (currentScaleFactor * currentScaleFactor);
yTranslation = yTranslation / (currentScaleFactor * currentScaleFactor);
// Use the (0,4,8) components to figure the eye's X axis in the model coordinate system, translate along that
temporaryMatrix = CATransform3DTranslate(currentCalculatedMatrix, xTranslation * currentCalculatedMatrix.m11, xTranslation * currentCalculatedMatrix.m21, xTranslation * currentCalculatedMatrix.m31);
// Use the (1,5,9) components to figure the eye's Y axis in the model coordinate system, translate along that
temporaryMatrix = CATransform3DTranslate(temporaryMatrix, yTranslation * currentCalculatedMatrix.m12, yTranslation * currentCalculatedMatrix.m22, yTranslation * currentCalculatedMatrix.m32);
if ((temporaryMatrix.m11 >= -100.0) && (temporaryMatrix.m11 <= 100.0))
currentCalculatedMatrix = temporaryMatrix;
[self convert3DTransform:¤tCalculatedMatrix toMatrix:currentModelViewMatrix];
// Black background, with depth buffer enabled
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
And below is the code I've worked for stopping and stopping
- (void)startOrStopAutorotation:(id)sender;
{
id dLink=nil;
if (aRotate){
dLink=[[REDisplayLink sharedDisplayLink] observers];
[[REDisplayLink sharedDisplayLink] removeObserver:[dLink objectAtIndex:0]];
}
else{
CADisplayLink *aDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleAutorotationTimer)];
[aDisplayLink setFrameInterval:2];
[aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
// [[REDisplayLink sharedDisplayLink] addObserver:[[REDirector alloc]init]];
}
aRotate = !aRotate;
}
Related
To Erase I'm using kCGBlendModeClear.
e.g. I have one erased image, would like to get redraw on erased image when move on CGContext.
Image : https://www.dropbox.com/s/hsltjqa3ue2dpx8/Simulator%20Screen%20Shot%20-%20iPhone%208%20-%202020-05-09%20at%2019.56.15.png?dl=0
My erase code :
-(void)initialize {
self.userInteractionEnabled = YES;
_tilesFilled = 0;
dragVw = [[UIView alloc] init];
dragVw.backgroundColor = [UIColor redColor];
[dragVw removeFromSuperview];
[self addSubview:dragVw];
if (nil == self.image) {
_tilesX = _tilesY = 0;
self.maskedMatrix = nil;
if (NULL != _imageContext) {
CGContextRelease(_imageContext);
_imageContext = NULL;
}
if (NULL != _colorSpace) {
CGColorSpaceRelease(_colorSpace);
_colorSpace = NULL;
}
} else {
self.touchPoints = [NSMutableArray array];
// CGSize size = self.image.size;
// CGSize fromImage = [self aspectScaledImageSizeForImageView:self image:self.image];
CGSize size = /*CGSizeMake(fromImage.width * pinchScale, fromImage.height * pinchScale);*/ CGSizeMake(self.image.size.width * self.image.scale, self.image.size.height * self.image.scale);
// initalize bitmap context
if (NULL == _colorSpace) {
_colorSpace = CGColorSpaceCreateDeviceRGB();
}
if (NULL != _imageContext) {
CGContextRelease(_imageContext);
}
_imageContext = CGBitmapContextCreate(0, size.width, size.height, 8, size.width * 4 , _colorSpace, kCGImageAlphaPremultipliedLast);
CGContextDrawImage(_imageContext, CGRectMake(0, 0, size.width, size.height), self.image.CGImage);
int blendMode = kCGBlendModeClear;
CGContextSetBlendMode(_imageContext, (CGBlendMode) blendMode);
_tilesX = size.width / (2 * __radius);
_tilesY = size.height / (2 * __radius);
offset = 0;
}
-(void)moveTouches:(NSSet*)touches {
// CGSize fromImage = [self aspectScaledImageSizeForImageView:self image:self.image];
CGSize size = /*CGSizeMake(fromImage.width, fromImage.height);*/ CGSizeMake(self.image.size.width * self.image.scale, self.image.size.height * self.image.scale);
CGContextRef ctx = _imageContext;
CGContextSetFillColorWithColor(ctx,[UIColor clearColor].CGColor);
CGContextSetStrokeColorWithColor(ctx,[UIColor colorWithRed:0 green:0 blue:0 alpha:0].CGColor);
// int tempFilled = _tilesFilled;
// process touches
for (UITouch *touch in touches) {
CGContextBeginPath(ctx);
CGPoint touchPoint = CGPointMake([touch locationInView:self].x , [touch locationInView:self].y);
touchPoint = fromUItoQuartz(touchPoint, self.bounds.size);
touchPoint = scalePoint(touchPoint, self.bounds.size, size);
CGPoint dragPoint = [touch locationInView:self];
CGFloat fineRadius = __radius;
NSLog(#"__radius : %zu",__radius);
dispatch_async(dispatch_get_main_queue(), ^{
self->dragVw.frame = CGRectMake(dragPoint.x - fineRadius/2 , dragPoint.y - fineRadius/2, fineRadius, fineRadius);
self->dragVw.layer.cornerRadius = self->dragVw.frame.size.height / 2;
self->dragVw.alpha = 0;
// NSLog(#"DragVw frame : %#",NSStringFromCGRect(self->dragVw.frame));
});
if(UITouchPhaseBegan == touch.phase){
[self.touchPoints removeAllObjects];
[self.touchPoints addObject:[NSValue valueWithCGPoint:touchPoint]];
[self.touchPoints addObject:[NSValue valueWithCGPoint:touchPoint]];
// on begin, we just draw ellipse
CGRect rect = CGRectMake(touchPoint.x - __radius, touchPoint.y - __radius, __radius*2, __radius*2);
CGContextAddEllipseInRect(ctx, rect);
CGContextFillPath(ctx);
static const FillTileWithPointFunc fillTileFunc = (FillTileWithPointFunc) [self methodForSelector:#selector(fillTileWithPoint:)];
(*fillTileFunc)(self,#selector(fillTileWithPoint:),rect.origin);
} else if (UITouchPhaseMoved == touch.phase) {
[self.touchPoints addObject:[NSValue valueWithCGPoint:touchPoint]];
// then touch moved, we draw superior-width line
CGContextSetStrokeColor(ctx, CGColorGetComponents([UIColor clearColor].CGColor));
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 2 * __radius);
while(self.touchPoints.count > 3){
CGPoint bezier[4];
bezier[0] = ((NSValue*)self.touchPoints[1]).CGPointValue;
bezier[3] = ((NSValue*)self.touchPoints[2]).CGPointValue;
CGFloat k = 0.3;
CGFloat len = sqrt(pow(bezier[3].x - bezier[0].x, 2) + pow(bezier[3].y - bezier[0].y, 2));
bezier[1] = ((NSValue*)self.touchPoints[0]).CGPointValue;
bezier[1] = [self normalizeVector:CGPointMake(bezier[0].x - bezier[1].x - (bezier[0].x - bezier[3].x), bezier[0].y - bezier[1].y - (bezier[0].y - bezier[3].y) )];
bezier[1].x *= len * k;
bezier[1].y *= len * k;
bezier[1].x += bezier[0].x;
bezier[1].y += bezier[0].y;
bezier[2] = ((NSValue*)self.touchPoints[3]).CGPointValue;
bezier[2] = [self normalizeVector:CGPointMake( (bezier[3].x - bezier[2].x) - (bezier[3].x - bezier[0].x), (bezier[3].y - bezier[2].y) - (bezier[3].y - bezier[0].y) )];
bezier[2].x *= len * k;
bezier[2].y *= len * k;
bezier[2].x += bezier[3].x;
bezier[2].y += bezier[3].y;
CGContextMoveToPoint(ctx, bezier[0].x , bezier[0].y + offset );
CGContextAddCurveToPoint(ctx, bezier[1].x , bezier[1].y + offset, bezier[2].x , bezier[2].y + offset, bezier[3].x , bezier[3].y + offset);
[self.touchPoints removeObjectAtIndex:0];
}
CGContextStrokePath(ctx);
CGPoint prevPoint = [touch previousLocationInView:self];
prevPoint = fromUItoQuartz(prevPoint, self.bounds.size);
prevPoint = scalePoint(prevPoint, self.bounds.size, size);
static const FillTileWithTwoPointsFunc fillTileFunc = (FillTileWithTwoPointsFunc) [self methodForSelector:#selector(fillTileWithTwoPoints:end:)];
(*fillTileFunc)(self,#selector(fillTileWithTwoPoints:end:),touchPoint, prevPoint);
}
}
}
So, it seems that GLKit has GLKMathUnproject which can be used to work out where you clicked in 3D space (awesome)
However, I cant get it to work, I have copied a few different examples in and it still does not detect me clicking on my cube at 0,0,0. I basically do a for next loop and see if my ray hits my cube.
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet* allTouches = [event allTouches];
UITouch*touch1 = [[allTouches allObjects] objectAtIndex:0];
CGPoint touch1Point = [touch1 locationInView:self.view];
GLKVector3 window_coord = GLKVector3Make(touch1Point.x,touch1Point.y, 0.0f);
bool result;
GLint viewport[4] = {};
glGetIntegerv(GL_VIEWPORT, viewport);
GLKVector3 near_pt = GLKMathUnproject(window_coord, _baseModelViewMatrix, _projectionMatrix, &viewport[0], &result);
window_coord = GLKVector3Make(touch1Point.x,touch1Point.y, 1.0f);
GLKVector3 far_pt = GLKMathUnproject(window_coord, _baseModelViewMatrix, _projectionMatrix, &viewport[0], &result);
//need to get z=0 from
//assumes near and far are on opposite sides of z=0
float z_magnitude = fabs(far_pt.z-near_pt.z);
float near_pt_factor = fabs(near_pt.z)/z_magnitude;
float far_pt_factor = fabs(far_pt.z)/z_magnitude;
GLKVector3 final_pt = GLKVector3Add( GLKVector3MultiplyScalar(near_pt, far_pt_factor), GLKVector3MultiplyScalar(far_pt, near_pt_factor));
float xDif = (final_pt.x - near_pt.x) / 1000;
float yDif = (final_pt.y - near_pt.y) / 1000;
float zDif = (final_pt.z - near_pt.z) / 1000;
for (int i = 0; i < 100; i ++)
{
if ((near_pt.x + (xDif * i)) > self.cube.position.x - self.cube.scale.x && (near_pt.x + (xDif * i)) < self.cube.position.x + self.cube.scale.x &&
(near_pt.y + (yDif * i)) > self.cube.position.y - self.cube.scale.y && (near_pt.y + (yDif * i)) < self.cube.position.y + self.cube.scale.y &&
(near_pt.z + (zDif * i)) > self.cube.position.z - self.cube.scale.z && (near_pt.z + (zDif * i)) < self.cube.position.z + self.cube.scale.z)
{
NSLog(#"%f %f %f", final_pt.x, final_pt.y, final_pt.z);
NSLog(#"Hit cube");
}
}
}
I found the answer here
Updating OpenGL ES Touch Detection (Ray Tracing) for iPad Retina?
- (void)handleTap: (UITapGestureRecognizer *)recognizer
{
CGPoint tapLoc = [recognizer locationInView:self.view];
tapLoc.x *= [UIScreen mainScreen].scale;
tapLoc.y *= [UIScreen mainScreen].scale;
bool testResult;
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
float uiKitOffset = 113; //Need to factor in the height of the nav bar + the height of the tab bar at the bottom in the storyboard.
GLKVector3 nearPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, (tapLoc.y-viewport[3]+uiKitOffset)*-1, 0.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);
GLKVector3 farPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, (tapLoc.y-viewport[3]+uiKitOffset)*-1, 1.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);
farPt = GLKVector3Subtract(farPt, nearPt);
....
}
I am trying hands at Core Animation on iphone.
Details of what I have done so far:
I am using layers and CAKeyFrameAnimation using path.
I have created a layer with Contents set to a bitmap file of a fly which I want to animate on a spiral path. The centre point of the spiral path is at CGPoint (150,150). The end point of the spiral path is a radius of 100.0f.
What I want to achieve:
I further want to increase the radius to a value so that the spiral can go beyond the bounds of the view frame, but when it reaches the bound, I desire the fly to trace back the path.
EDIT: (adding code):
-(IBAction) clickToAnimate:(id) sender
{
//create a path to animate the fly
CGFloat minRadius = 5.0f;
CGFloat maxRadius = 100.0f;
CGFloat radiusOffset = 5.0f;
float i;
int count =1;
int remainder;
curvePath = CGPathCreateMutable();
//this looping mimics the "spiral path"
for (i = minRadius; i <= maxRadius; i = i + 5.0f)
{
remainder = count % 2;
if (remainder == 0)
{
CGPathAddArc(curvePath, NULL, currentPoint.x, currentPoint.y, i, M_PI / 2, 1.5 * M_PI, NO);
}
else
{
CGPathAddArc(curvePath, NULL, currentPoint.x, currentPoint.y + radiusOffset, i, 1.5 * M_PI , M_PI / 2, NO);
}
count = count +1;
}
//add timer
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(checkCoordinatesOnTimer) userInfo:self repeats:YES];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
animation.calculationMode = kCAAnimationPaced;
animation.path = curvePath;
animation.duration = 25.0f;
animation.autoreverses = YES;
animation.fillMode = kCAFillModeFrozen;
CGPathRelease(curvePath);
[animationLayer addAnimation:animation forKey:#"position"];
}
Approach taken:
I set up a timer, which would check the co-ordinates of the animation layer every half second. The co-ordinates would be checked against the bounding x and y co-ordinates. If the co-ordinates are found to cross the boundary, we will disable the timer and start with the reverse animation process.
The reverse animation process would first check the angle from horizontal at which the animation is when it crosses the boundary. Using this angle and radius from center point, create a path for reverse animation. Details can be found in code below.
- (void) checkCoordinatesOnTimer
{
if (!presentLayer)
{
presentLayer =[[CALayer alloc] init];
}
presentLayer = [animationLayer presentationLayer];
CGPoint curPt;
curPt.x = presentLayer.position.x;
curPt.y = presentLayer.position.y;
currRadius = sqrt(pow(fabsf(curPt.x - centerPoint.x), 2) + pow(fabsf(curPt.y - centerPoint.y), 2));
if ((curPt.x >= CGRectGetMaxX(self.view.frame)) || (curPt.y >= CGRectGetMaxY(self.view.frame)))
{
[timer invalidate];
[self reverseAnimation:curPt];
}
}
-(void) reverseAnimation:(CGPoint)curPoint
{
CGFloat angle = (CGFloat)[self calculateAngleInRadians:curPoint];
maxRadius = currRadius;
float i;
int count =1;
int remainder;
BOOL firstLap = YES;
CGPathRelease(curvePath);
curvePath = CGPathCreateMutable();
for (i = maxRadius; i >= minRadius; i = i - 5.0f)
{
remainder = count % 2 ;
if (firstLap)
{
if ((angle >= (M_PI/2)) && (angle <= 1.5 *M_PI))
//2nd and third quard,
//angle to change from final angle to 90
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, angle, 1.5 * M_PI, FALSE);
}
else
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, angle, M_PI / 2 , FALSE);
}
firstLap = NO;
continue;
}
else
{
if (remainder == 0)
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, 1.5* M_PI, M_PI / 2, FALSE);
}
else
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y + radiusOffset, i, M_PI / 2 ,1.5* M_PI, FALSE);
}
}
count = count +1;
}
animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
animation.calculationMode =kCAAnimationPaced; // for even pacing of animation in segments.
animation.path = curvePath;
animation.duration = 40.0f;
animation.fillMode = kCAFillModeForwards;
CGPathRelease(curvePath);
[animationLayer addAnimation:animation forKey:#"position"];
}
-(CGFloat) calculateAngleInRadians:(CGPoint) pt
{
CGFloat xLen = fabsf(centerPoint.x - pt.x);
CGFloat yLen = fabsf(centerPoint.y - pt.y);
double value = yLen/xLen;
double angle = atan(value);
double angleInDeg = ( 180 * angle/ M_PI);
double finalAngle;
if ((pt.x > centerPoint.x) || (pt.y > centerPoint.y)) {
finalAngle = angle;
}
else if ((centerPoint.x > pt.x) || (pt.y > centerPoint.y))
{
finalAngle = M_PI/2 + angle;
}
else if ((centerPoint.x > pt.x) || (centerPoint.y > pt.y))
{
finalAngle = M_PI + angle;
}
else {
finalAngle = (1.5 * M_PI) + angle;
}
return finalAngle;
}
I'm trying to animate a view from the center of the screen to the upper left corner in a spiral-type motion. Here's what I'm doing:
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, viewOrigin.x, viewOrigin.y);
controlX1 = viewOrigin.x + halfScreenWidth*0.3;
controlY1 = viewOrigin.y + halfScreenHeight*0.1;
controlX2 = viewOrigin.x - halfScreenWidth*0.05;
controlY2 = viewOrigin.y + halfScreenHeight*0.5;
controlX3 = viewOrigin.x - halfScreenWidth*0.4;
controlY3 = viewOrigin.y;
rndX1 = viewOrigin.x + halfScreenWidth*.1;
rndX2 = viewOrigin.x - halfScreenWidth*.40;
rndY1 = viewOrigin.y + halfScreenHeight*.10;
rndY2 = viewOrigin.y + halfScreenHeight*.35;
}
CGPathAddQuadCurveToPoint(curvedPath, NULL, controlX1, controlY1, rndX1, rndY1);
CGPathAddQuadCurveToPoint(curvedPath, NULL, controlX2, controlY2, rndX2, rndY2);
CGPathAddQuadCurveToPoint(curvedPath, NULL, controlX3, controlY3, endPoint.x, endPoint.y);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeForwards;
[group setAnimations:[NSArray arrayWithObjects: pathAnimation, nil]];
group.duration = 3.0f;
group.delegate = self;
[group setValue:self.theView forKey:#"imageViewBeingAnimated"];
The view moves to each point on the curve, but it's not smooth, and not very curvy either. It just moves in pretty much a straight line to each point. Why isn't the path curved? I'm using this as a reference.
If you want a more smooth spiral, you could use the following function. It' s possible to adjust the code to have an opening spiral also.
-(void)addEnteringSpiralOnPath: (CGMutablePathRef) path
size: (CGSize)size
turns: (int)turns
{
CGPathMoveToPoint(path, NULL, size.width/2, 0); //To begining: Right
for (int turn = turns; turn >= 1; turn--) {
CGSize largeSize = CGSizeMake(size.width * turn/turns, size.height * turn/turns);
CGSize smallSize = CGSizeMake(size.width * (turn-1) / turns, size.height * (turn-1) / turns);
NSLog(#"Large: %#; Small: %#", NSStringFromCGSize(largeSize), NSStringFromCGSize(smallSize));
CGFloat wStep = (largeSize.width/2 - smallSize.width/2 ) / 360;
CGFloat hStep = (largeSize.height/2 - smallSize.height/2 ) / 360;
for (CGFloat i = 0; i<=360; i = i + 10) {
CGFloat iRad = i * M_PI / 180.0f;
CGPoint p = CGPointMake(cosf(iRad) * (largeSize.width/2 - wStep * i),
sinf(iRad) * (largeSize.height/2 - hStep * i));
CGPathAddLineToPoint(path, nil, p.x, p.y);
}
}
}
-(void)addOpenningSpiralOnPath: (CGMutablePathRef) path
size: (CGSize)size
turns: (int)turns
{
CGPathMoveToPoint(path, NULL, 0, 0); //To begining: Center
for (int turn = 1; turn <= turns; turn++) {
CGSize largeSize = CGSizeMake(size.width * turn/turns, size.height * turn/turns);
CGSize smallSize = CGSizeMake(size.width * (turn-1) / turns, size.height * (turn-1) / turns);
NSLog(#"Large: %#; Small: %#", NSStringFromCGSize(largeSize), NSStringFromCGSize(smallSize));
CGFloat wStep = (largeSize.width/2 - smallSize.width/2 ) / 360;
CGFloat hStep = (largeSize.height/2 - smallSize.height/2 ) / 360;
for (CGFloat i = 0; i<=360; i = i + 10) {
CGFloat iRad = i * M_PI / 180.0f;
CGPoint p = CGPointMake(cosf(iRad) * (smallSize.width/2 + wStep * i),
sinf(iRad) * (smallSize.height/2 + hStep * i));
CGPathAddLineToPoint(path, nil, p.x, p.y);
}
}
}
Then, you will just need a simple code like that to make the path:
CGMutablePathRef pathToDraw = CGPathCreateMutable();
[self addEnteringSpiralOnPath:pathToDraw size:CGSizeMake(400, 400) turns:3];
I'm trying to build something similar to Canabalt, adding holes and different heights between buildings (modules). You can see a screenshot of how the game is looking right now at: http://twitpic.com/4kb5jd
Here is the code I'm currently using:
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] )) {
moduleSize = 160;
screenSize = [[CCDirector sharedDirector] winSize];
CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"ModulesScene1.plist"];
CCTexture2D* gameArtTexture = [[CCTextureCache sharedTextureCache] addImage:#"ModulesScene1.png"];
// Create the background spritebatch
spriteBatch = [CCSpriteBatchNode batchNodeWithTexture:gameArtTexture];
[self addChild:spriteBatch];
numStripes = 1;
/* BEGIN MODULES */
NSString* frameName = [NSString stringWithFormat:#"Module0-hd.png"];
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(0, screenSize.height / 2);
[spriteBatch addChild:sprite z:0 tag:0];
frameName = [NSString stringWithFormat:#"Module0-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake((moduleSize - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:1 tag:1];
frameName = [NSString stringWithFormat:#"Module1-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake((moduleSize * 2) - 1.1f, screenSize.height / 2);
[spriteBatch addChild:sprite z:2 tag:2];
frameName = [NSString stringWithFormat:#"Module2-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 3) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:3 tag:3];
frameName = [NSString stringWithFormat:#"Module0-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 4) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:4 tag:4];
frameName = [NSString stringWithFormat:#"Module1-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 5) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:5 tag:5];
/* END MODULES */
// Get current scrollSpped
scrollSpeed = [[GameManager sharedGameManager] scrollSpeed];
speedFactors = [[CCArray alloc] initWithCapacity:numStripes];
[speedFactors addObject:[NSNumber numberWithFloat:2.5f]];
NSAssert([speedFactors count] == numStripes, #"speedFactors count does not match numStripes!");
[self scheduleUpdate];
}
return self;
}
-(void) update:(ccTime)delta
{
CCSprite* sprite;
scrollSpeed = [[GameManager sharedGameManager] scrollSpeed];
CCARRAY_FOREACH([spriteBatch children], sprite)
{
NSNumber* factor = [speedFactors objectAtIndex:0];
CGPoint pos = sprite.position;
pos.x -= scrollSpeed * [factor floatValue];
if (pos.x < -screenSize.width)
{
pos.x += ((screenSize.width * 2) - 2);
int x = (arc4random() % 3);
int xHole = (arc4random() % 10);
NSString *randomName = nil;
CCSpriteFrame *randomFrame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:randomName];
[sprite setDisplayFrame:randomFrame];
}
sprite.position = pos;
}
}
to add holes between the buildings you could add a simple rand() function like that in the init method:
...
sprite.position = CGPointMake(((moduleSize * 3) - 1.1f + (rand()%40)), screenSize.height / 2);
...
this will add a random gap (max 40 points)