绘图板/网格与可可

时间:2013-08-20 20:53:08

标签: objective-c cocoa 2d

我正在使用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];  
        }
    }   
}

这很好用,除了我看到瓷砖之间的颜色有些错误。我想这是由于一些抗锯齿或类似的。请参阅下面的屏幕截图(希望您也可以看到相同的问题......其中一些黑色线条与瓷砖重叠):

rendered board

因此我有以下问题:

  1. 在保持可调整大小/可扩展的电路板的同时,有什么方法可以删除这些图形文物吗?
  2. 我是否应该使用其他图形库,如Core Graphics或OpenGL?
  3. 更新

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

5 个答案:

答案 0 :(得分: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];

答案 1 :(得分:3)

首先,确保您的笔触颜色不是黑色或灰色。 (你正在设置color但是是中风还是填充颜色?我永远不会记得。)

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

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

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

答案 2 :(得分:3)

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

其次,创建填充矩形的bezier路径是过度的。您可以使用NSRectFill(r)执行相同的操作。这个函数可能更有效率,我怀疑不太容易为你的浮点数引入舍入错误 - 我假设你意识到如果你想要像素精确的矩形,你的浮点数不能有一个小数部分。我相信如果您的视图的宽度和高度是GRIDSIZE的倍数并且您使用NSRectFill,那么工件应该消失。

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

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

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

  [[NSGraphicsContext currentContext] setShouldAntialias:NO];

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

答案 3 :(得分:1)

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

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

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

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

答案 4 :(得分:1)

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

Apple Developer Docs