繁体   English   中英

可可画板/网格

[英]Drawing board/grid with Cocoa

我正在使用Cocoa为Mac OS X编写小型桌面游戏。 我实际的网格绘制如下:

- (void)drawRect:(NSRect)rect
{
    for (int x=0; x < GRIDSIZE; x++) {
        for (int y=0; y < GRIDSIZE; y++) {          

            float ix = x*cellWidth;
            float iy = y*cellHeight;

            NSColor *color = (x % 2 == y % 2) ? boardColors[0] : boardColors[1];
            [color set];

            NSRect r = NSMakeRect(ix, iy, cellWidth, cellHeight);

            NSBezierPath *path = [NSBezierPath bezierPath];
            [path appendBezierPathWithRect:r];

            [path fill];
            [path stroke];  
        }
    }   
}

效果很好,除了我看到磁贴之间的颜色有些错误。 我猜这是由于某些抗锯齿或类似原因。 请参阅下面的屏幕截图(希望您也可以看到相同的问题...在瓷砖重叠处出现一些黑线):

渲染板

因此,我有以下问题:

  1. 在保持可调整大小/可缩放的电路板的同时,有什么方法可以消除这些图形瑕疵?
  2. 我是否应该使用其他图形库,例如Core Graphics或OpenGL?

更新:

const int GRIDSIZE = 16;
cellWidth = (frame.size.width / GRIDSIZE);
cellHeight = (frame.size.height / GRIDSIZE);

如果要使用清晰的矩形,则需要对齐坐标,以使其与基础像素匹配。 NSView具有用于此目的的方法- (NSRect)backingAlignedRect:(NSRect)aRect options:(NSAlignmentOptions)options 这是绘制网格的完整示例:

const NSInteger GRIDSIZE = 16;

- (void)drawRect:(NSRect)dirtyRect {
    for (NSUInteger x = 0; x < GRIDSIZE; x++) {
        for (NSUInteger y = 0; y < GRIDSIZE; y++) {
            NSColor *color = (x % 2 == y % 2) ? [NSColor greenColor] : [NSColor redColor];
            [color set];
            [NSBezierPath fillRect:[self rectOfCellAtColumn:x row:y]];
        }
    }
}

- (NSRect)rectOfCellAtColumn:(NSUInteger)column row:(NSUInteger)row {
    NSRect frame = [self frame];
    CGFloat cellWidth = frame.size.width / GRIDSIZE;
    CGFloat cellHeight = frame.size.height / GRIDSIZE;
    CGFloat x = column * cellWidth;
    CGFloat y = row * cellHeight;
    NSRect rect = NSMakeRect(x, y, cellWidth, cellHeight);
    NSAlignmentOptions alignOpts = NSAlignMinXNearest | NSAlignMinYNearest |
            NSAlignMaxXNearest | NSAlignMaxYNearest ;
    return [self backingAlignedRect:rect options:alignOpts];
}

请注意,您无需stroke即可绘制游戏板。 要绘制像素对齐的笔划,您需要记住可可中的坐标实际上指向像素的左下角。 要使线条清晰,您需要将坐标从整数坐标偏移半个像素,以便坐标指向像素中心。 例如,要为网格单元格绘制清晰的边框,可以执行以下操作:

NSRect rect = NSInsetRect([self rectOfCellAtColumn:column row:row], 0.5, 0.5);
[NSBezierPath strokeRect:rect];

首先,请确保您的笔触颜色不是黑色或灰色。 (您正在设置color但是是笔触还是填充颜色?我记不起来了。)

其次,如果仅用绿色填充,然后在其上绘制红色方块,反之亦然,会发生什么?

还有其他方法可以做您想要的。 您可以使用CICheckerboardGenerator代替背景。

或者,您也可以使用CGBitmapContext填充的CGBitmapContext

首先,如果您实际上不希望矩形具有边框,则不应调用[path stroke]

其次,创建用于填充矩形的贝塞尔曲线路径是过大的。 您可以使用NSRectFill(r)进行相同的NSRectFill(r) 此功能可能更有效,并且我怀疑不太可能在浮点数上引入舍入误差–我假设您意识到,如果需要像素精确的矩形,则浮点数不得包含小数部分。 我相信,如果视图的宽度和高度是GRIDSIZE的倍数,并且您使用NSRectFill ,那么工件应该消失了。

第三,如果视图的宽度和高度不是GRIDSIZE的倍数,则存在一个明显的问题,即如何绘制电路板。 如果视图的大小是固定的并且是该常数的倍数,那么这当然不是问题。 但是,如果不是这样,则首先必须澄清如何处理可能剩下的宽度或高度。 应该有边界吗? 行或列中的最后一个单元格是否应该占用其余部分? 还是应该在行或列的单元格之间平均分配它? 您可能必须接受宽度和/或高度不同的单元格。 解决问题的最佳解决方案取决于您的确切要求。

您可能还想研究其他绘制棋盘的方法,例如使用CICheckerboardGenerator或使用CICheckerboardGenerator创建图案颜色( [NSColor colorWithPatternImage:yourImage] ),然后用它填充整个视图。

还可能(暂时)关闭抗锯齿功能。 为此,将以下行添加到绘图方法的开头:

  [[NSGraphicsContext currentContext] setShouldAntialias:NO];

我的最后观察是关于您的一般方法。 如果您的游戏将具有更复杂的图形和动画,例如动画的棋子运动,那么使用OpenGL可能会更好。

您的方块重叠。 ix + CELLWIDTH在循环的下一次迭代中与ix相同。

您可以通过将笔触颜色显式设置为透明或不调用stroke来解决此问题。

[color set];
[[NSColor clearColor] setStroke];

要么

[path fill];
// not [path stroke];

从iOS 6开始,您可以使用CICheckerboardGenerator生成棋盘图案。

您将要在这里防范武力解散,但这是基本的实现:

var checkerboardImage: UIImage? {
    let filter = CIFilter(name: "CICheckerboardGenerator")!

    let width = NSNumber(value: Float(viewSize.width/16))
    let center = CIVector(cgPoint: .zero)
    let darkColor = CIColor.red
    let lightColor = CIColor.green
    let sharpness = NSNumber(value: 1.0)

    filter.setDefaults()
    filter.setValue(width, forKey: "inputWidth")
    filter.setValue(center, forKey: "inputCenter")
    filter.setValue(darkColor, forKey: "inputColor0")
    filter.setValue(lightColor, forKey: "inputColor1")
    filter.setValue(sharpness, forKey: "inputSharpness")

    let context = CIContext(options: nil)
    let cgImage = context.createCGImage(filter.outputImage!, from: viewSize)
    let uiImage = UIImage(cgImage: cgImage!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.up)

    return uiImage
}

苹果开发人员文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM