撤消位图状态(CGContext)

时间:2014-12-26 22:12:17

标签: objective-c bitmap core-graphics

我正在制作一个涉及画线的多人游戏。现在我正在尝试将在线多人游戏实施到游戏中。但是我做了一些努力。问题是,如果来自服务器的数据包迟到客户端,我将需要反转绘制线的状态。我在这里搜索堆栈溢出但没有找到任何真正的答案如何“撤消”位图上下文。最大的问题是绘图需要非常快,因为游戏每20毫秒更新一次。但是我想出了并尝试了一些不同的方法:

  1. 保存整个上下文的状态,然后重绘它。这可能是最慢的方法。
  2. 仅通过循环每个像素将一部分上下文(100x100)保存在另一个隐藏的位图中,然后将每个像素从该位图循环到屏幕上显示的主位图。
  3. 在CGMutablePath引用中保存绘制路径的每个点,然后在还原上下文时,使用透明颜色(0,0,0,0)绘制此路径。
  4. 保存在单独数组中绘制的每个像素的位图中的位置,然后在需要撤消时将该像素alpha设置为0(在绘制的位图中)。
  5. 最后一种方法应该是最快的方法。但是,我不知道如何获得每个绘制像素的位置,除非我完全手动操作。现在我使用这段代码绘制线条。

        CGContextSetStrokeColorWithColor(cacheContext, [color CGColor]);
        CGContextSetLineCap(cacheContext, kCGLineCapRound);
        CGContextSetLineWidth(cacheContext, 6+thickness);
    
        CGContextBeginPath(cacheContext);
    
        CGContextMoveToPoint(cacheContext, point1.x, point1.y);
        CGContextAddLineToPoint(cacheContext, point2.x, point2.y);
        CGContextStrokePath(cacheContext);
    
        CGRect dirtyPoint1 = CGRectMake(point1.x-10, point1.y-10, 20, 20);
        CGRect dirtyPoint2 = CGRectMake(point2.x-10, point2.y-10, 20, 20);
        [self setNeedsDisplayInRect:CGRectUnion(dirtyPoint1, dirtyPoint2)];
    

    以下是如何设置CGBitmapcontext

    - (BOOL) initContext:(CGSize)size {
    
        scaleFactor = [[UIScreen mainScreen] scale];
         // scaleFactor = 1;
        //non-retina
        // scalefactor = 2; retina
    
        int bitmapBytesPerRow;
    
        // Declare the number of bytes per row. Each pixel in the bitmap in this
        // example is represented by 4 bytes; 8 bits each of red, green, blue, and
        // alpha.
        bitmapBytesPerRow = (size.width * 4*scaleFactor);
        bitmapByteCount = (bitmapBytesPerRow * (size.height*scaleFactor));
    
        // Allocate memory for image data. This is the destination in memory
        // where any drawing to the bitmap context will be rendered.
        cacheBitmap = malloc( bitmapByteCount );
        if (cacheBitmap == NULL){
            return NO;
        }
    
        CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little;
        colorSpace = CGColorSpaceCreateDeviceRGB();
    
        cacheContext = CGBitmapContextCreate (cacheBitmap, size.width*scaleFactor, size.height *scaleFactor, 8, bitmapBytesPerRow, colorSpace, bitmapInfo);
    
        CGContextScaleCTM(cacheContext, scaleFactor, scaleFactor);
    
        CGColorSpaceRelease(colorSpace);
    
        CGContextSetRGBFillColor(cacheContext, 0, 0, 0, 0.0);
        CGContextFillRect(cacheContext, (CGRect){CGPointZero, CGSizeMake(size.height*scaleFactor, size.width*scaleFactor)});
    
        return YES;
    }
    

    还有其他更好的撤消位图的方法吗?如果没有,我如何获得每个像素的位置与核心图形绘制?这甚至可能吗?

1 个答案:

答案 0 :(得分:0)

您的第4种方法将复制整个画布位图(如果您考虑平坦的NxM矩阵表示)或者在基于地图的结构或类似情况下导致性能混乱。

实际上,我相信第二种方法可以解决问题。在过去的几年里,我已经实现了几次撤消的方式,包括一个基于DirectX的绘图应用程序,其中包含大约25-30fps的渲染管道。

然而,你的#2描述有一些奇怪的提及" loop"你想在整个地区表演。你不需要循环,你需要的是一个适当的API方法来复制位图/图形上下文的一部分,它可能是CGContextDrawImage用于保存画布部分和相同的方法来撤消/重做绘图。