Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

drawRect lagging

KroupyKroupy Posts: 269Registered Users @ @
edited May 2009 in iOS SDK Development
Hi

I wrote a game were there's a ball that's flying around three triangles.

Wenn I touch the screen there appears a circle around my finger.

In my GameView file, in the drawRect method, if I allow it to draw the ball, the triangles and my finger's circle then the app just laggs! Well actually the ball and the triangles fly perfectly! But the circle around my finger doesn't follow my finger instantly but it somehow like laggs. It should look like as if I'm actually draging the cirlce, but the circle jumps along the path I drew with my finger on the screen...

If I say: ok, only the ball and my finger, NO triangles, then it doesn't really lag. It is a bit slower than my acutal finger but it's allright.

that means if I want the three triangles to be shown, my finger circle laggs more and more. One triangle lags a bit, two do more and three is like the overkill.

I'm new to this so I hope(!) that it's my code which is wronge. Look at this and please help me if you can finding anything that might be the reason why it's like this.

DrawRect:
- (void)drawRect:(CGRect)rect {
		
	timer += 0.1;
	
        //Frame around the screen

	CGContextRef context = UIGraphicsGetCurrentContext();
	CGContextSetLineWidth(context, 3);
        [[UIColor whiteColor] set];
	UIRectFrame([GameField frame]);
	

        //Flashes the screen if the ball hits the triangle
	if (dreieck.hit == YES) {
		CGContextSetFillColorWithColor(context, dreieck.color);	
		UIRectFill([GameField frame]);
	}
	else if (dreieck2.hit == YES) {
		CGContextSetFillColorWithColor(context, dreieck2.color);
		UIRectFill([GameField frame]);
	}
	else if (dreieck3.hit == YES) {
		CGContextSetFillColorWithColor(context, dreieck3.color);
		UIRectFill([GameField frame]);
	}
	else {
		[[UIColor clearColor] set];
		UIRectFill([GameField frame]);
	}
	


	if (start == 1) {
	
	//Ball	
		
	[[UIColor whiteColor] set];	
		
        CGContextSetStrokeColorWithColor(context, ball.color);
        CGContextSetLineWidth(context, 1.0);
	CGContextFillEllipseInRect(context, [ball getRect]);
		
	//Ring
		
	CGContextSetStrokeColorWithColor(context, dreieck.color);
	CGContextAddEllipseInRect(context, CGRectMake(currentTouch.x - 50, currentTouch.y - 50, 50 * 2.0, 50 * 2.0));
	CGContextStrokePath(context);
		
	
		NSString *ArcadeEinstellung = [[NSUserDefaults standardUserDefaults] stringForKey:@"Arcade"];
		
		if ([ArcadeEinstellung isEqualToString:@"Ja"]) {

	//Triangles
		
		CGContextBeginPath (context); 
		
		//Triangle1
		
		NSMutableArray *Points = [[NSArray alloc] initWithArray:[self getPointsDreieck1]];

		NSValue *theValue = [Points objectAtIndex:0];
		CGPoint startPoint = [theValue CGPointValue];
		CGContextMoveToPoint (context, startPoint.x, startPoint.y); 
		
		for (NSValue *theValue in Points) {
			CGPoint thePoint = [theValue CGPointValue];
			CGContextAddLineToPoint (context, thePoint.x, thePoint.y);
			
		}
		
		CGContextClosePath (context); 
		[[UIColor clearColor] setFill]; 
		CGContextSetStrokeColorWithColor(context, dreieck.color);
		CGContextDrawPath (context, kCGPathFillStroke);
		
		//Triangle2
		
		NSMutableArray *Points2 = [[NSArray alloc] initWithArray:[self getPointsDreieck2]];
		
		NSValue *theValue2 = [Points2 objectAtIndex:0];
		CGPoint startPoint2 = [theValue2 CGPointValue];
		CGContextMoveToPoint (context, startPoint2.x, startPoint2.y); 
		
		for (NSValue *theValue2 in Points2) {
			CGPoint thePoint2 = [theValue2 CGPointValue];
			CGContextAddLineToPoint (context, thePoint2.x, thePoint2.y);
			
		}
		CGContextClosePath (context); 
		[[UIColor clearColor] setFill]; 
		CGContextSetStrokeColorWithColor(context, dreieck2.color);
		CGContextDrawPath (context, kCGPathFillStroke);
		
		//Triangle3
		
		NSMutableArray *Points3 = [[NSArray alloc] initWithArray:[self getPointsDreieck3]];
		
		NSValue *theValue3 = [Points3 objectAtIndex:0];
		CGPoint startPoint3 = [theValue3 CGPointValue];
		CGContextMoveToPoint (context, startPoint3.x, startPoint3.y); 
		
		for (NSValue *theValue3 in Points3) {
			CGPoint thePoint3 = [theValue3 CGPointValue];
			CGContextAddLineToPoint (context, thePoint3.x, thePoint3.y);
			
		}
		CGContextClosePath (context); 
		[[UIColor clearColor] setFill]; 
		CGContextSetStrokeColorWithColor(context, dreieck3.color);
		CGContextDrawPath (context, kCGPathFillStroke);
		
		}
	
	}
	
	start = 1;
}
Post edited by Kroupy on
«1

Replies

  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    no one?
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    You're doing lots of things that could be zapping your efficiency:

    Accessing NSUserDefaults *every* frame you draw is bad. Read it once, somewhere outside your drawRect routine. Allocating and initializing arrays every frame that could be initialized once somewhere outside the drawRect.

    Actually redrawing these primitive shapes regularly is bad too. I'd draw them once each into individual CALayers and then move, rotate, and resize the layers as needed. If that sounds too complex for now, draw the things you need in a paint program and save them into PNG files (only as large as you need) and then use CGContextDrawImage to draw them as images... it wont be as fast or smooth as the CALayers method, but still faster than drawing paths.
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    thank you for your answer! I look for that...
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Got your PM, so to be a bit more clear... Either of my suggested methods should be faster than what you are doing right now. You can rotate or scale any image (loaded PNG files) using Affine Transforms. CALayers you can simply change their rotate.z property to spin them, or you can get very complicated with defining animations. The layer method would give you great performance, but it's more complicated to set up initially in code. I use CALayers in Rogue Touch and they are not at OpenGL performance levels, but not bad for what I needed to display. Certainly more than fast enough for this light duty test app you have.

    As for your user defaults, there's no need to load them inside the drawRect routine. Load them into some sort of globally accessible variable inside applicationDidFinishLaunching and then just refer to that variable each time you update the frame.

    I can tell you're not completely noobish by looking at the code you have here, but it probably wouldn't hurt to take a few steps back and read over some more objective C and iPhone developer info at Apple's site. Maybe look at some of the samples they have for drawing things on the screen, tracking movements, loading defaults.

    Good luck to you, hopefully you get the performance boost you're looking for :D
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    Got your PM, so to be a bit more clear... Either of my suggested methods should be faster than what you are doing right now. You can rotate or scale any image (loaded PNG files) using Affine Transforms. CALayers you can simply change their rotate.z property to spin them, or you can get very complicated with defining animations. The layer method would give you great performance, but it's more complicated to set up initially in code. I use CALayers in Rogue Touch and they are not at OpenGL performance levels, but not bad for what I needed to display. Certainly more than fast enough for this light duty test app you have.

    As for your user defaults, there's no need to load them inside the drawRect routine. Load them into some sort of globally accessible variable inside applicationDidFinishLaunching and then just refer to that variable each time you update the frame.

    I can tell you're not completely noobish by looking at the code you have here, but it probably wouldn't hurt to take a few steps back and read over some more objective C and iPhone developer info at Apple's site. Maybe look at some of the samples they have for drawing things on the screen, tracking movements, loading defaults.

    Good luck to you, hopefully you get the performance boost you're looking for :D


    Hi thanks again!

    Well, I took out this NSUserDefaults, that's not a problem. I will look for these CALayers. I actually have no idea what these things are ;-) but I look at Apple's site or elsewhere. Maybe I'll ask you again an other time ;-)
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    It's complicated, yes.

    Somehow when I'm having a drawLayer method it doesn't execute the drawRect method...and the [[UIColor color] setFill]; line doesn't work with layer. I can set the stroke color but not the Fill color.

    AAAAND. I managed (somehow, don't know how I got it) to draw one of my triangles into an layer and let it fly around, nice, but....it "paths" - I mean sometimes there is like a path behind the triangle, like the view forgot to delete the old positions, so it looks like 5 triangles just before it clears the view...

    I don't know...It's really weird....I hope I'm just too dumb XD

    Once again, if someone could just help me with this out...

    The coordinates of the triangle is calculated, everythings ready. Just need to put that triangle into a layer and spin it around.

    How shall I make 3 triangles? I have to have 3 layers, but it exists only one drawLayer method....

    I DON'T get IT.

    Please, help.

    Me


    EDIT: Really, just help me this way: Do I have to have ONE UIView file for ONE Layer or can I have ONE UIView file and multiple Layers? And when drawing them via "drawLayer", is it more efficient than drawRect?
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Kroupy wrote: »
    It's complicated, yes.

    Somehow when I'm having a drawLayer method it doesn't execute the drawRect method...and the [[UIColor color] setFill]; line doesn't work with layer. I can set the stroke color but not the Fill color.

    AAAAND. I managed (somehow, don't know how I got it) to draw one of my triangles into an layer and let it fly around, nice, but....it "paths" - I mean sometimes there is like a path behind the triangle, like the view forgot to delete the old positions, so it looks like 5 triangles just before it clears the view...

    I don't know...It's really weird....I hope I'm just too dumb XD

    Once again, if someone could just help me with this out...

    The coordinates of the triangle is calculated, everythings ready. Just need to put that triangle into a layer and spin it around.

    How shall I make 3 triangles? I have to have 3 layers, but it exists only one drawLayer method....

    I DON'T get IT.

    Please, help.

    Me


    EDIT: Really, just help me this way: Do I have to have ONE UIView file for ONE Layer or can I have ONE UIView file and multiple Layers? And when drawing them via "drawLayer", is it more efficient than drawRect?

    You can have one UIView with multiple layers. I did a test program with a friend recently that had over 120 CALayers added to one UIView... Rogue Touch uses only about 8 or 10. The idea of using layers here for your case is so that you only draw them ONCE, then do not draw them again. Then the performance will be lightning fast compared to what you have seen. Any rotations and whatnot are applied to the frame of the individual CALayer. If you need to rotate a triangle, do not re-draw it in the CALayer in a rotated position, simply set the rotate.z of the CALayer and let core animation handle it for you. That will be much quicker and smoother.

    To have different drawing activities for different layers:
    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
        if (layer==triangle1Layer) [self drawTriangle1Layer:ctx];
        if (layer==triangle2Layer) [self drawTriangle2Layer:ctx];
        if (layer==circle1Layer) [self drawCircle1Layer:ctx];
    }
    
    

    Then you build up 3 routines that do the drawing you want named "drawTriangle1Layer", "drawTriangle2Layer", and "drawCircle1Layer"....

    That way the drawing can be different depending on which layer needed to be drawn.

    Hope that pushes you further along. :D
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    Yeah, I thought the whole day about this, and I thought of something like this. I thought it has to be drawn once only and then modified.

    But, somehow the drawlayer method is executed tons of times....it should be only once initialized, shouldn't it?
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Kroupy wrote: »
    Yeah, I thought the whole day about this, and I thought of something like this. I thought it has to be drawn once only and then modified.

    But, somehow the drawlayer method is executed tons of times....it should be only once initialized, shouldn't it?

    Are you forcing updates with [setNeedsDisplay] somewhere? They should not re-trigger over and over again. My CALayers remain static unless I explicitly force them to redraw with setNeedsDisplay.

    You might need to post some new code if you get stuck on this for a while :)
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    A yes, I have setneeddisplay on bounds change, ok thanks, I'll change that.

    One more question, and I will be practising.

    These methods, that build up the layer, how do they know which layer they have to draw in? I pass over the context how to say: draw in layer1?

    Where do I start to draw? Is like CGPointMake(0,0) is this the top left corner of the screen or of the layer?? You know what I mean? Just this small step, I looked on the Apple Developer Documentary but they like draw it just "normal" and I don't see how it knows where it has to draw....
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Kroupy wrote: »
    A yes, I have setneeddisplay on bounds change, ok thanks, I'll change that.

    One more question, and I will be practising.

    These methods, that build up the layer, how do they know which layer they have to draw in? I pass over the context how to say: draw in layer1?

    Where do I start to draw? Is like CGPointMake(0,0) is this the top left corner of the screen or of the layer?? You know what I mean? Just this small step, I looked on the Apple Developer Documentary but they like draw it just "normal" and I don't see how it knows where it has to draw....


    if you follow the way I described and call other methods based on what Layer is passed into the drawLayer routine you would end up with something like this:
    -(void)drawTriangle1Layer:(CGContextRef)viewContext {
        // draw anything that needs to be in the triangle one layer here
    
    }
    
    -(void)drawTriangle2Layer:(CGContextRef)viewContext {
        // draw anything that needs to be in the triangle two layer here
    
    }
    
    -(void)drawCircle1Layer:(CGContextRef)viewContext {
        // draw anything that needs to be in the circle one layer here
    
    }
    
    

    Note that you are passing in the correct context, so you use that "viewContext" reference for your drawing in these methods. Other interesting bits for you:

    Top left inside the CALayer is 0,0.
    The X,Y position of a CALayer in its parent layer is centered on its frame width and height.
    You should be able to draw them once and have them transparently overlap each other on your screen, move them around, and rotate them.

    Good luck! Sounds like you're learning quite a bit already :D
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    Thank you a lot! I look what I can do. You get a free copy of this game XDDD
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    Strange. It sais "invalid context".

    I tried almost everything. I passed the Context from the viewcontroller to the view, or I called a method from the controller which gets the context and THEN calls drawLayer...

    but self made method: - (void)drawDreieck1:(CGContextRef)aContext

    says all the time and at every line "invalid context" in the debugger console.

    Any idea?

    I looked for some help, but they all say the only place to actually DRAW things HAS to be the drawRect method, but that can't be true, as you said I should make my own methods. Or shall these methods call drawRect?
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Kroupy wrote: »
    Strange. It sais "invalid context".

    I tried almost everything. I passed the Context from the viewcontroller to the view, or I called a method from the controller which gets the context and THEN calls drawLayer...

    but self made method: - (void)drawDreieck1:(CGContextRef)aContext

    says all the time and at every line "invalid context" in the debugger console.

    Any idea?

    I looked for some help, but they all say the only place to actually DRAW things HAS to be the drawRect method, but that can't be true, as you said I should make my own methods. Or shall these methods call drawRect?

    These methods would be called from WITHIN drawLayer (as I showed in an earlier post above). You wont be able to call them directly. When you want to set up the layers with the images inside them for the first time:
    [triangle1Layer setNeedsDisplay];
    [triangle2Layer setNeedsDisplay];
    [circle1Layer setNeedsDisplay];
    
    **** Note- place these somewhere that they will be called one time, like when you are just setting up your view and adding CALayers to it
    


    This is exactly the way I handle it in Rogue Touch, you setNeedsDisplay if you need to redraw a layer. Then drawLayer determines which layer in the UIView needs to be redrawn based on the layer passed into it (by the setNeedsDisplay call). Finally drawLayer passes the context out to a method that does the actual drawing inside that layer.

    I guarantee you if you follow the rules step by step you'll have a valid context to draw in ;)

    Maybe that clears up your issues? :D
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    Here you go, I call the prepareDrawLayer method from within the UIView's controller:
    - (void)drawDreieck1:(CGContextRef)aContext
    {
    	CGContextBeginPath (aContext); 
    	
    	CGContextMoveToPoint (aContext, 50.0, 0.9); 
    	CGContextAddLineToPoint (aContext, 0.0, 50.0);
    	CGContextAddLineToPoint (aContext, 100.0, 50.0);
    
    	CGContextClosePath (aContext); 
    	[[UIColor redColor] setFill]; 
    	CGContextSetStrokeColorWithColor(aContext, dreieck.color);
    	CGContextDrawPath (aContext, kCGPathFillStroke);
    }
    
    - (void)prepareDrawLayer:(CALayer *)aLayer {
    	CGContextRef context = UIGraphicsGetCurrentContext();
    	[self drawLayer:aLayer inContext:context];
    }
    - (void)drawLayer:(CALayer *)theLayer
            inContext:(CGContextRef)context
    {
    	if (theLayer.name==@&quot;LayerDreieck1&quot;) {
    		[self drawDreieck1:context];
    	}
    	
    	
    }
    
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Ahhh I see the problem:
    - (void)drawDreieck1:(CGContextRef)aContext
    {
    	CGContextBeginPath (aContext); 
    	
    	CGContextMoveToPoint (aContext, 50.0, 0.9); 
    	CGContextAddLineToPoint (aContext, 0.0, 50.0);
    	CGContextAddLineToPoint (aContext, 100.0, 50.0);
    
    	CGContextClosePath (aContext); 
    	[[UIColor redColor] setFill]; 
    	CGContextSetStrokeColorWithColor(aContext, dreieck.color);
    	CGContextDrawPath (aContext, kCGPathFillStroke);
    }
    
    // changed this a bit *****************************
    - (void)prepareDrawLayer {
          // just prepare the three layers in my sample by calling setNeedsDisplay on them
    
          [LayerDreieck1 setNeedsDisplay];
    
          // add in additional layers you need to prepare here...
    }
    - (void)drawLayer:(CALayer *)theLayer
            inContext:(CGContextRef)context
    {
    	if (theLayer.name==@&quot;LayerDreieck1&quot;) {
    		[self drawDreieck1:context];
    	}
    	
    	
    }
    


    The only time you can get a valid context to draw in is inside drawLayer. You cannot call drawLayer directly. You must call setNeedsDisplay and let the system handle the request... Maybe now you can make some progress ;)
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    awesome!

    No errors....except that I don't see anything at all.....But at least there are no errors....thanks a lot!
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    So, I see that inside my preparation method my "aLayer" has got a .name to ask for.

    But inside the drawlayer method when I write:

    NSLog(@layername %@", theLayer.name);

    I gett "layername: (NULL)"

    but the same NSLog command inside the "prepare" method shows the right name! My guess is that the drawlayer somehow doesn't get the layer it has to draw on....
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    How are you creating these additional layers and adding them to your UIView?
    myLayer = [CALayer layer];
    myLayer.frame = CGRectMake(0,0,100,100);
    myLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    myLayer.name = @&quot;myLayer&quot;;
    myLayer.opacity = 1.0;
    myLayer.delegate = self;
    // masterLayer is a layer I made to contain mine. You could probably do [self.layer addSublayer:myLayer] if you wanted
    [masterLayer addSublayer:myLayer];
    

    In this case myLayer would be declared in the header file of the UIView
    @interface myView : UIView  {
        CALayer *masterLayer; // if desired. I used this to contain all my sublayers
        CALayer *myLayer;
    }
    

    Anyway, once you've gotten them all added as subLayers they should have a retain count greater than 0, and should not disappear on you.

    Post more code if you are stuck beyond this... :)
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    Thank you....well where exatly shall I create these layers?

    I have a viewcontroller which does this
    CALayer *LayerDreieck1;
    	// create the layer and set the bounds and position
    	LayerDreieck1 =  [CALayer layer];
    	LayerDreieck1.position=CGPointMake(50.0f,50.0f);
    	LayerDreieck1.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f);
    	LayerDreieck1.name = @&quot;LayerDreieck1&quot;;
    	[(GameView *)self.view prepareDrawLayer:LayerDreieck1];
    

    It is inside the viewdidload method.

    It has somehow to be inside the viewcontorller not the UIView subclass because the viewcontroller gets the current position of the triangle and then sets the layout position to it.

    If I do this creating inside the init method of my view, how do I update then the values....


    EDIT:

    Here you see my UIView called GameView.m
    - (id)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
    		//Points = [[NSArray alloc] init];
    		myLayer = [CALayer layer];
    		myLayer.frame = CGRectMake(0,0,100,100);
    		myLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    		myLayer.name = @&quot;myLayer&quot;;
    		myLayer.opacity = 1.0;
    		myLayer.delegate = self;
    		// masterLayer is a layer I made to contain mine. You could probably do [self.layer addSublayer:myLayer] if you wanted
    		[masterLayer addSublayer:myLayer];
        }
        return self;
    }
    
    
    - (void)drawDreieck1:(CGContextRef)aContext
    {
    	NSLog(@&quot;inside&quot;);
    	CGContextBeginPath (aContext); 
    	
    	CGContextMoveToPoint (aContext, 50.0, 0.9); 
    	CGContextAddLineToPoint (aContext, 0.0, 50.0);
    	CGContextAddLineToPoint (aContext, 100.0, 50.0);
    	CGContextClosePath (aContext); 
    	[[UIColor redColor] setFill]; 
    	CGContextSetStrokeColorWithColor(aContext, dreieck.color);
    	CGContextDrawPath (aContext, kCGPathFillStroke);
    }
    
    - (void)prepareDrawLayer:(int)layerNumber {
    	if (layerNumber == 1) {
    		NSLog(@&quot;here&quot;);
    		[masterLayer setNeedsDisplay];
    		[myLayer setNeedsDisplay];
    	}
    
    }
    - (void)drawLayer:(CALayer *)theLayer
            inContext:(CGContextRef)context
    {
    		NSLog(@&quot;drawLayerPrep %@&quot;, theLayer.name);
    		if (theLayer.name==@&quot;myLayer&quot;) {
    		[self drawDreieck1:context];
    	}
    	
    	
    }
    

    Once again I get drawLayerPrep: (null) as a result for the last Log
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Kroupy wrote: »
    Thank you....well where exatly shall I create these layers?

    I have a viewcontroller which does this
    CALayer *LayerDreieck1;
    	// create the layer and set the bounds and position
    	LayerDreieck1 =  [CALayer layer];
    	LayerDreieck1.position=CGPointMake(50.0f,50.0f);
    	LayerDreieck1.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f);
    	LayerDreieck1.name = @&quot;LayerDreieck1&quot;;
    	[(GameView *)self.view prepareDrawLayer:LayerDreieck1];
    

    It is inside the viewdidload method.

    It has somehow to be inside the viewcontorller not the UIView subclass because the viewcontroller gets the current position of the triangle and then sets the layout position to it.

    If I do this creating inside the init method of my view, how do I update then the values....


    EDIT:

    Here you see my UIView called GameView.m
    - (id)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
    		//Points = [[NSArray alloc] init];
    		myLayer = [CALayer layer];
    		myLayer.frame = CGRectMake(0,0,100,100);
    		myLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    		myLayer.name = @&quot;myLayer&quot;;
    		myLayer.opacity = 1.0;
    		myLayer.delegate = self;
    		// masterLayer is a layer I made to contain mine. You could probably do [self.layer addSublayer:myLayer] if you wanted
    		[masterLayer addSublayer:myLayer];
        }
        return self;
    }
    
    
    - (void)drawDreieck1:(CGContextRef)aContext
    {
    	NSLog(@&quot;inside&quot;);
    	CGContextBeginPath (aContext); 
    	
    	CGContextMoveToPoint (aContext, 50.0, 0.9); 
    	CGContextAddLineToPoint (aContext, 0.0, 50.0);
    	CGContextAddLineToPoint (aContext, 100.0, 50.0);
    	CGContextClosePath (aContext); 
    	[[UIColor redColor] setFill]; 
    	CGContextSetStrokeColorWithColor(aContext, dreieck.color);
    	CGContextDrawPath (aContext, kCGPathFillStroke);
    }
    
    - (void)prepareDrawLayer:(int)layerNumber {
    	if (layerNumber == 1) {
    		NSLog(@&quot;here&quot;);
    		[masterLayer setNeedsDisplay];
    		[myLayer setNeedsDisplay];
    	}
    
    }
    - (void)drawLayer:(CALayer *)theLayer
            inContext:(CGContextRef)context
    {
    		NSLog(@&quot;drawLayerPrep %@&quot;, theLayer.name);
    		if (theLayer.name==@&quot;myLayer&quot;) {
    		[self drawDreieck1:context];
    	}
    	
    	
    }
    

    Once again I get drawLayerPrep: (null) as a result for the last Log

    So you have adapted part of what I showed you. Since you used masterLayer... where did you create that? It needs to be built up and added as a subLayer to the UIView's layer if you want it to show on screen and act as a container for further subLayers like myLayer...

    Basically you're creating myLayer and chucking it in the garbage right now. :D

    Did you declare masterLayer and myLayer in your header file too, as I did?
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    yes I did and no I didn't create master layer. I suppose masterlayer has to have the full size of the screen?...

    EDIT:

    could you explain this a bit further

    " It needs to be built up and added as a subLayer to the UIView's layer if you want it to show on screen and act as a container for further subLayers like myLayer..."

    I created it the way mylayer is created. But how do I add it like a sublayer to UIViews layer?

    EDIT2:

    Did this now:
    myLayer = [CALayer layer];
    		myLayer.frame = CGRectMake(0,0,100,100);
    		myLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    		myLayer.name = @&quot;myLayer&quot;;
    		myLayer.opacity = 1.0;
    		myLayer.delegate = self;
    		masterLayer = [CALayer layer];
    		masterLayer.frame = CGRectMake(0,0,320,480);
    		masterLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    		masterLayer.name = @&quot;myLayer&quot;;
    		masterLayer.opacity = 1.0;
    		masterLayer.delegate = self;
    		[self.layer addSublayer:masterLayer];
    		// masterLayer is a layer I made to contain mine. You could probably do [self.layer addSublayer:myLayer] if you wanted
    		[masterLayer addSublayer:myLayer];
    
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Another thought... you say your triangle position is known in the viewcontroller? Why? Is that where you are handling touches? If so, why not move the touch handling into the UIView that is being used to draw all this stuff. I do all my touch processing that way. It makes it easier to have different UIViews each with their own ways to interpret touches.
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
  • KroupyKroupy Posts: 269Registered Users @ @
    edited April 2009
    it IS handled by the UIView, the touches at least. But the gravity is calculated and the position of the ball also is done by their own classes, ball.m and triangle.m

    I posted my masterlayer creation in my old post above, please check this if you'd be so nice. Thank you!
  • CommanderDataCommanderData Posts: 486Registered Users
    edited April 2009
    Kroupy wrote: »
    yes I did and no I didn't create master layer. I suppose masterlayer has to have the full size of the screen?...

    EDIT:

    could you explain this a bit further

    " It needs to be built up and added as a subLayer to the UIView's layer if you want it to show on screen and act as a container for further subLayers like myLayer..."

    I created it the way mylayer is created. But how do I add it like a sublayer to UIViews layer?

    EDIT2:

    Did this now:
    myLayer = [CALayer layer];
    		myLayer.frame = CGRectMake(0,0,100,100);
    		myLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    		myLayer.name = @&quot;myLayer&quot;;
    		myLayer.opacity = 1.0;
    		myLayer.delegate = self;
    		masterLayer = [CALayer layer];
    		masterLayer.frame = CGRectMake(0,0,100,100);
    		masterLayer.position = CGPointMake((320/2),(480/2)); // Center of portrait screen, as an example
    		masterLayer.name = @&quot;myLayer&quot;;
    		masterLayer.opacity = 1.0;
    		masterLayer.delegate = self;
    		[self.layer addSublayer:masterLayer];
    		// masterLayer is a layer I made to contain mine. You could probably do [self.layer addSublayer:myLayer] if you wanted
    		[masterLayer addSublayer:myLayer];
    


    OK, I can see you have a lot more problems than I probably have time to address today since I need to prepare for a trip... I might be able to pop back once or twice to check but you've definitely got a lot more reading and learning to do. Don't just take what I give you and force it into your app because I'm just tossing out generic ideas, not completed products. The idea is to teach a man to fish as they say ;)

    A few more thoughts: Your master layer should be the entire viewable area. If you're in portrait that is 320x480. Landscape is 480x320. Right now you're making a 100x100 master layer (the same size as this dummy myLayer demo I gave you) and placing them both in the center of a portrait oriented screen, with myLayer inside Masterlayer, which is then put inside the UIView's main and only layer. I assume that if you want to move stuff around inside Masterlayer you want it's size and position to be such that it fills the bounds of the screen.

    Your ball and triangle classes will need to provide info in a way that you can reach it from within your UIView if you want this to work. Maybe use the AppDelegate to get at the calculated values. Or whatever you need to do. Just get everything you need handy to draw this correctly in where it can be accessed by the UView and its methods you are making for the draw. There should be plenty of threads around here about making things globally accessible inside your app :)

    Last thoughts... don't be afraid of Apple's docs. Nobody taught me any of this stuff, I had to just read through their docs and visualize what I wanted to accomplish. I'll check in later, I really hope you can make some progress! :D
    ChronoSoft - <a href="http://www.ChronoSoft.com"; target="_blank">Rogue Touch</a> Available now in the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303471870&mt=8"; target="_blank">App Store</a>! ... Version 1.5 available n
«1
Sign In or Register to comment.