0

我正在使用 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);
4

5 回答 5

8

如果您想要清晰的矩形,您需要对齐坐标,以便它们与底层像素匹配。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绘制游戏板。要绘制像素对齐的笔划,您需要记住 Cocoa 中的坐标实际上指向像素的左下角。要使线条清晰,您需要将坐标从积分坐标偏移半个像素,以便坐标指向像素中心。例如,要为网格单元绘制清晰的边框,您可以这样做:

NSRect rect = NSInsetRect([self rectOfCellAtColumn:column row:row], 0.5, 0.5);
[NSBezierPath strokeRect:rect];
于 2013-08-29T17:58:09.693 回答
3

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

其次,如果你只是用绿色填充,然后在上面画红色方块,或者反之亦然,会发生什么?

还有其他方法可以做你想做的事。您可以使用CICheckerboardGenerator来制作背景。

或者,您也可以使用CGBitmapContext手动填写的。

于 2013-08-22T04:15:35.507 回答
3

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

其次,创建一个填充矩形的贝塞尔路径是多余的。您可以对NSRectFill(r). 这个函数可能更有效,我怀疑你的浮点数不太容易引入舍入错误——我假设你意识到如果你想要像素精确的矩形,你的浮点数不能有小数部分。我相信,如果您的视图的宽度和高度是 的倍数GRIDSIZE并且您使用NSRectFill,那么伪影应该会消失。

第三,如果视图的宽度和高度不是GRIDSIZE. 如果您的视图大小是固定的并且是该常数的倍数,这当然不是问题。但是,如果不是,您首先必须澄清您希望如何处理可能的剩余宽度或高度。应该有边界吗?行或列中的最后一个单元格是否应该占据剩余部分?还是应该在行或列的单元格中平均分配?您可能必须接受不同宽度和/或高度的单元格。您的问题的最佳解决方案是什么,取决于您的确切要求。

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

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

  [[NSGraphicsContext currentContext] setShouldAntialias:NO];

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

于 2013-08-24T20:59:06.473 回答
2

从 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
}

苹果开发者文档

于 2018-11-30T21:54:23.687 回答
1

Your squares overlap. ix + CELLWIDTH is the same coordinate as ix in the next iteration of the loop.

You can fix this by setting the stroke color explicitly to transparent, or by not calling stroke.

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

or

[path fill];
// not [path stroke];
于 2013-08-23T13:48:13.547 回答