I want to animate a circle with a border thickness of about 10px. Any ideas how I can achieve this with Sparrow? I have tried using a texture map but the results aren't great. It is for a progress indicator so I am passing a variable from 0 - 100. Any help would be great. Thanks Matt
Animate a solid circle
(16 posts) (3 voices)-
Posted 6 months ago #
-
What do you mean? Starting at 10 px thickness and filling to a solid circle?
Posted 6 months ago # -
Sorry I should have changed the title. Essentially what I want to do is animate a circle with a thickness of about 10px. Like a clock it draws the circle as the passed in variable increases to 100.
Posted 6 months ago # -
It's probably best to use CoreGraphics draw methods in this case. See this page:
http://www.raywenderlich.com/2106/core-graphics-101-arcs-and-paths
Posted 6 months ago # -
I'm new to sparrow but can I draw to a SPSprite using Core Graphics ? or is there another way to do it?
Posted 6 months ago # -
Your SPView is a subclass of UIView, so just override the drawRect function as noted in the link (Don't need to use Sparrow classes).
Posted 6 months ago # -
Hello rosiematt,
First, what type of circle are you trying to achieve? I simple solid color circle with a fill and border? Or are you wanting to animate an image as the circle?
Second, borrden has the right idea if you don't want to go the OpenGL route, but you wouldn't use drawRect: since that method isn't invoked in an OpenGL view.
To draw Core Graphics into Sparrow you'd do something like this sample from Daniel: (I should give him some credit!)
SPTexture *cgTexture = [[SPTexture alloc] initWithWidth:256 height:128 draw:^(CGContextRef context) { // draw a string CGContextSetGrayFillColor(context, 1.0f, 1.0f); NSString *string = @"Hello Core Graphics"; [string drawAtPoint:CGPointMake(20.0f, 20.0f) withFont:[UIFont fontWithName:@"Arial" size:25]]; }];
As you can see, you can draw Quartz content inside an SPTexture. This method opens a whole other world of possibilities but it does have it's draw-backs with performance.
If you wan't something fairly simple to use for animating a circle with solid colors and you don't mind non anti-alaising, you might be interested in one of my old extensions: http://wiki.sparrow-framework.org/users/shilo/extensions/shcircle. This class was designed to render the circle with partial degrees, as you can see by the video. There as some issues with the class though, so take it with a grain of salt.
If you choose to go the Core Graphics / Quartz route, you'd have to research on how to draw the circle with arc paths or something along that line. I did create a sample class that does something similar to what you want, but I don't have time to improve it and it doesn't seem to work perfect, but you might get some ideas from it.
AnimatedCircleImage.m (Again, this class was just a quick mockup)
@interface AnimatedCircleImage () - (void)draw; @end @implementation AnimatedCircleImage @synthesize fillRadians = mFillRadians; - (id)initWithContentsOfFile:(NSString*)path { return [self initWithContentsOfFile:path fillRadians:PI]; } - (id)initWithContentsOfFile:(NSString*)path fillRadians:(float)fillRadians { if ((self = [super init])) { float contentScaleFactor = [SPStage contentScaleFactor]; NSString *fullPath = [SPUtils absolutePathToFile:path withScaleFactor:contentScaleFactor]; if (!fullPath) { [self release]; [NSException raise:SP_EXC_FILE_NOT_FOUND format:@"file '%@' not found", path]; } mFullPath = [fullPath retain]; mFillRadians = fillRadians; [self draw]; } return self; } - (void)setFillRadians:(float)fillRadians { if (fillRadians != mFillRadians) { mFillRadians = fillRadians; [self draw]; } } - (void)draw { UIImage *image = [UIImage imageWithContentsOfFile:mFullPath]; float width = image.size.width; float height = image.size.height; self.width = width; self.height = height; self.texture = [[[SPTexture alloc] initWithWidth:width height:height draw:^(CGContextRef context) { CGMutablePathRef path = CGPathCreateMutable(); CGPathAddArc(path, NULL, width/2, height/2, MAX(width,height)/2, 0, mFillRadians, 0); CGContextAddPath(context, path); CGContextClip(context); [image drawInRect:CGRectMake(0, 0, width, height)]; }] autorelease]; } - (void)dealloc { [super dealloc]; } @end
Posted 6 months ago # -
Oh dear...I am 0 for 2 now...how embarrassing :p. I guess I got confused with another project I am doing which is not an OpenGL view ><.
Posted 6 months ago # -
Non-sense! What matters is that you tried, and you did give valuable advice.
Posted 6 months ago # -
Thanks Shilo and Borrrden, worked like a charm !
Posted 6 months ago # -
Hi guys, I was wondering if anyone had any luck with masking?
My spaceships have a background image with a black SHCircle place above it and a foreground image on top. When the ship charges the SHCircle reduces;
[circle setDegrees: 360 - (int)([chargingObject currentCharge] * 360.0)];
showing the background image. I was wondering if I can use the SHCircle as a mask for the background image instead? I'm from a flash background so not really familiar with CG. Any ideas would be great. Thanks again for all your help.
SPImage *background;
SPImage *foreground;//mask background with circle
circle = [SHCircle circleWithWidth:41 height:41];
circle.radiusX = 20.5f;
circle.radiusY = 20.5f;
circle.degrees = 360;
circle.centerRotation = 45;
circle.color = 0x000000;
circle.innerColor = 0x000000;
circle.outerColor = 0x000000;
circle.border = NO;
circle.borderWidth = 1.0f;
circle.borderColor = 0xff0000;
circle.fill = YES;if (chargingTrack == Outer){
background = [SPImage imageWithContentsOfFile:@"orangebackground.png"];
[self addChild:background];
[self addChild:circle];
foreground = [SPImage imageWithContentsOfFile:@"orangeforeground.png"];
[self addChild:foreground];
}
else if (chargingTrack == Center){
background = [SPImage imageWithContentsOfFile:@"greenbackground.png"];
[self addChild:background];
[self addChild:circle];
foreground = [SPImage imageWithContentsOfFile:@"greenforeground.png"];
[self addChild:foreground];
}
else if (chargingTrack == Inner){
background = [SPImage imageWithContentsOfFile:@"purplebackground.png"];
[self addChild:background];
[self addChild:circle];
foreground = [SPImage imageWithContentsOfFile:@"purpleforeground.png"];
[self addChild:foreground];
}[background setWidth:40.0];
[background setHeight:40.0];
[background setTouchable:NO];[foreground setWidth:40.0];
[foreground setHeight:40.0];
[foreground setTouchable:NO];[self setPivotX:20.0];
[self setPivotY:20.0];[self setWidth:40.0];
[self setHeight:40.0];
self.touchable = YES;Posted 6 months ago # -
Sure...why not? What's the problem? Just keep a reference hanging around to the ship's circle so you can access it quickly :).
Posted 6 months ago # -
Sorry I don't know if I was clear enough. What I want to do is mask the image with the SHCircle. So you don't see the SHCircle, the SHCircle actually masks the image like in Flash when you mask a layer with a shape. If that makes sense?
Posted 6 months ago # -
Oh, I got it now. There have been posts about masking before, but none have had any great results.
CoreGraphics has a function for masking: http://iphonedevelopertips.com/cocoa/how-to-mask-an-image.html
However, it requires CGImages, which cannot be obtained from SPImages. You'd have to draw the circle with CoreGraphics (you can specify fill similar to the way flash works while you draw the arc), and then apply the mask to your (CGImage) background, inside the draw block of SPTexture init.
Posted 6 months ago # -
I worked out a good solution for this problem. Instead of the approach of masking I draw the circle with Core Graphics and use CGContextSetShadowWithColor to create the desired glow effect. At every frame I remove the SPimage, release the SPTexture and then alloc a new one with the new updated circle graphic. Not sure if it is the best way but it seems to run much better like this over using SHCircle. Here is the code if anyone is interested.
[self removeChild:ebackground]; [cgTexture release]; cgTexture = [[SPTexture alloc] initWithWidth:40 height:40 draw:^(CGContextRef context) { CGContextSetStrokeColorWithColor(context, setColour.CGColor); CGContextSetLineWidth(context, 4); CGContextSetShadowWithColor(context, CGSizeMake(0.5f, 0.5f), 5.0f, setColour.CGColor); // Draw progress CGPoint center = CGPointMake(40 / 2, 40 / 2); CGFloat radius = (40 - 4) / 2; CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees CGFloat endAngle = (progress * 2 * (float)M_PI) + startAngle; CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0); CGContextStrokePath(context); }]; ebackground = [SPImage imageWithTexture:cgTexture]; [self addChild:ebackground];
Posted 6 months ago # -
For a small bonus, consider just swapping the texture instead of creating a new SPImage every time ;).
Posted 6 months ago #
Reply
You must log in to post.