我正在使用Quartz 2D制作一款简单的多点触控绘图iPad游戏。游戏要求我每隔1/30秒在手指位置画一个新笔画。
据我所知,基本上没有办法让drawRect()在每次调用时都不清除上下文(self.clearsContextBeforeDrawing = NO;不起作用),所以我的解决方案是创建一个后台缓冲区位图(或图层,我可以使用两者),每个手指每次迭代都会将每个新的小笔划绘制到该缓冲区中,然后每次调用drawRect()时将缓冲区复制到屏幕中。换句话说:
backlayer = CGLayerCreateWithContext(context, CGSizeMake(W, H), NULL);
offctx = CGLayerGetContext (backlayer);
然后
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
//code here to draw small strokes from old finger position to new one
CGContextDrawLayerInRect(context, [self bounds], backlayer);
}
当我在iPad 2上进行测试时,这没有问题,但是昨天我注意到在新的iPad 3上相同的代码运行得慢得多。性能非常糟糕,我的游戏速度从30FPS减慢到大约5左右,可能是由于视网膜显示较大。我有同样的问题,如果我使用我创建的单独的CGBitmapContext,然后每次迭代我从它创建一个ImageRef并使用CGContextDrawImage绘制它。
我可以采取什么方法来解决这个问题?似乎我必须在每次迭代时重新绘制所有内容,因为它甚至不能通过一个小的矩形来绘制更改的内容(因为每次迭代都需要为每个手指设置几个矩形)
谢谢
答案 0 :(得分:2)
我设法解决了这个问题:
我创建了一个新的UIView子类标头和实现文件:
@interface fingerView : UIView {
}
然后在我的主视图中,在标题中我声明了其中5个视图:
fingerView* fview[5];
在我的主视图实现中,我创建了这个实例的5个视图,每个视图分别对应一个。此外,必须确保制作它们,为每个它们启用多点触控,并确保将clearsContextBeforeDrawing设置为NO,因为我们将一次更新每个中的微小rects,我们不希望系统清除我们的工作
for(int i=0;i<5;i++) {
fview[i] = [[pView alloc] initWithFrame:topFrame];
[self addSubview: fview[i]];
[self sendSubviewToBack: fview[i]];
fview[i].opaque= NO;
fview[i].clearsContextBeforeDrawing = NO;
fview[i].multipleTouchEnabled = YES;
}
现在,在每个手指视图中,保留一个大数组(我使用一个简单的数组,比如10,000长)的手指所绘制的x和y位置。每当手指移动时,主视图就会检测到它,然后调用[fview [i] updatePos(newx,newy)],关键的是,我们将命令视图仅在这些坐标周围更新一小部分:
[fview[i] setNeedsDisplayInRect: fingerRect];
其中fingerRect是一个以(newx,newy)为中心的小矩形。在每个手指视图的drawRect方法内,
- (void)drawRect:(CGRect)rect
{
if (movep==0) return;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, r, g, b, 1);
CGContextSetLineWidth(context, linewidth);
//paint finger
CGContextBeginPath(context);
CGFloat slack= 15;
CGFloat minx= CGRectGetMinX(rect)-slack;
CGFloat maxx= CGRectGetMaxX(rect)+slack;
CGFloat miny= CGRectGetMinY(rect)-slack;
CGFloat maxy= CGRectGetMaxY(rect)+slack;
bool drawing = NO;
for(int i=0;i<movep;i++) {
CGFloat xx= x[i];
CGFloat yy= y[i];
if(xx>minx && xx<maxx && yy>miny && yy<maxy) {
if(drawing) {
// continue line
CGContextAddLineToPoint(context, xx, yy);
CGContextMoveToPoint(context, xx, yy);
} else {
// start drawing
CGContextMoveToPoint(context, xx, yy);
drawing= YES;
}
} else {
drawing= NO;
}
}
CGContextStrokePath(context);
并且,正如我所提到的那样
- (void)updatePos: (CGFloat)xnew: (CGFloat) ynew
{
x[movep]= xnew;
y[movep]= ynew;
movep= movep+1;
希望你能弄明白这是如何运作的。每个视图都会查看已经修改过的这个矩形,并检查围绕该矩形的所有手指位置,并仅绘制那些。这将归结为非常少的笔画,因此整个代码运行得非常快。
总的来说,UIViews是非常优化的。尽可能地尝试制作一大堆它们,如果有的话,只在本地更新它们,并让Apple的魔法将它们融合在一起。