CGContext 不会立即更新
CGContext does not update immediately
问题:我有一个小游戏,您可以在其中将一张图片划到另一张图片上方。上面的图像在您抓挠的地方变得不可见。整个东西都放在 SpriteKit 视图中。问题是,在较弱的设备 (iPhone4) 上,只有当用户停止抓挠时,抓挠图像才会更新。
我假设图像只有在用户没有刮擦时才会更新,直到图像完全渲染和显示。
谁能建议一种立即看到划痕的更好方法。我知道刮擦会消耗很多性能,但我不介意它是否有点滞后。
这里是代码:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[_scratchImage drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 25.0f );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextSetBlendMode (UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextStrokePath(UIGraphicsGetCurrentContext());
_scratchImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_lastPoint = currentPoint;
SKTexture* scratchTexture = [SKTexture textureWithImage:_scratchImage];
_scratchSprite.texture = scratchTexture;
}
更新
我最终记录了正确答案中建议的要点。但除了在 CADisplayLink 回调中更新图像外,我在
中更新了屏幕
-(void)update(float currentTime)
来自 SpriteKit 的回调(对于 SpriteKit 用例有点相同)
更新方法中的代码如下所示:
-(void)displayUpdated
{
UIGraphicsBeginImageContext(self.view.frame.size);
[_scratchImage drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGMutablePathRef linePath = nil;
linePath = CGPathCreateMutable();
CGPathMoveToPoint(linePath, NULL, _lastPoint.x, _lastPoint.y);
for (NSValue* val in _recordedPoints) {
CGPoint p = [val CGPointValue];
CGPathAddLineToPoint(linePath, NULL, p.x, p.y);
NSLog(@"%f, %f", p.x, p.y);
_lastPoint = p;
}
//flush array
[_recordedPoints removeAllObjects];
CGContextAddPath(UIGraphicsGetCurrentContext(), linePath);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 25.0f );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextSetBlendMode (UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextStrokePath(UIGraphicsGetCurrentContext());
_scratchImage = UIGraphicsGetImageFromCurrentImageContext();
CGPathRelease(linePath);
UIGraphicsEndImageContext();
SKTexture* scratchTexture = [SKTexture textureWithImage:_scratchImage];
_scratchSprite.texture = scratchTexture;
}
一个更高效的代码也会包含对上下文的引用,但我无法让它工作。如果有人可以提出解决方案,我会很高兴。尽管如此,我在 iPhone 4 上的帧率从大约 5 fps 上升到 25-30 fps。
我对SpriteKit了解不多,在UIView中,你应该把绘图代码放在drawRect方法中。和 SpriteKit 一样吗?
我会尝试以下方法:
- 测量 Instruments.app Time Profiler.
- 通过创建 CGBitmapContext 作为实例变量来加快绘图速度。然后你可以跳过每个步骤中的
[_scratchImage drawInRect:...]
。
- 将绘图和事件处理分开。现在,您将始终为每个触摸事件创建一个新的
UIImage
。合并描边线可能会更好,这样 UIImage
的创建就不会经常发生。例如。将线段放入队列中并从 CADisplayLink. 中绘制回调
问题:我有一个小游戏,您可以在其中将一张图片划到另一张图片上方。上面的图像在您抓挠的地方变得不可见。整个东西都放在 SpriteKit 视图中。问题是,在较弱的设备 (iPhone4) 上,只有当用户停止抓挠时,抓挠图像才会更新。
我假设图像只有在用户没有刮擦时才会更新,直到图像完全渲染和显示。
谁能建议一种立即看到划痕的更好方法。我知道刮擦会消耗很多性能,但我不介意它是否有点滞后。
这里是代码:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[_scratchImage drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 25.0f );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextSetBlendMode (UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextStrokePath(UIGraphicsGetCurrentContext());
_scratchImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_lastPoint = currentPoint;
SKTexture* scratchTexture = [SKTexture textureWithImage:_scratchImage];
_scratchSprite.texture = scratchTexture;
}
更新
我最终记录了正确答案中建议的要点。但除了在 CADisplayLink 回调中更新图像外,我在
中更新了屏幕-(void)update(float currentTime)
来自 SpriteKit 的回调(对于 SpriteKit 用例有点相同)
更新方法中的代码如下所示:
-(void)displayUpdated
{
UIGraphicsBeginImageContext(self.view.frame.size);
[_scratchImage drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGMutablePathRef linePath = nil;
linePath = CGPathCreateMutable();
CGPathMoveToPoint(linePath, NULL, _lastPoint.x, _lastPoint.y);
for (NSValue* val in _recordedPoints) {
CGPoint p = [val CGPointValue];
CGPathAddLineToPoint(linePath, NULL, p.x, p.y);
NSLog(@"%f, %f", p.x, p.y);
_lastPoint = p;
}
//flush array
[_recordedPoints removeAllObjects];
CGContextAddPath(UIGraphicsGetCurrentContext(), linePath);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 25.0f );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextSetBlendMode (UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextStrokePath(UIGraphicsGetCurrentContext());
_scratchImage = UIGraphicsGetImageFromCurrentImageContext();
CGPathRelease(linePath);
UIGraphicsEndImageContext();
SKTexture* scratchTexture = [SKTexture textureWithImage:_scratchImage];
_scratchSprite.texture = scratchTexture;
}
一个更高效的代码也会包含对上下文的引用,但我无法让它工作。如果有人可以提出解决方案,我会很高兴。尽管如此,我在 iPhone 4 上的帧率从大约 5 fps 上升到 25-30 fps。
我对SpriteKit了解不多,在UIView中,你应该把绘图代码放在drawRect方法中。和 SpriteKit 一样吗?
我会尝试以下方法:
- 测量 Instruments.app Time Profiler.
- 通过创建 CGBitmapContext 作为实例变量来加快绘图速度。然后你可以跳过每个步骤中的
[_scratchImage drawInRect:...]
。 - 将绘图和事件处理分开。现在,您将始终为每个触摸事件创建一个新的
UIImage
。合并描边线可能会更好,这样UIImage
的创建就不会经常发生。例如。将线段放入队列中并从 CADisplayLink. 中绘制回调